系列文章目录:

接下来看configureStreams的流程,从CameraDeviceSession开始,这个调用是app通过createCaptureSession一路下来的(CameraDeviceClient–>Camera3Device–>CameraDeviceSession)

\hardware\interfaces\camera\device\3.4\default\CameraDeviceSession.cpp

从这里,即将进入CamX-CHI,

对一下结构体名字,没错

又要到camxhal3entry中去找了

\vendor\qcom\proprietary\camx\src\core\hal\camxhal3entry.cpp

下面几步跳转和open类似,不再赘述

\vendor\qcom\proprietary\camx\src\core\hal\camxhal3.cpp

\vendor\qcom\proprietary\camx\src\core\hal\camxhaldevice.cpp

很直观,先获取chi的接口对象,再通过这个对象去到chi实现中

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensioninterface.cpp

这个函数有六七百行,大略看一下:

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensionmodule.cpp

这个g_chiContextOps应该是CamX提供给CHI的对象,其中函数指针的映射是在ExtensionModule的初始化中完成的

过程就不细讲了,可以看这段解释:

“CHI中的ExtensionModule在初始化的时候,其构造方法中也会通过调用dlopen方法加载camera.qcom.so库,并将其入口方法ChiEntry通过dlsym映射出来,之后调用该方法,将g_chiContextOps(ChiContextOps,该结构体中定义了很多指针函数)作为参数传入CamX中,一旦进入CamX中,便会将本地的操作方法地址依次赋值给g_chiContextOps中的每一个函数指针,这样CHI之后就可以通过g_chiContextOps访问到CamX方法。”

ChiEntry方法中的函数指针定义在:

\vendor\qcom\proprietary\camx\src\core\chi\camxchi.cpp

接着往下看,进行了很多StreamConfig的设置

第一个框,看一下做了什么:

把当前camera对应的HalOps映射到m_HALOps本地,pHalOps是更上层传入的

回到InitializeOverrideSession中,第二个框看上去就很重要了,涉及到了Usercase的选择,有了之前的印象,我们可以知道Usecase是camx针对不同的stream建立的对象,用来管理选择feature,并且创建 pipeline以及session。

(更详细的介绍可以看https://blog.csdn.net/u012596975/article/details/107138576)

如此看来,接下来的m_pUsecaseSelector->GetMatchingUsecase这一步调用重要性可见一斑,看看具体做了什么:

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxusecaseutils.cpp

果然如同上述介绍所说,这里根据不同的使用场景,选择了不同的usecaseId,usecaseId结构的定义在:

\vendor\qcom\proprietary\chi-cdk\core\chiutils\chxdefs.h

最后把选择的usecaseId返回InitializeOverrideSession中,这里就要真正地创造usecase对象了:

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensionmodule.cpp

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxusecaseutils.cpp

可以看到,根据不同的usecaseId调用不同的Create方法向上返回usecase对象。并且通过这些case的名字来判断,预览应该走的是PreviewZSL的case,也就是创建了一个AdvancedCameraUsecase的对象,这个AdvancedCameraUsecase类也是使用最多的usecase。

至此,爽快直接,逻辑通顺,看来跟踪的流程是正确的

接着看AdvancedCameraUsecase::Create具体做了什么:

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

可以注意到,调用了一个从XML中获取usecase的方法GetXMLUsecaseByName,参数定义如下:

这里很容易联想到第一篇中定义了pipeline、node的那个xml,进去看一下:

这里并没有预想中打开特定xml之后读取的动作,看了一下高亮的这个变量应该是存储了所有的usecase,不幸的是里面涉及的数据结构比较复杂,这里先不深入了

回到Initialize:

又出现了关键词feature,跟进去看一下:

很长,但是可以理解。通过一系列设置,整了一个featureWrapper对象,最后把选好的feature设置到pStreamConfig里去

回到Initialize,看看用这个StreamConfig又干嘛了:

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

可以看到,FeatureSetup中把pStreamConfig设置好之后,就丢进了SelectUsecaseConfig进行下一步处理

这下,出现了两个很惊人的函数调用,首先看ConfigureStream,没想到是在这里调用

根据不同的usecaseId,把pStreamConfig中带下来的stream们保存到不同的本地stream变量里

这里大概能看出预览和拍照应该分别使用的是m_pPreviewStream和m_pSnapshotStream

确认这两个stream保存下来之后,计算了一个纵横比保存下来,最后调用了ConfigFdStream

看名字以为和设备有关,看上去也只是把一些参数设置到m_pFdStream变量中去,看一下这个m_pFdStream的定义:

看不出什么端倪,等等看之后的流程会不会用到吧

configStream算完事了,接下来回到SelectUsecaseConfig看BuildUsecase做了什么

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

主要填充了这两个Pipelines的数组

并且从6945行开始的两层循环可以看出来,每个物理摄像头可能对应多个feature,然后会把feature里的每个pipeline都保存下来

接着,usercase相关的信息也会保存到m_pClonedUsecase中

这样,SelectUsecaseConfig完成了需要关注的事务,回到AdvancedCameraUsecase::Initialize中

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

从SelectUsecaseConfig出来之后对m_pCallbacks做了一系列赋值操作,看看这个callback具体是callback什么

定义在\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.h

可以看出,主要就是result的回调,那看来还挺重要的。

第一个框里可以看出,每一个pipeline都有其callback(也可以从初始化的时候,给m_pCallbacks分配空间时候看出,5194行,用pipeline的num来申请空间)

第二个框,调用了CameraUsecaseBase::Initialize,把刚映射完成的callback传进去

框里的注释可以看出来,session和pipeline是一对一的关系,数量是一样的

接着往下看:

这里,终于正式开始创建pipeline,从循环次数和CreatePipeline接收的参数可以看出,这里也是把每个pipeline都创建出来,接着进入CreatePipeline中,注意一下第二个参数PipelineType::Default,值为5

继续看Pipeline::Create

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxpipeline.cpp

代码中能看到的Pipeline类有两个,chxpipeline,和camxpipeline。

虽然从参数来看可以知道这个Initialize调用到的是chxpipeline,但是camxpipeline是什么作用呢?它和chxpipeline有类似的接口设置,又有何用意?先把这个问题保留,对不上号的camxpipeline的参数是input/output两个data,留个印象:

接着先看chxpipeline中的Initialize

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxpipeline.cpp

为pipeline中的一系列成员变量赋值,注意445行,这里应该是不进if的,记得刚才提到传入的type吗,是Default而不是OfflinePreview

接下来可以回到CameraUsecaseBase::CreatePipeline中继续往下看了

可以看到对outputbuffer和inputbuffer中所有的sink和src进行了配置

sink和src又是什么呢,看它们和output/input的对应关系加上百度了一些相关知识,大概了解到sink一般对应一个模块的输出部分,src当然就是输入部分

那么推测这部分就是把pipeline中输入输出部分的buffer、node和port配置了一下

CreatePipeline中接着往下

配置好的pSinkTarget和pSrcTarget统一set到pPipelineData中,这些set方法没什么好说的,就是把传入的参数都保存到对应的成员变量里去。

再看看最后一个框中的调用:

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxpipeline.cpp

用所有保存好的信息,创建pipelineCreateData对象,然后传到ExtensionModule中的CreatePipelineDescriptor

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensionmodule.cpp

通过老朋友g_chiContextOps继续,这里就是向camx的调用了,不记得这个对象就看这里的函数映射关系

S:\virtualCam\vendor\qcom\proprietary\camx\src\core\chi\camxchi.cpp

继续跟着CreatePipelineDescriptor往下追踪:

\vendor\qcom\proprietary\camx\src\core\chi\camxchicontext.cpp

主要关注这个函数中,对pPipelineDescriptor这个对象做了什么,毕竟是要返回上去的,上图只能看到一些常规的赋值,接着往下看:

到这里,第一个框,大概知道根据pPipelineDescriptor中的信息,对pipelineCreateInputData和pipelineCreateOutputData做了一些设置。

而第二个框就有意思了,这两个参数唤起了沉睡的记忆,刚在initialize的时候遇到了两个pipeline类的问题,这里传入Pipeline::Create的是camxpipeline中的函数接收的input/output参数,也就可以回答上面提到的camxpipeline类是用来做什么的了。

解决了之前留下的问题,于是这里的Create调用到:

\vendor\qcom\proprietary\camx\src\core\camxpipeline.cpp

这里就相当冗长了

创建了一系列lock,后面也是很多从函数名看不出端倪的调用

追流程要抓关键,这个函数最终会返回result,那么很有理由相信result会作为关键调用的返回值被赋值,有了这个思想之后看看哪些地方修改了result的值

果然,看到了这个想看到的函数,进入看看:

\vendor\qcom\proprietary\camx\src\core\camxpipeline.cpp

可以看到,node数量和node信息之类的值都是pCreateInputData->pPipelineDescriptor带下来的,也就是说pipeline中就已经决定了使用哪些node

同样,追着result往下看:

\vendor\qcom\proprietary\camx\src\core\camxnode.cpp

这里创建了一个pFactory对象,这个对象赋值的时候同时把HwEnviroment中的HwFactory单例创建出来了。

这部分流程看上去不太重要,但是可以说明白pFactory->CreateNode调用的位置,不想看可以跳过,这里大致列一下调用流程:

\vendor\qcom\proprietary\camx\src\core\camxhwenvironment.h

m_pHwFactory是怎么创造出来的呢:

\vendor\qcom\proprietary\camx\src\core\camxhwenvironment.cpp

\vendor\qcom\proprietary\camx\src\core\camxhwenvironment.cpp

要素察觉,看着又是一系列函数指针定向

\vendor\qcom\proprietary\camx\src\hwl\titan17x\camxtitan17xhwl.cpp

\vendor\qcom\proprietary\camx\src\hwl\titan17x\camxtitan17xfactory.cpp

回到Node::Create中

\vendor\qcom\proprietary\camx\src\core\camxnode.cpp

通过上面支线解析可以知道,pFactory是HwFactory的子类Titan17xFactory的一个对象

所以CreateNode的调用位置就很好知道了:

\vendor\qcom\proprietary\camx\src\core\camxhwfactory.cpp

\vendor\qcom\proprietary\camx\src\hwl\titan17x\camxtitan17xfactory.cpp

终于看到了这些node最后被创造的地方,向上返回不同类型的Create创建返回的nodes

一直回到这里:

\vendor\qcom\proprietary\camx\src\core\camxnode.cpp

可以看到pNode还会调用一个Initialize函数,但是注意pNode创建的时候是由不同类型的Create创建返回的,所以这里不去关注这些node的初始化过程,接着向上返回

回到\vendor\qcom\proprietary\camx\src\core\camxpipeline.cpp:

看上去node创建出来之后,还对这个node的各种属性进行赋值

接着往下:

如注释所说,创建node的连接关系,输入输出port、link等等

这样一直到最后,完成CreateNodes的工作,回到

\vendor\qcom\proprietary\camx\src\core\camxpipeline.cpp

Initialize中:

接下来也没有什么值得说道的,Pipeline::Initialize结束,标记这个pipeline已经初始化后,向上返回

回到CreatePipelineDescriptor

\vendor\qcom\proprietary\camx\src\core\chi\camxchicontext.cpp

pPipelineDescriptor创建好了,继续向上返回到ChiCreatePipelineDescriptor

\vendor\qcom\proprietary\camx\src\core\chi\camxchi.cpp

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensionmodule.cpp

依然向上返回到CreateDescriptor中

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxpipeline.cpp

创建出来的descriptor保存到m_hPipelineHandle

再把信息保存到m_pipelineInfo.hPipelineDescriptor,继续向上返回到CreatePipeline中

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

CreatePipeline也就这样结束,看看Initialize中还做了什么

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

除了pipeline,看样子还创造了session,omfg以为已经结束了

先不管这个session的创建过程,有机会再细看吧

这样看完了CameraUsecaseBase::Initialize的过程,调用这个Initialize的上层是AdvancedCameraUsecase::Initialize

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

把usecase创建完成的事post一下,主要是把feature

AdvancedCameraUsecase::Initialize中,重要的调用(

GetXMLUsecaseByName、FeatureSetup、SelectUsecaseConfig、CameraUsecaseBase::Initialize)执行完毕后,也继续向上返回

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp

\vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxusecaseutils.cpp

继续一路返回到ExtensionModule::InitializeOverrideSession中:

\vendor\qcom\proprietary\chi-cdk\core\chiframework\chxextensionmodule.cpp

至此,一个logicalCamera对应的usecase就创建出来,可以看到创建好之后对这个对象的其他成员也都纷纷赋值或者新建,然后就继续向上返回

\vendor\qcom\proprietary\camx\src\core\hal\camxhaldevice.cpp

成功创建则向上返回true赋值状态

向上:

\vendor\qcom\proprietary\camx\src\core\hal\camxhal3.cpp

confige完毕之后,把stream的信息打印了一滩,之后也是向上返回

之后就会一路回到cameraservice了

ConfigureStream整体流程参考:

1 对 “ANDROID CAMERA 学习-configureStreams 在 QCOM CAMX架构中的调用”的想法;

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注