https://www.cnblogs.com/blogs-of-lxl/p/10685718.html
一、CAM CHI API功能介绍:
CHI API建立在Google HAL3的灵活性基础之上,目的是将Camera2/HAL3接口分离出来用于使用相机功能,它是一个灵活的图像处理驱动程序(摄像头硬件接口)。HAL3是根据摄像机pipeline request控制而设计,以提供完整的功能处理用户的控制请求。CHI旨在提供更细粒度的控制,以及访问ISP内的处理引擎,使得OEM和最终用户可以利用CHI API在相机驱动程序中实现自定义图像处理功能。如:通过高通的ISP、®Adreno™GPU 和 ®Hexagon™DSP等实现相应的Use Cases。
1.Qualcomm Spectra 2xx相机驱动程序有五个关键的可定制组件,使OEM能够充分利用CHI进行相机应用开发:
2.关键术语:
Use case:相机管道的特定配置,实现了良好的定义的功能,例如,带有ZSL的20 MP快照和2k上的预览显示是就是一个用例。 CHI API允许开发者在底层硬件的限制范围内自行配置use case,并且不需要修改驱动。
Session:相机管道被创建开始处理图像到被销毁的过程,称之为会话,同时可以存在多个会话。
Request :请求处理从图像传感器中提取的数据帧,或从内存中提取的数据帧,驱动处理结果必须返回到相机应用程序。
Sub-request :将单个HAL3请求分解为多个CHI子请求操作,子请求的结果不会从驱动程序中返回出去,而是合并为单个结果给原始请求。子请求一般用于启用Camera2的某些功能,例如HDR、多帧后处理等。
Stream:具有相同大小和格式的缓冲区序列,用于处理图像数据。可以将不同类型的多个stream指定为输入和输出到camera pipeline。stream是定义Camera2 / HAL3 use case的关键组成部分。
Per-session settings:影响相机管道处理的设置, 会话开始后就无法被更改。例如, 允许图像稳定处理。
Per-request settings:影响各个请求的设置。例如,设置手动曝光值。
Topology:有向无环图(DAG)由一系列处理节点和一组链接组成,它描述了那些正在被节点处理的缓冲区。拓扑通过XML文件指定。
Engine:用于处理数据的硬件。 如Spectra ISP,Snapdragon CPU, Adreno和DSP 是CHI API可用的引擎示例。
Node:像机管道中的逻辑功能块(节点),节点链接在一起形成拓扑。在初始版本中 CHI API,ISP外部的所有节点都通过CPU代码通过本地API(OpenCL和FastCV之类的引擎)调用,Chi API可以在将来扩展到允许在不重用本地api的情况下缓存和重用硬件命令。
Pipeline:启用数据操作的唯一上下文。每个管道都可以维护自己的状态跨多个请求,而不受其他管道的影响。管道利拓扑结构定义Engine使用和数据处理流程。
Statistics:包括3A算法,用于自动控制图像传感器和相机ISP实现更好的图像质量。这些特定领域的算法被处理成为CHI API的专用部分。
Live stream:从图像传感器接收数据的处理进程,不能修改之前请求的任何数据。如果处理速率和传感器数据传输不匹配则会移至Offline stream。
Offline stream:不从图像传感器直接获取数据处理的进程,在Chi API中,Offline stream可以与Live stream成对存在而不造成额外的延迟,处理结果可以返回到相机。
二、CHI 体系结构模式
1.基本拓扑关系图
2.Chi 硬件接口
谷歌HAL3的扩展接口,允许通过请求调整拓扑结构和低延迟控制。
一些谷歌HAL3接口使用的特性如下:
3.Chi 节点接口
CHI驱动程序提供默认节点来启用相机use cases。oem厂商可以在现有的CHI驱动上添加功能,以获得独特的相机体验。这是一个简单而强大的接口,可以在相机pipeline中无缝添加图像处理功能。
4.拓扑图形
CHI拓扑XML是相机use cases的拓扑框架描述(DAG:有向无环图),它在HAL进程初始化时被加载。它本质上是一个键值+数据的存储结构,其中的键值主要用于从可用集中选择特定数据,键值代表每个会话设置+集合的流。高通为常见use cases提供了默认拓扑XML(titan17x_usecases.xml)。oem厂商可以编辑默认XML和创建自定义拓扑XML,CHI API也提供了一个接口来显式地选择自定义拓扑。
5.use case示例
下面的时序图大致描述了一个CHI的use case创建流程:
其中CameraType定义如下:
三、Metadata
CHI中的沟通渠道可以分为以下几类:
(1)Data 传递给应用程序 (2)Data 传递到加工管道 (3)Inter-node 沟通使用发布和订阅机制 ChiNode1 ↔ ChiNode2 使用 Android tags/ChiVendorTags ChiNode1 ↔ ExtNode1 使用 Android tags/ChiVendorTags / ExtCompVendorTags ExtNode1 ↔ ExtNode2 使用 Android tags/ChiVendorTags/ExtCompVendorTags
元数据标签可以是预定义的Android tags,也可以是定制的vendor tags。元数据标签使CHI内外的组件能够与每个组件通信另外还有面向应用程序的摄像头API。在CHI中,Androidtags通过不可变值来预定义,而vendor tags不能是固定绝对值,要取决于目标扩展组件的数量和类型。CHI使用动态索引(base +偏移量)来使供应vendor tags组件能够彼此通信。
元数据标记ID是一个32位的值,它被限制在特定的部分中。每一个section以0x1_0000偏移量开始。标记空间的范围从0x0000_0000到0x8000_0000保留给Android tags,供应商部分是预定在0x8000_0000之后开始。在初始化期间,当CHI扫描目标中的可用组件时,它为发布自定义组件的每个组件分配一个vendor tags,组件通过Base + Offset枚举, 基地址由CHI分配。
metadata空间示例,包括ChiVendorTags和两个ExtCompVendorTags(EXT_COMP_1和EXT_COMP_2),如下图所示:
四、加载外部二进制文件
在camera服务启动时会加载初始化自定义的处理模块,包括那些由QTI的模块。
1.外部模块命名要求
每个节点必须由单独的.so实现,其命名结构如下:
com.
—— 对应厂商定义的节点模块。例如,节点由QTI提供,则命名为< QTI >。 —— 模块类型,有效值为 和 。 - so对应的独有算法名。 示例:
QTI提供的3A算法命名为:com.qti.3a.aec.so
对于nodes,名称必须和拓扑XML中指定的名称对应。
对于stats,有效值只有
所有.so文件必须位于/sys/data/camx/components/中。
2.初始化流程
设备开机过程中会初始化相机服务,加载CHI HAL3模块。在初始化CHI HAL3模块期间,驱动程序会查询并加载/sys/data/camx/components/下面正确命名的.so文件。
(1)导出入口函数:ChiNodeEntry()
根据.so文件的名称,CHI将导出.so对应的ChiNodeEntry()函数,驱动程序是阻塞调用entry函数,直到其处理完成。entry函数主要工作是初始化接口函数指针,另外不作任何进一步处理。此期间初始化的接口函数指针是用于相机会话对外部组件以及CHI驱动程序的调用。
(2)组件初始化函数:
每个组件都有一个名为ChiSetupComponent的函数作为其接口的一部分,CHI驱动会创建一个单独的线程来调用ChiSetupComponent函数,以便并行初始化其他组件。每个组件的ChiSetupComponent函数都接受一个SectionIdentifier,即用于填充CHI驱动程序和谷歌相机框架,包括该组件所需的自定义vendor tags。
(此处应有流程时序图。。。待画)
五、拓扑图XML解析
相机子系统中每个节点是一个功能逻辑块,实现一个use case需要多个node相互配合,用来描述节点之间联系及数据流通的结构称为拓扑。use case由一组要被处理的目标和每个会话如何处理数据的设置构成,每个use case可以由拓扑结构表示,定义了HAL3 API 之间如何进行信息传递和数据处理。在configure_streams期间会根据XML中的
1.Node, port, link
节点代表拓扑结构中的硬件或软件处理组件,包括QTI提供的默认节点,以及为使用CHI驱动自定义的节点。节点有一组输入端口和一组输出端口,输出数据到HAL3图像缓冲区的输出端口称为SinkBuffer,也有一些输出端口不输出到任何图像数据,仅用于发出该节点正在被使用的信号。拓扑中的DAG(有向无环图)是通过将节点的输入端口连接到前一个节点的输出端口形成,或者在需获取反馈结果的情况下,节点的输出端口也可以连接到自己的输入端口。各个节点之间的链接还包含有使用到的缓冲区的必要信息。
图解:
2.配置项解析
:根标记,属性必须定义。如: :用例,代表一种功能特性(如:ZSL),tags存在于 之间如下: - Value field. Exactly 1 tag is required. - Exactly 1 is required. - Value field. Exactly 1 is required. - Exactly 1 is required. - At least 1 is required. :流的列表,包括用例执行的格式和大小范围。这里列出的流对应于传入HAL3的configure_streams () API,通过tag值找到匹配的 。 and 用于从XML中选择一个 。 Valid tag: - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. At least 1 is required. - Exactly 1 is required. : 缓冲区的分辨率范围。 Valid tag: - Value field. Exactly 1 required. - Value Field. Exactly 1 required. - Value Field. Exactly 1 required. - Value Field. Exactly 1 required. 一个Target示例:(当驱动程序处理configure_streams()时,如果有一个输出流的缓冲区格式是YUV420NV12且分辨率小于等于1080p时,就会匹配到如下Target。)
TARGET_BUFFER_PREVIEW TargetOutput YUV420NV12 0 0 1920 1080
: 会话组的设定,与 结合使用定义了use case的键值,这些设置对应于Android属性。 Valid tag: - At least 1 is required. : 设置说明,用于选择对应的use case。 Valid tag: - Value field. Exactly 1 is required. - Value field. Exactly 1 is required - Value field. Exactly 1 is required 示例:
EIS BOOL FALSE
:描述了驱动对每个节点的顺序和依赖关系的解析,以处理上层请求。
Valid tag:
Valid tag:
: 单个处理逻辑块,用于告诉驱动如何来处理一个请求。 Valid tags: - Optional. Several properties allowed. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. 例子:
PropXYZ UINT 6 NodeXYZ 1 NodeXYZInstanceName0 0
驱动程序根据nodeId解析节点类型,对于所有自定义节点该字段的值为255,并带有一个NodeProperty来告知驱动程序切确的自定义节点类型。如下:
CustomNodeLibrary STRING customnodelib.so CustomNode 255 CustomNodeInstanceName0 0
: 描述节点列表以及它们如何相互连接。 Valid tags: - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - At least 1 is required. :单个node之间的连接。 Valid tags: - Exactly 1 is required. - At least 1 is required. - Optional. :一个节点的输出端口,该节点输出的图像数据到 被使用修改,从 到 可以有一对多的关系。 Valid tags: - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required.
:接收从 节点的输出数据。 Valid tags - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. :输入/输出缓冲区的属性。 Valid tags: - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required. - Value field. Exactly 1 is required :任何字符串可以定义一个用例名称; 例如,指定此流输出缓冲区由名为“NodeXYZ”的节点生成,则在标签内相应配置:
IFEOutputPortFull 0 IFE 65536 IFEInstanceName0 0 IPEInputPortFull 0 IPE 65538 IPEInstanceName0 0 false YUV420NV12 8 Ion MemFlagHw
:用于指定输出端口对应的缓冲区。
》》》以下标签指定了封装标签要用的值,不能在其中嵌入额外的标签:
:用于标识 Use case 的字符串。
Valid value:
Any string that is a valid C variable
例子:
: 该字串用于映射流的输出缓冲区到拓扑中节点的输出端口,其中 包含的字符串用于关联节点的输出端口与此流的输出缓冲区。
Valid value:
Any string that is a valid C variable, however, there must be a matching string name in the
1 |
|
Valid values: TargetOutput TargetInput TargetBidirectional 例子:TargetOutput
:此标签指定与流关联的缓冲区的格式。允许指定多个标签指定,如果其中一种格式与configure_streams()中给出的配置匹配,就认为与对应的use case相匹配。 Valid values: Jpeg Y8 Y16 YUV420NV12 YUV420NV21 YUV422NV16 Blob RawYUV8BIT RawQCOM RawMIPI RawPlain16 RawMeta8BIT UBWCTP10 UBWCNV12 UBWCNV124R 例子: YUV420NV12 :缓冲区的最小宽度。由 标记使用。 Valid value: Unsigned 32-bit integer, which must be less than . :缓冲区的最小高度。由 标记使用。 Valid value: Unsigned 32-bit integer, which must be less than . :缓冲区的最大宽度。由 标记使用。 Valid value: Unsigned 32-bit integer, which must be greater than . :缓冲区的最大高度。由 标记使用。 Valid value: Unsigned 32-bit integer, which must be greater than . :拓扑的名称。 Valid value: Any string :字符串描述的节点名称。 Valid value: Any string that is a valid C variable. :标识节点的ID,用于将节点的端口彼此链接。 :字符串以描述节点实例的名称。 Valid value: Any string that is a valid C variable. :标识节点唯一实例的ID,用于节点之间的端口连接。 Valid value: Unsigned 32-bit integer, which must correspond to a unique instantiation of a node of the same engine type. :描述设置名称的字符串。 :描述变量类型的字符串。 Valid values: INT UINT FLOAT BOOL STRING :描述配置变量类型的字符串。 Valid value: Any valid string, which is a valid constant for the tag. :用于标识节点资源的ID,用于将节点的端口彼此链接。 :用于标识节点的唯一实例的ID,用于将节点的端口链接到彼此。 Valid value: Unsigned 32-bit integer, which must correspond to a unique instantiation of a node of the same engine type. :描述端口名称的字符串。 Valid value: Any string that is a valid C variable. :端口的ID,用于各端口之间的连接。 :确定是否需要批处理。一般来说,只有在HFR中才需要该模式,使ISP在单个硬件提交中处理多帧,一般适用于无法离线操作的链接。 Valid value: 0 to disable batch mode, 1 to enable it. :缓冲区类型。 Valid values: Jpeg Y8 Y16 YUV420NV12 YUV420NV21 YUV422NV16 Blob RawYUV8BIT RawQCOM RawMIPI RawPlain16 RawMeta8BIT UBWCTP10 UBWCNV12 UBWCNV124R 示例: YUV420NV12 >一个链接允许创建的最大缓冲区数量。 Valid values: 32 bit-unsigned integer. :允许在camera ISP之外分配缓存的堆。 Valid values: System Ion DSP EGL :描述缓冲区的信息,例如设置MemFlagWriteAccess表示节点可写入。 Valid values: MemFlagHw MemFlagProtected MemFlagCmdBuffer MemFlagUMDAccess MemFlagCache MemFlagPacketBuffer MemFlagKMDAccess :节点属性值,包含对应要加载的so模块,如:com.company.node.hdvideo
六、自定义Use case示例
CHI override模块为实现HAL-ZSL接口以支持ZSL快照扩展了HAL3功能。此外,CHI override也提供了诸多的API,以实现像MFNR(多帧降噪)这样的多帧处理功能。
例如:override模块实现ZSL MFNR快照use case时有如下功能需求:
能够创建 和 管理 多个 会话 和 相关 的 管道 ZSL 快照需要一 个实时的RAW pipelien和一个离线会话。 MFNR 需要额外的离线会话用于预过滤、混合、再过滤阶段。 能够控制整个会话的各请求和结果传输。 能够在应答framework请求的响应内部生成请求。 能够记录所有内部结果并生成最终的framework应答。 能够管理ZSL队列缓冲区 (图像和元数据)。 能够控制 inter-session buffer, fence, 和 metadata 联系。 能够支持锚帧选择逻辑。
多帧降噪涉及到相机硬件对帧处理的复杂排序。有不同的处理阶段,即mfnn - prefilter,MFNR-Blend和MFNR-Postfilter,它们调用不同的pipeline,其中Node会在处理阶段被实例化具有不同的功能。例如,基于IPE硬件的预过滤阶段与混合阶段不同,override module实例化不同的实时和离线pipeline来实现MFNR ZSL快照。
1初始化
override module在摄像机服务器进程启动期间初始化,此时会加载com.qti.chi.override.so,该库提供了由QTI实现的CHI override接口,所需的函数指针由CHI override module加载,同时会遍历该平台上支持的以及包括自定义nodes的vendor tags。
入口函数的伪代码:
void chi_hal_override_entry ( const chi_hal_ops_t *ops, ///< [in] chi_hal_callback_ops_t *callbacks) ///< [in | out] { ... // Store the hal ops QtiChiOverride::m_chiOps = *ops; ... // Export the callback function pointers callbacks->chi_initialize_override_session = QtiChiOverride::InitializeOverrideSession; callbacks->chi_finalize_override_session = QtiChiOverride::QtiChiExtFinalizeOverrideSession; ... // Optional callback function pointers can be NULL }
2创建会话
驱动程序中的HAL3模块将chi_initialize_override_session传递到CHIoverride module,以便override module用于检查流的配置,以及决定是否重写或忽略use case。override module通过stream的格式、类型和使用标准等配置表明是否需要HAL-ZSL,如果满足ZSL use case的条件,它就将创建realtime和offline pipeline,具体会根据拓扑中对real-time pipeline的描述调用chi_create_pipeline来创建。real-time pipeline除了PREVIEW_TARGET外,还有一个RAW_TARGET来接收原始ZSL buffer的数据。override module会将新创建的real-time pipeline句柄返回给驱动程序。
Google Framework -> HAL3 -> CHI -> QTI CHI Extension
3 ZSL 预览
驱动程序将framework层发出的每个请求通过chi_override_process_request接口传递给override module。如果应用程序只需要预览,则只发出请求、申请缓冲区和设置对应preview stream即可。override module从framework获取请求后并为raw target添加额外的请求,override module为raw target分配内部缓冲区并进行管理。修改后的请求调用chi_submit_pipeline_request利用real-time session句柄传递给驱动程序。
在目标缓冲区fences都被标记后才会收到驱动返回的结果,驱动程序调用chi_override_result_notify接口来唤醒override module获取结果。override module提取raw target buffer元数据并推入ZSL队列。framework每次发出的预览请求都会重复这个过程。
(后面时序图画一下。。。。。)
4 ZSL 拍照(常规请求和结果)
用户通过应用程序发送拍照请求,override module通过chi_override_process_request接口获取request来解析对ZSL帧的需要。MFNR缺失vendor tags则会使override module做一个常规的ZSL快照,以及在real-time session中的raw target添加内部请求。除此之外,它还标记了两个内部请求,一个使用offline session_1对原始Bayer数据转换成yuv,一个使用offline session_2用于yuv到jpeg的转换,这样标记有助于在之后生成内部请求到pipeline。override module可以在不同的会话中配置访问缓冲区和相关的栅栏,它将会话间缓冲区和栅栏联系起来,以实现无缝控制。
对于常规的ZSL快照,在它提交完实时请求之后,override module就从ZSL队列及其元数据获取最新的帧,并将其提交到offline session_1。 real-time session返回结果的流程和操作ZSL预览类似,当override module接收到offline session_1的结果时,它将根据之前为offline session_2所做的标记生成一个内部请求,此请求将从offline session_1获取YUV输出,以生成一个JPEG编码照片,override module配置offline session_2来使用framework提供的拍照目标缓冲区。
(后面画下时序图。。。)
5 ZSL 拍照 (MFNR请求)
应用程序使用特殊的vendor tags请求ZSL MFNR拍照。当带有vendor tags的请求被override module获取时,它首先扫描可用的ZSL队列,以寻找合适的锚帧,以为raw target创建新的内部请求。
假设ZSL深度为4,MFNR深度为8,则实时请求的数量是:
情形1:对于ZSL队列的顶部帧,则MFNR_DEPTH (8) - (ZSL_DEPTH (4)) - AnchorIndex(0) = 4。
情形2:对于ZSL队列中的最后一帧,然后是MFNR_DEPTH (8) - (ZSL_DEPTH) (4) - 锚定指数(3)= 7。
情形3:对于ZSL队列中没有帧,则MFNR_DEPTH(8)。
除了实时请求外,还为不同的对象生成多个offline pipeline对应MFNR处理的不同阶段:MFNR预滤器 = 1; MFNR共混物= N-2 = (8) -2 = 6;MFNR后置滤波器= 1。
每一个请求都是交错的,并提交给相应的pipeline,这些请求在real-time 和 offline sessions之间ID相同。
以上大致介绍了 CHI API 框架和一些关键术语的理解,后面可以根据文档各API的说明结合代码进行流程分析。
参考文档:80-pc212-1_b_qualcomm_spectra_camera_chi_api_reference.pdf