1. HAL3 架构概述
Android Camera HAL3 是 Android 系统相机子系统的硬件抽象层,它定义了 Framework 与 Camera 硬件驱动之间的标准接口。HAL3 的核心设计目标是提供高性能、低延迟的相机数据通路,支持多路并发数据流(如预览、拍照、视频录制),并允许厂商灵活实现硬件加速与 ISP 流水线优化。
1.1 整体架构分层
HAL3 架构从上到下分为三层:
| 层级 | 组件 | 职责 |
|---|---|---|
| 应用层 | Camera2 API / CameraX | 提供 Java/Kotlin 接口给 App 开发者;管理 CaptureRequest、CaptureResult、Session 生命周期 |
| 框架层 | CameraService / CameraProvider | 协调多个 Camera 客户端;管理权限、策略、流配置;调用 HAL 接口下发请求 |
| HAL 层 | camera3_device_t / camera3_stream_t | 实现硬件相关的 Pipeline;管理 Stream、Buffer、Request 处理;对接 ISP 与 Sensor 驱动 |
关键点: HAL3 的 Stream 复用发生在 HAL 层,通过共享同一物理 Stream 对象服务多个 Framework Stream,从而减少 Buffer 分配与 ISP 重配置开销。
1.2 Pipeline 模型
HAL3 采用 Pipeline 模型 处理每一帧数据。每个 CaptureRequest 被拆分为多个阶段,依次经过 Sensor 曝光、ISP 处理、后处理、输出到目标 Stream。Pipeline 模型的核心优势在于:
- 流水线并行:不同帧的不同阶段可以重叠执行,提高吞吐量。
- 可配置性:每个阶段可以独立配置参数(如增益、白平衡、裁剪区域)。
- 延迟可控:通过 Pipeline 深度与 Buffer 管理,精确控制端到端延迟。
1.3 Stream 复用概念引入
在传统 HAL3 实现中,每个 Framework Stream(如预览流、拍照流、视频流)都对应一个独立的 HAL Stream,每个 Stream 拥有自己的 Buffer 队列和 ISP 配置。当多个 Stream 的格式、分辨率、使用场景高度相似时,这种“一对一”映射会造成严重的资源浪费:
- Buffer 内存浪费:每个 Stream 独立分配 Buffer 池,内存占用成倍增加。
- ISP 重配置开销:切换 Stream 时 ISP 需要重新初始化,增加帧延迟。
- 带宽瓶颈:多个 Stream 同时写入不同 Buffer,DDR 带宽压力增大。
Stream 复用 的核心思想是:在 HAL 层将多个 Framework Stream 映射到同一个物理 HAL Stream 上,共享 Buffer 队列和 ISP 管线。复用后的 Stream 通过 Buffer 别名 或 格式转换 机制,为不同 Framework Stream 提供符合其要求的输出。
典型复用场景: 预览流 (1080p YUV) 与视频录制流 (1080p YUV) 格式、分辨率完全一致,可以复用同一个 HAL Stream,仅通过 Buffer 句柄分发实现零拷贝输出。
1.4 复用带来的性能收益
Stream 复用不是简单的“少分配几个 Buffer”,而是从系统级优化内存、带宽和延迟。下表对比了复用前后的关键指标:
| 指标 | 未复用(一对一) | 复用后(多对一) | 收益 |
|---|---|---|---|
| Buffer 内存占用 | 3 × 4MB = 12MB | 1 × 4MB = 4MB | 减少 66% |
| ISP 重配置次数 | 每次 Stream 切换都重配 | 仅首次配置 | 减少 80%+ |
| DDR 带宽 | 3 路独立写入 | 1 路写入 + 别名分发 | 减少 50%~70% |
| 帧延迟抖动 | 高(重配置导致卡顿) | 低(稳定管线) | 降低 30%~50% |
注意: Stream 复用并非万能。当多个 Framework Stream 的格式、分辨率、帧率差异较大时(如 4K 拍照流与 720p 预览流),复用可能导致额外的格式转换开销或分辨率缩放延迟。此时需要根据实际场景评估是否复用。