HAL3 与 HAL2 架构对比:设计哲学、Pipeline 模型与 Stream 配置差异
Android Camera HAL 从 HAL2 演进到 HAL3,不仅仅是 API 版本的升级,更是对移动端相机工作流的根本性重构。HAL2 诞生于早期 Android 设备,设计上偏向“黑盒”与“固定管线”;而 HAL3 则引入了“灵活请求”与“分阶段处理”的哲学,为计算摄影、多帧融合和零延迟取景提供了底层支撑。理解这两者的差异,是掌握 Buffer 队列管理与帧同步优化的前提。
3.1 设计哲学:黑盒 vs 白盒
HAL2 的设计哲学可以概括为“一次配置,持续运行”。App 通过 Camera API 设置好预览尺寸、帧率和格式后,HAL 内部维护一个固定的处理管线,Sensor 持续输出帧,ISP 持续处理,Display 持续显示。这种模式简单、延迟低,但灵活性极差——任何参数变更(如切换分辨率、开启 HDR)都需要停止流、重新配置、再启动流,耗时可达数百毫秒。
HAL3 则采用了“请求-响应”模型。每一帧的采集和处理都由一个独立的 CaptureRequest 驱动。App 或 Camera Service 可以为每一帧指定不同的参数(曝光、增益、裁剪区域、输出目标等),HAL 根据请求动态调整 Sensor 和 ISP 的行为。这种设计使得多帧 HDR、人像虚化、超级夜景等需要逐帧参数变化的场景成为可能。
| 对比维度 | HAL2 | HAL3 |
|---|---|---|
| 控制粒度 | 流级别(Stream-level) | 帧级别(Frame-level) |
| 参数变更 | 需停止流 → 重配 → 启动流 | 逐帧下发 CaptureRequest |
| HAL 职责 | 维护固定管线状态 | 解析请求、调度硬件、返回结果 |
| App 控制力 | 弱(仅能设置初始参数) | 强(每帧可独立控制) |
| 典型场景 | 基础拍照、固定帧率录像 | 计算摄影、多帧融合、零延迟 |
3.2 Pipeline 模型:固定管线 vs 分阶段处理
HAL2 的 Pipeline 是一个“黑盒”顺序流水线。Sensor 输出 RAW 数据后,经过 ISP 处理、统计信息生成、编码/显示输出,所有步骤在 HAL 内部串联完成,外部无法干预中间结果。这种模型下,帧同步由 HAL 内部硬件同步信号(VSYNC)驱动,Buffer 队列管理相对简单——生产者(Sensor)和消费者(Display/Encoder)通过固定深度的环形 Buffer 交互。
HAL3 引入了“分阶段处理”模型,将 Pipeline 拆解为三个逻辑阶段:Sensor 阶段(曝光、RAW 输出)、ISP 阶段(YUV/JPEG 处理)、Post-processing 阶段(人脸检测、HDR 融合等)。每个阶段都可以独立配置输出目标,并且允许 App 通过 CaptureRequest 中的 android.control.* 参数控制每个阶段的行为。
3.3 Stream 配置差异:固定集合 vs 灵活组合
HAL2 的 Stream 配置是“静态集合”。App 在打开 Camera 时指定一组固定的 Stream(如预览流、拍照流、录像流),HAL 内部为每个 Stream 分配固定的 Buffer 队列和硬件资源。一旦配置完成,Stream 的数量、格式、尺寸都不能动态变更。如果需要切换分辨率,必须关闭所有 Stream 并重新配置。
HAL3 引入了 StreamConfigurationMap 和 SessionConfiguration 机制,允许 App 在创建 Session 时灵活组合多个 Stream,并且支持 dynamic resolution switching(动态分辨率切换)。关键差异包括:
- Stream 类型:HAL3 定义了
INPUT(输入流,用于 reprocessing)和OUTPUT(输出流)两种类型,HAL2 只有输出流。 - Buffer 格式:HAL3 支持更丰富的格式组合(如 RAW10、YUV420、NV21、HEIC),且允许同一 Session 内不同 Stream 使用不同格式。
- Stream 复用:HAL3 允许一个 Stream 被多个 Consumer 共享(如预览和录像共用同一 YUV 流),通过 Buffer 队列的“引用计数”机制实现。
- 配置延迟:HAL2 的配置延迟通常为 200-500ms(停止流 + 重配 + 启动流),HAL3 的
configureStreams调用延迟可优化至 50ms 以内。
| 配置维度 | HAL2 | HAL3 |
|---|---|---|
| 配置时机 | Camera 打开时一次性配置 | Session 创建时配置,支持动态更新 |
| Stream 数量 | 固定(通常 2-3 个) | 灵活(最多可达 8-10 个) |
| 输入流支持 | 不支持 | 支持(用于 reprocessing) |
| 格式灵活性 | 低(通常固定 YUV+JPEG) | 高(RAW/YUV/JPEG/HEIC 混搭) |
| 分辨率切换 | 需停止所有流 | 支持动态切换(需 HAL 实现) |
| Buffer 队列管理 | 每个 Stream 独立队列 | 支持跨 Stream Buffer 共享 |
3.4 帧同步机制对比
HAL2 的帧同步依赖硬件 VSYNC 信号。Sensor 在 VSYNC 上升沿开始曝光,曝光完成后触发 ISP 处理,ISP 处理完成后通知 Display/Encoder 消费。整个流程是“推模式”(Push Model),HAL 内部维护一个单调递增的帧计数器,Buffer 按顺序消费,无需显式的帧号匹配。
HAL3 的帧同步则采用“拉模式”(Pull Model)结合显式帧号。每一帧的流程如下:
- App 下发
CaptureRequest,携带唯一的FrameNumber。 - HAL 的
processCaptureRequest接收请求,将 FrameNumber 传递给 Sensor 和 ISP 硬件。 - Sensor 曝光完成后,HAL 通过
notify()回调SHUTTER事件,携带 FrameNumber。 - ISP 处理完成后,HAL 通过
processCaptureResult返回CaptureResult,其中包含 FrameNumber 和对应的 Buffer。 - Camera Service 根据 FrameNumber 将 Request、Result 和 Buffer 进行匹配,确保帧级一致性。
这种显式帧同步机制对 Buffer 队列管理提出了新要求:
- Buffer 必须携带 FrameNumber 标签:每个 Buffer 在队列中必须关联其所属的 FrameNumber,以便在乱序返回时正确匹配。
- 队列必须支持“按帧号查找”:当 HAL 返回 Result 时,Camera Service 需要根据 FrameNumber 在队列中查找对应的 Request 和 Buffer。
- 超时处理:如果某个 FrameNumber 的 Result 长时间未返回(超过 1-2 秒),Camera Service 会触发“帧超时”错误,并尝试恢复或关闭 Session。
| 帧同步维度 | HAL2 | HAL3 |
|---|---|---|
| 驱动模式 | 硬件 VSYNC 推模式 | 请求拉模式 + 显式帧号 |
| 帧号管理 | HAL 内部维护 | App/Camera Service 下发 |
| 乱序返回 | 不支持(严格顺序) | 支持(按 FrameNumber 匹配) |
| Buffer 匹配 | 按队列顺序匹配 | 按 FrameNumber 显式匹配 |
| 超时处理 | 无(硬件保证顺序) | 有(1-2 秒超时阈值) |