Android Camera简单整理(二)-Qcom HAL3 Camx架构学习
目录
一. Android Hal3回顾
Camera HAL3学习
HAL层操作简单总结:
1.Framework层发送捕获数据的异步请求。
2.HAL层设备必须按照次序处理请求。对于每个请求,HAL层需要输出元数据和一个或者多个图像数据。
3.对于请求和结果都需要遵循先进先出的原则;这个数据流将被后续的请求所参考。
4,对于同一个请求,所有输出数据的时间戳必须相同,以便framework层同步输出数据,如果需要的话。
5.在请求和结果数据总,所有捕获数据的配置和状态(除了3A处理),都需要封装起来。
二. Qcom Hal3 CamX架构
Qcom作为平台厂商会根据谷歌定义的HAL3接口来实现自己的Camera HAL3,新的主流的Qcom Camera HAL3 架构就是CamX了.
Camx的详细过程可参考高通文档:
80-pc212-1_d_qualcomm_spectra_isp_camera_chi_api_reference.pdf
最主要还是要看code,手机厂商对该层代码有自己的改动,可能差别还是有的,具体项目大体框架一致但细节有区别,差异和机型的高通基线也保持一致.
2.1 CamX架构总体结构
简单总结下:
Camx的架构入口为Camx包中的camxhal3entry.cpp,Camx中是高通平台Camx架构的核心跳转及处理业务的代码,一般手机厂商不会去更改,代码目录在vendor/qcom/proprietary/camx/下,编译结果是camera.qcom.so
Camx通过chxentensionInterface调用到chi-cdk 包下的代码,这里面一般是手机厂商自己定制功能的地方,代码目录在vendor/qcom/proprietary/chi-cdk/,编译结果是com.qti.chi.override.so
从这张图中大概知道一个request来业务流程交给camx处理,但会经过chi-cdk进行request定制化重新打包再交给camx实际去执行或和kernel driver层进行交互,camx部分代码即核心流程管控的代码,而chi-cdk正是手机厂商想要实现自己定制化功能的代码地方.
2.2 CamX架构中重要的数据结构及关系
缺一张图
Usecase /Session/ Feature /pipeline/ Node
Chi对Camx的操作,需要通过 ExtensionModule 进行操作,因此,camx对外提供的接口扩展需要通过ExtensionModule进行,里面一个重要的变量就是g_chiContextOps。
Camx对Chi的操作,是通过HAL3Module接口的m_ChiAppCallbacks进行的,因此chi里面释放的接口,都会在m_ChiAppCallbacks里面体现
Usecase:基本上与App上的各种模式有一定的对应关系,包括PreviewZSL,VideoLiveShot, SAT(Multicamera), RTB(Reatime Bokeh),QCFA, Dual, superslowmotionfrc…, 一个usecase包含了realtime和snapshot的session, 需要包含所有的在这个usecase的所有feature的pipeline列表
Feature: 在Usecase下打开某个功能设计的一种架构,通常情况下一个Usecase可以启用各种不同的feature,feture包含了usecase里面的部分pipeline, 一般都是snapshot的才会包含feature进行处理,因此,usecase与feautre的界限并不明显。
Session: 包含了ChxSession,ChiSession和CamxSession。Chxsession是对chi接口里面对CamxSession的封装,Usecase里面创建的Session都是要创建这一个。ChiSession是camx里面的一个部分,是对camxSession的继承和透传。
pipeline-包含单个经过验证的topology的可重用容器。驱动程序通过pipeline来了解所使用的引擎以及数据处理的流程。
Node—camera pipeline 内的逻辑功能块,在单个引擎上执行。node链接在一起构成一个topology。在CHI API的初始版本中,ISP外部的所有节点都是通过CPU代码调用的,调的是native API。
不同机型,产品性能及定位不同,即使基线一样usecase等也有可能不一样,高通这么做给了手机厂商极大的自定义空间,举个某机型例子,UseCase可以场景复用,对应的pipeline也可以不用或复用.

2.3 CamX操作过程
基本操作,截图自高通文档:
详细过程:
2.3.1 Open Camera

2.3.2 ConfigureStream

2.3.3 Request & Result
request:
result:
一旦底层有事件上传就会走到SyncManagerPollMethod中:
file: vendor/qcom/proprietary/camx/src/csl/hw/camxsyncmanager.cpp
--> VOID* SyncManager::SyncManagerPollMethod(VOID* pPollData)
|--> rc = poll(fds, 2, -1) //监听的syncFd有事件上传
| |--> VOID* pData[] = {pEv, NULL}; //这里的pEv是包含回调方法的,根据setRepeatingRequest中的分析,这里的回调就是Node::CSLFenceCallback
| |--> ioctl(pCtrl->syncFd, VIDIOC_DQEVENT, pEv); //取出事件
| |--> result = pCtrl->pThreadManager->PostJob(pCtrl->hJob, SyncManager::StoppedCbDispatchJob, pData, FALSE, FALSE); //这里就会调到之前注册的线程并回调SyncManager::CbDispatchJob方法
file: vendor/qcom/proprietary/camx/src/csl/hw/camxsyncmanager.cpp
| |--> VOID* SyncManager::CbDispatchJob(VOID* pData)
| | |--> Utils::Memcpy(&ev, reinterpret_cast<struct v4l2_event*> (pData), sizeof(ev));
| | |--> pPayloadData = CAM_SYNC_GET_PAYLOAD_PTR(ev, uint64_t);
| | |--> reinterpret_cast<CSLFenceHandler>(pPayloadData[0]))(reinterpret_cast<VOID* >(pPayloadData[1]), pEvHeader->sync_obj, fenceResult); //回调Node::CSLFenceCallba