3. Preview Pipeline 核心组件:CameraDevice、Camera3Stream、RequestThread、ResultThread 的角色与交互关系
在 Camera HAL3 架构中,Preview Pipeline 由四个核心组件协同驱动:CameraDevice、Camera3Stream、RequestThread 和 ResultThread。它们分别承担设备抽象、数据通道、请求生产与结果消费的职责,形成一条完整的“请求-处理-返回”闭环。
3.1 组件角色定义
| 组件 | 角色 | 核心职责 | 生命周期 |
|---|---|---|---|
| CameraDevice | HAL 设备抽象 | 管理设备打开/关闭、Pipeline 初始化、Stream 配置、Request 提交入口 | 与 Camera 会话绑定 |
| Camera3Stream | 数据流通道 | 定义 Buffer 格式/尺寸/使用标记,管理 BufferQueue 与 HAL 之间的内存流转 | 从 configure_streams 到 flush |
| RequestThread | 请求生产者 | 从上层捕获请求元数据,填充 capture_request,按帧率控制提交节奏 | 每帧触发一次 |
| ResultThread | 结果消费者 | 轮询 HAL 返回的 capture_result,分发 metadata 与 buffer 到对应 Stream | 每帧触发一次 |
设计要点:CameraDevice 是“门面”,不直接处理帧数据;真正的数据搬运由 Camera3Stream 和 ResultThread 完成。RequestThread 与 ResultThread 在时间上解耦,通过环形缓冲区或队列实现异步流水线。
3.2 组件交互关系
Preview 启动后,四个组件的交互遵循以下时序:
- CameraDevice::configure_streams() 创建 Camera3Stream 列表,指定预览流、拍照流等。
- RequestThread 循环构造
camera3_capture_request_t,关联目标 Stream 和 settings。 - Request 通过 CameraDevice::process_capture_request() 提交给 HAL。
- HAL 处理完成后,通过回调返回
camera3_capture_result_t。 - ResultThread 在回调中解析结果,将填充好的 buffer 推送到对应 Camera3Stream 的 consumer 端。
关键约束:RequestThread 不能等待 ResultThread 完成后再提交下一帧,否则会阻塞 Pipeline。实际实现中,RequestThread 使用独立的提交队列,ResultThread 使用独立的返回队列,两者通过原子计数器或 fence 同步。
3.3 交互架构图
3.4 关键交互细节
3.4.1 CameraDevice 与 Stream 的绑定
configure_streams() 是 Pipeline 的起点。CameraDevice 根据上层请求的流类型(preview、still_capture、video)创建对应的 Camera3Stream,并分配 buffer 池。每个 Stream 携带 usage 标记(如 GRALLOC_USAGE_HW_COMPOSER、GRALLOC_USAGE_HW_CAMERA_WRITE),决定 buffer 在 GPU、Display 或 Camera 之间的共享方式。
// HAL3 中 configure_streams 的典型调用
int32_t ret = device->ops->configure_streams(device, &stream_config);
// stream_config 包含 stream_list 指针、num_streams、操作模式等
// 返回后,每个 camera3_stream_t 的 max_buffers 字段被 HAL 填充
3.4.2 RequestThread 的提交策略
RequestThread 维护一个 pending request 队列,每次从队列头部取出一个 request 提交。提交后不阻塞,立即返回。关键参数包括:
- frame_number:单调递增,用于与 result 配对。
- settings:指向 AE/AWB/AF 等 3A 参数的 metadata。
- input_buffer:仅 reprocessing 场景使用,preview 中为 NULL。
- num_output_buffers:通常为 1(预览流)或 2(预览+显示流)。
性能陷阱:如果 RequestThread 提交速度超过 HAL 处理能力,pending 队列会持续增长,导致帧延迟累积。建议在 HAL 侧通过
notify() 中的 SHUTTER 事件反馈处理进度,RequestThread 据此动态调整提交间隔。
3.4.3 ResultThread 的分发逻辑
ResultThread 在 process_capture_result() 回调中执行:
- 解析
result->frame_number,与 RequestThread 的帧号匹配。 - 遍历
result->output_buffers,对每个 buffer 调用release_frame或直接推送到对应 Camera3Stream 的 consumer。 - 更新 metadata(如 sensor_timestamp、3A 状态)到全局结果缓存。
- 如果该帧包含多个 stream 的 buffer,确保所有 buffer 都处理完毕后再通知上层。
3.5 组件交互对比表
| 交互对 | 通信方式 | 数据内容 | 同步/异步 | 性能敏感点 |
|---|---|---|---|---|
| RequestThread → CameraDevice | 函数调用 | capture_request_t | 异步(不等待) | 调用频率需匹配 HAL 吞吐 |
| CameraDevice → HAL Pipeline | 内部消息/队列 | request 元数据 + buffer handle | 异步 | 队列深度与内存占用 |
| HAL Pipeline → ResultThread | 回调函数 | capture_result_t | 异步(回调触发) | 回调执行时间不可阻塞 |
| ResultThread → Camera3Stream | buffer 入队 | 填充后的 buffer | 异步 | buffer 释放时机与 fence |
3.6 性能优化切入点
- 减少 RequestThread 与 ResultThread 之间的锁竞争:使用无锁队列或 ring buffer 管理帧号映射表。
- Camera3Stream 的 buffer 复用策略:避免每帧申请新 buffer,使用 buffer pool 或双缓冲机制。
- ResultThread 回调轻量化:不要在回调中做耗时操作(如 JPEG 编码),仅做元数据解析和 buffer 转发,耗时任务另起 worker 线程。
- CameraDevice 的 configure_streams 预热:在 Preview 启动前预先分配好所有 stream 的 buffer 池,避免运行时动态分配。
实战建议:在 HAL 实现中,将 RequestThread 的提交间隔与 ResultThread 的返回间隔分别打点统计。如果 submit 间隔 < result 间隔,说明 HAL 处理能力不足,需要降帧或优化 ISP 管线;如果 submit 间隔 > result 间隔,说明上层请求不足,可以适当提高帧率。