來自:
https://www.cnblogs.com/szsky/articles/10861918.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。
但OEM并不能以此作為通用接口實現方式,Camera2/HAL3接口有如下幾個限制:
- 沒有接口可以單獨訪問ISP內部固定引擎
- 沒有接口可以顯示的對一個use case申請一個處理流程
- use case可以寬泛的定義,具體的處理流程可以實現的不一樣
- framework之前的請求必須全部有返回結果
- Pipeline深度基于use cases調整,實現太復雜的pipeline對于大部分HAL3 相機驅動來說請求太多
- 對于應用程序來說沒有"fast path"來簡化處理流程和降低延遲
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
- 多幀請求生成 和 處理
- 圖像穩定
- 低延遲后處理
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/ChiVendorTagsChiNode1 ? ExtNode1 使用 Android tags/ChiVendorTags / ExtCompVendorTagsExtNode1 ? 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-instancexsi: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 opsQtiChiOverride::m_chiOps = *ops;...// Export the callback function pointerscallbacks->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.