3、Stream复用核心思想

在Camera HAL层开发中,Stream复用(Stream Reuse)是提升系统整体吞吐量、降低资源消耗的关键设计模式。本章将深入剖析Stream复用的本质动机、量化收益以及典型应用场景。

3.1 为什么需要Stream复用

在Android Camera框架中,一个典型的预览-拍照-录像并发场景会创建多个独立的Stream。如果每个Stream都独占一份buffer队列和内存资源,系统将面临严重的资源碎片化和带宽瓶颈。

核心矛盾: 上层应用期望同时获取预览帧、拍照帧、录像帧,而底层ISP和内存带宽有限。Stream复用通过让多个消费者共享同一份buffer数据,避免重复的数据搬运和内存拷贝。

以下表格对比了无复用与有复用场景下的资源消耗差异:

资源维度 无复用(独立Stream) 有复用(共享Stream) 收益说明
内存占用 N × W × H × Bpp 1 × W × H × Bpp + 小量metadata 内存节省约 (N-1)/N
ISP处理带宽 N 次全尺寸处理 1 次全尺寸处理 + 轻量缩放/裁剪 带宽降低约 60%~80%
DDR带宽 N 次全帧写入/读取 1 次写入 + 多次引用 DDR带宽节省显著
功耗 高(ISP/DDR持续高负载) 低(减少无效数据搬运) 典型场景功耗降低 20%~40%
经验数据: 在4K@30fps预览+4K@30fps录像的并发场景下,使用Stream复用后,内存占用从约120MB降至约40MB,ISP负载从2路全尺寸降为1路全尺寸+1路轻量缩放,整体功耗降低约35%。

3.2 复用带来的性能收益

Stream复用的性能收益可以从三个核心维度量化评估:

3.2.1 内存收益

  • 减少buffer池大小: 复用后只需维护一份主buffer池,消费者通过引用计数共享同一块物理内存。
  • 消除冗余拷贝: 从ISP输出的原始帧直接映射到多个consumer的共享内存区域,无需逐帧memcpy。
  • 降低内存碎片: 单一大buffer池比多个小buffer池更易于管理,减少内存碎片率。

3.2.2 带宽收益

  • ISP输出带宽: 只需输出一次全尺寸帧,后续的缩放/裁剪由硬件scaler或GPU轻量完成。
  • DDR读写带宽: 从N次全帧读写降为1次全帧写 + (N-1)次轻量读,DDR带宽利用率提升。
  • 总线竞争降低: 减少对系统总线的占用,为其他模块(如GPU、NPU)留出带宽空间。

3.2.3 功耗收益

  • ISP功耗: 减少ISP的重复处理流水线,直接降低ISP核心功耗。
  • DDR功耗: 减少DDR的读写次数,DDR处于自刷新/低功耗状态的时间更长。
  • 系统整体功耗: 在长时间录像场景下,复用策略可延长电池续航约15%~25%。
注意: Stream复用并非零成本。引入引用计数、buffer生命周期管理、消费者同步等机制会带来额外的CPU开销。在低帧率或低分辨率场景下,复用收益可能被管理开销抵消,需要根据实际场景权衡。

3.3 复用场景分析

以下SVG图展示了典型的Stream复用架构,其中ISP输出一份原始帧,通过复用分发模块同时服务于预览、拍照、录像三个消费者:

Stream复用架构图 ISP 原始帧输出 全尺寸 YUV/Raw Stream 复用分发 预览 Consumer 直接引用 + 缩放 拍照 Consumer 全尺寸 JPEG 编码 录像 Consumer 视频编码器输入 复用关键点: • ISP只输出一份原始帧到共享buffer池 • 复用分发模块维护引用计数,消费者通过指针共享同一块物理内存 • 不同消费者按需进行缩放/裁剪/编码,无需重复ISP处理

3.3.1 典型复用场景清单

场景 复用方式 收益重点 典型配置
预览 + 拍照 预览流复用拍照流的原始帧 减少拍照延迟,节省内存 预览1080p,拍照全尺寸
预览 + 录像 预览流与录像流共享同一份YUV帧 降低ISP负载,减少DDR带宽 预览1080p,录像4K
预览 + 拍照 + 录像 三路复用同一份ISP输出 综合收益最大化 预览1080p,拍照全尺寸,录像4K
多路预览(画中画) 主预览流复用,副预览流缩放 减少GPU/DPU缩放次数 主预览全屏,副预览小窗
人脸检测 + 预览 人脸检测流复用预览帧 避免额外ISP处理 预览帧直接送入FD引擎

3.3.2 复用决策流程

在HAL层实现Stream复用时,需要遵循以下决策流程:

  1. 解析Stream配置: 从Camera3StreamConfig中提取所有Stream的格式、尺寸、用途(PREVIEW/STILL_CAPTURE/VIDEO_RECORD)。
  2. 识别可复用候选: 寻找格式相同或可转换、尺寸相近或可缩放、生命周期重叠的Stream对。
  3. 评估复用收益: 计算内存节省、带宽降低、功耗减少的量化指标,与引入的管理开销对比。
  4. 选择主Stream: 选择分辨率最高、帧率要求最严格的Stream作为主Stream,其他Stream作为从Stream。
  5. 配置硬件复用路径: 在ISP或MIPI CSI配置中设置共享输出路径,确保主Stream的buffer可被多个consumer访问。
  6. 实现引用计数管理: 在HAL层维护buffer的引用计数,确保所有consumer处理完毕后才释放buffer。
实现提示: 在Android Camera HAL3中,Stream复用通常通过 camera3_stream_t 的 usage 和 format 字段匹配来实现。对于需要不同尺寸的复用场景,可以利用硬件scaler(如ISP的downscaler或GPU的blit)在消费者侧完成尺寸转换,而不是让ISP输出多路不同尺寸的帧。

3.3.3 复用场景的边界条件

以下场景不适合或需要谨慎使用Stream复用:

  • 不同色彩格式: 一个Stream要求YUV420,另一个要求RAW10,无法直接复用同一份buffer。
  • 极端分辨率差异: 主Stream为4K,从Stream为QVGA,缩放比例过大导致硬件scaler质量下降。
  • 不同帧率要求: 主Stream为30fps,从Stream要求60fps,复用后从Stream无法获得足够帧率。
  • 安全/DRM场景: 受保护内容(如HDCP)的Stream不能与非安全Stream共享buffer。
最佳实践: 在HAL初始化阶段,通过一个StreamReusePlanner模块对所有Stream配置进行静态分析,输出复用决策表。运行时根据实际帧率动态调整复用策略,例如在低光照条件下关闭复用以保持画质。