第1章:Camera2 API架构——核心类解析

说实话,刚接触Camera2的时候,我也挺懵的。

五个核心类,名字还都带个"Camera",看着就头大。但你别怕,这东西说白了就是一套流程——打开相机、配置参数、发起请求、拿到结果。我做了这么多年摄像头开发,今天就把这套流程给你拆开揉碎了讲清楚。

1.1 CameraManager——相机管家

CameraManager是系统的相机服务管理器。它的职责很简单:发现相机、打开相机

我个人习惯把CameraManager理解成"酒店前台"。你想开房(打开相机),得先找前台问问有没有空房(获取相机列表),然后前台给你房卡(CameraDevice)。

核心方法:

  • getCameraIdList()——获取所有相机ID
  • getCameraCharacteristics(String cameraId)——获取相机特性
  • openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)——打开相机

嗯,这里要注意:openCamera()是异步的。你调用之后不会立刻拿到CameraDevice,而是通过回调告诉你"房卡准备好了"。我在项目中遇到过新手直接拿null去操作,结果崩溃得一塌糊涂。

// 获取CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

// 获取相机ID列表
String[] cameraIds = manager.getCameraIdList();

// 打开后置摄像头
manager.openCamera("0", new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        // 相机打开了,可以干活了
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        // 相机断开了
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        // 出错了
    }
}, null);

1.2 CameraDevice——相机设备

CameraDevice代表一个物理相机。拿到它之后,你才能做真正的操作——比如创建会话、发起拍照请求。

你可以把它想象成"房卡"。有了房卡,你才能进房间(创建CaptureSession),才能开灯、调空调(设置参数)。

我的经验:CameraDevice是重量级资源,用完后一定要调用close()释放。我曾经在早期项目里忘记释放,结果相机被占着,其他应用打不开,用户直接给了一星差评。

CameraDevice的核心方法就两个:

  • createCaptureSession()——创建捕获会话
  • createCaptureRequest(int templateType)——创建捕获请求模板

1.3 CameraCaptureSession——捕获会话

这个类管理着相机数据的"管道"。说白了,它决定了数据怎么流、流到哪里去。

你想想看,相机每秒可能产生30帧甚至60帧数据。这些数据要送到预览Surface、拍照的ImageReader、视频编码器……谁来调度?就是CameraCaptureSession。

核心方法:

  • setRepeatingRequest()——发起持续请求(预览用)
  • capture()——发起单次请求(拍照用)
  • abortCaptures()——中止所有请求

我记得有一次调试预览卡顿,查了半天发现是setRepeatingRequest()capture()混用导致冲突。后来我养成了习惯:预览只用setRepeatingRequest(),拍照单独走capture(),互不干扰。

1.4 CaptureRequest——捕获请求

CaptureRequest就是你要告诉相机"怎么拍"的指令集。它包含:

  • 输出目标(Surface列表)
  • 各种参数(对焦、曝光、白平衡等)

你可以通过Builder模式来构建它:

// 创建预览请求
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(
    CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(previewSurface);
builder.set(CaptureRequest.CONTROL_AF_MODE,
    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
CaptureRequest request = builder.build();

这里有个坑:Builder只能用一次。你调用build()之后,如果想改参数,必须重新创建Builder。我曾经踩过这个坑,以为可以复用,结果参数死活改不了。

1.5 CaptureResult——捕获结果

CaptureResult是相机给你的"答卷"。它告诉你:

  • 实际用了什么参数(可能和你设置的不一样)
  • 当前状态(对焦是否完成、曝光是否正常)
  • 元数据(时间戳、传感器信息等)

你通过CameraCaptureSession.CaptureCallback来接收结果:

session.setRepeatingRequest(request, new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
            @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
        // 拿到结果了
        Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
        // 根据对焦状态做后续处理
    }
}, null);

注意:CaptureResult是异步回调回来的。不要在回调里做耗时操作,否则会阻塞相机管道。我见过有人直接在回调里写文件,结果预览帧率掉到个位数。

1.6 核心流程总结

这五个类的关系,我用一张图给你画清楚:

Camera2 API 核心类工作流程 CameraManager openCamera() CameraDevice createCaptureSession() CameraCaptureSession CaptureRequest CaptureResult 设置参数 获取结果

流程其实就三步:

  1. CameraManager帮你找到并打开相机,拿到CameraDevice
  2. CameraDevice创建CaptureRequestCameraCaptureSession
  3. CameraCaptureSession把请求发出去,通过回调拿到CaptureResult

避坑指南:我曾经在项目里把CameraDevice.StateCallback写成匿名内部类,结果导致内存泄漏。后来我改成成员变量,并在onDisconnected()onError()里做好清理。记住:相机资源一定要及时释放

好了,这五个核心类的关系和用法,你应该心里有数了。下一章我们开始实战——写一个完整的预览+拍照Demo。


公众号:蓝海资料掘金营,微信deep3321