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)的对比:

Stream类型配置对比:标准模式 vs 重处理模式 标准模式(仅OUTPUT) 图像传感器 预览OUTPUT 拍照OUTPUT 两个OUTPUT Stream并行输出 无INPUT Stream 重处理模式(OUTPUT + INPUT) 图像传感器 YUV OUTPUT INPUT Stream 重处理OUTPUT YUV数据经应用回传至INPUT HAL完成二次处理(如降噪、HDR)

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处理管线中的位置:

Stream格式在HAL管线中的输出位置 传感器 ISP RAW Stream 传感器原始数据 YUV Stream ISP处理后YUV BLOB Stream JPEG编码数据 格式选择建议 • 预览/视频 → YUV • 专业拍照 → RAW • 普通拍照 → BLOB • 图像分析 → YUV • 重处理输入 → YUV/RAW

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如何影响内存分配和硬件访问路径:

usage flag驱动的内存分配与硬件访问路径 Gralloc Buffer 由usage flag决定 内存类型(ION/系统堆) Camera HAL HW_CAMERA_WRITE GPU纹理 HW_TEXTURE 视频编码器 HW_VIDEO_ENCODER CPU读取 SW_READ_OFTEN ⚠ 如果多个消费者需要访问同一Buffer,usage flag必须包含所有消费者的flag(按位或) 例如:预览+视频录制 → GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_CAMERA_WRITE

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进行以下验证:

  1. 类型检查:至少有一个OUTPUT Stream;INPUT Stream最多一个。
  2. 格式检查:格式必须在availableStreamConfigurations中,且与requestedStreamFormat匹配。
  3. 分辨率检查:宽高比必须与传感器输出一致(除非使用裁剪);分辨率必须在可用列表中。
  4. usage flag检查:OUTPUT Stream必须包含GRALLOC_USAGE_HW_CAMERA_WRITE;INPUT Stream必须包含GRALLOC_USAGE_HW_CAMERA_READ。
  5. 带宽检查:所有Stream的总像素吞吐量不能超过ISP和DMA的极限。
  6. 数据空间检查:YUV Stream的data_space必须与HAL支持的色彩空间一致。
总结:Stream配置是HAL3适配中最关键的环节之一。类型决定方向,格式决定数据形态,分辨率决定负载,usage flag决定内存访问路径。四者必须协同工作,才能保证CaptureRequest处理管线的高效与稳定。