3. Camera HAL 关键数据结构详解
在 Camera HAL 开发与调试中,理解核心数据结构是定位问题的基石。本章深入剖析 camera_metadata、camera3_stream_t、camera3_capture_request_t 和 camera3_capture_result_t 四个关键结构体,涵盖其设计意图、字段含义、生命周期及调试要点。
3.1 camera_metadata:控制与元数据的通用容器
camera_metadata 是 Android Camera 框架中用于传递控制参数和结果元数据的核心数据结构。它采用序列化的键值对存储方式,支持高效的查找与更新。
核心特点:
- 键值对存储: 每个条目由 tag(32位整数标识符)、类型、计数和数据组成。
- 两种类型:
camera_metadata_t(可变,用于构建请求)和const camera_metadata_t(不可变,用于结果)。 - 调试价值: 超过 90% 的 HAL 问题可通过检查 metadata 中的关键 tag 定位。
3.1.1 数据结构布局
// camera_metadata 内部布局(简化示意)
typedef struct camera_metadata {
size_t size; // 总大小
uint32_t version; // 版本号
uint32_t flags; // 标志位
size_t entry_count; // 当前条目数
size_t entry_capacity; // 最大条目容量
size_t data_count; // 当前数据项数
size_t data_capacity; // 最大数据容量
uint8_t* entries; // 条目数组起始地址
uint8_t* data; // 数据缓冲区起始地址
} camera_metadata_t;
3.1.2 常用操作与调试接口
| 操作 | 函数 | 调试场景 |
|---|---|---|
| 查找条目 | camera_metadata_find() |
确认某个 tag 是否被正确设置 |
| 更新条目 | camera_metadata_update() |
修改 AE/AWB 参数后验证写入 |
| 序列化/反序列化 | camera_metadata_encode() / decode() |
跨进程传递时检查数据完整性 |
| 打印内容 | dump_camera_metadata() |
全量输出 metadata 用于日志分析 |
调试技巧: 在 HAL 的
process_capture_request 和 process_capture_result 入口处调用 dump_camera_metadata(),对比请求与结果中的关键 tag(如 ANDROID_SENSOR_EXPOSURE_TIME、ANDROID_CONTROL_AE_MODE),可快速发现参数丢失或未生效问题。
3.2 camera3_stream_t:图像数据流的管道定义
camera3_stream_t 定义了从 HAL 到框架的图像数据流属性。每个流对应一个特定的消费者(如预览 Surface、拍照 JPEG 编码器、视频编码器)。
3.2.1 关键字段解析
typedef struct camera3_stream {
int stream_type; // CAMERA3_STREAM_OUTPUT / INPUT / BIDIRECTIONAL
uint32_t width; // 图像宽度(像素)
uint32_t height; // 图像高度(像素)
int format; // 像素格式(HAL_PIXEL_FORMAT_xxx)
uint32_t usage; // 消费者使用标志(GRALLOC_USAGE_xxx)
uint32_t max_buffers; // HAL 可同时持有的最大 buffer 数
void* priv; // HAL 私有数据指针
int rotation; // 输出旋转角度
int physical_camera_id; // 多摄场景下的物理 camera ID
} camera3_stream_t;
3.2.2 流配置与调试要点
| 字段 | 常见值 | 调试关注点 |
|---|---|---|
stream_type |
CAMERA3_STREAM_OUTPUT |
确认流方向是否正确(输出 vs 输入) |
format |
HAL_PIXEL_FORMAT_YCbCr_420_888 |
格式不匹配会导致 buffer 填充错误 |
usage |
GRALLOC_USAGE_HW_TEXTURE |
检查 GPU/显示/编码器使用标志是否遗漏 |
max_buffers |
3 ~ 8 | 值过小可能导致 dequeue 阻塞 |
常见陷阱:
priv 指针由 HAL 管理,但框架不会自动释放。在 configure_streams 被再次调用时,务必先清理旧流关联的私有资源,否则会造成内存泄漏或野指针。
3.3 camera3_capture_request_t:一次捕获的完整指令
该结构体封装了 HAL 执行一次图像捕获所需的所有信息:目标流、输入 buffer、控制参数和设置。
3.3.1 结构体定义
typedef struct camera3_capture_request {
uint32_t frame_number; // 帧序号,单调递增
const camera_metadata_t* settings; // 本次捕获的控制参数
size_t num_output_buffers; // 输出 buffer 数量
const camera3_stream_buffer_t* output_buffers; // 输出 buffer 数组
const camera3_stream_buffer_t* input_buffer; // 输入 buffer(ZSL/ reprocess 时使用)
} camera3_capture_request_t;
3.3.2 请求生命周期与调试
- 创建: CameraService 根据应用请求构建 request,填充 settings 和 output_buffers。
- 下发: 通过
process_capture_request传递给 HAL。 - 处理: HAL 解析 settings,驱动 sensor 曝光,ISP 处理,填充 output_buffers。
- 返回: HAL 通过
process_capture_result返回结果。
调试关键点:
- frame_number 连续性: 检查是否有跳号或重复,可发现 HAL 内部丢帧或重复处理问题。
- settings 指针有效性: 确认 settings 在 HAL 处理期间未被框架释放或修改。
- output_buffers 状态: 每个 buffer 的
status字段在返回时必须正确设置(CAMERA3_BUFFER_STATUS_OK或ERROR)。
3.4 camera3_capture_result_t:捕获结果的完整汇报
HAL 通过该结构体将处理完成的帧结果返回给框架,包含 metadata、输出 buffer 和错误信息。
3.4.1 结构体定义
typedef struct camera3_capture_result {
uint32_t frame_number; // 对应请求的帧序号
const camera_metadata_t* result; // 结果 metadata(AE/AWB/传感器参数等)
size_t num_output_buffers; // 返回的输出 buffer 数量
const camera3_stream_buffer_t* output_buffers; // 输出 buffer 数组
uint32_t partial_result; // 部分结果序号(用于分阶段返回)
} camera3_capture_result_t;
3.4.2 部分结果机制
HAL 可以分多次返回同一个 frame_number 的结果,通过 partial_result 字段标识阶段:
| partial_result 值 | 含义 | 典型内容 |
|---|---|---|
| 1 | 第一阶段结果 | 传感器 metadata(曝光、增益、时间戳) |
| 2 | 第二阶段结果 | 3A 状态、统计信息 |
| … | 后续阶段 | 输出 buffer 就绪 |
| 0 | 最终结果 | 所有 buffer 和 metadata 完整返回 |
调试建议: 在 HAL 中记录每个 frame_number 的 partial_result 到达时间和内容。如果框架长时间未收到最终结果(partial_result=0),通常是 HAL 未释放 buffer 或 metadata 构造出错。
3.5 数据结构关系总览
下图展示了四个关键数据结构在一次完整 capture 流程中的交互关系:
3.6 调试实战:常见问题与数据结构关联
| 现象 | 可能原因 | 涉及数据结构 | 检查方法 |
|---|---|---|---|
| 预览黑屏 | output_buffers 未正确填充或 status 错误 | camera3_stream_buffer_t |
检查 buffer handle 和 release fence |
| 拍照曝光异常 | settings 中 AE 参数未生效 | camera_metadata |
对比 request 和 result 中的 AE tag |
| 帧率不稳定 | frame_number 不连续或 partial_result 超时 | camera3_capture_request_t / result_t |
打印 frame_number 序列和时间戳 |
| 应用崩溃 | stream 配置与 buffer 格式不匹配 | camera3_stream_t |
验证 format 和 usage 字段一致性 |
总结: 四个数据结构构成了 Camera HAL 与框架之间的通信契约。调试时,建议在 HAL 的入口和出口处统一记录这些结构体的关键字段,形成“请求-处理-结果”的完整日志链路,这是快速定位问题的核心方法。