第一章:高通Camera HAL架构全景

各位同学,今天我们来聊聊高通Camera HAL的整体架构。说实话,这个架构图我第一次看的时候,也懵了好一阵子。但别担心,我会用最直白的方式,带你理清这条从Android框架到高通HAL的链路。

1.1 Android Camera框架:上层在做什么?

先看上层。Android的Camera框架,说白了就是一套标准接口。它定义了APP怎么打开相机、怎么拍照、怎么预览。这套接口叫Camera API2,里面有个核心概念叫CameraDeviceCaptureRequest

举个例子,APP发一个“我要拍照”的请求,这个请求会经过框架层,最终落到HAL层。HAL层拿到请求后,驱动传感器、ISP、DSP等硬件,把数据处理好,再返回给上层。

嗯,这里要注意:Android框架只关心“接口长什么样”,不关心“底层怎么实现”。所以高通、MTK、展锐各家都有自己的HAL实现。这就是我们接下来要讲的重点。

1.2 高通HAL的演变:从mm-camera到CamX

高通早期用的是mm-camera架构。这个架构怎么说呢?功能是有的,但扩展性很差。我当年调试一个双摄功能,改一个文件要牵动好几个模块,改完还得重新编译整个HAL,效率极低。

后来高通推出了CamX(Camera eXtension)架构。这玩意儿的设计理念,说白了就是“模块化”和“可配置”。每个功能模块独立编译,通过配置文件(XML)来组合。你想想看,这样改一个功能,只需要改对应的模块和配置文件,不用动整个HAL。

我个人习惯把CamX比作乐高积木。每个积木块是一个功能单元,你可以自由组合,搭出你想要的相机功能。而CHI(Camera Hardware Interface)就是这些积木块的接口规范。

2.1 CamX核心设计理念:分层与解耦

CamX架构分三层:

  • UILayer(上层接口层):对接Android HAL接口,负责把Android的请求转换成CamX内部请求。
  • CoreLayer(核心层):负责调度、同步、Pipeline管理。这是CamX的大脑。
  • CSLLayer(芯片支持层):直接跟硬件打交道,比如传感器、ISP、DSP的驱动。

为什么要分这么细?我举个例子。你在调试一个预览功能,如果发现帧率不对,你不需要去改UILayer的代码,直接去CSLLayer查传感器配置就行。这就是解耦的好处。

核心要点:CamX的Pipeline设计,把拍照流程拆成多个节点(Node)。每个节点负责一个处理步骤,比如“去噪”、“色彩校正”、“缩放”。节点之间通过Buffer传递数据。这种设计让调试变得非常灵活。

2.2 CHI架构:配置驱动一切

CHI的全称是Camera Hardware Interface。它最大的特点就是“配置驱动”。什么意思呢?就是大部分功能逻辑,不是写在C/C++代码里,而是写在XML配置文件里。

我记得有一次,客户要求修改HDR的触发策略。按照以前mm-camera的做法,我得改代码、编译、烧录。但在CHI架构下,我只需要改一个XML文件,把HDR的触发条件从“自动”改成“手动”,重启相机就生效了。效率提升不是一点半点。

CHI的配置文件主要分两类:

  • Usecase配置:定义相机使用场景,比如“普通预览”、“高帧率录像”、“夜景模式”。每个Usecase对应一组Pipeline。
  • Pipeline配置:定义具体的处理流程,包括哪些Node、Node之间的连接关系、每个Node的参数。

个人经验:刚开始接触CHI配置时,我建议你先从Usecase配置入手。因为Usecase是最高层的抽象,理解了Usecase,你就知道整个相机功能是怎么组织的。我曾经带过一个新人,他上来就啃Pipeline配置,结果越看越晕。后来我让他先看Usecase,三天就理清了思路。

3.1 从Android框架到高通HAL的数据流

我们来走一遍完整的数据流。假设APP发起一个预览请求:

  1. APP调用CameraCaptureSession.setRepeatingRequest(),发送一个预览请求。
  2. Android框架把这个请求封装成CaptureRequest,传给HAL的processCaptureRequest()接口。
  3. CamX的UILayer收到请求,解析出里面的参数(比如分辨率、帧率、AE/AWB模式)。
  4. UILayer根据参数,找到对应的Usecase配置,然后创建或复用一条Pipeline。
  5. Pipeline里的Node开始工作。比如SensorNode负责曝光、ISPNode负责图像处理。
  6. 处理完的数据,通过Buffer返回给UILayer,UILayer再返回给Android框架。
  7. Android框架把数据送给APP,APP显示在屏幕上。

你看,整个过程环环相扣。任何一个环节出问题,预览就会卡顿或者黑屏。我曾经遇到过一个案例,预览帧率只有15fps,查了两天才发现是SensorNode的曝光时间配置错了,导致帧率被限制。

3.2 避坑指南:常见问题与调试思路

这里我总结几个常见问题,都是我在项目中踩过的坑:

  • 预览黑屏:先检查Sensor是否正常出图。可以用高通提供的cam_test工具,直接读Sensor的原始数据。如果原始数据正常,那就是ISP或Pipeline配置的问题。
  • 拍照卡顿:多半是Buffer分配不足。检查一下stream_config.xml里的Buffer数量配置。我建议至少配3个Buffer,否则容易丢帧。
  • HDR效果不对:先确认HDR的触发条件。在CHI配置里,HDR的触发条件可能跟AE状态绑定。如果AE没收敛,HDR就不会生效。

警告:千万不要在生产环境直接修改XML配置文件。我曾经有一次手滑,把Usecase配置里的Pipeline ID写错了,结果相机直接打不开。后来我养成了一个习惯:修改配置文件前,先备份一份。改完后,用高通提供的chi_validate工具验证一下语法。

4.1 总结:CamX与CHI的核心价值

说了这么多,我们来总结一下。CamX和CHI的核心价值,其实就是两句话:

  • 模块化:每个功能独立成Node,可以单独开发、调试、升级。
  • 可配置:大部分功能逻辑通过XML配置,不用改代码。

这种设计,让高通平台的Camera开发变得非常灵活。你可以快速适配不同的传感器、不同的ISP、不同的算法。当然,代价就是学习曲线比较陡。XML配置文件的层级关系、Node之间的依赖关系,刚开始确实容易搞混。

我个人建议,初学者可以先从usecase.xmlpipeline.xml这两个文件入手。把这两个文件的结构搞清楚了,CamX的架构也就理解了一半。

好了,第一章的内容就到这里。下一章,我们会深入讲解CamX的Pipeline设计,包括Node的创建、连接、以及Buffer管理。到时候我会带大家手写一个简单的Node,体验一下CamX的开发流程。

课后思考:如果你现在要添加一个“美颜”功能,你觉得应该在CamX的哪一层实现?是UILayer、CoreLayer还是CSLLayer?为什么?