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 启动后,四个组件的交互遵循以下时序:

  1. CameraDevice::configure_streams() 创建 Camera3Stream 列表,指定预览流、拍照流等。
  2. RequestThread 循环构造 camera3_capture_request_t,关联目标 Stream 和 settings。
  3. Request 通过 CameraDevice::process_capture_request() 提交给 HAL。
  4. HAL 处理完成后,通过回调返回 camera3_capture_result_t。
  5. ResultThread 在回调中解析结果,将填充好的 buffer 推送到对应 Camera3Stream 的 consumer 端。
关键约束:RequestThread 不能等待 ResultThread 完成后再提交下一帧,否则会阻塞 Pipeline。实际实现中,RequestThread 使用独立的提交队列,ResultThread 使用独立的返回队列,两者通过原子计数器或 fence 同步。

3.3 交互架构图

Preview Pipeline 核心组件交互架构 请求生产侧 HAL 处理核心 结果消费侧 RequestThread CameraDevice HAL Pipeline ResultThread Camera3Stream process_capture_request 内部转发 capture_result 回调 填充 buffer SurfaceFlinger/App ⓘ 异步流水线说明 RequestThread 提交第 N 帧后立即返回,不等待第 N 帧结果;ResultThread 在回调中处理第 N 帧时,RequestThread 可能已在提交第 N+1 帧。 典型帧时序(N 帧) T0: RequestThread 构造 capture_request (stream=preview, settings=auto) T1: CameraDevice::process_capture_request() → HAL 开始 ISP 处理 T2: HAL 完成 → 回调 notify() + process_capture_result() T3: ResultThread 解析 result,将 buffer 入队到 Camera3Stream 的 consumer 端

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() 回调中执行:

  1. 解析 result->frame_number,与 RequestThread 的帧号匹配。
  2. 遍历 result->output_buffers,对每个 buffer 调用 release_frame 或直接推送到对应 Camera3Stream 的 consumer。
  3. 更新 metadata(如 sensor_timestamp、3A 状态)到全局结果缓存。
  4. 如果该帧包含多个 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 间隔,说明上层请求不足,可以适当提高帧率。