3. Camera HAL 架构深度解析:HAL3 vs HAL1 核心差异与 Pipeline 流程

在帧率抖动优化中,Camera HAL(硬件抽象层)是连接 Framework 与 Sensor/ISP 硬件的关键桥梁。HAL 版本直接决定了 Pipeline 的调度方式、Buffer 管理策略以及性能 Profiling 的切入点。本章深入剖析 HAL3 与 HAL1 的核心差异,并详细拆解 Request→Capture→Result 的完整 Pipeline 流程,为后续的帧率抖动根因定位打下架构基础。

3.1 HAL1 vs HAL3:架构演进与核心差异

HAL1 是 Android 早期 Camera 架构,采用 “预览-拍照”分离的同步模型;HAL3 自 Android 5.0 引入,基于 “Request-Result”异步 Pipeline 模型,支持逐帧精细控制。下表从关键维度对比两者差异:

对比维度 HAL1 HAL3
Pipeline 模型 同步、固定管线(Preview/Video/Capture 三路独立) 异步、可编程 Pipeline(Request 驱动,逐帧配置)
Buffer 管理 HAL 内部管理 Buffer Queue,Framework 被动接收 Framework 通过 process_capture_request 下发 Buffer Handle,HAL 填充后返回
帧率控制 固定帧率(如 30fps),HAL 内部决定跳帧策略 逐帧指定 android.control.aeTargetFpsRange,支持动态帧率
Metadata 粒度 全局设置,无法逐帧修改 AE/AWB/AF 参数 每帧携带完整 CaptureRequest / CaptureResult Metadata
性能 Profiling 难度 黑盒,难以定位帧率抖动根因 白盒,可通过 Request 时间戳、Result 延迟、Buffer 状态精确分析
多摄像头支持 逻辑摄像头映射复杂,同步困难 原生支持物理摄像头组,logicalCameraId 统一调度
优化启示: HAL3 的逐帧 Request 模型虽然增加了复杂度,但为帧率抖动优化提供了“可观测性”。每一帧的延迟、丢帧、Buffer 超时都可以通过 CaptureResult 中的时间戳和状态字段精确追踪。

3.2 HAL3 Pipeline 核心流程:Request → Capture → Result

HAL3 的 Pipeline 是一个 生产者-消费者异步循环。Framework 作为生产者下发 CaptureRequest,HAL 作为消费者处理并返回 CaptureResult。下图展示了单帧的完整生命周期:

HAL3 Pipeline 单帧生命周期(Request → Capture → Result) Framework 下发 CaptureRequest HAL process_capture_request 解析 Request + 获取 Buffer Sensor 曝光 & ISP 处理 硬件执行 Capture HAL process_capture_result 填充 Buffer + Metadata Framework 消费 Result 送显 / 编码 / 回调 ⏱ 关键时间戳(帧率抖动分析依据) • T1: Framework 下发 Request 时间(request.frameNumber) • T2: HAL 调用 process_capture_request 时间 • T3: HAL 调用 process_capture_result 时间 → 计算 Pipeline 延迟 = T3 - T1

3.3 关键接口详解:process_capture_request 与 process_capture_result

这两个接口是 HAL3 Pipeline 的“入口”和“出口”,也是性能 Profiling 的核心埋点。下面分别拆解其调用约定、参数结构及性能敏感点。

3.3.1 process_capture_request:请求下发与 Buffer 绑定

Framework 通过该接口将 CaptureRequest 传递给 HAL。HAL 必须在此接口中完成:

  • 解析 Metadata:读取 android.control.*、android.sensor.* 等控制参数。
  • 获取输出 Buffer:从 request.outputBuffers 中取出 StreamBuffer,绑定到硬件 DMA 地址。
  • 提交硬件:将配置写入 Sensor / ISP 寄存器,触发 Capture。
// 关键数据结构:camera3_capture_request_t
typedef struct camera3_capture_request {
    uint32_t                frame_number;       // 帧序号,单调递增
    const camera3_stream_buffer_t *output_buffers; // 输出 Buffer 数组
    uint32_t                num_output_buffers; // Buffer 数量
    const camera_metadata_t *settings;          // 逐帧 Metadata
    // ... 其他字段
} camera3_capture_request_t;

// HAL 实现示例(伪代码)
int process_capture_request(const camera3_capture_request_t *request) {
    // 1. 记录 T2 时间戳(Profiling 点)
    uint64_t t2 = get_system_time_ns();

    // 2. 解析 settings,提取 AE/AWB/AF 参数
    camera_metadata_ro_entry entry;
    find_camera_metadata_ro_entry(request->settings,
                                  ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry);
    int32_t min_fps = entry.data.i32[0];
    int32_t max_fps = entry.data.i32[1];

    // 3. 绑定输出 Buffer
    for (uint32_t i = 0; i < request->num_output_buffers; i++) {
        camera3_stream_buffer_t *buf = &request->output_buffers[i];
        // 将 buf->buffer 映射到 ISP 输出地址
        hw_config_isp_output(buf->buffer, buf->stream->width, buf->stream->height);
    }

    // 4. 触发硬件 Capture(非阻塞)
    hw_trigger_capture(request->frame_number);

    return 0;
}
性能陷阱: process_capture_request 必须 非阻塞 返回。如果在此接口中执行了 I2C 慢速读写、内存拷贝或同步等待,会直接阻塞 Framework 的 Request 下发线程,导致帧率抖动。建议将耗时操作(如 3A 计算)放入 HAL 内部工作线程。

3.3.2 process_capture_result:结果返回与 Buffer 通知

HAL 在硬件完成 Capture 后,通过该接口将 CaptureResult 返回给 Framework。该接口可能被调用多次(partial result),用于提前返回 Metadata 或 Buffer。

// 关键数据结构:camera3_capture_result_t
typedef struct camera3_capture_result {
    uint32_t                frame_number;       // 对应 Request 的帧序号
    const camera_metadata_t *result;            // 结果 Metadata(AE 实际值、时间戳等)
    uint32_t                num_output_buffers; // 已完成的 Buffer 数量
    const camera3_stream_buffer_t *output_buffers; // 填充好的 Buffer
    // ... 其他字段
} camera3_capture_result_t;

// HAL 实现示例(伪代码)
void on_capture_done(uint32_t frame_number, camera_metadata_t *result_meta,
                     camera3_stream_buffer_t *filled_buffers, uint32_t num_buf) {
    camera3_capture_result_t capture_result = {0};
    capture_result.frame_number = frame_number;
    capture_result.result = result_meta;
    capture_result.output_buffers = filled_buffers;
    capture_result.num_output_buffers = num_buf;

    // 记录 T3 时间戳(Profiling 点)
    uint64_t t3 = get_system_time_ns();
    // 计算 Pipeline 延迟 = t3 - request_t1[frame_number]

    // 调用 Framework 回调
    camera3_callback_ops->process_capture_result(camera3_device, &capture_result);
}

3.4 HAL3 Pipeline 中的帧率抖动关键路径

基于上述接口分析,帧率抖动在 HAL3 中主要源于以下三个环节:

  1. Request 下发延迟:Framework 侧 Buffer 饥饿或 IPC 阻塞导致 process_capture_request 调用间隔不均。
  2. 硬件 Capture 延迟抖动:Sensor 曝光时间波动、ISP 处理超时、3A 收敛震荡。
  3. Result 返回延迟:HAL 内部线程调度、Buffer 填充完成通知不及时。
Profiling 切入点: 在 process_capture_request 和 process_capture_result 入口处插入高精度时间戳(CLOCK_MONOTONIC),记录每帧的 T1/T2/T3。通过分析帧间间隔(Inter-Frame Interval, IFI)的方差,即可定位抖动发生在 Pipeline 的哪个阶段。

3.5 HAL1 到 HAL3 迁移的帧率优化收益

下表总结了从 HAL1 迁移到 HAL3 后,帧率抖动优化可获得的直接收益:

优化维度 HAL1 限制 HAL3 能力 帧率抖动改善
逐帧帧率控制 固定 fps,无法动态调整 每帧指定 aeTargetFpsRange 消除场景切换时的帧率跳变
Buffer 延迟 HAL 内部 Buffer 队列不可观测 Framework 直接管理 Buffer Handle 减少 Buffer 排队导致的帧间隔不均
3A 收敛速度 全局 3A,无法逐帧微调 逐帧 AE/AWB/AF 参数,支持快速收敛 避免因 3A 震荡导致的帧率波动
多摄同步 需要 HAL 内部同步,易丢帧 Framework 统一调度物理摄像头 多摄切换零帧率抖动