2. Preview链路基础:Preview Pipeline的启动流程、Stream配置、Buffer分配与流转机制

Preview链路是Camera HAL中最常被调用的数据通路,其性能直接决定取景器(Viewfinder)的流畅度与功耗。本章深入剖析Preview Pipeline的启动流程、Stream配置、Buffer分配与流转机制,帮助开发者建立从上层请求到底层硬件调度的完整认知。

2.1 Preview Pipeline启动流程

Preview链路的启动遵循“配置→创建→请求→回调”的固定时序,涉及Camera Service、HAL、Kernel与ISP四层协作。下图展示了完整的启动流程与关键交互节点:

Preview Pipeline启动流程 Preview Pipeline 启动流程 Camera Service (Framework) Camera HAL (HAL3) Kernel / V4L2 / ISP configureStreams() createStream() processCaptureRequest() processCaptureResult() 解析Stream配置 分配Buffer池 下发Request到ISP 填充Metadata+Buffer 配置Sensor/ISP 申请ION Buffer ISP处理Frame DMA完成中断 关键时序说明 1. configureStreams() 必须在第一次 processCaptureRequest() 之前调用,且只能调用一次。 2. createStream() 返回的 stream ID 必须与后续 request 中的 stream 指针一致。 3. HAL 在 processCaptureResult() 中返回的 buffer_handle_t 必须与 request 中传入的相同。 4. 从 configureStreams() 到第一个 result 回调的延迟称为“启动延迟”,通常应 < 200ms。 5. 启动过程中若 ISP 未就绪,HAL 应返回 -EBUSY 并等待,不可阻塞 Framework 线程。
启动延迟优化要点: 在 configureStreams() 阶段预分配 Buffer 池,避免在 processCaptureRequest() 中动态申请内存;ISP 初始化应异步执行,不阻塞 HAL 线程。

2.2 Stream配置详解

Stream配置是Preview链路的基础,决定了图像格式、分辨率、数据方向与Buffer数量。HAL3通过 camera3_stream_t 结构体描述每个Stream,Framework通过 configureStreams() 一次性下发所有Stream配置。

2.2.1 Stream配置参数表

参数 类型 说明 Preview典型值
stream_type camera3_stream_type_t CAMERA3_STREAM_OUTPUT / INPUT / BIDIRECTIONAL CAMERA3_STREAM_OUTPUT
width uint32_t 图像宽度(像素) 1920 / 1280 / 640
height uint32_t 图像高度(像素) 1080 / 720 / 480
format int 像素格式(HAL_PIXEL_FORMAT_*) HAL_PIXEL_FORMAT_YCbCr_420_888
usage uint32_t Gralloc usage flags(GRALLOC_USAGE_*) GRALLOC_USAGE_SW_READ_OFTEN
max_buffers uint32_t HAL建议的最大Buffer数 4 ~ 6
data_space android_dataspace_t 色彩空间(HAL_DATASPACE_*) HAL_DATASPACE_V0_JFIF
rotation int 输出旋转角度(0/90/180/270) 0(由Sensor方向决定)

2.2.2 Stream配置流程

  1. Framework调用 configureStreams():传入 camera3_stream_configuration_t,包含所有Stream的数组指针。
  2. HAL校验Stream组合:检查分辨率、格式、方向是否满足硬件能力;若不支持,返回 -EINVAL。
  3. HAL设置Stream私有数据:在 camera3_stream_t->priv 中保存HAL内部句柄,Framework不修改此字段。
  4. HAL调整 max_buffers:根据ISP管线深度和内存压力,向Framework建议最优Buffer数量。
  5. Framework分配Buffer:基于HAL返回的 max_buffers 和 usage 标志,通过Gralloc分配Buffer。
常见配置错误: 多个Stream使用不同 usage 标志可能导致Gralloc分配冲突;Preview Stream的 format 必须与SurfaceView/TextureView的期望格式匹配,否则SurfaceFlinger合成会降级。

2.3 Buffer分配机制

Buffer分配是Preview链路性能的关键瓶颈。HAL3采用“Framework分配、HAL使用”的模式,Buffer通过Gralloc分配,在Framework与HAL之间传递 buffer_handle_t 句柄。

2.3.1 Buffer分配流程

Buffer分配与流转流程 Buffer分配与流转流程 Framework请求Buffer Gralloc分配ION内存 注册到HAL HAL填充图像数据 processCaptureResult() Framework释放Buffer Buffer生命周期关键点 • Buffer所有权在Framework与HAL之间交替传递,HAL不得在processCaptureResult()后继续访问Buffer。 • 使用GRALLOC_USAGE_HW_CAMERA_WRITE标志可避免CPU cache刷新,提升写入性能。

2.3.2 Buffer数量选择策略

场景 推荐Buffer数 原因
低延迟Preview(30fps) 3 ~ 4 ISP管线深度2~3帧,预留1个Buffer给Framework消费
高帧率Preview(60fps) 4 ~ 6 减少Buffer饥饿概率,容忍ISP调度抖动
多Stream并发(Preview+Video) 6 ~ 8 每个Stream独立Buffer池,避免互相阻塞
低内存设备 2 ~ 3 牺牲部分流畅度换取内存占用
性能调优建议: 在HAL的 configureStreams() 中,根据当前系统内存水位动态调整 max_buffers。例如,当可用内存 < 200MB 时,将Preview Stream的Buffer数从4降为3,避免触发LMK(Low Memory Killer)。

2.4 Buffer流转机制

Buffer流转是Preview链路的核心循环:Framework将Buffer交给HAL → HAL填充数据 → HAL返回Buffer给Framework → Framework消费后再次提交。这个循环的效率决定了Preview的帧率与延迟。

2.4.1 流转状态机

每个Buffer在生命周期中经历以下状态:

  1. FREE:Buffer空闲,在Framework的BufferQueue中等待被提交。
  2. DEQUEUED:Framework从BufferQueue取出Buffer,准备提交给HAL。
  3. QUEUED:Buffer通过 processCaptureRequest() 提交给HAL,HAL开始处理。
  4. IN_FLIGHT:HAL正在填充数据(ISP处理中),Buffer不可用。
  5. FILLED:HAL通过 processCaptureResult() 返回Buffer,Framework开始消费。
  6. RELEASED:Framework消费完成,Buffer回到FREE状态。
Buffer状态流转图 Buffer状态流转图 FREE QUEUED IN_FLIGHT FILLED dequeue processRequest ISP完成 Framework消费后 release → FREE 流转性能指标 • 单帧流转时间 = QUEUED → FILLED 的时间,应 < 33ms(30fps)或 < 16.7ms(60fps)。 • Buffer饥饿率 = 因无可用Buffer导致丢帧的次数 / 总帧数,应 < 0.1%。

2.4.2 流转中的关键性能问题

问题 表现 根因 优化方案
Buffer饥饿 帧率抖动、丢帧 Buffer数量不足或Framework消费过慢 增加max_buffers;优化SurfaceFlinger合成效率
Buffer泄漏 内存持续增长,最终OOM HAL未在processCaptureResult()中返回Buffer 添加Buffer超时监控,强制回收超时Buffer
Cache抖动 CPU访问Buffer时延迟突增 HAL写入后未clean cache,Framework读取时触发cache miss 使用GRALLOC_USAGE_HW_CAMERA_WRITE避免CPU cache操作
跨进程拷贝 CPU占用高、延迟大 HAL与Framework之间通过binder传递buffer_handle_t时发生隐式拷贝 使用dma-buf传递fd,避免memcpy

2.5 Preview链路性能调优实践

基于上述机制,以下是在实际项目中验证有效的Preview链路调优策略:

调优清单:
  • Stream配置阶段: 优先选择原生格式(如NV12/YV12),避免格式转换;分辨率对齐ISP输出能力,避免scaling。
  • Buffer分配阶段: 使用 GRALLOC_USAGE_HW_CAMERA_WRITE | GRALLOC_USAGE_HW_TEXTURE 减少CPU介入;Buffer数量设为ISP管线深度+2。
  • 流转阶段: 在HAL内部维护Buffer状态表,使用原子操作标记IN_FLIGHT状态;processCaptureResult()中优先返回Buffer再填充Metadata。
  • 监控手段: 在HAL中记录每次processCaptureRequest()到processCaptureResult()的耗时,通过dumpsys输出;设置单帧超时阈值(如100ms),超时则跳过该帧。