17、Camera子系统:Camera HAL3、CameraService、Preview与Capture流程

Camera 子系统,说复杂也复杂,说简单也简单。你想想看,从用户按下快门到最终拿到一张照片,中间经过了多少层?我当年刚接触 Android Camera 时,也被这层层叠叠的架构搞得头晕。但摸清楚 HAL3、CameraService 和 Preview/Capture 流程后,你会发现——嗯,其实就那么回事。

17.1 Camera 整体架构概览

先看一张图,把 Camera 子系统的骨架搭起来。我个人习惯把 Camera 架构分成三层:

  • 应用层:你写的 Camera App,调用 Camera2 API。
  • 框架层:CameraService 是核心,管理所有 Camera 设备。
  • 硬件抽象层:Camera HAL3 接口,直接跟硬件打交道。
应用层 (Camera App) 框架层 (CameraService) 设备管理 · 权限控制 · 流配置 硬件抽象层 (Camera HAL3) Pipeline · 3A算法 · Buffer管理 Request/Result 模型 硬件 (Sensor/ISP)

这张图我建议你记在脑子里。每次遇到 Camera 问题,先定位是哪个层的问题,能省不少时间。

17.2 Camera HAL3 接口详解

HAL3 是 Android 从 5.0 开始引入的,取代了老旧的 HAL1。为什么?因为 HAL1 太死板了,只能做简单的 Preview 和 Capture,没法满足现代拍照需求。

HAL3 的核心思想是 Request/Result 模型。说白了就是:

  • 上层下发一个拍照请求(Request)
  • HAL 处理完后返回结果(Result)
  • 每个 Request 可以指定不同的参数:曝光、对焦、白平衡等等

17.2.1 关键接口方法

方法名 作用 我踩过的坑
initialize() 初始化 HAL,传入回调接口 回调没注册好,后面所有流程都卡住
configureStreams() 配置数据流(Preview、Capture、ZSL等) 流配置顺序错了,HAL 直接 crash
processCaptureRequest() 下发拍照请求 Request 的 buffer 没填对,黑屏
flush() 清空所有待处理的 Request 多线程调用 flush 容易死锁
重点:HAL3 的 processCaptureRequest() 是异步的。你下发 Request 后,HAL 通过回调返回 Result。千万别同步等待,否则性能直接崩掉。

17.3 CameraService 的角色

CameraService 是系统服务,运行在 cameraserver 进程中。它负责:

  1. 设备管理:打开/关闭 Camera 设备
  2. 权限检查:没有权限?直接拒绝
  3. 流配置协调:多个 App 同时用 Camera?Service 来仲裁
  4. Binder 通信:把 App 的请求转给 HAL

我记得有一次,客户反馈说打开 Camera 特别慢。查了半天,发现是 CameraService 在初始化时做了太多同步操作。后来改成懒加载,速度提升了一倍。

17.3.1 服务启动流程

// 伪代码,展示 CameraService 启动核心逻辑
void CameraService::onFirstRef() {
    // 1. 枚举所有 Camera HAL
    mModule = hw_get_module(CAMERA_HARDWARE_MODULE_ID, ...);
    
    // 2. 获取 HAL 设备数量
    int numCameras = mModule->get_number_of_cameras();
    
    // 3. 为每个 Camera 创建设备实例
    for (int i = 0; i < numCameras; i++) {
        sp<CameraDevice> device = new CameraDevice(i);
        mDevices.push_back(device);
    }
    
    // 4. 注册服务到 ServiceManager
    publish();
}
小技巧:调试 CameraService 时,可以用 adb shell dumpsys media.camera 查看当前所有 Camera 设备的状态。这个命令我几乎天天用。

17.4 Preview 流程深度剖析

Preview 流程,说白了就是让用户看到取景画面。流程是这样的:

  1. App 调用 createCaptureSession() 创建会话
  2. CameraService 调用 HAL 的 configureStreams() 配置 Preview 流
  3. App 下发重复的 Preview Request
  4. HAL 不断返回 Preview 帧数据
  5. 数据通过 Surface 送到屏幕上

你想想看,Preview 要求的是低延迟。如果一帧延迟超过 33ms(30fps),画面就会卡顿。我曾经在一个项目里,Preview 延迟到了 50ms,用户说「这相机怎么像幻灯片一样」。

17.4.1 Preview 的关键参数

参数 推荐值 说明
分辨率 1920x1080 太高了带宽不够,太低了画质差
格式 YUV_420_888 兼容性好,处理方便
帧率 30fps 够用,功耗也平衡
Buffer 数量 3~4 个 太少容易丢帧,太多延迟高
避坑指南:我曾经在配置 Preview 流时,把分辨率设成了 4000x3000。结果 HAL 直接报错,说带宽不足。后来查文档才知道,Preview 流的分辨率不能超过屏幕分辨率太多。嗯,这个坑我替你们踩过了。

17.5 Capture 流程深度剖析

Capture 流程比 Preview 复杂得多。因为拍照需要更高的画质,还要处理 3A(自动对焦、自动曝光、自动白平衡)。

核心流程:

  1. App 下发单次 Capture Request
  2. HAL 执行 3A 算法,调整参数
  3. Sensor 曝光,ISP 处理 RAW 数据
  4. 输出最终图像(JPEG 或 YUV)
  5. 通过回调返回给 App

17.5.1 Capture Request 示例

// 构建一个拍照请求
CameraCaptureRequest request;
request.stream = &captureStream;
request.settings = {
    .aeMode = AE_MODE_ON,
    .aeTargetFpsRange = {15, 30},
    .awbMode = AWB_MODE_AUTO,
    .afMode = AF_MODE_AUTO,
    .sensorSensitivity = 400,  // ISO
    .sensorFrameDuration = 33333333  // 30fps 对应的纳秒数
};
request.buffers = {
    {.stream = &jpegStream, .buffer = jpegBuffer}
};

// 下发请求
status_t ret = halDevice->processCaptureRequest(&request, 1, nullptr);
注意:Capture 请求的 sensorFrameDuration 参数很关键。设得太短,曝光不足;设得太长,拍照延迟高。我一般建议根据场景动态调整——白天用短曝光,晚上用长曝光。

17.6 Preview 与 Capture 的协同

实际场景中,Preview 和 Capture 是同时进行的。用户看着 Preview 画面,然后按下快门拍照。这时候需要处理两个流:

  • Preview 流:持续输出低分辨率帧,用于显示
  • Capture 流:单次输出高分辨率帧,用于拍照

HAL3 支持多流并发。你可以在 configureStreams() 中同时配置 Preview 流和 Capture 流。HAL 内部会做 Buffer 复用和调度。

我记得有一次,客户要求「拍照时 Preview 不能卡顿」。这其实挺难的,因为拍照瞬间 ISP 要全力处理高分辨率数据,Preview 流可能被饿死。解决方案是给 Preview 流设置更高的优先级,或者用独立的 ISP pipeline。

17.7 常见问题与调试技巧

做 Camera 开发,你一定会遇到这些问题:

问题 可能原因 我的排查方法
Preview 黑屏 Buffer 没填对,或 Surface 未注册 检查 dumpsys 中的 BufferQueue 状态
拍照卡顿 3A 算法耗时太长 看 logcat 中 HAL 的 3A 日志
画面偏色 AWB 参数不对 手动设置 AWB 模式,排除硬件问题
闪退 HAL 接口调用顺序错误 对照 HAL3 规范检查调用顺序
调试利器:adb logcat -s CameraService 只看 CameraService 的日志。配合 adb shell dumpsys media.camera,大部分问题都能定位。

嗯,Camera 子系统就讲到这里。HAL3 的 Request/Result 模型、CameraService 的设备管理、Preview 和 Capture 的流程,这些都是你必须要掌握的。下次遇到 Camera 问题,先画个架构图,定位到具体层,再深入排查——这是我多年来的习惯,分享给你。


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