4、Camera HAL3核心概念:Pipeline、Stream、Request与Result、同步与超时机制

好,咱们今天来啃一块硬骨头——HAL3的核心概念。说实话,我刚接触HAL3的时候,也被Pipeline、Stream、Request这些词搞得晕头转向。但后来我发现,只要理解了这几个概念之间的关系,整个Camera HAL3的架构就清晰了。

我个人习惯把HAL3想象成一条「流水线」。你想想看,流水线上有原料进来,经过一道道工序,最后产出成品。Camera HAL3也是这个道理。

4.1 Pipeline:整条流水线

Pipeline,说白了就是一条完整的图像处理链路。从Sensor采集原始数据,经过ISP处理,再到输出给上层应用,整条链路就是一个Pipeline。

在HAL3中,一个Camera设备可以同时运行多个Pipeline吗?嗯,这里要注意——一个Camera设备同一时刻只能有一个Pipeline在运行。但一个Pipeline可以包含多个Stream。

核心要点:Pipeline是逻辑上的概念,它定义了「从Sensor到输出」的完整路径。每个Pipeline对应一个Camera设备实例。

我在项目中遇到过一个问题:某个平台宣称支持三路同时预览,但实际调试时发现,第三路预览的帧率掉到了10fps以下。后来排查发现,是Pipeline的带宽预算没算对,ISP的处理能力成了瓶颈。

4.2 Stream:流水线上的不同出口

Stream是什么?你可以把它理解成Pipeline上的「出口」。同一个Pipeline,可以分出多个Stream,每个Stream输出不同格式、不同分辨率的图像数据。

举个例子:

  • Stream 0:预览,1920x1080,NV12格式
  • Stream 1:拍照,4096x3072,JPEG格式
  • Stream 2:视频编码,1920x1080,NV12格式

这三个Stream共享同一个Pipeline,但输出不同。这就是HAL3最强大的地方——多路输出

Stream类型 典型用途 常见格式 分辨率
PREVIEW 取景器显示 NV12, YUYV 屏幕分辨率
STILL_CAPTURE 拍照 JPEG, RAW Sensor最大分辨率
VIDEO_RECORD 视频编码 NV12 视频分辨率
ZSL 零延时拍照 NV12 与预览相同
RAW 专业摄影/算法 RAW10, RAW16 Sensor原生分辨率

我的经验:配置Stream时,一定要确认硬件是否支持同时输出这些格式。我曾经遇到过,Sensor支持4K拍照,但ISP不支持4K预览+4K拍照同时输出。这种坑,提前看datasheet能避免。

4.3 Request与Result:请-应答模式

HAL3的工作模式是「请求-响应」式的。上层(Framework)下发一个Request,底层(HAL)处理完后返回一个Result。

一个Request包含:

  • 要使用的Stream列表
  • 要设置的参数(AE、AWB、AF等)
  • 要输出的Buffer

一个Result包含:

  • 处理完成的Buffer数据
  • 最终的参数状态(实际AE值、AWB值等)
  • 时间戳、Metadata等信息

为什么会设计成这种模式?说白了,就是为了解耦。Framework不需要知道HAL内部怎么处理,它只管下发Request、收Result。HAL也不需要关心Framework什么时候要数据,它只管处理完就返回。

关键点:Request和Result是一一对应的。你下发一个Request,就一定会收到一个Result。但Result的顺序不一定和Request的顺序一致——HAL可以乱序返回。

我记得有一次调试,发现预览画面卡顿。打log一看,Framework下发了10个Request,但HAL只返回了5个Result。后来发现是某个Stream的Buffer分配不够,HAL在等Buffer释放,导致后续Request被阻塞了。

4.4 同步机制:别让数据打架

多路Stream同时跑,数据怎么同步?这是个好问题。

HAL3的同步机制主要靠两个东西:

  1. Frame Number:每个Request都有一个递增的Frame Number。同一个Frame Number下的所有Stream,数据是同步的。
  2. Timestamp:每个Result都带一个时间戳。不同Stream的Result,可以通过时间戳对齐。

举个例子:

// Framework下发Request
Request req1 = new Request();
req1.frameNumber = 100;
req1.addStream(streamPreview);
req1.addStream(streamCapture);

// HAL处理完后返回Result
Result resultPreview = new Result();
resultPreview.frameNumber = 100;
resultPreview.stream = streamPreview;
resultPreview.timestamp = 1234567890;

Result resultCapture = new Result();
resultCapture.frameNumber = 100;
resultCapture.stream = streamCapture;
resultCapture.timestamp = 1234567890;

你看,同一个Frame Number 100,预览和拍照的Result都有。上层拿到这两个Result后,就知道它们是同一帧的数据。

注意:千万不要假设不同Stream的Result会同时返回。HAL可能先返回预览的Result,再返回拍照的Result。上层必须根据Frame Number来匹配。

4.5 超时机制:别让系统卡死

如果HAL处理Request超时了怎么办?系统不能一直等下去。HAL3定义了超时机制:

场景 超时时间 后果
processCaptureRequest 通常4-5帧时间 HAL可能被重启
flush 1000ms 强制关闭Camera
Buffer dequeue 由HAL实现定义 丢帧或报错

我曾经在项目中遇到一个诡异的bug:手机连续拍照10张后,第11张就卡住了。查了三天,发现是HAL内部的一个Buffer队列满了,但Framework还在不停下发Request。HAL没有及时返回错误,导致整个Pipeline死锁。

解决方案?在HAL里加了一个超时检测:如果某个Request处理超过500ms,就直接返回错误Result,并清空队列。这样虽然会丢一帧,但至少系统不会卡死。

我的建议:实现HAL3时,一定要给每个Request设置一个最大处理时间。不要依赖Framework的超时,HAL自己要有保护机制。我曾经见过一个方案,HAL内部用了一个watchdog线程,专门监控Request的处理时间。

4.6 整体流程串起来

好了,我们把上面几个概念串起来,看看完整的流程:

  1. Framework创建CameraDevice,配置Pipeline和Stream
  2. Framework下发Request,包含Stream列表和参数
  3. HAL收到Request,开始处理
  4. HAL从Sensor读取数据,经过ISP处理
  5. HAL把处理后的数据填入各个Stream的Buffer
  6. HAL返回Result,包含Buffer和时间戳
  7. Framework收到Result,把数据送给Display、Encoder等模块
  8. 如果超时,Framework会触发恢复机制

下面这张图展示了Pipeline、Stream、Request/Result之间的关系:

Pipeline(流水线) Sensor ISP处理 Stream 0: 预览 Stream 1: 拍照 Stream 2: 视频 Request/Result Request Result 超时检测 Watchdog 500ms 图4-1:Pipeline、Stream、Request/Result 关系图

嗯,这张图基本把核心逻辑都画出来了。你仔细看看,应该能理解Pipeline、Stream、Request/Result之间的关系。

4.7 避坑指南

最后,我总结几个实际开发中容易踩的坑:

  • Stream配置冲突:不同Stream的格式、分辨率、usage flag不能冲突。比如,你不能同时要求一个Stream输出NV12和JPEG。
  • Buffer数量不足:每个Stream至少需要2-3个Buffer,否则容易卡住。我曾经因为只分配了1个Buffer,导致dequeue一直失败。
  • 乱序Result处理:上层一定要按Frame Number匹配Result,不要假设顺序。我见过一个Framework实现,直接按收到顺序处理Result,结果画面花屏了。
  • 超时处理不完善:HAL内部要有超时保护,不能依赖Framework来兜底。Framework的超时是最后一道防线,不是常规手段。

重要提醒:HAL3的同步和超时机制,是保证系统稳定性的关键。很多车载项目出问题,都是因为这两个地方没处理好。车载场景下,Camera不能出任何问题,否则可能影响行车安全。

好了,这一章的内容就到这里。HAL3的核心概念其实不复杂,但需要你在实际项目中反复体会。下一章我们会深入HAL3的Buffer管理机制,那是另一个容易踩坑的地方。


公众号:蓝海资料掘金营,微信deep3321