1. HAL3 架构概述:从设计理念到 Pipeline 模型
Android Camera HAL3 是 Android 5.0(Lollipop)引入的相机硬件抽象层架构,其设计目标是为现代移动摄影提供高吞吐、低延迟、多帧并行的硬件控制能力。与 HAL1 的“黑盒”模型不同,HAL3 将相机传感器和 ISP 的每个处理阶段暴露给框架,使 Camera Service 能够以逐帧粒度编排请求和结果。
1.1 设计理念:从“黑盒”到“可编程管线”
HAL3 的核心设计理念可概括为三个关键词:
- 逐帧控制(Per-frame Control):每一帧的曝光、增益、白平衡、对焦、输出格式等参数均可独立设置,不再依赖全局状态机。
- 多输出流(Multi-stream):同一帧可以同时输出不同分辨率、不同格式的多个图像流(如预览、拍照、视频、YUV 分析流),由 ISP 硬件并行处理。
- 请求-结果模型(Request-Result Model):应用层提交
CaptureRequest,HAL 返回CaptureResult,形成严格的异步流水线。
关键区别:HAL1 中应用调用
startPreview() 后,框架只能通过回调被动接收帧数据,无法逐帧修改参数;HAL3 则要求每一帧都显式提交 Request,框架拥有完整的控制权。
1.2 HAL1 与 HAL3 核心区别对比
| 对比维度 | HAL1 | HAL3 |
|---|---|---|
| 控制粒度 | 全局状态机(一次设置,持续生效) | 逐帧独立参数(Per-frame) |
| 输出流数量 | 通常 1~2 路(预览 + 拍照) | 支持 3~8 路并发(预览/拍照/视频/YUV/深度) |
| 帧同步模型 | 同步回调,框架被动接收 | 异步 Request-Result 流水线 |
| 3A 控制 | HAL 内部自动完成,框架干预有限 | 框架可指定 3A 模式、区域、触发策略 |
| 元数据通道 | 无标准元数据,厂商自定义 | Android Camera Metadata(ACAM)标准化 |
| 硬件抽象层次 | Sensor → ISP → JPEG 编码器(黑盒) | Sensor → ISP → 各处理阶段(可编程管线) |
| 移植复杂度 | 较低,适配简单 | 较高,需实现完整 Pipeline |
移植提示:从 HAL1 迁移到 HAL3 时,最大的工程挑战不是代码量,而是思维模式的转变——从“配置硬件”变为“编排请求”。建议先实现一个仅支持单流的简化 Pipeline,再逐步增加多流和 3A 集成。
1.3 Pipeline 模型介绍
HAL3 的 Pipeline 模型将相机处理流程拆解为多个逻辑阶段(Stage),每个阶段负责一个独立的图像处理或控制任务。框架通过 CaptureRequest 携带的 android.* 元数据,精确控制每个阶段的行为。
典型的 HAL3 Pipeline 包含以下核心阶段:
- Sensor Stage:控制曝光时间、模拟/数字增益、帧间隔、像素合并(Binning)。
- ISP Stage:执行黑电平校正、去马赛克、白平衡、颜色校正、Gamma 映射。
- Post-Processing Stage:包括降噪、锐化、HDR 合成、多帧融合。
- Output Stage:将处理后的图像裁剪、缩放、格式转换,输出到各目标流(Surface)。
- Metadata Stage:收集各阶段的实际参数和统计信息,打包为
CaptureResult返回。
1.4 请求-结果循环与 Pipeline 深度
HAL3 的 Pipeline 支持多帧并发(In-flight Requests)。框架可以连续提交多个 Request,HAL 内部以流水线方式并行处理。Pipeline 深度(即最大并发帧数)由硬件能力和 HAL 实现共同决定,通常为 2~6 帧。
常见移植陷阱:Pipeline 深度设置过大可能导致 ISP 缓冲区溢出或帧延迟抖动;设置过小则无法充分利用硬件并行能力。建议初始移植时设为 2,稳定后再根据实际帧率和延迟调优。
以下代码片段展示了 HAL3 中 Pipeline 处理一个 Request 的核心流程(简化伪代码):
// HAL3 Pipeline 单帧处理流程(伪代码)
status_t processCaptureRequest(const CaptureRequest& request) {
// 1. 解析 Request 中的元数据
int64_t exposureTime = request.metadata.get(ANDROID_SENSOR_EXPOSURE_TIME);
int32_t sensitivity = request.metadata.get(ANDROID_SENSOR_SENSITIVITY);
// 2. 配置 Sensor 阶段
sensorDriver->setExposure(exposureTime);
sensorDriver->setGain(sensitivity);
// 3. 触发 Sensor 曝光并读取 RAW 数据
buffer_handle_t rawBuffer = sensorDriver->capture();
// 4. ISP 阶段处理
buffer_handle_t yuvBuffer = ispDriver->process(rawBuffer, request.metadata);
// 5. 后处理(降噪/锐化/HDR)
buffer_handle_t finalBuffer = postProcessor->process(yuvBuffer, request.metadata);
// 6. 输出到目标 Surface
for (auto& output : request.outputs) {
output.surface->queueBuffer(finalBuffer);
}
// 7. 收集元数据并返回 Result
CaptureResult result;
result.metadata.set(ANDROID_SENSOR_TIMESTAMP, sensorDriver->getTimestamp());
result.metadata.set(ANDROID_CONTROL_AE_STATE, aeState);
notify(result);
return OK;
}
1.5 小结:HAL3 架构适配的关键认知
- Request-Result 是核心契约:HAL 必须为每个 Request 返回一个 Result,不允许丢帧或乱序。
- Pipeline 阶段可裁剪:低端平台可以合并 ISP 和 Post-Processing 阶段,但必须保持接口语义一致。
- 元数据是“胶水”:所有阶段之间的参数传递和状态同步都通过
android.*元数据完成,不要依赖全局变量。 - 多流输出是性能瓶颈:移植初期先保证单流稳定,再逐步增加并发流数。
工程建议:在开始编码之前,先在纸上画出目标平台的 Pipeline 阶段划分图,明确每个阶段的输入/输出 buffer 格式、元数据依赖和硬件模块映射。这份图将成为后续移植工作的“架构蓝图”。