一、声明必要的权限

在 Android 项目中,需要在AndroidManifest.xml文件中添加相机使用权限:

1
<uses-permission android:name = "android.permission.CAMERA"/>

二、创建管理器

在 Java 或 Kotlin 代码中,创建一个CameraManager实例来管理相机设备:

  • 在java中:

    1
    
    CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
    
  • 在Kotlin中:

    1
    
    val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
    

三、获取相机信息

查询相机列表,找到要打开的目标相机:

  • 在java中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
             String[] cameraIds = cameraManager.getCameraIdList();
             String rearCameraId = null;
             for (String id : cameraIds) {
                 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
                 Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                 if (facing!= null && facing == CameraCharacteristics.LENS_FACING_BACK) {
                     rearCameraId = id;
                     break;
                 }
             }
    
  • 在Kotlin中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
             val cameraIds = cameraManager.cameraIdList
             var rearCameraId: String? = null
             for (id in cameraIds) {
                 val characteristics = cameraManager.getCameraCharacteristics(id)
                 val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
                 if (facing!= null && facing == CameraCharacteristics.LENS_FACING_BACK) {
                     rearCameraId = id
                     break
                 }
             }
    

四、打开相机

通过管理器,打开指定的相机:

  • 在java中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
           CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
               @Override
               public void onOpened(CameraDevice camera) {
                   // 相机已打开,可以进行后续操作
               }
    
               @Override
               public void onDisconnected(CameraDevice camera) {
                   camera.close();
               }
    
               @Override
               public void onError(CameraDevice camera, int error) {
                   camera.close();
               }
           };
           cameraManager.openCamera(rearCameraId, stateCallback, null);
    
  • 在Kotlin中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
           val stateCallback = object : CameraDevice.StateCallback() {
               override fun onOpened(camera: CameraDevice) {
                   // 相机已打开,可以进行后续操作
               }
    
               override fun onDisconnected(camera: CameraDevice) {
                   camera.close()
               }
    
               override fun onError(camera: CameraDevice, error: Int) {
                   camera.close()
               }
           }
           cameraManager.openCamera(rearCameraId, stateCallback, null)
    

五、开启相机会话,并配置相机参数,获取YUV数据

打开相机成功后(在onOpened方法中),开始配置相机参数以获取 YUV 数据。

  • 在java中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
           CameraDevice cameraDevice; // 已打开的相机设备
           CameraCaptureSession.StateCallback sessionCallback = new CameraCaptureSession.StateCallback() {
               @Override
               public void onConfigured(CameraCaptureSession session) {
                   try {
                       CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                       // 设置输出格式为YUV_420_888
                       builder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRILINEAR);
                       ImageReader imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2);
                       imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
                           @Override
                           public void onImageAvailable(ImageReader reader) {
                               Image image = reader.acquireLatestImage();
                               if (image!= null) {
                                   // 在这里处理YUV数据
                                   ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
                                   ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
                                   ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
                                   byte[] yData = new byte[yBuffer.remaining()];
                                   byte[] uData = new byte[uBuffer.remaining()];
                                   byte[] vData = new byte[vBuffer.remaining()];
                                   yBuffer.get(yData);
                                   uBuffer.get(uData);
                                   vBuffer.get(vData);
                                   image.close();
                               }
                           }
                       }, null);
                       builder.addTarget(imageReader.getSurface());
                       session.setRepeatingRequest(builder.build(), null, null);
                   } catch (CameraAccessException e) {
                       e.printStackTrace();
                   }
               }
    
               @Override
               public void onConfigureFailed(CameraCaptureSession session) {
                   // 配置失败处理
               }
           };
           cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), sessionCallback, null);
    
  • 在Kotlin中:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    
           val cameraDevice: CameraDevice // 已打开的相机设备
           val sessionCallback = object : CameraCaptureSession.StateCallback() {
               override fun onConfigured(session: CameraCaptureSession) {
                   try {
                       val builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                       // 设置输出格式为YUV_420_888
                       builder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRILINEAR)
                       val imageReader = ImageReader.newInstance(width, height, ImageFormat.YUV_420_888, 2)
                       imageReader.setOnImageAvailableListener({ reader ->
                           val image = reader.acquireLatestImage()
                           if (image!= null) {
                               // 在这里处理YUV数据
                               val yBuffer = image.planes[0].buffer
                               val uBuffer = image.planes[1].buffer
                               val vBuffer = image.planes[2].buffer
                               val yData = ByteArray(yBuffer.remaining())
                               val uData = ByteArray(uBuffer.remaining())
                               val vData = ByteArray(vBuffer.remaining())
                               yBuffer.get(yData)
                               uBuffer.get(uData)
                               vBuffer.get(vData)
                               image.close()
                           }
                       }, null)
                       builder.addTarget(imageReader.surface)
                       session.setRepeatingRequest(builder.build(), null, null)
                   } catch (e: CameraAccessException) {
                       e.printStackTrace()
                   }
               }
    
               override fun onConfigureFailed(session: CameraCaptureSession) {
                   // 配置失败处理
               }
           }
           cameraDevice.createCaptureSession(listOf(imageReader.surface), sessionCallback, null)
    

六、注意事项

  • 内存管理:在处理 YUV 数据时,要注意及时释放相关的ByteBufferImage对象,以避免内存泄漏。
  • 设备兼容性:不同的 Android 设备可能对Camera2 API 的支持存在差异,可能需要进行一些兼容性处理。
  • 性能优化:获取和处理 YUV 数据可能会消耗较多的系统资源,特别是在高分辨率或高帧率的情况下。可以根据实际需求调整相机参数(如分辨率、帧率等)来优化性能。