目录
下图是简单模型的pipeline (sensor --> IFE --> IPE --> SinkTarget)
IFE output port的buffer在Camx中申请
IPE output port使用的buffer来自上层传入, IPE input port使用IFE的output port的buffer.
枚举物理camera (ProbeImageSensorModules)
解析相机信息表, 创建各种Camera ID的映射关系, 向上层返回FwCameraNums
devicetree中的xxx_camera-sensor.dtsi文件
枚举物理camera的过程 (ProbeImageSensorModules)
为了方便操作, fwkCameraId和logicalCameraId的对应关系会记录在全局数组m_cameraIdxToFwkId中
疑问: 最终目的是操作物理camera, 通过fwkCameraId也可以找到物理camera, 为什么还需要logicalCameraId ?
Qcom Camera HAL使用了两套MetadataBuffer管理接口
Camx中的DRQ和Chi中的FeatureGraph管理模型的对比
相较于Qcom以前的Chi架构, Feature2有如下优势:
使用RTBayer2YUV这个FeatureGraph完成单帧拍照
背景
比较简单的整理一下Qcom Camera HAL中的主要模块和流程, 包括如下内容:
-
Android相机软件框架 :Qcom HAL主要包括Camx和Chi.
-
get_number_of_cameras :创建HAL的Environment, 枚举物理camera, 解析相机信息表. 建立cameraId映射关系。
-
Open接口 :cameraId映射关系的使用,创建HAL Device
-
configure_streams :根据场景, 配置stream. 创建pipeline, 申请ImageBuffer和metadataBuffer.
-
ImageBuffer管理 :保存图像数据的buffer, 使用MemPoolMgr(内存池)和ImagebufferManger两部分管理.
-
MetadataBuffer管理 :保存TAG的buffer, 使用ChiMetadataManager(相当于内存池)和camx中MetadataPool两部分管理
-
request 过程 :Request在Camx中处理, Request在Chi中的处理
Android相机软件框架
Camera HAL3是个per-frame Request的模型, 用一个Request来描述上层希望底层如何处理某一帧, 基本的处理框架如下所示:
调用关系: APP --> Frameworks --> cameraservice --> provider--> OEM HAL --> Qcom HAL.
Qcom HAL主要包括Camx和Chi两部分
-
Camx中完成一条pipeline的处理, 通过DRQ完成Request在Node中的调度.
-
Chi中客制化一些Usecase, Feature, 使用Camx中的一条或者多条pipeline来实现.
Camx中Pipeline 和 node
-
高通将功能模块抽象成Node来管理. 将Node串联, 形成Pipeline. Pipeline 的输入是srcTarget, 输出是SinkTarget。
-
Node有多个Port口, 使用Link, 通过Port口将Node与Node, Node与SrcTarget, Node与SinkTarget连接起来.
下图是简单模型的pipeline (sensor --> IFE --> IPE --> SinkTarget)
-
这条pipeline包括sensor, ife, ipe三个node, 没有3A node, 仅用于调试使用.
-
Sensor输出Raw数据的信号, 经IFE处理转为YUV数据, 经IPE降噪裁剪输出到SinkTarget buffer.
Pipeline中的buffer管理
IFE output port的buffer在Camx中申请
-
Node的non sink output port的buffer在Camx中申请.
IPE output port使用的buffer来自上层传入, IPE input port使用IFE的output port的buffer.
-
Node的sink output port的buffer上层传入.
-
Node的input port使用父node(上行) 的output port的buffer.
下面整理一些关键函数和模块的实现
get_number_of_cameras
获取当前设备中相机的总和, 包括单摄, 多摄, 虚拟Camera. 在provider启动的时候调用, 主要完成三件事, 流程如下:
创建HAL工作的Environment
-
在Camx中创建HAL3Module, HwEnvironment.
-
在Chi中创建ExtensionModule.
-
在这个过程中, 创建了一些线程, 创建了很多static类型的数据, 相机退出的时候不会销毁.
枚举物理camera (ProbeImageSensorModules)
通过CameraModuleData和SendorDriverData文件, 结合devicetree中的sensor信息, 枚举物理camera
解析相机信息表, 创建各种Camera ID的映射关系, 向上层返回FwCameraNums
-
每个设备都有相机信息表, 描述当前设备中的单摄, 多摄, 虚拟Camera等信息
-
将fwkCameraId和物理camera的对应关系保存到全局数据区中.
-
HAL中为camera定义了RoleId, 创建RoleId和fwkCameraId的map关系, 返回给APP.
HAL中定义了多种CameraId, CameraId之间会有对应的映射关系, 先总结一下CameraId的最终使用。
cameraId的最终使用过程
App中通过RoleId, 找到对应fwkCameraId, open的时候下发给HAL.
HAL中通过fwkCameraId找到logicalCameraId, 然后通过logicalCameraId找到物理cameraId, 然后操作对应的物理设备.
四个文件的使用
在get_number_of_cameras流程中, 涉及四个文件, 下面分析四个文件的使用,
重点关注相机信息表和cameraID映射关系的建立.
devicetree中的xxx_camera-sensor.dtsi文件
代码路径: vendor/qcom/proprietary/devicetree/qcom/camera/renoir-sm7350-camera-sensor.dtsi
每个camera在dtsi文件中都有对应的配置信息.
在KMD中 probe sensor的driver时候解析, 其中用cell-index标识具体的物理camera. 假如手机有4个camera, cell-index依次为0, 1, 2, 3
// wide camera
qcom,cam-sensor0 {
cell-index = <0>;
compatible = "qcom,cam-sensor";
csiphy-sd-index = <1>;
sensor-position-roll = <90>;
sensor-position-pitch = <0>;
sensor-position-yaw = <180>;
eeprom-src = <&eeprom_wide>;
actuator-src = <&actuator_wide>;
led-flash-src = <&led_flash_wide>;
cam_vio-supply = <&L5I>;
cam_vdig-supply = <&L1I>;
cam_vana-supply = <&L6I>;
cam_vaf-supply = <&L3I>;
cam_clk-supply = <&cam_cc_titan_top_gdsc>;
regulator-names = "cam_vio", "cam_vdig", "cam_vana", "cam_vaf",
"cam_clk";
};
其中,cell-index = <0>; 是重点。
cameraModuleData文件
代码路径: vendor/qcom/proprietary/chi-cdk/oem/qcom/module/renoir_module/renoir_ofilm_s5kgw3_wide_module.xml
每个模组都有对应的cameraModuleData文件, 模组中包括sensor, eeprom, flash等模块的信息.
文件中的cameraId和dtsi文件中的cell-index一样, 标识具体的物理camera. 如果是同一camera, 这两个值必须一样.
通过sensorName可以找到对应的sensorDriverData.
<cameraModuleData
<!--Module group can contain either 1 module or 2 modules
Dual camera, stereo camera use cases contain 2 modules in the group -->
<moduleGroup>
<!--Module configuration -->
<moduleConfiguration description="Module configuration">
<!--CameraId is the id to which DTSI node is mapped.
Typically CameraId is the slot Id for non combo mode. -->
<cameraId>0</cameraId>
<!--Name of the sensor in the image sensor module -->
<sensorName>renoir_ofilm_s5kgw3_wide</sensorName>
<!--Name of the module integrator -->
<moduleName>renoir</moduleName>
<!--Actuator name in the image sensor module
This is an optional element. Skip this element if actuator is not present -->
<actuatorName>renoir_ofilm_s5kgw3_dw9800_wide</actuatorName>
<!--EEPROM name in the image sensor module
This is an optional element. Skip this element if EEPROM is not present -->
<eepromName>renoir_ofilm_s5kgw3_gt24p128e_wide_eeprom</eepromName>
<!--Flash name is used to used to open binary.
Binary name is of form flashName_flash.bin Ex:- pmic_flash.bin -->
<position>REAR</position>
<!--CSI Information -->
</moduleConfiguration>
</moduleGroup>
</cameraModuleData>
重点:
<cameraId>0</cameraId>
<!--Name of the sensor in the image sensor module -->
<sensorName>renoir_ofilm_s5kgw3_wide</sensorName>
sensorDriverData文件
代码目录: chi-cdk/oem/qcom/sensor/renoir_sensor/renoir_ofilm_s5kgw3_wide_sensor/gedit s5kgw3_sensor.xml
sensorDriverData文件中定义了camera sensor的I2C slaveAddress 和 sensorId等信息.
枚举物理camera的过程 (ProbeImageSensorModules)
-
传入slaveAddress, 通过I2C读取sensorId对应的寄存器,
-
读出的值与文件中的sensorId值匹配, 如果相同, 则probe sensor成功.
-
probe成功的个数就是物理camera的个数.
<sensorDriverData
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../../../api/sensor/camxsensordriver.xsd">
<module_version major_revision="1" minor_revision="0" incr_revision="0"/>
<!--Sensor slave information -->
<slaveInfo>
<!--Name of the sensor -->
<sensorName>renoir_ofilm_s5kgw3_wide</sensorName>
<!--8-bit or 10-bit write slave address -->
<slaveAddress>0x20</slaveAddress>
<!--Register address / data size in bytes -->
<regAddrType range="[1,4]">2</regAddrType>
<!--Register address / data size in bytes -->
<regDataType range="[1,4]">2</regDataType>
<!--Register address for sensor Id -->
<sensorIdRegAddr>0x0000</sensorIdRegAddr>
<!--Sensor Id -->
<sensorId>0x7309</sensorId>
<!--Mask for sensor id. Sensor Id may only be few bits -->
<sensorIdMask>0xFFFFFFFF</sensorIdMask>
<!--I2C frequency mode of slave
logicalcamerainfo文件(相机信息表)
路径: vendor/qcom/proprietary/chi-cdk/oem/qcom/multicamera/logicalcamerainfo/renoir/renoir.xml
每个手机都有对应的logicalcamerainfo文件, 例如K9使用renoir.xml, 文件中定义了当前手机中相机情况,
-
包括有几个单摄, 几个多摄和VT camera, 各个相机的功能是什么, 使用的fwkCameraId是什么, 对应的物理camera是什么.
-
文件中的 slotId 和 'cameraModuleData文件中的cameraId', 以及 ‘dtsi文件中的cell-index’ 一样, 标识具体的物理sensor.
-
文件中的cameraId其实是返回给APP的fwkCameraId.
-
name=“RearPhysicalCam" slotId="0" cameraId="0", 表示后置摄像头, 物理cameraId是0, fwkCameraId是0
-
“MultiCamera”用于SAT, 它fwkCameraId是4, 使用Ultra (slotId 为3) 和 Rear (slotId 为0)两个摄像头.
-
-
在BuildLogicalCameraInfo阶段, 会将文件中的信息整理保存到全局数据区m_logicalCameraInfo中.
-
文件中定义的相机的总数, 就是get_number_of_cameras返回给APP的FwkCameraNums.
<Devices
<PhysicalDevice name="RearPhysicalCam" slotId="0" cameraId="0"/>
<PhysicalDevice name="FrontPhysicalCam" slotId="1" cameraId="1"/>
<PhysicalDevice name="MacroPhysicalCam" slotId="2" cameraId="2"/>
<PhysicalDevice name="UltraPhysicalCam" slotId="3" cameraId="3"/>
<LogicalDevice name="MultiCamera" cameraId="4" primaryCamName="RearPhysicalCam">
<PhysicalDeviceRef>UltraPhysicalCam</PhysicalDeviceRef>
<PhysicalDeviceRef>RearPhysicalCam</PhysicalDeviceRef>
</LogicalDevice>
<LogicalDevice name="bokeh" cameraId="5" primaryCamName="RearPhysicalCam">
<PhysicalDeviceRef>UltraPhysicalCam</PhysicalDeviceRef>
<PhysicalDeviceRef>RearPhysicalCam</PhysicalDeviceRef>
</LogicalDevice>
<LogicalDevice name="VTCamera" cameraId="6" primaryCamName="RearPhysicalCam">
<PhysicalDeviceRef>RearPhysicalCam</PhysicalDeviceRef>
<PhysicalDeviceRef>UltraPhysicalCam</PhysicalDeviceRef>
<PhysicalDeviceRef>MacroPhysicalCam</PhysicalDeviceRef>
</LogicalDevice>
<LogicalDevice name="VTCameraFront" cameraId="7" primaryCamName="FrontPhysicalCam">
<PhysicalDeviceRef>FrontPhysicalCam</PhysicalDeviceRef>
<PhysicalDeviceRef>RearPhysicalCam</PhysicalDeviceRef>
</LogicalDevice>
</Devices>
生成 logicalCameraId
上述分析, 得到了fwkCameraId, 物理cameraId. 我们在HAL中实际使用的是logicalCameraId, 这个logicalCameraId怎么来?
把全局数组m_logicalCameraInfo的下标当做logicalcameraId.
为了统一管理, HAL中会根据camera的position的顺序, 对m_logicalCameraInfo数组进行排序.
/// @brief camera sensor role/type
typedef enum ChiSensorPositionType
{
NONE = 0, /// not part of multicamera
REAR = 1, /// Rear main camera
FRONT = 2, /// Front main camera
REAR_AUX = 3, /// Rear Aux Camera
FRONT_AUX = 4, /// Front aux camera
} CHISENSORPOSITIONTYPE;
根据position使用冒泡算法进行排序
SortSensorDataObjects()
{
for (UINT i = 0; i < m_numberOfDataObjs; i++)
{
for (UINT j = 0; j< m_numberOfDataObjs - i - 1; j++)
{
m_ppDataObjs[j]->GetCameraPosition(&tmpPosition0);
m_ppDataObjs[j+1]->GetCameraPosition(&tmpPosition1);
if (tmpPosition0 > tmpPosition1)
{
pTmpImageSensorModuleData = m_ppDataObjs[j];
m_ppDataObjs[j] = m_ppDataObjs[j + 1];
m_ppDataObjs[j + 1] = pTmpImageSensorModuleData;
}
}
}
}
logicalcameraId 最终顺序
-
多摄ID按照logicalcamerainfo文件中定义的顺序.
-
单摄ID顺序为: REAR (cameraId 0) -- > FRONT (cameraId 1) --> REAR_AUX(cameraId 2) --> FRONT_AUX (cameraId 3)
多个 REAR_AUX camera情况, 比如有macro和ultra, 他们的position相同 , 他们的logicalcameraId怎么确定?
多个 REAR_AUX camera的排序
-
由HAL读取cameraModuleData的bin文件的顺序决定, 先被读到的排在前面.
-
bin文件的读取顺序跟d_off的属性相关. 不同的rom版本中的bin文件的d_off属性不同, logicalCameraId的顺序也会不同.
排序只影响了logicalCameraId, 并不影响frameworkId和CameraId的对应关系.
RoleId和fwkcameraId的对应关系
HAL为相机定义了RoleId的概念, 并且建立了fwkcameraId 和 RoleId的对应关系, 如下所示:
然后将这个对应关系以TAG的形式传递给APP.
fwkcameraId RoleId
std::map<UINT32, UINT32> CameraConfigFwr2RoleId = {
{0, RoleIdRearWide },
{1, RoleIdFront },
{2, RoleIdRearMacro2x},
{3, RoleIdRearUltra },
{4, RoleIdRearSat },
{5, RoleIdRearBokeh },
{6, RoleIdRearVt },
{7, RoleIdFrontVt },
};
enum CameraRoleId {
RoleIdTypeNone = -1, // used for diagcheck
RoleIdRearWide = 0,
RoleIdFront = 1,
RoleIdRearTele = 20,
RoleIdRearUltra = 21,
RoleIdRearMacro = 22,
RoleIdRearTele4x = 23,
RoleIdRearMacro2x = 24,
};