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 包含以下核心阶段:

  1. Sensor Stage:控制曝光时间、模拟/数字增益、帧间隔、像素合并(Binning)。
  2. ISP Stage:执行黑电平校正、去马赛克、白平衡、颜色校正、Gamma 映射。
  3. Post-Processing Stage:包括降噪、锐化、HDR 合成、多帧融合。
  4. Output Stage:将处理后的图像裁剪、缩放、格式转换,输出到各目标流(Surface)。
  5. Metadata Stage:收集各阶段的实际参数和统计信息,打包为 CaptureResult 返回。
HAL3 Pipeline 架构图 App / Framework CaptureRequest Sensor Stage ISP Stage Post-Processing Output Stage Metadata Stage CaptureResult Pipeline 关键特征: • 每个 Request 独立经过 Sensor → ISP → Post → Output → Metadata 五个阶段 • 框架通过 Metadata Stage 收集各阶段实际参数,打包为 CaptureResult 返回给 App

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;
}
请求-结果循环时序(Pipeline 深度 = 3) 时间 Request #1 Result #1 Request #2 Result #2 Request #3 Result #3 Request #4 Result #4 流水线并行说明: • 当 Request #1 进入 ISP 阶段时,Sensor 已经开始处理 Request #2 • 最大并发帧数 = Pipeline 深度,此处为 3(Request #1~#3 同时处于不同阶段) • Result 返回顺序与 Request 提交顺序一致(FIFO),但各阶段处理时间可能不同

1.5 小结:HAL3 架构适配的关键认知

  • Request-Result 是核心契约:HAL 必须为每个 Request 返回一个 Result,不允许丢帧或乱序。
  • Pipeline 阶段可裁剪:低端平台可以合并 ISP 和 Post-Processing 阶段,但必须保持接口语义一致。
  • 元数据是“胶水”:所有阶段之间的参数传递和状态同步都通过 android.* 元数据完成,不要依赖全局变量。
  • 多流输出是性能瓶颈:移植初期先保证单流稳定,再逐步增加并发流数。
工程建议:在开始编码之前,先在纸上画出目标平台的 Pipeline 阶段划分图,明确每个阶段的输入/输出 buffer 格式、元数据依赖和硬件模块映射。这份图将成为后续移植工作的“架构蓝图”。