Android : Camera之CHI API

sheldon_blogs

https://www.cnblogs.com/blogs-of-lxl/p/10685718.html

Android : Camera之CHI API

一、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进行相机应用开发:

  • CHI Override 模块补充了Google HAL3接口,允许符合HAL3标准的相机应用程序直接控制图像处理流水线的生成、引擎选择和多帧控制等。
  • CHI拓扑结构 由xml进行配置,旨在将任意的计算管道构造用于图像处理,管道可以由QTI或扩展节点提供的ISP(FF-ISP)固定功能模块组成,由摄像机驱动程序堆栈外部控制。
  • 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的扩展接口,允许通过请求调整拓扑结构和低延迟控制。
  一些谷歌HAL3接口使用的特性如下:

  • 自定义ZSL
  • 多帧请求生成 和 处理
  • 图像稳定
  • 低延迟后处理

 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定义如下:

  

  • 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. 

1

例子:<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的说明结合代码进行流程分析。

  参考文档:80-pc212-1_b_qualcomm_spectra_camera_chi_api_reference.pdf

猜你喜欢

转载自blog.csdn.net/zhong29/article/details/89430258