Android前置后置摄像头录制视频综合版

公司有个项目,有一个需求是录制视频上传到网上,原本准备使用系统的录制功能,发现界面的跳转不能满足需求。于是就只能用自己写的,然后我也不会,就找了很多网上的例子,发现总是有些问题,然后我总结了一下写成了一个工具类,现在分享出来。

import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List;  import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.hardware.Camera; import android.hardware.Camera.AutoFocusCallback; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; import android.media.MediaRecorder; import android.text.TextUtils; import android.util.Log; import android.view.OrientationEventListener; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.RelativeLayout; import android.widget.Toast;  import com.vomont.fileloadsdk.ACache;  /**  * 用于录制视频的工具类  *  * @author 街角慢嗨  * @email 773675907@qq.com  * @time 2017-04-21  */ @SuppressWarnings({
   "unused", "deprecation"})
public class MediaRecorderUtil {

    private MediaRecorder mediaRecorder;   // 录像camera  private Camera camera;   // 用于判断前置摄像头还是后置摄像头  private int cameraPosition = 1;   // 判断前置摄像头 还是后置  private boolean isCheck;   private SurfaceHolder.Callback callback;   // 上下文  private Context context;   // 容器  private SurfaceView surfaceView;   private String filePath;   OrientationEventListener orientationEventListener;   boolean flagRecord = false;// 是否正在录像   int rotationFlag = 90;   int rotationRecord = 90;   int frontRotate;   int frontOri;   int camaraType = 0;   Activity activity;   private int m, n;   /**  * 旋转界面UI  */  private void rotationUIListener() {
        orientationEventListener = new OrientationEventListener(context) {
            @Override  public void onOrientationChanged(int rotation) {
                if (!flagRecord) {
                    if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) {
                        // 竖屏拍摄  if (rotationFlag != 0) {
                            // 旋转logo  // rotationAnimation(rotationFlag, 0);  // 这是竖屏视频需要的角度  rotationRecord = 90;  // 这是记录当前角度的flag  rotationFlag = 0;  }
                    } else if (((rotation >= 230) && (rotation <= 310))) {
                        // 横屏拍摄  if (rotationFlag != 90) {
                            // 旋转logo  // rotationAnimation(rotationFlag, 90);  // 这是正横屏视频需要的角度  rotationRecord = 0;  // 这是记录当前角度的flag  rotationFlag = 90;  }
                    } else if (rotation > 30 && rotation < 95) {
                        // 反横屏拍摄  if (rotationFlag != 270) {
                            // 旋转logo  // rotationAnimation(rotationFlag, 270);  // 这是反横屏视频需要的角度  rotationRecord = 180;  // 这是记录当前角度的flag  rotationFlag = 270;  }
                    }
                }
            }
        };  orientationEventListener.enable();  }

    /**  * 创建录制环境  * <p>  * 需要用到的surfaceview  *  * @param context 上下文  */  public void create(RelativeLayout relativeLayout, final Context context, Activity activity) {
        this.context = context;  this.activity = activity;  relativeLayout.removeAllViews();  surfaceView = new SurfaceView(context);  relativeLayout.addView(surfaceView); // this.surfaceView = surfaceView;  surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  surfaceView.setKeepScreenOn(true);  callback = new SurfaceHolder.Callback() {
            // 在控件创建的时候,进行相应的初始化工作  public void surfaceCreated(SurfaceHolder holder) {
                // 打开相机,同时进行各种控件的初始化mediaRecord等  if (camera != null) {
                    camera.stopPreview();  camera.release();  camera = null;  }
                try {
                    camera = Camera.open();  } catch (Exception e) {
                    Toast.makeText(context, "没有权限,请打开录像权限!", Toast.LENGTH_SHORT).show();  return;  }

                mediaRecorder = new MediaRecorder();  }

            // 当控件发生变化的时候调用,进行surfaceView和camera进行绑定,可以进行画面的显示  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                doChange(surfaceView.getHolder());  }

            @Override  public void surfaceDestroyed(SurfaceHolder holder) {
                holder.removeCallback(this);  if (camera != null) {
                    camera.stopPreview();  camera.release();  camera = null;  }
            }
        };    // 为SurfaceView设置回调函数  surfaceView.getHolder().addCallback(callback);  rotationUIListener();  }

    // 当我们的程序开始运行,即使我们没有开始录制视频,我们的surFaceView中也要显示当前摄像头显示的内容  private void doChange(SurfaceHolder holder) {
        try {
            if (camera != null) {
                Camera.Parameters parameters = camera.getParameters();  m = getCloselyPreSize(surfaceView.getWidth(), surfaceView.getHeight(), parameters.getSupportedPreviewSizes()).width;  n = getCloselyPreSize(surfaceView.getWidth(), surfaceView.getHeight(), parameters.getSupportedPreviewSizes()).height;  if (camaraType == 0) {
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦  camera.cancelAutoFocus();// 2如果要实现连续的自动对焦,这一句必须加上  }
                if (rotationRecord == 90) {
                    parameters.setPreviewSize(getCloselyPreSize(surfaceView.getWidth(), surfaceView.getHeight(), parameters.getSupportedPreviewSizes()).width,  getCloselyPreSize(surfaceView.getWidth(), surfaceView.getHeight(), parameters.getSupportedPreviewSizes()).height);  }
                camera.setParameters(parameters);  camera.setPreviewDisplay(holder);  // 设置surfaceView旋转的角度,系统默认的录制是横向的画面,把这句话注释掉运行你就会发现这行代码的作用  if (camaraType == 1) {
                    frontCameraRotate();  camera.setDisplayOrientation(frontRotate);  } else {
                    camera.setDisplayOrientation(90);  }
                camera.startPreview();  }
        } catch (IOException e) {
            e.printStackTrace();  }
    }

    /**  * 旋转前置摄像头为正的  */  private void frontCameraRotate() {
        Camera.CameraInfo info = new Camera.CameraInfo();  Camera.getCameraInfo(1, info);  int degrees = getDisplayRotation(activity);  int result;  if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;  result = (360 - result) % 360; // compensate the mirror  } else { // back-facing  result = (info.orientation - degrees + 360) % 360;  }
        frontOri = info.orientation;  frontRotate = result;  }

    /**  * 获取旋转角度  */  private int getDisplayRotation(Activity activity) {
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();  switch (rotation) {
            case Surface.ROTATION_0:
                return 0;  case Surface.ROTATION_90:
                return 90;  case Surface.ROTATION_180:
                return 180;  case Surface.ROTATION_270:
                return 270;  }
        return 0;  }

    /**  * 切换摄像头  */  public void changeCamara() {
        // 切换前后摄像头  int cameraCount = 0;  CameraInfo cameraInfo = new CameraInfo();  cameraCount = Camera.getNumberOfCameras();// 得到摄像头的个数  for (int i = 0; i < cameraCount; i++) {
            Camera.getCameraInfo(i, cameraInfo);// 得到每一个摄像头的信息  if (cameraPosition == 1) {
                // 现在是后置,变更为前置  if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
   // 代表摄像头的方位,CAMERA_FACING_FRONT前置  // CAMERA_FACING_BACK后置  camera.stopPreview();// 停掉原来摄像头的预览  camera.release();// 释放资源  camera = null;// 取消原来摄像头  frontCameraRotate();// 前置旋转摄像头度数  camera = Camera.open(i);// 打开当前选中的摄像头  camaraType = i;  try {
                        camera.setPreviewDisplay(surfaceView.getHolder());// 通过surfaceview显示取景画面  camera.setDisplayOrientation(frontRotate);  } catch (IOException e) {
                        e.printStackTrace();  }
                    camera.startPreview();// 开始预览  cameraPosition = 0;  isCheck = true;  break;  }
            } else {
                // 现在是前置, 变更为后置  if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
   // 代表摄像头的方位,CAMERA_FACING_FRONT前置  // CAMERA_FACING_BACK后置  camera.stopPreview();// 停掉原来摄像头的预览  camera.release();// 释放资源  camera = null;// 取消原来摄像头  camera = Camera.open(i);// 打开当前选中的摄像头  camaraType = i;  cameraPosition = 1;  isCheck = false;  doChange(surfaceView.getHolder());  break;  }
            }
        }
    }

    /**  * 停止录制  */  public void stopRecord() {
        // 当结束录制之后,就将当前的资源都释放  if (mediaRecorder != null) {
            mediaRecorder.release();  }
        if (camera != null) {
            camera.stopPreview();  camera.release();  }
        camera = null;  mediaRecorder = null;  }

    /**  * 重新开始的初始化方法  */  public void resCreate() {
        deleteFile(filePath);  if (cameraPosition == 0) {
            camera = Camera.open(1);  isCheck = true;  camaraType = 1;  } else {
            camera = Camera.open(0);  camaraType = 0;  isCheck = false;  }
        // // 然后再重新初始化所有的必须的控件和对象   mediaRecorder = new MediaRecorder();  doChange(surfaceView.getHolder());  }

    /**  * 打开闪光灯的接口  */  @SuppressLint("NewApi")
    public void openMode(boolean isOpen) {
        Camera.Parameters p = camera.getParameters();  if (isOpen) {
            p.setFlashMode(Parameters.FLASH_MODE_TORCH);  } else {
            p.setFlashMode(Parameters.FLASH_MODE_OFF);  }
        camera.setParameters(p);  }

    /**  * 视频镜头的伸缩  * 改变zoom值 改变视频的伸缩距离  *  * @param m 传入的值 不同手机支持的最大m不同  * @see [类、类#方法、类#成员]  */  @SuppressLint("NewApi")
    public void setZoom(int m) {
        Camera.Parameters p = camera.getParameters();  if (m <= 0) {
            p.setZoom(0);  } else if (m >= p.getMaxZoom()) {
            p.setZoom(p.getMaxZoom());  } else {
            p.setZoom(m);  }
        camera.setParameters(p);  }

    /**  * 是否支持视频镜头的伸缩  *  * @return  * @see [类、类#方法、类#成员]  */  public boolean isSupportZoom() {
        boolean isSuppport = true;  if (camera.getParameters().isSmoothZoomSupported()) {
            isSuppport = false;  }
        return isSuppport;  }

    /**  * 不同的手机最大伸缩的值不一样  *  * @return  * @see [类、类#方法、类#成员]  */  public int getMaxZoom() {
        if (camera != null) {
            Camera.Parameters p = camera.getParameters();  return p.getMaxZoom();  }
        return 0;  }

    /**  * 拍照  *  * @param callBack  * @return  * @see [类、类#方法、类#成员]  */  public boolean TakePicture(PictureCallback callBack) {
        if (null == camera) {
            return false;  }
        camera.takePicture(null, null, callBack);  return true;  }

    public void deleteVideo() {
        if (filePath != null) {
            File file = new File(filePath);  if (file != null && file.exists() && file.isDirectory()) {
                file.delete();  }
        }
    }

    public static void deleteFile(String filePaths) {
        File file = new File(filePaths);  if (file.exists() && file.isDirectory()) {
            file.delete();  }
    }

    /**  * 通过对比得到与宽高比最接近的尺寸(如果有相同尺寸,优先选择)  *  * @param surfaceWidth 需要被进行对比的原宽,surface view的宽度  * @param surfaceHeight 需要被进行对比的原高 surface view的高度  * @param preSizeList 得到的支持预览尺寸的list,parmeters.getSupportedPreviewSizes()  * 需要对比的预览尺寸列表  * @return 得到与原宽高比例最接近的尺寸  */  protected Camera.Size getCloselyPreSize(int surfaceWidth, int surfaceHeight, List<Size> preSizeList) {
        int ReqTmpWidth;  int ReqTmpHeight;  // 当屏幕为垂直的时候需要把宽高值进行调换,保证宽大于高  if (rotationRecord == 90) {
            ReqTmpWidth = surfaceHeight;  ReqTmpHeight = surfaceWidth;  } else {
            ReqTmpWidth = surfaceWidth;  ReqTmpHeight = surfaceHeight;  }
        // 先查找preview中是否存在与surfaceview相同宽高的尺寸  for (Camera.Size size : preSizeList) {
            if ((size.width == ReqTmpWidth) && (size.height == ReqTmpHeight)) {
                return size;  }
        }
        // 得到与传入的宽高比最接近的size  float reqRatio = ((float) ReqTmpWidth) / ReqTmpHeight;  float curRatio, deltaRatio;  float deltaRatioMin = Float.MAX_VALUE;  Camera.Size retSize = null;  for (Camera.Size size : preSizeList) {
            curRatio = ((float) size.width) / size.height;  deltaRatio = Math.abs(reqRatio - curRatio);  if (deltaRatio < deltaRatioMin) {
                deltaRatioMin = deltaRatio;  retSize = size;  }
        }
        return retSize;  }

    /**  * 开始录制  * @param path 录制保存的路径  * @param name 文件名称  */  public int startRecord(String path, String name) {
        // 先释放被占用的camera,在将其设置为mediaRecorder所用的camera  // 解锁并将摄像头指向MediaRecorder  if (camera != null)
            camera.unlock();  if (camera == null) {
            return 0;  }
        if (null == mediaRecorder) {
            Toast.makeText(context, "请打开录音权限!", Toast.LENGTH_SHORT).show();  return 0;  }
        mediaRecorder.setCamera(camera);  // 指定输入源  mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);  mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);  // mediaRecorder.setCamera(camera)如果不用这个方式 那么下面这句话可以加入用来设置视频清晰度的 不然会产生冲突  // 报错 我也不知道是为什么  // mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));  // 设置输出格式和编码格式  mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);  // 设置编码格式  mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);  mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);  // 根据缓存 选择视频的比特率 从而改变清晰度  ACache aCache = ACache.get(context);  String av = aCache.getAsString("videosetting");  if (!TextUtils.isEmpty(av)) {
            if (av.equals("0")) {
                // 如果只设置比特率 不设置分辨率 清晰度是没有用的  mediaRecorder.setVideoEncodingBitRate(56 * 8 * 1024);  // 改成 640*480可以通用 但其他的 有些分辨率 有些手机是不支持的,所以最好不要定死,而是根据你录像窗口的  // 的大小 选择一个最靠近的分辨率  // 另外 应为camera的parameters.setPreviewSize()设置了大小,所以如果不统一,录制出来的画面会有拉伸  // 所以两边的分辨率最好统一起来  mediaRecorder.setVideoSize(m, n);  } else if (av.equals("1")) {
                mediaRecorder.setVideoEncodingBitRate(84 * 8 * 1024);  mediaRecorder.setVideoSize(m, n);  } else {
                mediaRecorder.setVideoEncodingBitRate(256 * 8 * 1024);  mediaRecorder.setVideoSize(m, n);  }
        } else {
            mediaRecorder.setVideoEncodingBitRate(56 * 8 * 1024);  mediaRecorder.setVideoSize(m, n);  }
        int frontRotation;  if (rotationRecord == 180) {
            // 反向的前置  frontRotation = 180;  } else {
            // 正向的前置  frontRotation = (rotationRecord == 0) ? 270 - frontOri : frontOri; // 录制下来的视屏选择角度,此处为前置  }
        mediaRecorder.setOrientationHint((camaraType == 1) ? frontRotation : rotationRecord);  // 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错  // 还有个设置焦距的 发现没卵用 我就不加了 自己找去  // 保存的路径以及文件名称  filePath = path + "/" + name + ".mp4";  mediaRecorder.setOutputFile(filePath);  // 预览输出  mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());  // // 判断是前置摄像头还是后置摄像头 然后设置视频旋转 如果不加上 后置摄像头没有问题 但是前置摄像头录制的视频会导致上下翻转  // 开始录制  try {
            mediaRecorder.prepare();  try {
                mediaRecorder.start();  } catch (Exception e) {
                Toast.makeText(context, "请打开录音权限!", Toast.LENGTH_SHORT).show();  return 0;  }
        } catch (IOException e) {
            e.printStackTrace();  }
        return 1;  }
}

使用的demo

import com.example.videocamara.R;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private Button button, button2, button3;
	private SurfaceView surfaceView;
	private String path;
	private String name;
	private MediaRecorderUtil util;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		init();
		initSurfaceView();
	}

	private void initSurfaceView() {

		surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
		util = new MediaRecorderUtil();
		util.create(surfaceView, this);

	}

	private void init() {
		button = (Button) findViewById(R.id.button);
		button2 = (Button) findViewById(R.id.button2);
		button3 = (Button) findViewById(R.id.button3);
		button.setOnClickListener(this);
		button2.setOnClickListener(this);
		button3.setOnClickListener(this);
		path = Environment.getExternalStoragePublicDirectory(
				Environment.DIRECTORY_PICTURES).getAbsolutePath()
				+ "/yundd_vedio";
		name = "123213";
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button:
			util.startRecord(path, name);
			break;
		case R.id.button2:
			util.stopRecord();
			break;
		case R.id.button3:
			util.changeCamara();
			break;
		}
	}

}

    原文作者:慢慢哈皮
    原文地址: https://blog.csdn.net/sz754155526/article/details/54313423
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞