4、Stream 配置数据结构:camera3_stream_t 与 camera3_stream_configuration_t 详解
在 Camera HAL3 多路 Stream 并行捕获中,camera3_stream_t 和 camera3_stream_configuration_t 是连接 Framework 与 HAL 的核心数据结构。Framework 通过 configure_streams() 调用将配置下发,HAL 据此分配硬件管道、ISP 带宽和内存缓冲区。理解这两个结构体的每个字段,是正确实现多路并行捕获的前提。
关键认知: camera3_stream_configuration_t 描述“一组 Stream 的集合”,而 camera3_stream_t 描述“单个 Stream 的属性”。HAL 必须根据集合中的约束(如操作模式、Stream 数量)来验证每个 Stream 的参数是否合法。
4.1 camera3_stream_t:单个 Stream 的属性定义
每个 Stream 代表一条从 Sensor 到内存的数据通路。其结构体定义如下:
typedef struct camera3_stream {
uint32_t stream_type; // CAMERA3_STREAM_OUTPUT / INPUT / BIDIRECTIONAL
uint32_t width; // 图像宽度(像素)
uint32_t height; // 图像高度(像素)
int32_t format; // 像素格式(如 HAL_PIXEL_FORMAT_YCbCr_420_888)
uint32_t rotation; // 旋转角度(0 / 90 / 180 / 270)
int32_t usage; // 缓冲区使用标志(GRALLOC_USAGE_*)
uint32_t max_buffers; // HAL 请求的最大缓冲区数
void *priv; // HAL 私有数据指针
uint32_t data_space; // 色彩空间(HAL_DATASPACE_*)
int32_t rotation_override; // 旋转覆盖(Android 12+)
uint32_t *physical_camera_id;// 物理 Camera ID 数组(多摄)
int32_t num_physical_cameras;// 物理 Camera 数量
int32_t timestamp_source; // 时间戳来源(TANSPARENT / REALTIME)
} camera3_stream_t;
字段详解:
- stream_type:决定数据流向。OUTPUT 用于预览/拍照/录像;INPUT 用于 reprocess(如美颜);BIDIRECTIONAL 用于 YUV 回写。
- format:多路并行时,不同 Stream 可使用不同格式。例如预览用 YCbCr_420_888,拍照用 JPEG。
- usage:影响 Gralloc 分配策略。VIDEO_ENCODER 需连续内存,SW_READ_OFTEN 需 CPU 可访问。
- max_buffers:HAL 通过此字段告知 Framework 需要多少个 buffer 才能保持流水线不空转。多路并行时,每个 Stream 的 max_buffers 之和受限于 ISP 带宽。
- priv:HAL 内部使用,Framework 不修改。可用于存储 Stream 对应的硬件管道 ID。
4.2 camera3_stream_configuration_t:Stream 集合与操作模式
该结构体将多个 Stream 打包,并携带全局配置参数:
typedef struct camera3_stream_configuration {
uint32_t num_streams; // Stream 数量
camera3_stream_t **streams; // Stream 指针数组
uint32_t operation_mode; // CAMERA3_STREAM_CONFIGURATION_*
const camera_metadata_t *session_parameters;// 会话级参数(如 HDR 模式)
uint32_t stream_config_counter;// 配置计数器(用于去重)
} camera3_stream_configuration_t;
常见陷阱: 多路并行时,
num_streams 可能达到 4~6 个(预览 + 拍照 + 录像 + 深度 + 回调)。HAL 必须检查所有 Stream 的 width/height/format 组合是否在 ISP 能力范围内。如果某个 Stream 的 max_buffers 设置过大,可能导致其他 Stream 无法分配足够 buffer。
4.3 多路并行配置的约束关系
下表总结了多路 Stream 并行时各字段的典型约束:
| 字段 | 单路场景 | 多路并行场景 | 常见错误 |
|---|---|---|---|
| stream_type | OUTPUT | 可混合 OUTPUT + INPUT | BIDIRECTIONAL 用于非 reprocess 流 |
| format | YUV 或 JPEG | 不同 Stream 可不同格式 | JPEG 流与 YUV 流分辨率不匹配 |
| width/height | 固定分辨率 | 各 Stream 分辨率可不同,但需满足 ISP 缩放比 | 预览 1920x1080 + 拍照 4000x3000 超出 ISP 最大输入 |
| usage | GRALLOC_USAGE_HW_TEXTURE | 需根据用途组合(VIDEO_ENCODER + SW_READ_OFTEN) | 所有 Stream 使用相同 usage 导致内存浪费 |
| max_buffers | 3~4 | 总和受限于 ISP 带宽,通常 ≤ 12 | 单个 Stream 设置 8 导致其他 Stream 无 buffer |
| operation_mode | NORMAL | CONSTRAINED_HIGH_SPEED 用于高速连拍 | 多路并行时误用 NORMAL 导致帧率下降 |
4.4 多路 Stream 配置流程图
以下 SVG 展示了 Framework 下发配置后,HAL 内部对 camera3_stream_configuration_t 的解析与验证流程:
4.5 多路并行配置实战要点
- Stream 数量上限:通常 HAL 支持 4~6 个并行 Stream。超过时需降级或拒绝配置。
- 分辨率组合:所有 Stream 的宽高必须 ≤ Sensor 最大输出分辨率。例如 48MP Sensor 不能同时输出 48MP 预览 + 48MP 拍照。
- 格式兼容性:JPEG 流通常需要额外的 YUV 中间流,HAL 需在内部创建隐藏 Stream。
- max_buffers 计算:建议按“帧率 × 流水线深度”估算。30fps 预览 + 30fps 录像,每个 Stream 至少 4 个 buffer。
- operation_mode 选择:多路并行时优先使用
CAMERA3_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED以获取更高帧率。
实战案例: 某设备需要同时输出 1080p 预览(YUV)、4K 录像(YUV)和 12MP 拍照(JPEG)。HAL 在
configure_streams() 中应:
- 检查 1080p + 4K 是否在 ISP 缩放范围内;
- 为 JPEG 流内部创建 12MP YUV 中间流;
- 设置预览 max_buffers=4,录像 max_buffers=6,拍照 max_buffers=2;
- 返回时在
stream->max_buffers中填入实际值。
4.6 数据结构关系图
以下 SVG 展示了 camera3_stream_configuration_t 与 camera3_stream_t 之间的层级关系:
4.7 常见问题与避坑指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
| configure_streams 返回 BAD_VALUE | Stream 格式或分辨率不在 HAL 支持列表中 | 在 getCameraCharacteristics() 中正确上报 SCALER_AVAILABLE_STREAM_CONFIGURATIONS |
| 预览卡顿,录像丢帧 | max_buffers 设置过小,导致 dequeue 等待 | 增大 max_buffers,或降低帧率要求 |
| 拍照 JPEG 花屏 | JPEG 流缺少对应的 YUV 中间流 | HAL 内部创建隐藏 YUV Stream 用于 JPEG 编码 |
| 多路 Stream 帧率不一致 | ISP 带宽分配不均,或某个 Stream 占用过多 buffer | 使用 session_parameters 设置带宽分配策略 |
调试建议: 在 HAL 的
configure_streams() 实现中,打印所有 Stream 的 width/height/format/max_buffers 到 log。对比 Framework 下发的值与实际 ISP 能力,可以快速定位配置不匹配问题。