一、CAM CHI API功能介绍:
- 没有接口可以单独访问ISP内部固定引擎
- 没有接口可以显示的对一个use case申请一个处理流程
- use case可以宽泛的定义,具体的处理流程可以实现的不一样
- framework之前的请求必须全部有返回结果
- Pipeline深度基于use cases调整,实现太复杂的pipeline对于大部分HAL3 相机驱动来说请求太多
- 对于应用程序来说没有"fast path"来简化处理流程和降低延迟
![](https://i-blog.csdnimg.cn/blog_migrate/30b5018ee8ed7a6599920e98d046b6f0.png)
1.Qualcomm Spectra 2xx相机驱动程序有五个关键的可定制组件,使OEM能够充分利用CHI进行相机应用开发:
- CHI Override 模块补充了Google HAL3接口,允许符合HAL3标准的相机应用程序直接控制图像处理流水线的生成、引擎选择和多帧控制等。
- CHI pipeline 旨在将任意的计算管道构造用于图像处理,管道可以由QTI或扩展节点提供的ISP(FF-ISP)固定功能模块组成,由摄像机驱动程序堆栈外部控制。对于Camera2/HAL3实现,可以利用XML文件指定与现有Camera2/HAL3 use case 的拓扑图,然后通过程序直接调用CHI来实现pipeline。
- CHI节点扩展是CHI的进一步扩展,提供了方便的hooks方法来简化CPU,GPU(通过OpenCL,OpenGL ES或Vulkan),或 DSP(通过OpenDSP,FastCV™软件开发套件或自定义编程)上的额外处理。 自定义节点可以指定私有供应商标记,用于被应用使用以及 与CHI FF-ISP节点或其他扩展节点交互。
- CHI统计信息覆盖(包括3A)机制允许覆盖任何QTI的默认值统计算法,且无需改驱动程序。外部统计算法可以存储私有数据,也可以由自定义节点访问。
- CHI传感器XML允许设备制造商为其特定硬件配置参数,包括相机模块,图像传感器, 执行器,电子可擦除可编程只读存储器(EEPROM)和 闪存组件。
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的扩展接口,允许通过请求调整拓扑结构和低延迟控制,一些使用特性如下:
- 自定义ZSL
- 多帧请求生成 和 处理
- 图像稳定
- 低延迟后处理
CHI驱动程序提供默认节点来启用相机use cases。oem厂商可以在现有的CHI驱动上添加功能,以获得独特的相机体验。这是一个简单而强大的接口,可以在相机pipeline中无缝添加图像处理功能。
下面的时序图大致描述了一个CHI的use case创建流程:
其中CameraType定义如下:
- Nodes:每个请求都会访问所有节点,也可以忽略某些请求不需要的节点。
- Links: 链接指定了所有使用到的缓冲区格式和大小(无论作为源还是接收器)。节点之间的链接可以根据父节点上输出端口的最小数量指定尽可能多的格式,以及在子节点上的接收端口的数量。
- Buffers: Topology 控制给定类型的缓冲区数量,应用程序可以根据需要多少缓冲区微调内存使用情况以减少处理延迟。
三、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.<vendor>.<category>.<algorithm>.so
<vendor> —— 对应厂商定义的节点模块。例如,节点由QTI提供,则命名为< QTI >。 <category> —— 模块类型,有效值为 <node> 和 <stats>。 <algorithm> - so对应的独有算法名。
示例:
-
QTI提供的3A算法命名为:com.qti.3a.aec.so
- QTI提供的高通®Clear Sight™相机功能后处理节点命名为:com.qti.node.clearsight.so
对于nodes,名称必须和拓扑XML中指定的名称对应。
对于stats,有效值只有 <af>、<aec>、<awb>、<asd>和<afd>。
所有.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中的<Targets>和< SystemwideSettings >两个部分来选择一个用例:
- XSD模式定义了XML结构。
- 工具用于将XML文件打包为二进制文件,供CHI驱动程序使用。
1.Node, port, link
节点代表拓扑结构中的硬件或软件处理组件,包括QTI提供的默认节点,以及为使用CHI驱动自定义的节点。节点有一组输入端口和一组输出端口,输出数据到HAL3图像缓冲区的输出端口称为SinkBuffer,也有一些输出端口不输出到任何图像数据,仅用于发出该节点正在被使用的信号。拓扑中的DAG(有向无环图)是通过将节点的输入端口连接到前一个节点的输出端口形成,或者在需获取反馈结果的情况下,节点的输出端口也可以连接到自己的输入端口。各个节点之间的链接还包含有使用到的缓冲区的必要信息。
图解:
2.配置项解析
<UsecaseDef> :根标记,属性必须定义。如: <UsecaseDef xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:noNamespaceSchemaLocation="topology.xsd">
<Usecase> :用例,代表一种功能特性(如:ZSL),tags存在于<Usecase> </Usecase>之间如下:
<UsecaseName> - Value field. Exactly 1 tag is required.
<Targets> - Exactly 1 is required.
<StreamConfigMode> - Value field. Exactly 1 is required.
<SystemwideSetting> - Exactly 1 is required.
<Topology> - At least 1 is required.
<Targets> :流的列表,包括用例执行的格式和大小范围。这里列出的流对应于传入HAL3的configure_streams () API,通过tag值找到匹配的<Usecase>。
<Target> and <SystemwideSettings> 用于从XML中选择一个<Usecase>。
Valid tag:
<TargetName> - Value field. Exactly 1 is required.
<TargetDirection> - Value field. Exactly 1 is required.
<TargetFormat> - Value field. At least 1 is required.
<Range> - Exactly 1 is required. <Range> : 缓冲区的分辨率范围。
Valid tag:
<MinW> - Value field. Exactly 1 required.
<MinH> - Value Field. Exactly 1 required.
<MaxW> - Value Field. Exactly 1 required.
<MaxH> - Value Field. Exactly 1 required.
一个Target示例:(当驱动程序处理configure_streams()时,如果有一个输出流的缓冲区格式是YUV420NV12且分辨率小于等于1080p时,就会匹配到如下Target。)
<Targets> <Target> <TargetName>TARGET_BUFFER_PREVIEW</TargetName> <TargetDirection>TargetOutput</TargetDirection> <Formats>YUV420NV12</Formats> <Range> <MinW>0</MinW> <MinH>0</MinH> <MaxW>1920</MaxW> <MaxH>1080</MaxH> </Range> </Target> </Targets>
<SystemwideSettings> : 会话组的设定,与<targets>结合使用定义了use case的键值,这些设置对应于Android属性。
Valid tag:
<Setting> - At least 1 is required.
<Setting> : 设置说明,用于选择对应的use case。
Valid tag:
<SettingName> - Value field. Exactly 1 is required.
<SettingDataType> - Value field. Exactly 1 is required
<SettingMatch> - Value field. Exactly 1 is required
示例:
<SystemwideSettings> <SettingName>EIS</SettingName> <SettingDataType>BOOL</SettingDataType> <SettingMatch>FALSE</SettingMatch> </SystemwideSettings>
<Topology> :描述了驱动对每个节点的顺序和依赖关系的解析,以处理上层请求。
Valid tag:
<TopologyName> - Value field. Exactly 1 is required.
<TopologyNodesList> - Exactly 1 is required.
<PortLinkage> - At least 1 is required.
<TopologyNodesList> :包含在Topology中的Node列表,形成处理框架。
Valid tag:
<Node> - At least 1 is required.
<Node> : 单个处理逻辑块,用于告诉驱动如何来处理一个请求。
Valid tags:
<NodeProperty> - Optional. Several properties allowed.
<NodeName> - Value field. Exactly 1 is required.
<NodeId> - Value field. Exactly 1 is required.
<NodeInstance> - Value field. Exactly 1 is required.
<NodeInstanceId> - Value field. Exactly 1 is required.
例子:
<Node> <NodeProperty> <PropertyName>PropXYZ</PropertyName> <PropertyDataType>UINT</PropertyDataType> <PropertyValue>6</PropertyValue> </NodeProperty> <NodeName>NodeXYZ</NodeName> <NodeId>1</NodeId> <NodeInstance>NodeXYZInstanceName0</NodeInstance> <NodeInstanceId>0</NodeInstanceId> </Node>
驱动程序根据nodeId解析节点类型,对于所有自定义节点该字段的值为255,并带有一个NodeProperty来告知驱动程序切确的自定义节点类型。如下:
<Node> <NodeProperty> <PropertyName>CustomNodeLibrary</PropertyName> <PropertyDataType>STRING</PropertyDataType> <PropertyValue>customnodelib.so</PropertyValue> </NodeProperty> <NodeName>CustomNode</NodeName> <NodeId>255</NodeId> <NodeInstance>CustomNodeInstanceName0</NodeInstance> <NodeInstanceId>0</NodeInstanceId> </Node>
<NodePortLinkage> : 描述节点列表以及它们如何相互连接。
Valid tags:
<SourceNode> - Value field. Exactly 1 is required.
<SourceNodeInstance> - Value field. Exactly 1 is required.
<Link> - At least 1 is required.
<Link> :单个node之间的连接。
Valid tags:
<SrcPort> - Exactly 1 is required.
<DstPort> - At least 1 is required.
<BufferProperties> - Optional.
<SrcPort> :一个节点的输出端口,该节点输出的图像数据到<DstPort>被使用修改,从<SrcPort>到<DstPort>可以有一对多的关系。
Valid tags:
<PortName> - Value field. Exactly 1 is required.
<PortId> - Value field. Exactly 1 is required.
<NodeName> - Value field. Exactly 1 is required.
<NodeId> - Value field. Exactly 1 is required.
<NodeInstance> - Value field. Exactly 1 is required.
<NodeInstanceId> - Value field. Exactly 1 is required.
<DstPort> :接收从<SrcPort>节点的输出数据。
Valid tags
<PortName> - Value field. Exactly 1 is required.
<PortId> - Value field. Exactly 1 is required.
<NodeName> - Value field. Exactly 1 is required.
<NodeId> - Value field. Exactly 1 is required.
<NodeInstance> - Value field. Exactly 1 is required.
<NodeInstanceId> - Value field. Exactly 1 is required.
<BufferProperties> :输入/输出缓冲区的属性。
Valid tags:
<BatchMode> - Value field. Exactly 1 is required.
<BufferFormat> - Value field. Exactly 1 is required.
<BufferQueueDepth> - Value field. Exactly 1 is required.
<BufferHeap> - Value field. Exactly 1 is required.
<BufferFlags> - Value field. Exactly 1 is required
<UsecaseName>:任何字符串可以定义一个用例名称;
例如,指定此流输出缓冲区由名为“NodeXYZ”的节点生成,则在<Link>标签内相应配置:
<Link> <SrcPort> <PortName>IFEOutputPortFull</PortName> <PortId>0</PortId> <NodeName>IFE</NodeName> <NodeId>65536</NodeId> <NodeInstance>IFEInstanceName0</NodeInstance> <NodeInstanceId>0</NodeInstanceId> </SrcPort> <DstPort> <PortName>IPEInputPortFull</PortName> <PortId>0</PortId> <NodeName>IPE</NodeName> <NodeId>65538</NodeId> <NodeInstance>IPEInstanceName0</NodeInstance> <NodeInstanceId>0</NodeInstanceId> </DstPort> <BufferProperties> <BatchMode>false</BatchMode> <BufferFormat>YUV420NV12</BufferFormat> <BufferQueueDepth>8</BufferQueueDepth> <BufferHeap>Ion</BufferHeap> <BufferFlags>MemFlagHw</BufferFlags> </BufferProperties> </Link>
<TargetName>:用于指定输出端口对应的缓冲区。
》》》以下标签指定了封装标签要用的值,不能在其中嵌入额外的标签:
<UsecaseName> :用于标识 Use case 的字符串。
Valid value: Any string that is a valid C variable
例子:<UsecaseName>UsecasePreview</UsecaseName>
<TargetName> : 该字串用于映射流的输出缓冲区到拓扑中节点的输出端口,其中<TargetName>包含的字符串用于关联节点的输出端口与此流的输出缓冲区。
Valid value:
Any string that is a valid C variable, however, there must be a matching string name in the <PortName> of any <DstPort> which is a sink port.
例子:<TargetName>TARGET_BUFFER_PREVIEW</TargetName>
<TargetDirection>:此标签用于指定流的方向(或流类型),即它是否是输入流、输出流或双向流。
Valid values:
TargetOutput
TargetInput
TargetBidirectional
例子:<TargetDirection>TargetOutput</TargetDirection>
<TargetFormat>:此标签指定与流关联的缓冲区的格式。允许指定多个标签指定,如果其中一种格式与configure_streams()中给出的配置匹配,就认为与对应的use case相匹配。
Valid values:
Jpeg
Y8
Y16
YUV420NV12
YUV420NV21
YUV422NV16
Blob
RawYUV8BIT
RawQCOM
RawMIPI
RawPlain16
RawMeta8BIT
UBWCTP10
UBWCNV12
UBWCNV124R
例子:<TargetFormat>YUV420NV12</TargetFormat>
<MinW> :缓冲区的最小宽度。由<Range>标记使用。
Valid value:
Unsigned 32-bit integer, which must be less than <MaxW>.
<MinH> :缓冲区的最小高度。由<Range>标记使用。
Valid value:
Unsigned 32-bit integer, which must be less than <MaxH>. <MaxW> :缓冲区的最大宽度。由<Range>标记使用。
Valid value:
Unsigned 32-bit integer, which must be greater than <MinW>.
<MaxH> :缓冲区的最大高度。由<Range>标记使用。
Valid value:
Unsigned 32-bit integer, which must be greater than <MinH>.
<TopologyName> :拓扑的名称。
Valid value:
Any string
<NodeName>:字符串描述的节点名称。
Valid value:
Any string that is a valid C variable. <NodeId>:标识节点的ID,用于将节点的端口彼此链接。
<NodeInstance>:字符串以描述节点实例的名称。
Valid value:
Any string that is a valid C variable. <NodeInstanceId>:标识节点唯一实例的ID,用于节点之间的端口连接。
Valid value:
Unsigned 32-bit integer, which must correspond to a unique instantiation of a node of the same engine type. <SettingName>:描述设置名称的字符串。
<SettingDataType>:描述变量类型的字符串。
Valid values:
INT
UINT
FLOAT
BOOL
STRING <SettingMatch>:描述配置变量类型的字符串。
Valid value:
Any valid string, which is a valid constant for the <SettingMatch> tag.
<SourceNode>:用于标识节点资源的ID,用于将节点的端口彼此链接。
<SourceNodeInstance>:用于标识节点的唯一实例的ID,用于将节点的端口链接到彼此。
Valid value:
Unsigned 32-bit integer, which must correspond to a unique instantiation of a node of the same engine type. <PortName> :描述端口名称的字符串。
Valid value:
Any string that is a valid C variable.
<PortId> :端口的ID,用于各端口之间的连接。 <BatchMode>:确定是否需要批处理。一般来说,只有在HFR中才需要该模式,使ISP在单个硬件提交中处理多帧,一般适用于无法离线操作的链接。
Valid value:
0 to disable batch mode, 1 to enable it. <BufferFormat>:缓冲区类型。
Valid values:
Jpeg
Y8
Y16
YUV420NV12
YUV420NV21
YUV422NV16
Blob
RawYUV8BIT
RawQCOM
RawMIPI
RawPlain16
RawMeta8BIT
UBWCTP10
UBWCNV12
UBWCNV124R
示例:<BufferFormat>YUV420NV12</BufferFormat>>
<BufferQueueDepth> 一个链接允许创建的最大缓冲区数量。
Valid values:
32 bit-unsigned integer.
<BufferHeap>:允许在camera ISP之外分配缓存的堆。
Valid values:
System
Ion
DSP
EGL <BufferFlags>:描述缓冲区的信息,例如设置MemFlagWriteAccess表示节点可写入。 Valid values:
MemFlagHw
MemFlagProtected
MemFlagCmdBuffer
MemFlagUMDAccess
MemFlagCache
MemFlagPacketBuffer
MemFlagKMDAccess <NodePropertyValue>:节点属性值,包含对应要加载的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的说明结合代码进行流程分析。
六、CHI interface
CHI向谷歌HAL3接口添加了几个关键元素,以支持更细粒度的控制。下面的函数用于访问CHI驱动程序,它们对Camera2/HAL3没有任何依赖。
1.VOLD ChiEntry( CHICONTEXTOPS* pContextOps); CHI驱动程序的入口点,该函数用指向CHI函数的指针填充pContextOps,在使用CHI的每个进程中,必须至少调用该函数一次。
2.CHIHANDLE (*PFNCHIOPENCONTEXT)(); 此函数用于创建ChiContext的唯一实例。ChiContext是state在ChiSessions中传输的上下文。每个进程至少有1个ChiContext。chicontext之间没有通信信息的机制,ChiSessions和ChiPipelines只能在创造它们的ChiContex中t所使用。返回值:新创建的 ChiContext handle 或 NULL。
3.VOID (*PFNCHICLOSECONTEXT)(CHIHANDLE hChiContext); 此函数用于关闭ChiContext,将终止任何未完成的请求,并释放此上下文声明的所有资源。用户应该在调用PFNCHICLOSECONTEXT之前销毁所有未完成的ChiSessions 和 ChiPipeline,否则可能导致资源泄漏。
4.UINT (*PFNCHIGETNUMCAMERAS)( CHIHANDLE hChiContext); 此函数用于确定平台上可用的相机传感器的数量,可以在创建ChiContext之前调用。如果一个平台有多个相机组合成一个物理通道(例如,在桥接芯片后面),这些相机被认为是一个物理传感器。如果ChiContext句柄无效,则此函数返回-1。
5.CDKResult (*PFNCHIGETCAMERAINFO)( CHIHANDLE hChiContext, UINT32 cameraId, CHICAMERAINFO* pCameraInfo); 该函数用于获取特定camera的详细信息,可以在创建ChiContext之前调用。如果将传感器信息写入pCameraInfo,则返回一个错误代码。
6.CDKResult (*PFNCHIENUMERATESENSORMODES)( CHIHANDLE hChiContext, UINT32 cameraId, UINT32 numSensorModes, CHISENSORMODEINFO* pSensorModeInfo); 该函数用于获取特定sensor模组的详细信息
7.CHIPIPELINEDESCRIPTOR (*PFNCHICREATEPIPELINEDESCRIPTOR)( CHIHANDLE hChiContext, const CHIPIPELINECREATEDESCRIPTOR* pDescriptor, UINT32 numOutputs,CHIPORTBUFFERDESCRIPTOR* pOutputBufferDescriptors, UINT32 numInputs, CHIPIPELINEINPUTOPTIONS* pInputBufferOptions); 该函数用于读取pipeline描述符,确认描述符中包含的拓扑,然后返回pipeline内部驱动程序表示的句柄。在代码的时间敏感部分不应调用此函数。这个函数可以在HAL设备创建之后的任何时候调用。调用者负责使用后销毁pipeline。pipeline可以在会话之间共享,不包含对缓冲区格式或大小的任何绑定。PFNCHICREATEPIPELINEDESCRIPTOR申请输出缓冲区,并确定拓扑中每个节点的入口的大小要求。返回的默认配置保证对给定的输出缓冲区集有效。对于使用传感器作为输入的管道,将返回有效的传感器模式列表,以便用户进行微调。对于使用内存作为输入的管道,将返回大小需求列表。
8.VOID (*PFNCHIDESTROYPIPELINEDESCRIPTOR)( CHIHANDLE hChiContext, CHIPIPELINEDESCRIPTOR hPipelineDescriptor); 销毁一个pipeline描述符,pipeline不维护任何状态(这是session的职责),因此可以在任何时候销毁它们。
9.CHIHANDLE (*PFNCHICREATESESSION)( CHIHANDLE hChiContext, UINT numPipelines, CHIPIPELINEINFO* pPipelineInfo, CHICALLBACKS* pCallbacks, VOID* pPrivateCallbackData, CHISESSIONFLAGS flags); 此函数创建包含一个或多个pipeline的独立处理单元会话。会话是在“停用”状态下创建的,只有在试图激活会话时才会获得资源。会话是不可变的,并且拥有pipeline的所有资源。互斥会话在pipeline之间共享资源。非互斥会话为所有pipeline保留了足够的资源,pipeline可以从内存(offline)或通过流(realtime)获取输入数据。
10.VOID (*PFNCHIDESTROYSESSION )( CHIHANDLE hChiContext, CHIHANDLE hSession BOOL isForced); 销毁一个camera session。
11.CDKResult (*PFNCHIACTIVATEPIPELINE)( CHIHANDLE hChiContext, CHIHANDLE hSession, CHIHANDLE pipeline, CHISENSORMODEINFO* pSensorModeInfo); 此函数激活会话中的pipeline,然后可以开始向pipeline提交请求。
12.CDKResult (*PFNCHIDEACTIVATEPIPELINE)( CHIHANDLE hChiContext, CHIHANDLE hSession, CHIHANDLE pipeline, CHIDEACTIVATEPIPELINEMODE mode); 禁用pipeline,释放会话的资源。驱动程序会试图保留尽可能多的资源,以实现快速地重新激活会话。
13.CDKResult (*PFNCHISUBMITPIPELINEREQUEST)( CHIHANDLE hChiContext, CHIPIPELINEREQUEST* pRequest); 在会话中向特定pipeline提交请求。
14.
15.
16.
17.
18.
19.
20.
参考文档:80-pc212-1_b_qualcomm_spectra_camera_chi_api_reference.pdf