Camera2适用是Android5.0(API 级别 21)或更高版本的所有设备


总览

  • 1、加入权限
  • 1.1 系统Android6.0以下
  • 1.2 系统Android6.0以上或者更高版本
  • 2、实现功能列表
  • 2.1 Camera2基础(入门篇)
  • 2.1.1 显示预览图
  • 2.1.1 摄像头方向切换
  • 2.1.2 预览图片出现拉伸情况处理
  • 2.1.3 手动对焦和自动对焦
  • 2.1.4 缩放镜头大小
  • 2.2 图片
  • 2.2.1 图片拍摄
  • 2.2.2 图片剪辑
  • 2.3 视频
  • 2.3.1 视频录制
  • 2.3.2 视频剪辑
  • 2.3.3 直播流程
  • 2.4 保存处理
  • 2.4.1 视频分段保存
  • 2.4.2 图片压缩


1、加入权限

(所需要的的权限有:读写文件权限、拍摄照片和录制视频权限、 录音权限)

1.1 系统Android6.0以下

  • 系统Android6.0以下的版本的直接在AndroidManifest.xml加入*
// 读写权限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />
	// 拍摄照片和录制视频权限
    <uses-permission android:name="android.permission.CAMERA"/> 
	// 录音权限
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

1.2 系统Android6.0以上或者更高版本

  • 系统Android6.0或者更高版本需要动态获取权限(一般应用安装第一次打开获取,只获取一次就好)*
//先把所需要的的权限用数组装起来
	//READ_CALENDAR、WRITE_EXTERNAL_STORAGE : 读写权限
	//CAMERA : 拍摄照片和录制视频权限
	//RECORD_AUDIO: 录音权限
	private static String[] PERMISSIONS_STORAGE = {
	            "android.permission.READ_CALENDAR",
	            "android.permission.WRITE_EXTERNAL_STORAGE",
	            "android.permission.CAMERA",
	            "android.permission.RECORD_AUDIO"};

    public void verifyStoragePermissions(Activity activity) {
   		//然后通过其中的一个函数来申请
        int checkSelfPermission = ActivityCompat.checkSelfPermission(activity, PERMISSIONS_STORAGE[0]);
        if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
            // 没有写的权限,去申请写的权限,会弹出对话框
            ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
        }
    }

2、实现功能列表

2.1 Camera2基础(入门篇)

2.1.1 显示预览图

  1. 利用渲染图层中TextureView.SurfaceTextureListener监听,以下为监听的方法解析

方法

解析

onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height)

当TextureView准备好使用Surface的SurfaceTexture时调用 (在这个方法里面做打开相机操作)

onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height)

SurfaceTexture的缓冲区大小更改时调用

onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture)

在将SurfaceTexture要销毁指定的对象时调用

onSurfaceTextureUpdated(SurfaceTexture surfaceTexture)

SurfaceTexture通过更新指定的值 时调用

  1. 接收有关摄像头设备状态的更新CameraDevice.StateCallback(其中包括:摄像头打开,摄像头关闭,打开摄像头错误原因)

方法

解析

onOpened( CameraDevice camera)

照相机设备完成打开时调用的方法

onDisconnected(CameraDevice camera)

当照相机设备不再可用时调用的方法(一般是其他应用占用了会回调,释放资源,调用camera.close())

onError(CameraDevice camera, int error)

相机设备遇到严重错误时调用的方法(一般会释放资源,调用camera.close())

  • 在onOpened(CameraDevice camera) 得到CameraCaptureSession(一个用于接收有关摄像机捕获会话状态更新的回调对象)
/**
     * 渲染图层
     */
    private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
            surface = new Surface(surfaceTexture);
            openCameraBase();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {}

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {}

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
    };
	/**
     * 摄像头状态回调
     */
    private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
        	//成员变量
            device = camera;
            try {
                device.createCaptureSession(Collections.singletonList(surface), new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        cameraCaptureSession = session;
                        try {
                            //创建一个请求
                            //TEMPLATE_PREVIEW:创建适合摄像机预览窗口的请求
                            //TEMPLATE_MANUAL:用于捕获参数的直接应用程序控制的基本模板
                            //TEMPLATE_RECORD:创建适合视频录制的请求
                            //TEMPLATE_STILL_CAPTURE:创建适合静态图像捕获的请求
                            //TEMPLATE_VIDEO_SNAPSHOT:创建一个适合在录制视频时捕获静态图像的请求
                            //TEMPLATE_ZERO_SHUTTER_LAG:创建一个适合零快门滞后仍然捕获的请求
                            builder = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            //在此请求的目标列表中添加一个表面
                            builder.addTarget(surface);
                            cameraCaptureSession.setRepeatingRequest(builder.build(), null, null);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                    }
                }, null);

            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            Log.i(TAG, "onDisconnected: " + "摄像头已打开");
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            camera.close();
            device.close();
            Log.i(TAG, "onDisconnected: " + "摄像头已关闭");
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            camera.close();
        }
    };
 	/**
     * 打开摄像头
     */
    private void openCameraBase() {
        //摄像头管理 获取系统服务
        CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        //判断系统摄像机权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            //权限处理
            verifyStoragePermissions(getContext());
        }
        try {
            //打开摄像头
            assert cameraManager != null;
            cameraManager.openCamera(cameraDirection, stateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

注意:当切换到后台再进来会发现预览图画面卡着问题(是因为相机关闭了,渲染图层TextureView.SurfaceTextureListener没有清除图层,所以会以为画面卡着),解决方案如下:

/**
    * 防止其他应用占用摄像头,所以每一次进去都新打开摄像头
    */
   @Override
   protected void onResume() {
       super.onResume();
       openCameraBase();
   }
   /**
    * (关闭相机)释放资源
    */
   @Override
   protected void onPause() {
       super.onPause();
       if (device != null) {
           device.close();
       }
   }

2.1.1 摄像头方向切换

在 cameraManager.openCamera(cameraDirection, stateCallback, null);中cameraDirection是控制摄像头的方向(摄像头方向:“1”:为前置 “0”:为后置 (默认值为0))

//切换摄像头
    binding.button2.setOnClickListener(v -> {
         if (device.getId().equals(index)) {
             cameraDirection = "1";
         } else {
             cameraDirection = "0";
         }
         //先关闭,再打开
         device.close();
         openCameraBase();
    });

注意:记得先关闭当前摄像头,再打开要切换的摄像头

2.1.2 预览图片出现拉伸情况处理

  • 一、自定义TextureView,重写宽高
  • 二、初始化控件
private int ratioW = 0;
    private int ratioH = 0;
    public void setAspectRation(int width, int height){
        if (width < 0 || height < 0){
            throw new IllegalArgumentException("width or height can not be negative.");
        }
        ratioW = height;
        ratioH = width;
        //请求重新布局
        requestLayout();
    }
	@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        if (0 == ratioW || 0 == ratioH){
            //未设定宽高比,使用预览窗口默认宽高
            setMeasuredDimension(width, height);
        }else {
            //设定宽高比,调整预览窗口大小(调整后窗口大小不超过默认值)
            if (width < height * ratioW / ratioH){
                setMeasuredDimension(width, width * ratioH / ratioW);
            }else {
                setMeasuredDimension(height * ratioW / ratioH, height);
            }
        }
    }

注意:用法在跟TextureView控件一样,其他没有变

2.1.3 手动对焦和自动对焦

2.1.4 缩放镜头大小

2.2 图片

2.2.1 图片拍摄

2.2.2 图片剪辑

2.3 视频

2.3.1 视频录制

2.3.2 视频剪辑

2.3.3 直播流程

2.4 保存处理

2.4.1 视频分段保存

2.4.2 图片压缩