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输出一份原始帧,通过复用分发模块同时服务于预览、拍照、录像三个消费者:
3.3.1 典型复用场景清单
| 场景 | 复用方式 | 收益重点 | 典型配置 |
|---|---|---|---|
| 预览 + 拍照 | 预览流复用拍照流的原始帧 | 减少拍照延迟,节省内存 | 预览1080p,拍照全尺寸 |
| 预览 + 录像 | 预览流与录像流共享同一份YUV帧 | 降低ISP负载,减少DDR带宽 | 预览1080p,录像4K |
| 预览 + 拍照 + 录像 | 三路复用同一份ISP输出 | 综合收益最大化 | 预览1080p,拍照全尺寸,录像4K |
| 多路预览(画中画) | 主预览流复用,副预览流缩放 | 减少GPU/DPU缩放次数 | 主预览全屏,副预览小窗 |
| 人脸检测 + 预览 | 人脸检测流复用预览帧 | 避免额外ISP处理 | 预览帧直接送入FD引擎 |
3.3.2 复用决策流程
在HAL层实现Stream复用时,需要遵循以下决策流程:
- 解析Stream配置: 从Camera3StreamConfig中提取所有Stream的格式、尺寸、用途(PREVIEW/STILL_CAPTURE/VIDEO_RECORD)。
- 识别可复用候选: 寻找格式相同或可转换、尺寸相近或可缩放、生命周期重叠的Stream对。
- 评估复用收益: 计算内存节省、带宽降低、功耗减少的量化指标,与引入的管理开销对比。
- 选择主Stream: 选择分辨率最高、帧率要求最严格的Stream作为主Stream,其他Stream作为从Stream。
- 配置硬件复用路径: 在ISP或MIPI CSI配置中设置共享输出路径,确保主Stream的buffer可被多个consumer访问。
- 实现引用计数管理: 在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配置进行静态分析,输出复用决策表。运行时根据实际帧率动态调整复用策略,例如在低光照条件下关闭复用以保持画质。