2. CaptureRequest 数据结构详解
在 Android Camera HAL3 架构中,CaptureRequest 是连接上层应用与底层硬件驱动的最核心数据载体。每一次拍照、预览或录像,本质上都是构建一个或多个 CaptureRequest 并提交给 Camera HAL 处理。理解其内部结构,是进行参数校验和链路异常定位的基础。
2.1 整体结构总览
一个标准的 CaptureRequest 包含以下五个核心字段,它们共同定义了单次图像捕获的完整语义:
| 字段 | 类型 | 必选/可选 | 核心作用 |
|---|---|---|---|
| request ID | int32_t | 必选 | 唯一标识一次捕获请求,用于结果回传时的匹配 |
| settings | ACameraMetadata | 必选 | 包含所有控制参数(AE/AWB/AF、传感器模式、输出尺寸等) |
| output buffers | buffer_handle_t 数组 | 必选 | 指定图像数据写入的目标缓冲区(Surface/ANativeWindow) |
| input buffers | buffer_handle_t 数组 | 可选 | 指定输入缓冲区(用于 reprocess 场景,如 ZSL、美颜) |
| physical camera settings | ACameraMetadata 数组 | 可选 | 多摄场景下,为物理摄像头单独指定的参数覆盖 |
process_capture_request() 函数收到的第一个参数就是 camera3_capture_request_t 结构体。该结构体与上表中的字段一一对应,是驱动层解析请求的入口。
2.2 request ID:链路的“身份证”
request ID 是一个单调递增的 32 位无符号整数,由 Camera Framework 在构建请求时自动分配。它在 HAL3 链路中承担两个关键角色:
- 请求-结果匹配: HAL 在完成捕获后,通过
camera3_capture_result_t结构体返回结果,其中包含相同的frame_number(即 request ID),Framework 据此将结果与原始请求关联。 - 异常回溯锚点: 当出现 buffer 超时、参数无效或 HAL 崩溃时,log 中记录的 request ID 是定位问题发生时刻的唯一线索。
frame_number 与 Framework 期望的不一致,会导致 result callback 无法匹配,进而引发 ANR 或预览黑屏。调试时务必检查 ID 是否连续、无跳变。
2.3 settings:参数校验的核心战场
settings 是一个 ACameraMetadata 对象,本质上是 key-value 对的集合。每个 key 对应一个 camera_metadata_tag_t,value 可以是 int32、float、int64、double、rational 或它们的数组。
根据作用域,settings 中的参数可分为三类:
| 参数类别 | 示例 Tag | 校验要点 |
|---|---|---|
| 3A 参数 | ANDROID_CONTROL_AE_MODE ANDROID_CONTROL_AF_MODE ANDROID_CONTROL_AWB_MODE |
值必须在 available 列表中;OFF 模式下需提供手动值 |
| 传感器参数 | ANDROID_SENSOR_EXPOSURE_TIME ANDROID_SENSOR_SENSITIVITY ANDROID_SENSOR_FRAME_DURATION |
必须在 min/max 范围内;帧时长不能小于曝光时间 |
| 输出参数 | ANDROID_SCALER_CROP_REGION ANDROID_SCALER_ROTATION ANDROID_STATISTICS_FACE_DETECT_MODE |
crop region 必须在 active array 内;旋转角度必须为 0/90/180/270 |
process_capture_request() 入口处,打印 settings 中所有非默认值的 key,与 HAL 的 static_metadata 进行交叉比对。
2.4 output buffers:图像数据的“目的地”
output buffers 是一个 buffer_handle_t* 数组,每个元素对应一个待填充的图像缓冲区。这些缓冲区通常来自 Surface 或 ANativeWindow,由 Framework 的 Stream 配置阶段预先分配。
在 HAL3 中,output buffers 的配置遵循以下规则:
- 数量限制: 每个 request 的 output buffers 数量不能超过
ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS(通常为 3~4 个)。 - 格式匹配: buffer 的格式(如 YUV420_888、JPEG、RAW10)必须与创建 Stream 时声明的格式一致。
- 尺寸匹配: buffer 的宽高必须与 Stream 配置的尺寸完全一致,否则 HAL 会拒绝写入。
- 生命周期: HAL 在
process_capture_request()中获取 buffer 的handle,在process_capture_result()中释放。Framework 负责 buffer 的分配与回收。
CAMERA3_BUFFER_STATUS_ERROR,首先检查 output buffers 的 handle 是否为 NULL,其次检查 buffer 的 stride 是否与 HAL 期望的对齐要求一致。
2.5 input buffers:reprocess 场景的“原料”
input buffers 仅在 reprocess 请求中出现,用于提供需要重新处理的原始图像数据。典型场景包括:
- ZSL(零快门延迟): 从环形缓冲区中取出之前捕获的 RAW 图,重新处理为 JPEG。
- 美颜/滤镜: 对已拍好的 YUV 图进行二次处理,输出新的 YUV 或 JPEG。
- 多帧合成: 输入多张 RAW 图,输出一张 HDR 或超分辨率结果。
input buffers 的校验要点:
| 校验项 | 要求 | 异常后果 |
|---|---|---|
| buffer 非空 | reprocess 请求必须提供 input buffer | HAL 返回 NULL 指针,链路中断 |
| 格式兼容 | input 格式必须与 HAL 声明的 reprocess 能力匹配 | HAL 拒绝处理,返回错误 |
| 时间戳有效 | input buffer 的 timestamp 必须在合理范围内 | 3A 同步失败,图像颜色/亮度异常 |
2.6 physical camera settings:多摄场景的“参数覆盖”
在逻辑摄像头(Logical Camera)架构下,一个 CaptureRequest 可能对应多个物理摄像头(Physical Camera)。physical camera settings 允许为每个物理摄像头单独指定参数,覆盖逻辑摄像头 settings 中的全局值。
典型使用场景:
- 主摄+广角同时输出: 主摄使用 ANDROID_CONTROL_AE_MODE_ON,广角使用 ANDROID_CONTROL_AE_MODE_OFF 并手动设置曝光时间。
- 景深计算: 主摄输出彩色图,副摄输出黑白图,各自使用不同的 sensor 增益和帧率。
ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS 中声明的 key 列表。只有列表中的 key 才能在 physical settings 中被覆盖,否则 HAL 会忽略该设置。
2.7 数据结构在 HAL3 链路中的流转
理解 CaptureRequest 的五个字段后,需要掌握它们在 HAL3 链路中的完整流转路径:
- Framework 构建: CameraService 根据应用层请求,组装
CaptureRequest,分配 request ID,填充 settings 和 buffers。 - HAL 接收: HAL 的
process_capture_request()被调用,传入camera3_capture_request_t指针。 - 参数校验: HAL 内部校验 settings 的合法性,检查 output buffers 的有效性,解析 physical camera settings。
- 硬件执行: HAL 将参数下发到 ISP 和传感器驱动,开始曝光和图像处理。
- 结果回传: HAL 通过
process_capture_result()返回camera3_capture_result_t,包含相同的 request ID 和填充后的 buffers。
static_metadata 声明的范围,必须返回 CAMERA3_MSG_ERROR_REQUEST 错误,并停止处理该 request。这是参数校验的最后一道防线。
2.8 常见异常与调试建议
基于 CaptureRequest 数据结构的特性,以下是实际调试中最高频的异常场景及应对策略:
| 异常现象 | 根因分析 | 调试命令/方法 |
|---|---|---|
| 预览黑屏,log 显示 buffer 错误 | output buffers 的 handle 为 NULL,或格式/尺寸不匹配 | 在 HAL 的 process_capture_request 中打印每个 buffer 的 handle、width、height、format |
| 拍照后 JPEG 花屏 | settings 中的 JPEG 质量参数超出范围,或 output buffer 的 stride 不对齐 | 检查 ANDROID_JPEG_QUALITY 是否在 [1,100] 内;检查 buffer 的 stride 是否 16 字节对齐 |
| 多摄切换时卡顿 | physical camera settings 中指定了不支持的 key | 对比 ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS 与实际设置的 key 列表 |
| reprocess 请求失败 | input buffer 的时间戳与当前 3A 状态不匹配 | 打印 input buffer 的 timestamp,与 HAL 内部的 sensor 时间戳进行比对 |