网上关于高通CameraHAL3的介绍文档不多,之前做高通CameraHAL3的一些收集、总结,杂乱了一点,将就着看吧。
一.初步认知
高通CameraHAL3的架构很庞大,代码量也很巨大。
先对CamX、Chi-CDK的关键术语、目录等有个初步认知
1.1 术语
- ABF :Auto Bayer Filter,Bayer 域的降噪算法
- ACE :Advanced Chroma Enhancement 高级色度增强
- ADRC:automatic dynamic range compression 自动动态范围压缩
- AFD :Auto Flicker Detection,频闪自动检测
- ASD :Auto Scene Detection
- ASF :Adaptive Spatial Filter,自适应空间滤波
- BDS :Bayer Download Scaler
- BPC :Bad Pixel Correction,坏点校准
- BPS :Bayer processing segment(for snapshot)
- CDS :Chroma DownSampler
- CDK :Camera Development Kit 相机开发包
- CHI :Camera Hardware Interface 相机硬件接口
- CS :Chroma Suppression,色度抑制
- CSID:Camera serial interface decoder module
- CV :Chroma Enhancement 色度增强
- DPU :Display processing unit
- GTM :Global Tone Mapping, 全局色调映射
- IFE :Image Front End,Sensor 输出的数据首先会到达IFE
- IPE :Image processing engine
- KMD :Kernal ModeDriver
- LPM :low power manager(低功耗下运行)
- LTM :Local Tone Mapping,局部色调映射
- MCTF:Motion Compensation Temporal Filtering 录像时的多帧降噪
- MCE :Memory Color Enhancement
- MFNR:Multi Frame Noise Reduction 拍照时的多帧降噪
- OPE :Offline Processing Engine
- PDAF:phase difference auto focus,相位对焦
- QCFA:Quad (Bayer Coding) Color Filter Arrangement/Array
- RDI :Raw Dump Interface
- RTB :Real Time Bokeh
- SCE :Skin Color Enhancement, 肤色增强
- TNR :temporal noise reduction,时域降噪
- TFE :Thin Front End
- UMD :User Mode Driver
- VPU :Video processing unit(codec)
- WNR :Wavelet Noise Reduction,小波降噪,Yuv域的降噪算法
1.2 主要目录
1.2.1 CamX 中有如下几个主要目录:
- core/ : 用于存放camx的核心实现模块,其中还包含了主要用于实现hal3接口的hal/目录,以及负责与CHI进行交互的chi/目录
- csl/: 用于存放主要负责camx与camera driver的通讯模块,为camx提供了统一的Camera driver控制接口
- hwl/: 用于存放自身具有独立运算能力的硬件node,该部分node受csl管理
- swl/: 用于存放自身并不具有独立运算能力,必须依靠CPU才能实现的node
1.2.2 Chi-Cdk 中有如下几个主要目录:
- chioverride/: 用于存放CHI实现的核心模块,负责与camx进行交互并且实现了CHI的总体框架以及具体的业务处理。
- bin/: 用于存放平台相关的配置项
- topology/: 用于存放用户自定的Usecase xml配置文件
- node/: 用于存放用户自定义功能的node
- module/: 用于存放不同sensor的配置文件,该部分在初始化sensor的时候需要用到
- tuning/: 用于存放不同场景下的效果参数的配置文件
- sensor/: 用于存放不同sensor的私有信息以及寄存器配置参数
- actuator/: 用于存放不同对焦模块的配置信息
- ois/: 用于存放防抖模块的配置信息
- flash/: 存放着闪光灯模块的配置信息
- eeprom/: 存放着eeprom外部存储模块的配置信息
- fd/: 存放了人脸识别模块的配置信息
二.Camx整体架构
2.1 Camx整体的架构图:
2.2 CamX-CHI通信机制
CamX 与 Chi-Cdk 通过互相dlopen对方的So库,获取了对方的入口方法:
2.3 CameraHAL3数据流向
CamraHAL3数据流向图:
Camera数据从sensor出来,首先会经过IFE,然后分预览/视频和拍照2种情况。
如果是预览或者录像,是先经过IPE处理,最后输出到显示。
如果是拍照,则是先经过BSP处理,然后再经过JPEG编码器,最后保存为图片输出。
IFE、IPE、BPS、JPEG,它们分别表示芯片内部的硬件处理单元,
数据在这些单元内部的处理还是比较复杂的,在不同的处理单元里面,会进行一些复杂的算法处理,这里先有个认识,有个基本概念。
三.CamX CHI-CDK基本组件
3.1 UseCase
UseCase,字面意思:用例
官方注解:
A set of streams configured by the client combined with a set of static properties specifying the processing of those streams
由客户端配置的一组流,这组流是有着一系列静态属性相结合描述的流
See createCaptureSession in the Android CameraDevice documentation
那就结合下面这段代码来好好理解下:
//UseCase: 预览+录像 List<Surface> surfaces = new ArrayList<>(); if(previewSurface != null && previewSurface.isValid()){ surfaces.add(previewSurface); mPreviewBuilder.addTarget(previewSurface); } if(mMediaRecorder != null && mMediaRecorderSurface != null && mMediaRecorderSurface.isValid()){ surfaces.add(mMediaRecorderSurface); mPreviewBuilder.addTarget(mMediaRecorderSurface); } mCameraDevice.createCaptureSession(surfaces,...,...);
这段代码,是把预览的surface和录像的surface都设进去,然后去创建session
就是表示我预览和录像都需要拿到camera数据。
假设我预览设置的size是1080 x 720,录像是1080p的,那这个1080 x 720预览+1080p录像
就是一个usecase(用例)
其它类推。
UseCase在camx中很有很多衍生类,这是camx针对不同的stream来建立不同的usecase对象,用来管理选择feature,并且创建 pipeline以及session。
3.2 Feature
Feature 代表一个特定的功能。
高通CameraHAL3的 feature 有HDR(高动态范围)、SuperNight(超级夜景)、MFNR(多帧降噪)等等。
Usecase选择相应的feature,然后关联一组pipeline,上层下发request请求,hal层会根据request去选择对应的feature。
3.3 Node
Node是单个具有独立处理功能的抽象模块,可以是软件单元也可以是硬件单元。
Node是camx中非常重要的一个父类,是处理camera 请求的一个中间节点,用于处理pipeline下发的请求。
Node 节点在camx chi架构中至关重要,数据的处理都是通过封装好的Node节点来进行的。
Node初始化流程:
3.4 Pipeline
一连串node的集合。pipeline提供单一特定功能的所有资源集合,维护着所有硬件资源以及数据的流转。
3.5 Session
若干个有关联的pipeline的集合,用于管理pipeline的抽象控制单元,其中至少包含一个pipeline,并控制着所有的硬件资源,管控着每个pipeline内部的request流转以及数据的输入输出。
3.6 Link
定义不同的Port的连接端口(输入端口和输出端口)
3.7 Port
作为Node的输入输出端口,使用SrcPort以及DstPort结构定义XML文件。
3.8 Topologies
3.9 常用Usecase、Pipeline及其对应关系
Camx、Chi-Cdk做成组件化的目的在于:
不同机型、产品性能及定位不同,即使基线一样usecase等也有可能不一样
给了手机厂商极大的自定义空间,UseCase可以场景复用,对应的pipeline也可以不用或复用
常用Usecase、Pipeline的对应关系:
四.组件之间的关系
4.1 基本组件之间的关系:
- 上层根据需求,config对应的stream下来
- 下面会根据申请的stream来选择对应的usecase
- usecase选择完成后,又会去选择需要的feature
- 不同的feature会去关联对应的pipeline
- pipeline是由一系列node组成的
- 最终上层config的stream,就会交由各个node去处理
组件关系图:
目前高通Camera HAL3的架构已逐步改为以Feature为中心,摒弃之前Usecase为中心的架构模式
五.基础组件与上层交互
5.1 Camera App整体渲染流程以及与CamX交互流程图:
5.2 Request流转
上层由Session下发的每一个Request对应了三个Result:
- partial metadata
- metadata
- image data
对于每一个Result,上传过程可以大致分为以下两个阶段:
- Session内部完成图像数据的处理,将结果发送至Usecase中
- Usecase接收到来自Session的数据,并将其上传至Provider
5.3 Session回调函数在CamX的体现
5.3.1 Session::StreamOn()
该方法主要用于开始硬件的数据输出
具体点儿就是进行配置Sensor寄存器,让其开始出图,并且将当前的Session的状态告知每一Node,让它们在自己内部也做好处理数据的准备,所以之后的相关Request的流转都是以该方法为前提进行的,所以该方法重要性可见一斑。
Session的StreamOn方法中主要做了如下两个工作:
调用FinalizeDeferPipeline()方法
如果当前pipeline并未初始化,则会调用pipeline的FinalizePipeline()方法,这里方法里面会去针对每一个从属于当前pipeline的Node依次做FinalizeInitialization、CreateBufferManager、NotifyPipelineCreated以及PrepareNodeStreamOn操作
FinalizeInitialization用于完成Node的初始化动作,NotifyPipelineCreated用于通知Node当前Pipeline的状态,此时Node内部可以根据自身的需要作相应的操作,
PrepareNodeStreamOn()方法的主要是完成Sensor以及IFE等Node的控制硬件模块出图前的配置,其中包括了曝光的参数的设置
CreateBufferManagers()方法涉及到CamX-CHI中的一个非常重要的Buffer管理机制,用于Node的ImageBufferManager的创建,而该类用于管理Node中的output port的buffer申请/流转/释放等操作。
- 调用Pipeline的StreamOn()方法
这个方法里面会进一步通知CSL部分开启数据流,并且调用每一个Node的OnNodeStreamOn()方法,该方法会去调用ImageBufferManager的Activate(),该方法里面会去真正分配用于装载图像数据的buffer,之后会去调用CHI部分实现的用户自定义的Nod的pOnStreamOn()方法,用户可以在该方法中做一些自定义的操作。
5.3.2 Session::ProcessCaptureRequest()
针对每一次的Request的流转,都是以该方法为入口开始的,具体流程见下图:
Pipeline首次针对每一个Node通过调用AddDeferredNode方法加入到DRQ中
此时所有的Node都会加入到m_readyNodes中,然后通过调用dispatchReadyNodes方法,触发DRQ开始进行整个内部处理流程
基本流程可以参见下图:
Session内部完成图像数据的处理后是如何将结果发送至Usecase的:
Usecase接收到Session的数据,是如何发送至Provider的,
以常用的AdvancedCameraUsecase为例进行代码的梳理:
六.日志TAG:
6.1 摄像头驱动上电:
driver上电日志:cam_sensor_driver_cmd | Probe success
6.2 摄像头驱动下电:
driver下电日志:
cam_sensor_driver_cmd: CAM_STOP_DEV Success for productname_ofilm_s5khm2_wide sensor_id:0x1ad2,sensor_slave_addr:0x20
cam_sensor_driver_cmd: CAM_RELEASE_DEV Success for productname_ofilm_s5khm2_wide sensor_id:0x1ad2, slave_addr:0x20
6.3 打开摄像头开始传第一帧之前:
CAM_START_DEV
6.4 底层遍历摄像头:
- CHIUSECASE: [INFO ] chifeature2graphselector.cpp:11256 BuildCameraIdSet() cameraId 4, set 54
- CHIUSECASE: [INFO ] chifeature2graphselector.cpp:11256 BuildCameraIdSet() cameraId 0, set 50
- CHIUSECASE: [INFO ] chifeature2graphselector.cpp:11256 BuildCameraIdSet() cameraId 1, set 50
- CHIUSECASE: [INFO ] chifeature2graphselector.cpp:11256 BuildCameraIdSet() cameraId 2, set 50
- CHIUSECASE: [INFO ] chifeature2graphselector.cpp:11256 BuildCameraIdSet() cameraId 3, set 50
6.5 打开相机:
CameraService: CameraService::connect|first frame arrived|CameraService: disconnect: Disconnected|CAM_ACQUIRE_DEV|CAM_START_DEV|CAM_STOP_DEV|CAM_RELEASE_DEV
"configure_streams":配置流
"pipelineName":pipeline名称
CamX :|CHIUSECASE:|STREAM_ONSelectFeatureGraphforRequestFromTable|Node::|CamX:|CHIUSECASE:|Camera3|CameraDevice
七.其他
7.1 定义pipeline中node的xml地址:
vendor/qcom/proprietary/chi-cdk/oem/qcom/topology/titan/usecase-components/usecases/UsecaseZSL/pipelines
7.2 Node链接方式定义:
Pipeline中的Node以及连接方式都在XML中被定义,其主要包含了以下几个标签定义:
- PipelineName: 用来定义该条Pipeline的名称
- NodeList: 该标签中定义了该条Pipeline的所有的Node
- PortLinkages: 该标签定义了Node上不同端口之间的连接关系
7.3 vendortag定义文件:
/vendor/qcom/proprietary/chi-cdk/api/common/chioemvendortagdefines.h
7.4 sensor驱动目录:
某项目名为productname,其一颗摄像头的驱动文件目录:
vendor\qcom\proprietary\chi-cdk\oem\qcom\sensor\productname_sensor\productname_ofilm_ov16a1q_front_sensor