4. Stream配置:stream类型(INPUT/OUTPUT)、格式(YUV/RAW/BLOB)、分辨率与usage flag
在Camera HAL3框架中,Stream(数据流)是连接图像传感器、ISP(图像信号处理器)与应用程序内存之间的核心抽象。HAL层通过配置Stream的类型、格式、分辨率和usage flag,决定每一帧数据从何处来、以何种格式存放、最终流向哪里。本节将逐一拆解这四个配置维度,并给出典型的配置组合。
核心原则:Stream配置必须在
configure_streams()调用中一次性完成,且所有Stream必须满足“至少一个OUTPUT Stream”的约束。INPUT Stream仅用于ZSL(零快门延迟)或Reprocessing(重处理)场景。
4.1 Stream类型:INPUT vs OUTPUT
Stream类型决定了数据流的方向。HAL3规范定义了两种基本类型:
| 类型 | 方向 | 典型用途 | 数量限制 |
|---|---|---|---|
| OUTPUT | HAL → 应用/框架 | 预览、拍照、视频录制、图像分析 | 至少1个,最多无硬限制(受硬件资源约束) |
| INPUT | 应用/框架 → HAL | ZSL重处理、RAW重处理、HDR合成输入 | 0或1个(仅当支持重处理时) |
关键区别:OUTPUT Stream由HAL填充数据,应用消费;INPUT Stream由应用提供数据,HAL进行二次处理。一个配置中不能同时存在多个INPUT Stream。
以下SVG展示了典型的双Stream配置(预览OUTPUT + 拍照OUTPUT)与带重处理的配置(OUTPUT + INPUT)的对比:
4.2 Stream格式:YUV / RAW / BLOB
格式决定了像素数据在内存中的排列方式。HAL3中常见的三种格式对应不同的应用场景:
| 格式 | 像素深度 | 典型用途 | HAL处理要求 |
|---|---|---|---|
| YUV(如NV12、NV21、YV12) | 12–16 bit/pixel | 预览、视频录制、图像分析(人脸检测、QR码) | HAL必须支持至少一种YUV格式;通常由ISP直接输出 |
| RAW(如RAW10、RAW16、RAW_OPAQUE) | 10–16 bit/pixel | 专业摄影、DNG输出、后期处理 | 需要传感器直出,未经ISP处理;RAW_OPAQUE允许HAL自定义封装 |
| BLOB(JPEG编码数据) | 可变(压缩后) | JPEG拍照、HEIC拍照 | HAL内部完成编码,输出完整的JPEG字节流 |
常见陷阱:YUV格式的“色彩空间”和“范围”必须与
android.colorCorrection.mode和android.control.aeMode对齐。RAW格式的“拜耳排列”必须通过android.sensor.info.colorFilterArrangement上报给框架。
以下SVG展示了三种格式在HAL处理管线中的位置:
4.3 分辨率与usage flag
4.3.1 分辨率约束
分辨率必须从HAL上报的android.scaler.availableStreamConfigurations中选择。关键约束包括:
- 宽高比对齐:所有OUTPUT Stream的宽高比必须与传感器输出的宽高比一致(除非使用
SCALER_CROPPING)。 - 最小分辨率:通常为320×240(QVGA),用于小尺寸预览或缩略图。
- 最大分辨率:受传感器输出能力和ISP处理能力限制,通常为传感器全分辨率。
- 多Stream分辨率组合:HAL必须保证所有Stream的总带宽不超过ISP和DMA的极限。
性能提示:如果应用同时请求4K预览和4K视频录制,HAL可以复用同一Stream(通过
GRALLOC_USAGE_HW_VIDEO_ENCODER标记),避免重复的ISP管线开销。
4.3.2 usage flag详解
usage flag是Gralloc分配内存时的“用途标签”,告诉HAL和Gralloc该Stream的内存将被哪些硬件模块访问。常见的flag组合如下:
| Flag常量 | 值(十六进制) | 含义 | 典型Stream |
|---|---|---|---|
GRALLOC_USAGE_SW_READ_OFTEN |
0x00000003 | CPU频繁读取(如图像分析) | YUV分析Stream |
GRALLOC_USAGE_SW_WRITE_OFTEN |
0x00000005 | CPU频繁写入(如重处理输入) | INPUT Stream |
GRALLOC_USAGE_HW_TEXTURE |
0x00000100 | GPU纹理采样(如预览SurfaceView) | 预览OUTPUT |
GRALLOC_USAGE_HW_VIDEO_ENCODER |
0x00010000 | 视频编码器输入(如MediaCodec) | 视频OUTPUT |
GRALLOC_USAGE_HW_CAMERA_WRITE |
0x00020000 | Camera HAL写入(所有OUTPUT Stream必须包含) | 所有OUTPUT |
GRALLOC_USAGE_HW_CAMERA_READ |
0x00040000 | Camera HAL读取(INPUT Stream必须包含) | INPUT Stream |
重要:HAL在
configure_streams()中必须检查usage flag的合法性。例如,如果应用为BLOB Stream设置了GRALLOC_USAGE_SW_READ_OFTEN,HAL需要确保JPEG编码后的数据能被CPU高效读取。如果HAL不支持,应返回-EINVAL。
以下SVG展示了usage flag如何影响内存分配和硬件访问路径:
4.4 典型Stream配置组合示例
以下代码展示了HAL3中一个典型的configure_streams()配置,包含预览、拍照和视频录制三个Stream:
// 典型Stream配置:预览(YUV) + 拍照(BLOB) + 视频(YUV)
camera3_stream_t preview_stream = {
.stream_type = CAMERA3_STREAM_OUTPUT,
.width = 1920,
.height = 1080,
.format = HAL_PIXEL_FORMAT_YCbCr_420_888, // YUV
.usage = GRALLOC_USAGE_HW_TEXTURE |
GRALLOC_USAGE_HW_CAMERA_WRITE,
.max_buffers = 4,
.data_space = HAL_DATASPACE_STANDARD_BT709,
.rotation = CAMERA3_STREAM_ROTATION_0
};
camera3_stream_t jpeg_stream = {
.stream_type = CAMERA3_STREAM_OUTPUT,
.width = 4032,
.height = 3024,
.format = HAL_PIXEL_FORMAT_BLOB, // BLOB
.usage = GRALLOC_USAGE_SW_READ_OFTEN |
GRALLOC_USAGE_HW_CAMERA_WRITE,
.max_buffers = 2,
.data_space = HAL_DATASPACE_V0_JFIF,
.rotation = CAMERA3_STREAM_ROTATION_0
};
camera3_stream_t video_stream = {
.stream_type = CAMERA3_STREAM_OUTPUT,
.width = 1920,
.height = 1080,
.format = HAL_PIXEL_FORMAT_YCbCr_420_888, // YUV
.usage = GRALLOC_USAGE_HW_VIDEO_ENCODER |
GRALLOC_USAGE_HW_CAMERA_WRITE,
.max_buffers = 6,
.data_space = HAL_DATASPACE_STANDARD_BT709,
.rotation = CAMERA3_STREAM_ROTATION_0
};
// 配置数组
camera3_stream_t* streams[] = {
&preview_stream,
&jpeg_stream,
&video_stream
};
camera3_stream_configuration_t config = {
.num_streams = 3,
.streams = streams,
.operation_mode = CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE
};
// 调用HAL
int ret = hal_dev->ops->configure_streams(hal_dev, &config);
最佳实践:当预览和视频使用相同分辨率(如1920×1080)时,可以配置为同一个Stream并设置
usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_CAMERA_WRITE,减少内存占用和ISP管线切换开销。
4.5 配置验证清单
HAL在configure_streams()中必须对每个Stream进行以下验证:
- 类型检查:至少有一个OUTPUT Stream;INPUT Stream最多一个。
- 格式检查:格式必须在
availableStreamConfigurations中,且与requestedStreamFormat匹配。 - 分辨率检查:宽高比必须与传感器输出一致(除非使用裁剪);分辨率必须在可用列表中。
- usage flag检查:OUTPUT Stream必须包含
GRALLOC_USAGE_HW_CAMERA_WRITE;INPUT Stream必须包含GRALLOC_USAGE_HW_CAMERA_READ。 - 带宽检查:所有Stream的总像素吞吐量不能超过ISP和DMA的极限。
- 数据空间检查:YUV Stream的
data_space必须与HAL支持的色彩空间一致。
总结:Stream配置是HAL3适配中最关键的环节之一。类型决定方向,格式决定数据形态,分辨率决定负载,usage flag决定内存访问路径。四者必须协同工作,才能保证CaptureRequest处理管线的高效与稳定。