4. Camera HIDL 接口定义(ICameraDevice)
ICameraDevice.hal 是 Camera HAL 开发中 最核心 的接口文件,它定义了上层框架(Camera Service)与 HAL 实现之间的通信契约。本章将深入分析该接口中的四个核心方法:open、close、configureStreams 和 processCaptureRequest,理解它们的调用时机、参数含义以及实现要点。
关键认知: ICameraDevice 接口是 Camera HAL 的“业务入口”,所有拍照、预览、录像等上层请求最终都会通过这里下发到 HAL 层。掌握这些方法,就等于掌握了 HAL 开发的“七寸”。
4.1 接口概览与调用链路
在 Android HIDL 架构中,ICameraDevice 继承自 android.hardware.camera.device@3.2::ICameraDevice(或更高版本)。上层通过 ICameraService::connectDevice() 获取到 ICameraDevice 的代理对象,然后依次调用其方法完成相机生命周期管理。
4.2 open() —— 打开相机设备
open() 是 ICameraDevice 的入口方法,上层调用它来获取一个相机设备的操作句柄。其 HIDL 定义如下:
// ICameraDevice.hal (Android 10+)
interface ICameraDevice {
open(ICameraDeviceCallback callback)
generates (Status status, ICameraDeviceSession session);
// ...
};
| 参数/返回值 | 类型 | 说明 |
|---|---|---|
| callback | ICameraDeviceCallback | 上层注册的回调接口,用于接收异步事件(如错误、快门、结果元数据) |
| status | Status | 操作结果:OK / INTERNAL_ERROR / CAMERA_IN_USE / MAX_CAMERAS_IN_USE 等 |
| session | ICameraDeviceSession | 返回的会话对象,后续所有操作(configureStreams、processCaptureRequest)都通过此会话进行 |
实现要点: 在 open() 中,HAL 需要完成硬件初始化(如打开 sensor、初始化 ISP)、分配内部缓冲区池、注册回调代理。注意:
open() 可能被多次调用,需要做好重入保护。
4.3 close() —— 关闭相机设备
close() 是资源释放的终点。当上层不再使用相机时(如用户退出相机应用),会调用此方法。其定义通常为:
// ICameraDeviceSession.hal
interface ICameraDeviceSession {
close()
generates (Status status);
// ...
};
| 行为 | 说明 |
|---|---|
| 停止所有流 | 关闭所有正在运行的 preview / capture / video 流 |
| 释放缓冲区 | 归还所有从 framework 申请的 gralloc 缓冲区 |
| 关闭硬件 | 关闭 sensor、ISP、MIPI 接口等物理设备 |
| 清理线程 | 停止内部工作线程、销毁同步锁 |
常见陷阱: close() 调用后,HAL 不能再向 framework 发送任何回调(如 processCaptureResult)。如果此时仍有未完成的请求,必须立即丢弃或返回错误。否则会导致 framework 侧野指针崩溃。
4.4 configureStreams() —— 配置数据流
configureStreams() 是 HAL 开发中最复杂的方法之一。它负责根据上层需求,配置相机输出的数据流组合(如预览流 + 拍照流 + 录像流)。
// ICameraDeviceSession.hal
configureStreams(StreamConfiguration config)
generates (Status status, StreamConfiguration outConfig);
StreamConfiguration 结构体包含:
- streams:一个
Stream数组,每个 Stream 定义了分辨率、格式、用途(PREVIEW / STILL_CAPTURE / VIDEO_RECORD / ZSL 等) - operationMode:操作模式,如 NORMAL / CONSTRAINED_HIGH_SPEED(高速连拍)
- sessionParams:可选的会话级参数(如 HDR 模式、帧率范围)
性能关键: configureStreams() 可能会触发 ISP 重新初始化、MIPI 通道重配、时钟频率调整等耗时操作。建议在实现时做“增量配置”优化:如果新配置与当前配置差异很小(如只改变分辨率),尽量复用已有资源,避免全量重建。
4.5 processCaptureRequest() —— 提交捕获请求
processCaptureRequest() 是 HAL 的“工作马”,每次拍照、每一帧预览都通过它提交。其定义如下:
// ICameraDeviceSession.hal
processCaptureRequest(vec<CaptureRequest> requests,
vec<BufferCache> cachesToRemove)
generates (Status status, uint32_t numRequestProcessed);
CaptureRequest 结构体包含:
| 字段 | 说明 |
|---|---|
| frameNumber | 帧序号,单调递增,用于匹配结果回调 |
| settings | 捕获参数(AE/AWB/AF 模式、曝光时间、ISO、3A 状态等) |
| outputBuffers | 输出缓冲区列表,每个缓冲区指定了对应的 stream ID 和 buffer handle |
| inputBuffer | 可选输入缓冲区(用于 reprocessing,如 ZSL 场景) |
典型处理流程:
- 解析请求:提取 frameNumber、settings、outputBuffers
- 参数生效:将 settings 中的 3A 参数写入 sensor 驱动(如通过 V4L2 的
VIDIOC_S_EXT_CTRLS) - 触发捕获:向 sensor 发送 trigger(如 software trigger 或 hardware trigger)
- 等待完成:等待 sensor 输出 RAW 数据,经过 ISP 处理后填入 outputBuffers
- 回调结果:通过
ICameraDeviceCallback::processCaptureResult()返回结果元数据和填充好的缓冲区
批量优化: processCaptureRequest() 支持一次传入多个 CaptureRequest(
vec<CaptureRequest>)。HAL 可以利用这个特性做批量提交,减少 HIDL 跨进程调用开销。例如,在高速连拍场景下,一次传入 10 个请求,HAL 内部用 DMA 连续触发。
4.6 方法对比总结
| 方法 | 调用时机 | 耗时 | 是否阻塞 | 关键约束 |
|---|---|---|---|---|
| open() | 应用启动时 | 中等(10~50ms) | 是 | 必须成功返回 session,否则相机无法使用 |
| close() | 应用退出时 | 短(<10ms) | 是 | 必须幂等,多次调用不崩溃 |
| configureStreams() | 配置变更时 | 长(20~200ms) | 是 | 必须验证流组合合法性,失败返回错误码 |
| processCaptureRequest() | 每帧/每次拍照 | 短(<5ms 提交) | 否(异步) | 必须保证帧序号连续,结果回调不能丢帧 |
学习路径建议: 在阅读 ICameraDevice.hal 源码时,建议结合
CameraMetadata(相机元数据)一起理解。因为 processCaptureRequest 中的 settings 和返回的 results 都是通过 CameraMetadata 传递的,它定义了数百个 tag(如 ANDROID_SENSOR_EXPOSURE_TIME、ANDROID_CONTROL_AE_MODE 等)。下一章将专门讲解 CameraMetadata 的结构与使用方法。