初识高通camx

article/2025/6/7 14:35:03

        一、chi和camx之间如何通信:

  • Chi对Camx的操作,需要通过 ExtensionModule 进行操作,因此,CamX对外提供的接口扩展需要通过ExtensionModule进行,里面一个重要的变量就是g_chiContextOps

  • Camx对Chi的操作,是通过HAL3Module接口的m_ChiAppCallbacks进行的,因此chi里面释放的接口,都会在m_ChiAppCallbacks里面体现。

  • 具体可以参考链接:

  • 高通CamX关键流程

(一定要先看此链接再看后续的)

二、 为什么存在camx架构

        为了更精细化控制底层硬件(Sensor/ISP等关键硬件),同时方便手机厂商自定义一些功能,现在提出了CamX-CHI架构. 它将一些高度统一的功能性接口抽离出来放到CamX中,将可定制化的部分放在CHI中供不同厂商进行修改,实现各自独有的特色功能.

        这样设计的好处显而易见,那便是即便开发者对于CamX并不是很了解,但是依然可以很方便的加入自定义的功能,从而降低了开发者在高通平台的开发门槛。

三、Open Camera

一旦用户打开了相机应用,App中便会去调用CameraManager的openCamera方法,该方法之后会最终调用到Camera Service中的CameraService::connectDevice方法,然后通过ICameraDevice::open()这一个HIDL接口通知Provider,然后在Provider内部又通过调用之前获取的camera_module_t中methods的open方法来获取一个Camera 设备.

对应于HAL中的camera3_device_t结构体,紧接着,在Provider中会继续调用获取到的camera3_device_t的initialize方法进行初始化动作。接下来我们便来详细分析下CamX-CHI对于open以及initialize的具体实现流程:

3.1 open

该方法是camera_module_t的标准方法,主要用来获取camera3_device_t设备结构体的,CamX-CHI对其进行了实现,open方法中完成的工作主要有以下几个:

  1. 将当前camera id传入CHI中进行remap操作,当然这个remap操作逻辑完全是根据CHI中用户需求来的,用户可以根据自己的需要在CHI中加入自定义remap逻辑。

  2. 实例化HALDevice对象,其构造函数中调用Initialize方法,该方法会填充CamX中自定义的Camera3Device结构体。

  3. 将m_HALCallbacks.process_capture_result指向了本地方法ProcessCaptureResult以及m_HALCallbacks.notify_result指向了本地方法Notify(之后会在配置数据流的过程中,将m_HALCallbacks注册到CHI中, 一旦当CHI数据处理完成之后,便会通过这两个回调方法将数据或者事件回传给CamX)。

  4. 最后将HALDevice 中的Camera3Device成员变量作为返回值给到Provider中的CameraCaptureSession中。

Camera3Device 其实重定义了camera3_device_t,其中HwDevice对应于camera3_device_t中的hw_device_t,Camera3DeviceOps对应于camera3_device_ops_t,而在HALDevice的初始化过程中,会将CamX实现的HAL3接口的结构体g_camera3DeviceOps赋值给Camera3DeviceOps中。

3.2 initialize

该方法在调用open后紧接着被调用,主要用于将上层的回调接口传入HAL中,一旦有数据或者事件产生,CamX便会通过这些回调接口将数据或者事件上传至调用者,其内部的实现较为简单。

initialize方法中有两个参数,分别是之前通过open方法获取的camera3_device_t结构体和实现了camera3_callback_ops_t的CameraDevice,很显然camera3_device_t结构体并不是重点,所以该方法的主要工作是将camera3_callback_ops_t与CamX关联上,一旦数据准备完成便通过这里camera3_callback_ops_t中回调方法将数据回传到Camera Provider中的CameraDevice中,基本流程可以总结为以下几点:

  1. 实例化了一个Camera3CbOpsRedirect对象并将其加入了g_HAL3Entry.m_cbOpsList队列中,这样方便之后需要的时候能够顺利拿到该对象。

  2. 将本地的process_capture_result以及notify方法地址分别赋值给Camera3CbOpsRedirect.cbOps中的process_capture_result以及notify函数指针。

  3. 将上层传入的回调方法结构体指针pCamera3CbOpsAPI赋值给Camera3CbOpsRedirect.pCbOpsAPI,并将Camera3CbOpsRedirect.cbOps赋值给pCamera3CbOpsAPI,通过JumpTableHal3的initialize方法将pCamera3CbOpsAPI传给HALDevice中的m_pCamera3CbOps成员变量,这样HALDevice中的m_pCamera3CbOps就指向了CamX中本地方法process_capture_result以及notify。

经过这样的一番操作之后,一旦CHI有数据传入便会首先进入到本地方法ProcessCaptureResult,然后在该方法中获取到HALDevice的成员变量m_pCamera3CbOps,进而调用m_pCamera3CbOps中的process_capture_result方法,即camxhal3entry.cpp中定义的process_capture_result方法,然后这个方法中会去调用JumpTableHAL3.process_capture_result方法,该方法最终会去调用Camera3CbOpsRedirect.pCbOpsAPI中的process_capture_result方法,这样就调到从Provider传入的回调方法,将数据顺利给到了CameraCaptureSession中。

针对上一段,结合图来解释:

CHI有数据后调用本地ProcessCaptureResult

 

 然后在该方法中获取到HALDevice的成员变量m_pCamera3CbOps,进而调用m_pCamera3CbOps中的process_capture_result方法,即camxhal3entry.cpp中定义的process_capture_result方法

VOID HALDevice::ProcessCaptureResult(const camera3_device_t*         pCamera3Device,const camera3_capture_result_t* pCamera3_CaptureResult)
{const Camera3CaptureResult* pCamera3CaptureResult = reinterpret_cast<const Camera3CaptureResult*>(pCamera3_CaptureResult);HALDevice*                  pHALDevice            = static_cast<HALDevice*>(pCamera3Device->priv);CamxResult                  result                = CamxResultSuccess;const StaticSettings*       pSettings             = HwEnvironment::GetInstance()->GetStaticSettings();BOOL                        updateFramework       = TRUE;// Keep track of information related to request for error conditionsFrameworkRequestData* pFrameworkRequest = pHALDevice->GetFrameworkRequestData(pCamera3CaptureResult->frameworkFrameNum, FALSE);// ...
// ...pHALDevice->GetCallbackOps()->process_capture_result(pHALDevice->GetCallbackOps(), pCamera3_CaptureResult);

下图为camxhal3entry.cpp中的 m_pCamera3CbOps中的process_capture_result方法绑定camxhal3entry.cpp里面的process_capture_result

 

 然后这个方法中会去调用JumpTableHAL3.process_capture_result方法

 

 

综上:当hal中有数据产生时,调用process_capture_request最终会调用到g_jumpTableHAL3里面的process_capture_request函数。 

四、Configure Streams

在打开相机应用过程中,App在获取并打开相机设备之后,会调用CameraDevice.createCaptureSession来获取CameraDeviceSession,并且通过Camera api v2标准接口,通知Camera Service,调用其CameraDeviceClient.endConfigure方法,在该方法内部又会去通过HIDL接口ICameraDeviceSession::configureStreams_3_4通知Provider开始处理此次配置需求,在Provider内部,会去通过在调用open流程中获取的camera3_device_t结构体的configure_streams方法来将数据流的配置传入CamX-CHI中,之后由CamX-CHI完成对数据流的配置工作.

接下来我们来详细分析下CamX-CHI对于该标准HAL3接口 configure_streams的具体实现,配置数据流是整个CamX-CHI流程比较重要的一环,其中主要包括两个阶段:

  • 选择UsecaseId

  • 根据选择的UsecaseId创建Usecase

4.1 选择UsecaseId

不同的UsecaseId分别对应的不同的应用场景,该阶段是通过调用UsecaseSelector::GetMatchingUsecase()方法来实现的,该函数中通过传入的operation_mode、num_streams配置数据流数量以及当前使用的Sensor个数来选择相应的UsecaseId,比如当numPhysicalCameras值大于1同时配置的数据流数量num_streams大于1时选择的就是UsecaseId::MultiCamera,表示当前采用的是双摄场景。

4.2 创建Usecase

根据之前选择的UsecaseId,通过UsecaseFactory来创建相应的Usecase,
其中Class Usecase是所有Usecase的基类,其中定义并实现了一些通用接口,CameraUsecaseBase继承于Usecase,并扩展了部分功能。AdvancedCameraUsecase又继承于CameraUsecaseBase,作为主要负责大部分场景的Usecase实现类,另外对于多摄场景,现提供了继承于AdvancedCameraUsecase的UsecaseMultiCamera来负责实现。

除了双摄场景,其它大部分场景使用的都是AdvancedCameraUsecase类来管理各项资源的,接下来我们重点梳理下AdvancedCameraUsecase::Create()方法。
在AdvancedCameraUsecase::Create方法中做了很多初始化操作,其中包括了以下几个阶段:

  1. 获取XML文件中Usecase配置信息

  2. 创建Feature

  3. 保存数据流,重建Usecase的配置信息

  4. 调用父类CameraUsecaseBase的initialize方法,进行一些常规初始化工作

接下来我们就这几个阶段逐一进行分析:

4.2.1 获取XML文件中Usecase配置信息

这一部分主要通过调用CameraUsecaseBase::GetXMLUsecaseByName方法进行实现。
该方法的主要操作是从PerNumTargetUsecases数组中找到匹配到给定的usecaseName的Usecase,并作为返回值返回给调用者,其中这里我们以”UsecaseZSL“为例进行分析,PerNumTargetUsecases的定义是在g_pipeline.h中,该文件是在编译过程中通过usecaseconverter.pl脚本将定义在个平台目录下的common_usecase.xml中的内容转换生成g_pipeline.h。

4.2.2 创建Feature

如果当前场景选取了Feature,则调用FeatureSetup来完成创建工作。
该方法主要是通过诸如operation_mode、camera数量以及UsecaseId等信息来决定需要选择哪些Feature,具体逻辑比较清晰,一旦决定需要使用哪一个Feature之后,便调用相应的Feature的Create()方法进行初始化操作。

4.2.3 保存数据流,重建Usecase的配置信息

从Camera Service 传入的数据流,需要将其存储下来,供后续使用,同时高通针对Usecase也加入了Override机制,根据需要可以选择性地扩展Usecase,这两个步骤的实现主要是通过SelectUsecaseConfig方法来实现。

其中主要是调用以下两个方法来实现的:

  • ConfigureStream:该方法将从上层配置的数据流指针存入AdvancedCameraUsecase中,其中包括了用于预览的m_pPreviewStream以及用于拍照的m_pSnapshotStream。

  • BuildUsecase:这个方法用来重新在原有的Usecase上面加入了Feature中所需要的pipeline,并创建了一个新的Usecase,并将其存入AdvancedCameraUsecase中的m_pChiUsecase成员变量中,紧接着通过SetPipelineToSessionMapping方法将pipeline与Session进行关联。

4.2.4 调用父类CameraUsecaseBase的initialize方法

调用父类CameraUsecaseBase的initialize方法,进行一些常规初始化工作. 该方法中的操作主要有以下三个:

  • 设置Session回调

  • 创建Pipeline

  • 创建Session

设置Session回调

该方法有两个参数,第二个是缺省的,第一个是ChiCallBacks,该参数是作为创建的每一条Session的回调方法,当Session中的pipeline全部跑完之后,会回调该方法将数据投递到CHI中。

创建Pipeline
根据之前获取的pipeline信息开始创建每一条pipeline,通过调用CreatePipeline()方法实现。

创建Session
创建Session,通过CreateSession()方法实现,此时会将AdvancedCameraUsecase端的回调函数注册到Session中,一旦Session中数据处理完成,便会调用回调将数据回传给AdvancedCameraUsecase。

综上,整个configure_stream过程,基本可以概括为以下几点:

  1. 根据operation_mode、camera 个数以及stream的配置信息选取了对应的UsecaseId

  2. 根据所选取的UsecaseId,使用UsecaseFactory简单工厂类创建了用于管理整个场景下所有资源的AdvancedCameraUsecase对象。

  3. 创建AdvancedCameraUsecase对象是通过调用其Create()方法完成,该方法中获取了common_usecase.xml定义的关于Usecase的配置信息,之后又根据需要创建了Feature并选取了Feature所需的pipeline,并通过Override机制将Feature中所需要的Pipeline加入重建后的Usecase中。

  4. 最后通过调用CameraUsecaseBaese的initialize方法依次创建了各个pipeline以及Session,并且将AdvancedCameraUsecase的成员方法注册到Session,用于Session将数据返回给Usecase中


http://www.hkcw.cn/article/TJdmxIxAck.shtml

相关文章

NebulaAI V2.6.0发布:工作流功能正式上线!

2025年5月30日&#xff0c;NebulaAI V2.6.0版本正式上线&#xff01; 在V2.6.0版本中&#xff0c;NBAI团队对工作流功能进行了重磅升级&#xff0c;用户可以通过创建工作流来与大模型交互&#xff1a; 支持选择常用大模型进行工作流的交互&#xff1b; 支持文件上传&#…

Flowith,有一种Agent叫无限

大家好&#xff0c;我是羊仔&#xff0c;专注AI工具、智能体、编程。 今天羊仔要和大家聊聊一个最近发现的超级实用的Agent平台&#xff0c;名字叫Flowith。 这篇文章会带你从零了解到实战体验&#xff0c;搞清楚Flowith是如何让工作效率飙升好几倍&#xff0c;甚至重新定义未…

【Linux系统编程】库制作与原理

目录 理解软硬链接 动态库与静态库 手动制作静态库并使用 制作静态库 使用静态库方法一 使用静态库方法二 使用静态库方法三 手动制作动态库并使用 制作动态库 使用动态库方法一 使用动态库方法二 使用动态库方法三 动静态库同时使用的细节说明 动态库的理解、动…

SAP学习笔记 - 开发20 - 前端Fiori开发 Nest View(嵌套视图) ,Fragment(片段)

上一章讲了Page和Panel&#xff0c;Shell Control(信箱效果)&#xff0c;Margin / Padding&#xff0c;自定义CSS。 SAP学习笔记 - 开发19 - 前端Fiori开发 Page和Panel&#xff0c;Shell Control(信箱效果)&#xff0c;Margin / Padding&#xff0c;自定义CSS-CSDN博客 本章…

选择正确的电平转换解决方案

1. 简介 在目前大多数电子系统中&#xff0c;对电压电平转换的需求非常普遍。 例如&#xff0c; ASIC可能在电源电压 VCCA 下工作&#xff0c;而 I/O器件可能在电源电压VCCB下工作。 为了使这些器件间能够互相通信&#xff0c;需要如下图所示的电平转换解决方案。   电子器件…

OpenLayers:通过自动布局调整解决Overlay重叠问题

一、解决Overlay重叠问题的尝试 我在最近的开发工作中遇到了一个问题。我开发的项目需要给地图上的站点添加Tooltip提示框&#xff08;即Overlay&#xff09;&#xff0c;但是由于地图上的部分站点比较密集&#xff0c;导致Tooltip的重叠比较严重&#xff0c;部分Tooltip的内容…

7.5- Loading a pretrained LLM

Chapter 7-Fine-tuning to follow instructions 7.5- Loading a pretrained LLM 开始微调前&#xff0c;我们先加载GPT2模型&#xff0c;加载 3.55 亿参数的中型版本&#xff0c;因为 1.24 亿模型太小&#xff0c;无法通过指令微调获得定性合理的结果 ​ 加载 gpt2-medium (…

C++:内存管理

一.深入理解C/C的内存分布 以上是一张C/C 程序内存分区示意图&#xff1a; 栈区 存放内容&#xff1a;局部变量&#xff08;如函数内部定义的普通变量 int a 10; &#xff09;、函数的形式参数 。其特点是由编译器自动分配和释放&#xff0c;遵循先进后出原则&#xff0c;…

【结构型模式】装饰器模式

文章目录 装饰器模式装饰器模式当中的角色和职责装饰器模式的代码实现装饰器模式与代理模式有何不同&#xff1f;装饰器模式的优缺点适用场景 装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;&#xff1a;动态地给一个对象增加一些额外的职责&#xff0c;对于…

Ubuntu 挂载新盘

1.磁盘分区 rootljz:/# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 4K 1 loop /snap/bare/5 loop1 7:1 0 104.2M 1 loop /snap/core/17200 loop2 7:2 0 73.9M 1 loop /snap/core22/1908 loop3 7:3 0 104.6M 1 loo…

Flink03-学习-套接字分词流自动写入工具

上一节中通过如下命令启动服务摸来模拟Socket流。 现在我们写一个ServerSocket来模拟让流自动写入不用手动操作。 pom.xml和上一节一致不需要修改 编写代码 同样适用Socket流 // 使用socket流创建一个从 socket 读取文本的数据流&#xff0c;以换行符 \n 作为分隔符DataStre…

2022年 国内税务年鉴PDF电子版Excel

2022年 国内税务年鉴PDF电子版Excelhttps://download.csdn.net/download/2401_84585615/89784658 https://download.csdn.net/download/2401_84585615/89784658 2022年国内税务年鉴是对中国税收政策、税制改革和税务管理实践的全面总结。这份年鉴详细记录了中国税收系统的整体状…

Gitee Wiki:以知识管理赋能 DevSecOps,推动关键领域软件自主演进

关键领域软件研发中的知识管理困境 传统文档管理模式问题显著 关键领域软件研发领域&#xff0c;传统文档管理模式问题显著&#xff1a;文档存储无系统&#xff0c;查找困难&#xff0c;降低效率&#xff1b;更新不及时&#xff0c;与实际脱节&#xff0c;误导开发&#xff1…

Hadoop 3.x 伪分布式 8088端口无法访问问题处理

【Hadoop】YARN ResourceManager 启动后 8088 端口无法访问问题排查与解决(伪分布式启动Hadoop) 在配置和启动 Hadoop YARN 模块时&#xff0c;发现虽然 ResourceManager 正常启动&#xff0c;JPS 进程中也显示无误&#xff0c;但通过浏览器访问 http://主机IP:8088 时却无法打…

【最小生成树】P2573 [SCOI2012] 滑雪

题目 洛谷&#xff1a;P2573 [SCOI2012] 滑雪 分析 题目条件要点分析&#xff1a; 这道题要求 i 能到达 j 的前提是 i 、j 之间有一条连通的边并且i 的高度比 j 高。这意味着本题给出的是一个有向图。时间胶囊可以返回到上一个景点&#xff0c;可以无限使用&#xff0c;意…

2.2.2 06年T2

Stratford的两大对立力量&#xff1a;令人讽刺的居民与令人同情的公司 - 2006年考研英语Text 2精析 本文解析2006年考研英语Text 2&#xff0c;揭示Stratford小镇居民与皇家莎士比亚剧团(RSC)的深层矛盾。 一、原文与翻译 Paragraph 1&#xff1a;对立双方的形成 L1: Stratfor…

基于人工智能算法实现的AI五子棋博弈

1. 项目概述 本项目实现了一个完整的五子棋游戏系统&#xff0c;包含游戏界面、交互逻辑和人工智能对战功能。 系统采用Python语言开发&#xff0c;使用Pygame库进行图形界面渲染&#xff0c;实现了三种游戏模式&#xff1a;人人对战、人机对战和AI对战。 AI算法基于博弈树搜…

在 Ubuntu 系统上使用 Python 的 Matplotlib 库时遇到的字体缺失问题

报错问题 findfont: Font family [SimHei] not found. Falling back to DejaVu Sans. 在现实图片时尝试显示中文字符命令行报错&#xff0c;在图片中显示方框。 最终解决方案 在尝试了各种方法之后&#xff0c;在代码中添加下图中选中行&#xff0c;问题直接解决。

webstrom中git插件勾选提交部分文件时却出现提交全部问题怎么解决

原因是我有个.husky的文件制定了执行提交的时候就是提交所有的文件 修改.husky/pre-commit文件就可以啦 #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh"# 获取通过 WebStorm 提交的暂存文件&#xff08;仅勾选的部分&#xff09; STAGED_FILES$(gi…

KINGCMS被入侵

现象会强制跳转到 一个异常网站,请掉截图代码. 代码中包含经过混淆处理的JavaScript&#xff0c;它使用了一种技术来隐藏其真实功能。代码中使用了eval函数来执行动态生成的代码&#xff0c;这是一种常见的技术&#xff0c;恶意脚本经常使用它来隐藏其真实目的。 这段脚本会检…