本文为《开源鸿蒙相机:驱动到应用预览显示》系列发布版。
当前章节:第3章 能力注入与流桥接(HDF/HDI/VDI)
代码基线:~/work/ohos5.1/nt_backclip_vendor(基于 OpenHarmony 5.1.0 Release 移植)
发布说明:使用ai codex移植调试开源鸿蒙摄像头的任务全流程在链接https://github.com/chenlong3388/codex_fix_OpenHarmony_Camera

第3章 能力注入与流桥接(HDF/HDI/VDI)

本章目标

回答 5 个问题:

  1. HCS 到底有哪些参数,按原始分区怎么分。
  2. 每个参数干什么。
  3. 参数值从哪里来(驱动、DTS、defconfig、板级映射、运行时实测)。
  4. 参数如何起作用(读取函数 -> 生效函数 -> 失败信号)。
  5. 调用链是否完整,每个函数在链路里的职责是什么。

两份 HCS,不同职责(先定边界)

  1. vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs
    用于 UHDF/HDI/VDI 主链:逻辑相机映射 + CameraMetadata 能力注入。
  2. vendor/gkhos/nt_backclip_vendor/hdf_config/khdf/camera/camera_config.hcs
    用于 KHDF model camera:设备分区开关、ctrl 能力表、stream 上限枚举。

一句话:camera_host_config.hcs 决定“上层看到什么能力并如何 open”,camera_config.hcs 决定“KHDF 设备层认为哪些模块/能力存在”。

总调用图(函数全注释版)

[UHDF 能力注入链]
camera_host_config.hcs
  -> CameraHostService::GetVdiLibList
     作用: 从 root 读取 vdiLibList,决定加载哪个 VDI so
  -> CameraHostService::GetInstance
     作用: HdfLoadVdi 动态装载 host vdi 实现
  -> CameraHostConfig::ReadConfigFile
     作用: 读取 camera_host_config.hcb,构建逻辑ID/能力缓存
  -> HcsDeal::DealCameraAbility
     作用: 解析 logicCameraId/physicsCameraIds/metadata
  -> HcsDeal::DealMetadata
     作用: 把 metadata 字段写入 CameraMetadata tag
  -> CameraHostVdiImpl::GetCameraIds/GetCameraAbility/OpenCamera
     作用: 枚举ID/返回能力/Open时按 physicsCameraIds 上电
  -> HCameraHostManager::GetCameraAbility
     作用: service 侧拉取并缓存能力向 framework 提供
  -> CameraManager::ParseCapability
     作用: 按 ProfileLevel > Extend > Basic 优先级生成 profile
  -> ParseExtendCapability / ParseBasicCapability
     作用: 转换 preview/photo/video 配置供上层输出创建

[KHDF 设备配置链]
camera_config.hcs
  -> HdfCameraDriverInit
     作用: camera core 启动时读取 device->property
  -> HdfParseCameraConfig
     作用: 解析 abilityConfig 根块
  -> ParseCameraDeviceConfig(+Sensor/Isp/Vcm/Lens/Flash/Stream 分区)
     作用: 把 mode/name/id/ctrlValue/formatType 等落到 g_configCameraRoot
  -> CheckCameraDevice / CheckDeviceOps / CameraStreamEnumDevice
     作用: 按分区 mode 与 stream 上限能力对外枚举和门禁

参数全景(按原始分区)

A. camera_host_config.hcs 分区全景(UHDF 主链)

原始分区 参数 含义 读取函数 生效函数
root module HCS 模块名 HCS 编译阶段 配置组织用途
root vdiLibList[] 要加载的 VDI 动态库列表 CameraHostService::GetVdiLibList CameraHostService::GetInstanceHdfLoadVdi
camera_host_config match_attr 匹配 camera host 接口 HDF 配置匹配阶段 决定节点是否被 host 看到
ability_xx logicCameraId 对外逻辑相机 ID HcsDeal::DealCameraAbility CameraHostConfig::cameraIdMap_ / GetCameraIds
ability_xx physicsCameraIds[] 逻辑 ID 对应物理相机枚举 HcsDeal::DealPhysicsCameraId CameraHostVdiImpl::OpenCamera -> CameraPowerUp
ability_xx.metadata aeAvailableAntiBandingModes[] AE 防频闪能力 DealAeAvailableAntiBandingModes metadata 下发到 framework
ability_xx.metadata aeAvailableModes[] AE 模式集合 DealAeAvailableModes 同上
ability_xx.metadata availableFpsRange 能力范围 FPS DealAvailableFpsRange ParseBasicCapability 组 video fps
ability_xx.metadata cameraPosition 前后摄位置标签 DealCameraPosition framework 设备分组/展示
ability_xx.metadata cameraType 广角等类型 DealCameraType framework 选择策略
ability_xx.metadata cameraConnectionType 内置/外接 DealCameraConnectionType builtin/usb 分支策略
ability_xx.metadata cameraMemoryType buffer 内存类型语义 DealCameraMemoryType stream 相关约束
ability_xx.metadata faceDetectMaxNum 最大人脸数 DealCameraFaceDetectMaxNum 人脸能力报告
ability_xx.metadata aeCompensationRange 曝光补偿范围 DealAeCompensationRange AE UI/算法范围
ability_xx.metadata aeCompensationSteps 曝光补偿步长 DealAeCompensationSteps AE 调节粒度
ability_xx.metadata availableAwbModes[] AWB 模式集合 DealAvailableAwbModes AWB 能力报告
ability_xx.metadata sensitivityRange ISO 范围 DealSensitivityRange 传感器能力报告
ability_xx.metadata faceDetectMode 人脸检测模式 DealFaceDetectMode 统计能力
ability_xx.metadata focalLength 焦距 DealFocalLength 相机信息展示
ability_xx.metadata focusAvailableModes[] 对焦模式 DealAvailableFocusModes AF 能力
ability_xx.metadata exposureAvailableModes[] 曝光模式 DealAvailableExposureModes AE 能力
ability_xx.metadata meterAvailableModes[] 测光模式 DealAvailableMetereModes 测光能力
ability_xx.metadata flashAvailableModes[] 闪光灯模式 DealAvalialbleFlashModes 闪光控制能力
ability_xx.metadata mirrorSupported 是否支持镜像 DealMirrorSupported 前摄镜像能力
ability_xx.metadata basicAvailableConfigurations 基础流能力(格式/宽/高) DealAvaliableBasicConfigurations ParseBasicCapability
ability_xx.metadata extendAvailableConfigurations 模式化流能力(mode/stream/fps) DealAvaliableExtendConfigurations ParseExtendCapability
ability_xx.metadata sensorOrientationSupported sensor 方向 DealSensorOrientation 旋转策略
ability_xx.metadata videoStabilizationAvailableModes[] 防抖模式 DealAvalialbleVideoStabilizationModes 视频防抖能力
ability_xx.metadata flashAvailable 是否存在闪光灯 DealAvalialbleFlash 闪光灯开关可用性
ability_xx.metadata afAvailable[] AF 可用模式 DealAvalialbleAutoFocus AF 能力
ability_xx.metadata zoomRatioRange 变焦范围 DealZoomRationRange zoom 能力
ability_xx.metadata jpegOrientation JPEG 方向 DealJpegOrientation 拍照方向元数据
ability_xx.metadata jpegQuality JPEG 质量等级 DealJpegQuality 拍照质量策略
ability_xx.metadata availableCharacteristicsKeys[] 对外能力键集合 HCS 提供 framework 查询可见键
ability_xx.metadata availableRequestKeys[] 可设置请求键集合 HCS 提供 request 下发可见键
ability_xx.metadata availableResultKeys[] 结果可见键集合 HCS 提供 result 上报可见键

B. camera_config.hcs 分区全景(KHDF model camera)

原始分区 参数 含义 读取函数 生效函数
abilityConfig uvcMode 是否支持 UVC ParseCameraConfig CheckSwitchType(UVC_TYPE)
device deviceName 相机设备名 ParseCameraDeviceConfig HdfCameraInitDevice(deviceName)
SensorConfig mode sensor 分区开关 ParseCameraSensorConfig CheckSwitchType(SENSOR_TYPE)
SensorDevice name/id/exposure/mirror/gain/ctrlValue sensor 能力与控制项 ParseCameraSensorDeviceConfig SetCtrlCapInfo + 设备门禁
IspConfig mode + name/id/brightness/contrast/saturation/hue/sharpness/gain/gamma/whiteBalance/ctrlValue ISP 分区能力 ParseCameraIspConfig / ParseCameraIspDeviceConfig CheckSwitchType(ISP_TYPE)
VcmConfig mode + focus/autoFocus/zoom/zoomMaxNum/ctrlValue VCM 能力 ParseCameraVcmConfig CheckSwitchType(VCM_TYPE)
LensConfig mode + aperture/ctrlValue Lens 能力 ParseCameraLensConfig CheckSwitchType(LENS_TYPE)
FlashConfig mode + flashMode/flashIntensity/ctrlValue Flash 能力 ParseCameraFlashConfig CheckSwitchType(FLASH_TYPE)
StreamConfig mode + heightMaxNum/widthMaxNum/frameRateMaxNum/bufferCount/bufferType/formatType 流上限与格式能力 ParseCameraStreamDeviceConfig CameraStreamEnumDevice 返回给上层

参数值从哪里来(配置来源方法)

参数组 推荐来源 当前源码锚点示例
physicsCameraIds 板级硬件映射(枚举 ID 到硬件名) device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:20-27
前后摄位置类(cameraPositionlensFacing DTS 的 rockchip,camera-module-facing + 模组安装方向 device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsi:239-241
驱动启用关系 defconfig 的 CONFIG_VIDEO_* device/board/gkhbd/nt_backclip_5cun_v1/kernel/configs/nt_backclip_vendor_oh_defconfig:3759,3798
分辨率/FPS 能力 sensor 驱动 mode 表 + frame_interval kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c:863-943
lane/link 速率 DTS endpoint + 驱动 link-freq 回退机制 device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsi:244-249,283-289 + kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c:953-975
stream 上限(KHDF) camera_config.hcs StreamConfig + 驱动可实现能力交叉 vendor/gkhos/nt_backclip_vendor/hdf_config/khdf/camera/camera_config.hcs:166-177

参数值从哪里来(细化到代码与实操)

本节整体规划(A-B-C-D)

A. 全量参数总览:先把“所有参数”放进统一对照框架(来源/HCS/读取函数/驱动生效点/日志旁证)。
B. 映射链深挖:重点讲清 physicsCameraIds -> rkisp_v5/Imx600 -> SensorManager/IspManager -> Linux
C. 流能力深挖:basic/extend/fps/orientation 的数组位语义、解析函数、驱动上限与实测闭环。
D. 控制与分区深挖:AE/AWB/ISO/ctrlValue 与 KHDF 分区开关如何真正影响可用能力。

一句话规则:每个参数都按“来源 -> HCS -> 读取 -> 生效 -> 日志”五步闭环,不允许只停在 HCS 文本层。

A) 全量参数总览(所有参数统一入表)

A.1 UHDF camera_host_config.hcs (ability_01) 参数全集对照

参数 HCS当前值(摘要) 读取函数 来源(应对齐) 驱动/运行时生效锚点
logicCameraId lcam001 DealCameraAbility 产品逻辑ID规划 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:94-117
physicsCameraIds CAMERA_FIRST DealPhysicsCameraId 板级映射 device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp:196-203,248-273
aeAvailableAntiBandingModes OFF DealAeAvailableAntiBandingModes 驱动可支持模式 + 策略 tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt:61-64
aeAvailableModes ON/OFF DealAeAvailableModes 驱动 AE 能力 同上
availableFpsRange [15,15] DealAvailableFpsRange sensor mode + 实测 fps kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c:863-931 + tmp_test/v4l2_compare_stable_tail_0402_182338/99_report.txt:32-45
cameraPosition FRONT DealCameraPosition DTS camera-module-facing device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsi:239-241
cameraType WIDE_ANGLE DealCameraType 产品定义 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:299-322
cameraConnectionType BUILTIN DealCameraConnectionType 板级连接形态 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:324-347
cameraMemoryType USERPTR DealCameraMemoryType V4L2 buffer 策略 drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_buffer.cpp:90-118
faceDetectMaxNum 10 DealCameraFaceDetectMaxNum 算法策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:374-397
aeCompensationRange [0,0] DealAeCompensationRange AE 补偿能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:399-420
aeCompensationSteps [0,0] DealAeCompensationSteps AE 步进能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:422-443
availableAwbModes AUTO/OFF DealAvailableAwbModes AWB 控件能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:445-469
sensitivityRange [32,2400] DealSensitivityRange 驱动 gain/iso 范围 tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt:53-55
faceDetectMode OFF DealFaceDetectMode 算法能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:494-516
availableCharacteristicsKeys 一组 tag HCS透传 framework 可见键策略 vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs:154-183
availableRequestKeys 一组 tag HCS透传 request 可下发键 vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs:184-192
availableResultKeys 一组 tag HCS透传 result 可回传键 vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs:193-200
focalLength 24.0 DealFocalLength 模组参数 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:518-538
focusAvailableModes MANUAL/CAF/AF/LOCKED DealAvailableFocusModes AF 能力 + 策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:540-566
exposureAvailableModes MANUAL/CAF/LOCKED/AUTO DealAvailableExposureModes AE 能力 + 策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:568-594
meterAvailableModes SPOT/REGION/OVERALL DealAvailableMetereModes 测光策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:596-621
flashAvailableModes CLOSE/OPEN/AUTO/ALWAYS_OPEN DealAvalialbleFlashModes 闪光策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:623-648
mirrorSupported ON DealMirrorSupported 前摄镜像策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:650-673
basicAvailableConfigurations [3,640,480,3,1280,960,4,1280,960] DealAvaliableBasicConfigurations 格式/尺寸来源于驱动能力 tmp_test/color_fullpack_0402_181021/07_v4l2_formats.txt:14-25
extendAvailableConfigurations mode/stream/detail 数组 DealAvaliableExtendConfigurations mode 输出策略 + basic细化 foundation/multimedia/camera_framework/interfaces/inner_api/native/camera/include/camera_stream_info_parse.h:49-109
sensorOrientationSupported 180 DealSensorOrientation 模组安装方向 DTS朝向 + UI旋转链
videoStabilizationAvailableModes OFF DealAvalialbleVideoStabilizationModes 算法/ISP能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:760-784
flashAvailable FALSE DealAvalialbleFlash 板级闪光器件是否存在 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:786-809
afAvailable OFF DealAvalialbleAutoFocus AF 控件是否可用 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:811-835
zoomRatioRange [1.0,1.0] DealZoomRationRange 光学/数字变焦能力 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:837-868
jpegOrientation 180 DealJpegOrientation 编码旋转策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:870-903
jpegQuality 2 DealJpegQuality 编码质量策略 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:928-953

A.2 KHDF camera_config.hcs 参数对照

参数 HCS当前值(摘要) 来源(应对齐) 生效锚点
abilityConfig.uvcMode true 是否支持 UVC 热插拔策略 drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:494-522
SensorConfig.mode true sensor 分区开关 drivers/hdf_core/framework/model/camera/utils/src/camera_utils.c:120-166
SensorDevice.name rkisp_v5 与 VDI 硬件映射一致 device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:21 + drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:215-352
SensorDevice.exposure true 曝光能力声明 tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt:53,61-64
SensorDevice.ctrlValue id/min/max/step/default 数组 控件能力范围 drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:215-352
IspConfig.mode/name true/ISP0 ISP 分区与命名策略 drivers/hdf_core/framework/model/camera/utils/src/camera_utils.c:120-166 + drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/isp_manager.cpp:25-37
StreamConfig.mode true 流能力分区开关 drivers/hdf_core/framework/model/camera/utils/src/camera_utils.c:120-166
StreamDevice.name rkisp_v5 与 sensor 链路一致性 device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:21
widthMaxNum/heightMaxNum 2592/1944 驱动支持上限 tmp_test/color_fullpack_0402_181021/07_v4l2_formats.txt:14-25
frameRateMaxNum 15 mode表+实测帧率 kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c:863-931 + tmp_test/v4l2_compare_stable_tail_0402_182338/99_report.txt:32-45
bufferType [2] USERPTR 策略 vendor/gkhos/nt_backclip_vendor/hdf_config/khdf/camera/camera_config.hcs:110-114,191
formatType [1,2,204,300] YUV/Bayer/JPEG 格式集合 vendor/gkhos/nt_backclip_vendor/hdf_config/khdf/camera/camera_config.hcs:115-139,192

A.3 关键源码摘选(A段补强:总入口 + 数字位语义)

源码摘选A-1(UHDF 参数总入口):

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:94-117,145-192
int32_t ret = pDevResIns->GetString(&node, "logicCameraId", &cameraId, nullptr);
(void)DealPhysicsCameraId(node, phyCameraIds);
...
const struct DeviceResourceNode *metadataNode = pDevResIns->GetChildNode(&node, "metadata");
RetCode rc = DealMetadata(cameraId, *metadataNode);
...
DealAvaliableBasicConfigurations(node, metadata);
DealAvaliableExtendConfigurations(node, metadata);
cameraMetadataMap_.insert(std::make_pair(cameraId, metadata));

逐行解释:

  1. logicCameraId 是逻辑入口,决定 framework 看见的相机 ID。
  2. DealPhysicsCameraIdphysicsCameraIds 读成枚举字符串数组。
  3. metadata 子节点是能力池,后续 DealXxx 全在这里取值。
  4. basic/extend 都是由这里注入 cameraMetadataMap_,不是 framework 直接读 HCS。

源码摘选A-2(KHDF 参数总入口):

// drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:494-522,218-254
cameraConfigNode = drsOps->GetChildNode(node, "abilityConfig");
ret = ParseCameraConfig(cameraConfigNode, drsOps, &g_configCameraRoot);
...
ret = drsOps->GetUint32(node, "heightMaxNum", &streamConfig->heightMaxNum, 0);
ret = drsOps->GetUint32(node, "widthMaxNum", &streamConfig->widthMaxNum, 0);
ret = drsOps->GetUint32(node, "frameRateMaxNum", &streamConfig->frameRateMaxNum, 0);
ret = drsOps->GetUint32Array(node, "bufferType", streamConfig->bufferType, streamConfig->bufferTypeNum, 0);
ret = drsOps->GetUint32Array(node, "formatType", streamConfig->formatType, streamConfig->formatTypeNum, 0);

逐行解释:

  1. KHDF 统一从 abilityConfig 进入,不会跳过根节点直读子段。
  2. width/height/fps 是显式字段,不是推导值。
  3. bufferType/formatType 是数组字段,元素数量先做上限校验再读取。

源码摘选A-3(ctrlValue 五元组位语义):

// drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:23-37
for (i = 0; i < ctrlValueNum; i += CTRL_INFO_COUNT) {
    ctrlCap[i / CTRL_INFO_COUNT].ctrlId = ctrlValue[i + CTRL_ID_INDEX];
    ctrlCap[i / CTRL_INFO_COUNT].max = ctrlValue[i + CTRL_MAX_INDEX];
    ctrlCap[i / CTRL_INFO_COUNT].min = ctrlValue[i + CTRL_MIN_INDEX];
    ctrlCap[i / CTRL_INFO_COUNT].step = ctrlValue[i + CTRL_STEP_INDEX];
    ctrlCap[i / CTRL_INFO_COUNT].def = ctrlValue[i + CTRL_DEF_INDEX];
}

数字串位定义(你关心的“第一位第二位”):

  1. 第1位:ctrlId
  2. 第2位:min
  3. 第3位:max
  4. 第4位:step
  5. 第5位:default
    注意:代码先写 max 再写 min,但索引常量仍对应“五元组语义”;检查时以常量定义与日志双证据为准。

A.4 参数总表升级:函数入口编号(F)+ 检查命令模板

编号 入口函数(源码锚点) 覆盖参数组 检查命令模板(仓内可直接执行) 通过判据(双证据)
F1 DealCameraAbility (drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:94-131) logicCameraIdphysicsCameraIds `rg -n "logicCameraId physicsCameraIds" vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs`
F2 DealPhysicsCameraId (drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:133-143) physicsCameraIds[] `rg -n "CAMERA_FIRST CAMERA_SECOND" device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h`
F3 DealMetadata (drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:145-192) 全部 metadata 参数 rg -n "Deal[A-Za-z]+\\(" drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp 目标参数对应 DealXxx 已被调用
F4 DealAvaliableBasicConfigurations (drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:704-733) basicAvailableConfigurations `rg -n "basicAvailableConfigurations STREAM_INFO_ITEM_LENGTH
F5 DealAvaliableExtendConfigurations (drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp) extendAvailableConfigurations rg -n "extendAvailableConfigurations" vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs HCS 数组结构完整且含 -1 分隔
F6 ParseCapability (foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2253-2268) profile/extend/basic 解析优先级 `rg -n "ParseCapability OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS
F7 ParseExtendCapability (foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2103-2134) mode-stream-detail 到 profile `rg -n "ParseExtendCapability getModeInfo
F8 CameraStreamInfoParse::getDetailAbilityInfo (foundation/multimedia/camera_framework/interfaces/inner_api/native/camera/include/camera_stream_info_parse.h:144-176) format/width/height/fixed/min/max/abilityId 位语义 `rg -n "formatOffset widthOffset
F9 HdfParseCameraConfig + ParseCameraConfig (drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:494-522,466-492) KHDF 总入口/uvcMode `rg -n "HdfParseCameraConfig ParseCameraConfig
F10 ParseCameraStreamDeviceConfig (drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:218-254) widthMaxNum/heightMaxNum/frameRateMaxNum/bufferType/formatType `rg -n "heightMaxNum widthMaxNum
F11 SetCtrlCapInfo (drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:23-37) ctrlValue 五元组 `rg -n "SetCtrlCapInfo CTRL_ID_INDEX
F12 V4L2GetCapability (drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_fileformat.cpp:119-149) cameraId -> /dev/videoX 匹配 `rg -n "cameraId != cap.driver

补充:实机采样命令模板(板端)

v4l2-ctl -d /dev/video0 --all
v4l2-ctl -d /dev/video0 --list-formats-ext
media-ctl -p

补充:仓内日志回放模板(离线复核)

rg -n "Driver name|Pixel Format|exposure|gain|auto_exposure" tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt
rg -n "2592x1944|Stepwise|NV12|NV21" tmp_test/color_fullpack_0402_181021/07_v4l2_formats.txt
rg -n "15\\.03 fps|15\\.04 fps" tmp_test/v4l2_compare_stable_tail_0402_182338/99_report.txt

A.5 F1~F12 失败分流(每条一行,现场直接照做)

编号 常见失败信号 一行分流顺序(固定)
F1 cameraId 枚举不到/打开失败 先查 camera_host_config.hcslogicCameraId/physicsCameraIds,再查 DealCameraAbility 是否读到,最后查 OpenCamera 日志是否进入 CameraPowerUp
F2 physicsCameraIds 配了但不生效 先查 project_hardware.h 是否有该枚举,再查 CameraIdToHardware 映射,最后对 v4l2-ctl --allDriver name
F3 单个 metadata 参数“声明了但没出现在能力里” 先查 HCS metadata{} 字段拼写,再查 DealMetadata 内是否调用对应 DealXxx,最后查 framework 侧是否读到该 tag。
F4 basic 能力格式/尺寸异常 先按三元组切 basicAvailableConfigurations,再查 formatArray 映射,最后用 v4l2-ctl --list-formats-ext 校对尺寸上限。
F5 extend 解析失败或 profile 缺项 先查 extendAvailableConfigurations-1/-1/-1 分隔,再查 ParseExtendCapability 是否命中 mode,最后查输出 profile 列表。
F6 实际走了 basic 没走 extend 先查 metadata 是否带 OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS,再看 ParseCapability 分支命中,最后核对 profile 结果。
F7 指定模式(如 VIDEO)无对应 profile 先查 extend 数组首位 mode 是否有目标模式,再查 ConvertMetaToFwkMode 映射,最后看 CreateProfile4StreamType 是否被调用。
F8 一串数字解释不清或解析错位 先按 format,width,height,fixed,min,max 六元头切块,再按 ABILITY_FINISH=-1 收尾,最后核对 abilityId 列表。
F9 KHDF 配置整体不生效 先查 abilityConfig 根节点是否存在,再查 HdfParseCameraConfig 是否成功返回,最后查各分区 mode 是否被短路。
F10 widthMaxNum/frameRateMaxNum 与运行时不一致 先查 camera_config.hcs 数值,再查 ParseCameraStreamDeviceConfig 读取日志,最后对比 v4l2-ctl 与 sensor 驱动 mode 表。
F11 ctrlValue 数字串语义混乱 先每5位切组(id/min/max/step/default),再查 SetCtrlCapInfo 索引常量,最后对照 v4l2-ctl --all 的控件范围。
F12 cameraId/dev/videoX 绑定失败 先查 cap.driver 是否等于期望 cameraId,再查 deviceMatch 是否插入,最后查 Driver name 与板级映射是否一致。

B) 映射参数族深挖:physicsCameraIds 到 Linux 驱动

源码摘选1(HCS设定):

// vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs:127-131
logicCameraId = "lcam001";
physicsCameraIds = ["CAMERA_FIRST"];

逐行解释:

  1. 这里只声明“逻辑相机绑哪一路枚举”。
  2. 没有直接出现 ov5648/rkisp 字符串。

源码摘选2(枚举到硬件名来源):

// device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:20-26
{CAMERA_FIRST, DM_M_SENSOR, DM_C_SENSOR, (std::string) "rkisp_v5"},
{CAMERA_FIRST, DM_M_ISP,    DM_C_ISP,    (std::string) "isp"},
{CAMERA_SECOND,DM_M_SENSOR, DM_C_SENSOR, (std::string) "Imx600"},

逐行解释:

  1. CAMERA_FIRST 在 sensor 维度对应 rkisp_v5
  2. ISP 维度固定是 isp,单独 manager。
  3. CAMERA_SECOND -> Imx600 当前是模板链路。

源码摘选3(实际生效函数链):

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp
config->GetPhysicCameraIds(cameraId, phyCameraIds);
CameraPowerUp(cameraId, phyCameraIds);

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/v4l2_device_manager.cpp
(*iter)->PowerUp(CameraIdToHardware(cameraId, (*iter)->GetManagerId()));

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/sensor_controller.cpp
sensorVideo_->start(GetName());

逐行解释:

  1. HCS 的 CAMERA_FIRST 先在 host 层取出。
  2. 到 device manager 按 manager 维度翻译成硬件名。
  3. sensor controller 用该名走 V4L2 打开设备并开始流。

源码摘选4(如何连到 Linux 节点):

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_fileformat.cpp
V4L2MatchDevice(cameraIDs); // 遍历 /dev/videoX
V4L2GetCapability(..., cameraId) {
    if (cameraId != (char*)cap.driver) return RC_ERROR;
}

逐行解释:

  1. VDI 用 cap.driver == cameraID 做匹配。
  2. 匹配成功后才建立 cameraID -> /dev/videoX 映射。
  3. 后续 VIDIOC_S_FMT/REQBUFS/STREAMON 都落在这个节点。

运行时旁证:

// tmp_test/color_fullpack_0402_181021/05_media_ctl_p.txt:117-126
... "m00_f_ov5648 4-0036" -> "rockchip-csi2-dphy0" [ENABLED]
... fmt:SBGGR10_1X10/2592x1944@1/15

结论:实际物理 sensor 是 ov5648rkisp_v5 是 VDI 侧匹配入口名,不是最终日志里 sensor 节点名。

B.1 rkisp_v5/Imx600 与 HCS/DTS 并排对照(补强)

维度 配置值 配置来源 代码生效点 运行时可见信号
UHDF 逻辑映射 physicsCameraIds=["CAMERA_FIRST"] vendor/gkhos/nt_backclip_vendor/hdf_config/uhdf/camera/hdi_impl/camera_host_config.hcs:128-131 DealPhysicsCameraId -> CameraPowerUp OpenCamera 后进入 deviceManager->PowerUp
板级硬件映射 CAMERA_FIRST->rkisp_v5CAMERA_SECOND->Imx600 device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:20-26 CameraIdToHardware(cameraId, managerId) v4l2-ctl --all 看到 Driver name : rkisp_v5
真实 sensor 驱动 compatible = "ovti,ov5648" device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsi:223-241 Linux i2c sensor probe media-ctl -p 显示 m00_f_ov5648

B.2 SensorManager/IspManager 分轨代码摘选与逐行解释

源码摘选B-1(IspManager/IspController):

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/isp_manager.cpp:25-40,57-64
if (controllerId == DM_C_ISP) {
    std::shared_ptr<IspController> isp = std::make_shared<IspController>(hardwareName);
    rc = isp->Init();
    if (rc == RC_OK) { ispList_.push_back(isp); }
}
...
if ((*iter)->GetName() == hardwareName) {
    return (*iter)->PowerUp();
}

逐行解释:

  1. ISP 轨只处理 DM_C_ISP 控制器。
  2. hardwareName 来自 CameraIdToHardware(..., DM_M_ISP),即 project_hardware.hisp
  3. PowerUp/PowerDown 是 ISP 侧生命周期门禁。

源码摘选B-2(SensorController):

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/sensor_controller.cpp:104-143
rc = sensorVideo_->start(GetName());
sensorVideo_->ConfigSys(GetName(), CMD_V4L2_SET_FORMAT, format);
sensorVideo_->ReqBuffers(GetName(), buffCont_);

逐行解释:

  1. Sensor 轨最终进入 HosV4L2DevGetName() 就是 rkisp_v5/Imx600 这类硬件名。
  2. ConfigSys(...SET_FORMAT...) 对应 VIDIOC_S_FMT
  3. ReqBuffers 对应 VIDIOC_REQBUFS,真正申请视频缓冲。

B.3 与 Linux 节点绑定的双证据

  1. 代码锚点:V4L2GetCapabilityif (cameraId != cap.driver) return RC_ERROR;drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/driver_adapter/src/v4l2_fileformat.cpp:136-141)。
  2. 实际日志:tmp_test/color_fullpack_0402_181021/06_v4l2_all.txtDriver name : rkisp_v5 与 HCS/板级映射一致;同时 tmp_test/color_fullpack_0402_181021/05_media_ctl_p.txt 出现 ov5648,证明最终链路落到真实 Linux sensor 驱动。

C) 流能力参数族深挖:basic/extend/fps/orientation

C.1 basicAvailableConfigurations 位定义 + 生效链

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:704-733
if (i % 3 == 0) {
    basicConfigAvaliableInt32s.push_back(formatArray[(int32_t)nodeValue - 1]);
} else {
    basicConfigAvaliableInt32s.push_back((int32_t)nodeValue);
}

逐行解释:

  1. basic 固定三元组:format,width,height
  2. format 位会被重映射,不是原值直通。
  3. 这就是“为什么 HCS 写 3/4/5,framework 看到的枚举会变”。

C.2 extendAvailableConfigurations 位定义 + 解析器

// foundation/multimedia/camera_framework/interfaces/inner_api/native/camera/include/camera_stream_info_parse.h
formatOffset=0; widthOffset=1; heightOffset=2;
fixedFpsOffset=3; minFpsOffset=4; maxFpsOffset=5;
ABILITY_FINISH=-1; STREAM_FINISH=-1; MODE_FINISH=-1;

逐行解释:

  1. detail 前 6 位固定语义:format,width,height,fixed,min,max
  2. 后续可跟 abilityId...
  3. -1 既是 detail 结束,也是 stream/mode 的分隔语义。

最小合法结构:

[mode, streamType, format, width, height, fixedFps, minFps, maxFps, -1, -1, -1]

C.3 与驱动上限对齐(必须双证据)

  1. 驱动 mode 表给出上限:kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c2592x1944@15
  2. 实测格式上限:tmp_test/color_fullpack_0402_181021/07_v4l2_formats.txt2592x1944
  3. 实测 fps 稳定:tmp_test/v4l2_compare_stable_tail_0402_182338/99_report.txt15.03/15.04 fps
  4. 因此 availableFpsRange=[15,15]、extend 里 2592x1944@15 是可闭环的。

C.4 ParseExtendCapability + getDetailAbilityInfo 联合逐行解释

源码摘选C-1(framework 选择 extend 解析):

// foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2253-2268
if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL)) {
    ParseProfileLevel(...);
} else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS)) {
    ParseExtendCapability(profilesWrapper, mode, item);
} else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS)) {
    ParseBasicCapability(...);
}

逐行解释:

  1. 优先级是 profile_level > extend > basic
  2. 设备只要带 extend tag,默认走 ParseExtendCapability
  3. 这就是“为什么 basic 配了但 profile 仍异常”的常见根因。

源码摘选C-2(extend 数组拆解):

// foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2103-2134
modeStreamParse->getModeInfo(item.data.i32, item.count, extendInfo);
...
if (modeName == scMode) {
    CreateProfile4StreamType(profilesWrapper, streamType, i, j, extendInfo);
}

逐行解释:

  1. 先把一维 int32[] 数组拆成 mode->stream->detail 三层结构。
  2. 再按 modeName 过滤,只有匹配模式会生成 profile。
  3. CreateProfile4StreamType 最终产出 preview/photo/video 能力集合。

源码摘选C-3(detail 六元头 + ability 列表):

// foundation/multimedia/camera_framework/interfaces/inner_api/native/camera/include/camera_stream_info_parse.h:146-169
uint32_t allOffset = 6;
format = originInfo[m + 0];
width = originInfo[m + 1];
height = originInfo[m + 2];
fixedFps = originInfo[m + 3];
minFps = originInfo[m + 4];
maxFps = originInfo[m + 5];
for (n = m + allOffset; n < abilityEndIndex_.front(); n++) {
    abilityId.push_back(originInfo[n]);
}

逐行解释:

  1. 每个 detail 前 6 位是固定头,不能改顺序。
  2. 第 7 位开始是可选 abilityId 列表,直到遇到 -1
  3. 所以你看到的长数字串,先按 6+N 一组切,再看分隔 -1

C.5 终端工具与实际日志(实操证据)

推荐命令:

v4l2-ctl -d /dev/video0 --all
v4l2-ctl -d /dev/video0 --list-formats-ext
media-ctl -p

当前仓证据摘录:

  1. tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt 显示 Driver name : rkisp_v5Pixel Format : 'NV21'
  2. 同文件显示控件范围:exposure min=4 max=1980gain min=16 max=248
  3. tmp_test/color_fullpack_0402_181021/07_v4l2_formats.txt 显示 stepwise 上限到 2592x1944
  4. tmp_test/v4l2_compare_stable_tail_0402_182338/99_report.txt 显示采集稳定在 15.03~15.04 fps

D) 控制与分区参数族深挖:AE/AWB/ISO/ctrlValue/mode

D.1 UHDF 控制参数如何起作用

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp
DealAeAvailableModes(...)
DealAvailableAwbModes(...)
DealSensitivityRange(...)
metadata->addEntry(...)

逐行解释:

  1. HCS 控制参数先写入 metadata。
  2. framework/服务端据此决定“哪些控制可下发、可回传”。
  3. 日志侧需要看到对应控件存在和值变化,否则就是“声明未落地”。

日志旁证:

// tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt
exposure: min=4 max=1980 value=500
gain: min=16 max=248 value=96
auto_exposure: Auto Mode

解释:曝光/增益控制项真实存在并有范围,不是仅 HCS 文本声明。

D.2 KHDF modectrlValue 如何起作用

// drivers/hdf_core/framework/model/camera/utils/src/camera_utils.c (CheckSwitchType)
// drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c (ParseCamera*Config)

逐行解释:

  1. mode=true/false 是门禁开关;关掉后分区能力不参与枚举。
  2. ctrlValue 数组语义是五元组:id,min,max,step,default
  3. 这些值用于构建设备能力边界,不应脱离驱动真实控件范围。

D.3 控制项从 OHOS tag 到 V4L2 CID 的实际函数链

源码摘选D-1(Tag -> CID 映射):

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/sensor_controller.cpp:21-27
{OHOS_SENSOR_EXPOSURE_TIME, V4L2_CID_EXPOSURE_AUTO},
{OHOS_CONTROL_AWB_MODE, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE},
{OHOS_CONTROL_FOCUS_MODE, V4L2_CID_FOCUS_AUTO},
{OHOS_CONTROL_EXPOSURE_MODE, V4L2_CID_EXPOSURE_AUTO},
{OHOS_CONTROL_FLASH_MODE, V4L2_CID_FLASH_LED_MODE},

逐行解释:

  1. framework 传的是 OHOS tag,不是直接传 V4L2 CID。
  2. SensorController 内部完成 tag 到 CID 的桥接。
  3. 桥接表缺项时,控制项会“声明存在但下发无效”。

源码摘选D-2(配置下发链):

// drivers/peripheral/camera/vdi_base/common/adapter/platform/v4l2/src/device_manager/sensor_controller.cpp:81-102,104-117
RetCode SensorController::Configure(std::shared_ptr<CameraMetadata> meta)
{
    return SendSensorMetaData(meta);
}
...
RetCode SensorController::ConfigFps(std::shared_ptr<CameraMetadata> meta)
{
    RetCode rc = SendFpsMetaData(data);
    return rc;
}
...
rc = sensorVideo_->start(GetName());

逐行解释:

  1. Configure 入口处理通用控制(AE/AWB/AF 等)。
  2. ConfigFps 单独处理帧率元数据。
  3. ConfigStart 开启设备后,控制值才会在流上体现。

D.4 mode 门禁与 ctrlValue 位定义的代码双证据

源码摘选D-3(mode 门禁):

// drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:264-270,293-299
ret = drsOps->GetUint8(node, "mode", &sensorConfig->mode, 0);
if (sensorConfig->mode == DEVICE_NOT_SUPPORT) { return HDF_SUCCESS; }
...
ret = drsOps->GetUint8(node, "mode", &ispConfig->mode, 0);
if (ispConfig->mode == DEVICE_NOT_SUPPORT) { return HDF_SUCCESS; }

逐行解释:

  1. mode=false 不会报错,但该分区直接短路退出。
  2. 这就是“配置文件看起来有字段,但运行时没有能力”的第一检查点。

源码摘选D-4(ctrlValue 五元组解析):

// drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:27-36
ctrlCap[...].ctrlId = ctrlValue[i + CTRL_ID_INDEX];
ctrlCap[...].max    = ctrlValue[i + CTRL_MAX_INDEX];
ctrlCap[...].min    = ctrlValue[i + CTRL_MIN_INDEX];
ctrlCap[...].step   = ctrlValue[i + CTRL_STEP_INDEX];
ctrlCap[...].def    = ctrlValue[i + CTRL_DEF_INDEX];

位定义(检查模板):

  1. 第1位 id:控件 ID。
  2. 第2位 min:最小值。
  3. 第3位 max:最大值。
  4. 第4位 step:步进。
  5. 第5位 default:默认值。
    检查动作:将 camera_config.hcs 中每 5 个数切一组,与 v4l2-ctl --all 的控件范围逐组对齐。

D.5 HCS 与实测日志并排示例(曝光/增益)

  1. HCS 侧:vendor/gkhos/nt_backclip_vendor/hdf_config/khdf/camera/camera_config.hcs:150-154 声明了 ctrlValue
  2. 解析侧:SetCtrlCapInfo 把五元组写入 ctrlCapdrivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:23-37)。
  3. 运行侧:tmp_test/color_fullpack_0402_181021/06_v4l2_all.txt 实测 exposure min=4 max=1980gain min=16 max=248
  4. 判据:若 HCS 声明与 V4L2 范围不一致,以驱动实测范围为最终约束,回写 HCS。

本节收口(你要求的“整体规划”落地检查)

  1. 是否先有全参数总表:有(A.1 + A.2)。
  2. 是否每组都连到驱动生效点:有(B/C/D 的函数链 + ioctl/日志)。
  3. 是否有源码摘选+逐行分析+hcs对比:有(A/B/C/D 都覆盖)。
  4. 是否可实操复核:可,按“五步法”逐参数复用。

    关键源码摘选与分析

1) vdiLibList 决定是否能装载 VDI

// drivers/peripheral/camera/hdi_service/v1_0/src/camera_host_service.cpp
int32_t elemNum = pDevResIns->GetElemNum(pRootNode, "vdiLibList");
for (int i = 0; i < elemNum; i++) {
    pDevResIns->GetStringArrayElem(pRootNode, "vdiLibList", i, &vdiLib, nullptr);
    vdiLibList.push_back(std::string(vdiLib));
}
...
struct HdfVdiObject *cameraHostVdiLoader = HdfLoadVdi(vdiLib.c_str());

分析:

  1. vdiLibList 为空会直接返回 INVALID_ARGUMENT,host 起不来。
  2. 这是 UHDF 主链最前置门禁,后面所有 GetCameraIds/OpenCamera 都依赖它。

2) logic/physics + metadata 的统一解析入口

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp
int32_t ret = pDevResIns->GetString(&node, "logicCameraId", &cameraId, nullptr);
(void)DealPhysicsCameraId(node, phyCameraIds);
...
RetCode rc = DealMetadata(cameraId, *metadataNode);

分析:

  1. 先建 cameraIdMap_,再建 cameraMetadataMap_,两者缺一不可。
  2. logicCameraId 配错是“枚举/打开找不到”,metadata 配错是“能力解析错配”。

3) basicAvailableConfigurations 的格式重映射

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp
if (i % STREAM_INFO_ITEM_LENGTH == 0) {
    basicConfigAvaliableInt32s.push_back(formatArray[static_cast<int32_t>(nodeValue) - 1]);
} else {
    basicConfigAvaliableInt32s.push_back(static_cast<int32_t>(nodeValue));
}

分析:

  1. HCS 里的格式号不是直接下发,先经过 formatArray 映射。
  2. 这就是“看起来填了 3/4/5,但 framework 实际看到的是映射后值”的根因。

4) OpenCamera 真正用到 physicsCameraIds 上电

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp
RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds);
if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) {
    CAMERA_LOGE("camera powerup failed.");
    CameraPowerDown(phyCameraIds);
    return DEVICE_ERROR;
}

分析:

  1. physicsCameraIds 是 open 阶段真实执行参数,不是“展示字段”。
  2. 多映射或错映射会直接表现为 camera powerup failed

5) framework 能力解析优先级

// foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp
if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL)) {
    ParseProfileLevel(...);
} else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS)) {
    ParseExtendCapability(...);
} else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS)) {
    ParseBasicCapability(...);
}

分析:

  1. 同时存在时优先走 ProfileLevel,其次 Extend,最后 Basic
  2. 所以 extendAvailableConfigurations 结构错误会优先污染 profile,不会自动回到 basic。

6) KHDF camera_config.hcs 的真实解析入口

// drivers/hdf_core/framework/model/camera/core/src/camera_core.c
if (HdfParseCameraConfig(device->property) != HDF_SUCCESS) {
    return HDF_FAILURE;
}
...
for (i = 0; i < rootConfig->deviceNum; i++) {
    ret = HdfCameraInitDevice(rootConfig->deviceConfig[i].deviceName);
}

分析:

  1. camera_config.hcs 在 core init 就会解析,不是“文档参数”。
  2. mode 开关直接影响对应分区是否被认作支持设备。

函数逐行解释:DealMetadata

目标函数:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:145-193

源码摘选:

// drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:145-193
RetCode HcsDeal::DealMetadata(const std::string &cameraId, const struct DeviceResourceNode &node)
{
    struct DeviceResourceAttr *drAttr = nullptr;
    DEV_RES_NODE_FOR_EACH_ATTR(&node, drAttr) {}

    const int ENTRY_CAPACITY = 30;
    const int DATA_CAPACITY = 2000;
    std::shared_ptr<CameraMetadata> metadata = std::make_shared<CameraMetadata>(ENTRY_CAPACITY, DATA_CAPACITY);
    if (metadata == nullptr) {
        return RC_ERROR;
    }
    DealAvailableFpsRange(node, metadata);
    DealCameraPosition(node, metadata);
    ...
    DealAvaliableBasicConfigurations(node, metadata);
    ...
    DealAvaliableExtendConfigurations(node, metadata);
    ...
    cameraMetadataMap_.insert(std::make_pair(cameraId, metadata));
    return RC_OK;
}

逐行解释:

  1. DEV_RES_NODE_FOR_EACH_ATTR:先扫描 metadata 节点属性,确认节点结构可遍历。
  2. ENTRY_CAPACITY/DATA_CAPACITY:为 metadata 容器预分配空间。
  3. make_shared<CameraMetadata>:创建能力容器实例。
  4. if (metadata == nullptr):创建失败立即终止,避免写空指针。
  5. DealAvailableFpsRange/DealCameraPosition/...:把 HCS 文本和数组逐项转成标准 metadata tag。
  6. DealAvaliableBasicConfigurations:注入 basic 三元组能力。
  7. DealAvaliableExtendConfigurations:注入 extend 模式化能力。
  8. cameraMetadataMap_.insert(...):把能力绑定到 cameraId,这是上层可见的最终落点。
  9. return RC_OK:函数成功返回,后续 GetCameraAbility 才能读到完整结果。

函数逐行解释:ParseCapability

目标函数:foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2253-2279

源码摘选:

// foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2253-2279
void CameraManager::ParseCapability(..., const int32_t modeName, camera_metadata_item_t& item, ...)
{
    if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL)) {
        ...
        ParseProfileLevel(profilesWrapper, mode, item);
    } else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS)) {
        ...
        ParseExtendCapability(profilesWrapper, mode, item);
    } else if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS)) {
        ParseBasicCapability(profilesWrapper, metadata, item);
    } else {
        MEDIA_ERR_LOG("Failed get stream info");
    }
    if (g_isCapabilitySupported(metadata, item, OHOS_ABILITY_DEPTH_DATA_PROFILES)) {
        ...
        ParseDepthCapability(mode, item);
    }
}

逐行解释:

  1. 第一个 if:优先检查 PROFILE_LEVEL,这是最高优先级路径。
  2. 命中后 ParseProfileLevel:直接按 profile-level 生成能力,不再进入 extend/basic。
  3. 第二个 else if:如果没有 profile-level,才看 EXTEND_CONFIGURATIONS
  4. 命中后 ParseExtendCapability:解析 mode->stream->detail 结构。
  5. 第三个 else if:前两者都缺失才回退 ParseBasicCapability
  6. else 错误日志:三条主能力标签都没有时,报 Failed get stream info
  7. 尾部独立 if:深度能力 DEPTH_DATA_PROFILES 是并行解析,不受主分支互斥影响。

函数逐行解释:DealAvaliableBasicConfigurations

目标函数:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:704-733

  1. 第 707-708 行:声明 nodeValuebasicConfigAvaliableInt32s
    重点:后者就是最终写入 metadata 的 basic 配置数组。
  2. 第 710 行:读取 basicAvailableConfigurations 元素个数。
    重点:这里拿的是 HCS 原始数组长度,不做组数校验。
  3. 第 713 行:STREAM_INFO_ITEM_LENGTH=3
    重点:basic 语义固定为 3 元组:format,width,height
  4. 第 714-723 行:逐元素读取并重写。
    重点A:i%3==0 时认定当前元素是格式位,会执行 formatArray[nodeValue-1] 映射。
    重点B:非格式位(宽高)直接原样写入。
    重点C:这就是“写 3/4/5,框架看到的是映射后枚举”的直接代码证据。
  5. 第 725-726 行:将重写后的数组写入 tag OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS
    重点:这是 basic 能力最终生效点。
  6. 第 727-730 行:写入失败返回 RC_ERROR
    重点:这一段失败时,framework 只能尝试 extend/profile-level 分支。
  7. 第 731-732 行:日志成功并返回 RC_OK
    重点:只代表“写入 metadata 成功”,不代表上层一定会选中该 profile。

函数逐行解释:ParseExtendCapability

目标函数:foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2103-2137

  1. 第 2106 行:初始化 ExtendInfo
    重点:这是解析后 mode/stream/detail 的结构化承载对象。
  2. 第 2107 行:创建 CameraStreamInfoParse 解析器。
    重点:后续解析完全依赖这个对象对 -1 分隔语义的理解。
  3. 第 2108 行:getModeInfo(item.data.i32, item.count, extendInfo)
    重点:把 metadata 原始 int32 数组解包成 mode -> streamType -> detail 三级结构。
  4. 第 2109-2123 行:modeName==VIDEO 时先额外扫描 HIGH_FRAME_RATE
    重点:视频模式会先补一轮高帧率能力,这是 video 特有分支。
  5. 第 2112-2113 行:ConvertMetaToFwkMode 做元数据 mode 到 framework mode 映射。
    重点:映射失败时会打印错误,常见原因是 extend 里 mode 编码不合法。
  6. 第 2117-2121 行:遍历 streamType 并 CreateProfile4StreamType
    重点:真正把 detail 生成 preview/photo/video profile 的地方。
  7. 第 2124-2135 行:常规模式匹配分支。
    重点A:逐个 mode 找与 modeName 相等的分组。
    重点B:命中后生成 profile 并 break,不会继续扫后续 mode。
  8. 第 2137 行:函数结束。
    重点:该函数不显式返回错误码,异常多靠日志和 profile 结果侧面体现。

两个函数的高频坑位(配套)

函数 常见坑位 直接信号 最小验证动作
DealAvaliableBasicConfigurations format 填值和 formatArray 映射预期不一致 preview/profile 格式看起来“变了” 对照 drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:718-721 + 打印 cameraAbility
DealAvaliableBasicConfigurations 数组长度不是 3 的倍数(隐式脏数据) 上层 profile 维度异常 检查 HCS 数组是否严格三元组
ParseExtendCapability -1 分隔语义破坏(mode/stream/detail 边界错) ValidateOutputProfile ... fail 或 profile 缺失 CameraStreamInfoParse 路径核对原始数组结构
ParseExtendCapability mode 编码无法映射到 framework scene mode 日志出现 ConvertMetaToFwkMode 相关异常 对照 mode 值与实际枚举定义

参数如何起作用(按流程拆解)

轨道A:映射与上电

  1. logicCameraId/physicsCameraIdsDealCameraAbility 解析进 cameraIdMap_
    锚点:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:94-143
  2. OpenCamera 通过逻辑 ID 取物理 ID,逐个 PowerUp
    锚点:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp:195-205,266-277
  3. 上层只看到逻辑 ID,实际供电和驱动匹配用的是物理枚举。
    锚点:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_config.cpp:98-106

轨道B:能力注入与 profile 构造

  1. metadata 字段经 DealMetadata 一次性入 CameraMetadata
    锚点:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:145-193
  2. service 通过 HDI 拉取能力并缓存。
    锚点:foundation/multimedia/camera_framework/services/camera_service/src/hcamera_host_manager.cpp:251-279
  3. framework 依据优先级解析 profile,最后用于 preview/photo/video 输出创建。
    锚点:foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2253-2268,2055-2137

轨道C:KHDF 分区门禁

  1. abilityConfig 被解析到 g_configCameraRoot
    锚点:drivers/hdf_core/framework/model/camera/parser/src/camera_config_parser.c:494-522
  2. mode 字段被 CheckSwitchType 作为开关门禁。
    锚点:drivers/hdf_core/framework/model/camera/utils/src/camera_utils.c:120-166
  3. StreamConfig 上限会通过 CameraStreamEnumDevice 返回。
    锚点:drivers/hdf_core/framework/model/camera/device_impl/src/camera_stream.c:472-483

双证据检查模板(本章强制)

检查项 前序知识点判据 实际源码锚点 结论写法
physicsCameraIds 是否正确 “Open 失败优先查逻辑到物理映射” drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp:195-205,266-277 + device/board/gkhbd/nt_backclip_5cun_v1/camera/vdi_impl/v4l2/device_manager/include/project_hardware.h:20-27 判据+锚点一致/不一致
朝向是否一致 “UI前后摄异常先查 metadata 与 DTS 朝向一致性” drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:274-297 + device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsi:239-241 cameraPosition 与 DTS facing 对齐/错配
能力表是否可解析 “preview/profile 异常先查 extend/basic 结构” drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp:704-733,967-999 + foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp:2055-2137 能解析/分隔符或结构异常
驱动能力是否支撑 HCS “HCS 分辨率/FPS 不应超过驱动 mode 表” kernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c:863-943 能力覆盖/超配

配置改动影响范围速查

参数 第一生效函数 第二影响函数 常见失败信号
vdiLibList CameraHostService::GetInstance host 初始化整体失败 Vdi library list is empty
logicCameraId CameraHostConfig::GetCameraIds framework 枚举设备 ID GetCameraIds 不含目标 ID
physicsCameraIds CameraHostVdiImpl::OpenCamera CameraPowerUp camera powerup failed
basicAvailableConfigurations ParseBasicCapability preview/video profile 列表 profile 稀疏/缺失
extendAvailableConfigurations ParseExtendCapability mode 输出匹配 ValidateOutputProfile ... fail
cameraPosition DealCameraPosition GetSupportedCameras 选择与展示 前后摄分组异常
camera_config.hcs 的各分区 mode CheckSwitchType KHDF dispatch 开放能力 not supported

为什么这样设计(优点与取舍)

设计点 优点 取舍
逻辑 ID 与物理 ID 分离 上层接口稳定,底层硬件可换 需要维护映射一致性
metadata 驱动能力注入 板级差异尽量配置化 参数语义复杂,错误不易一眼看出
Extend 优先 Basic 兜底 能表达 mode/stream/fps 细粒度能力 extend 写坏会优先影响能力解析
KHDF 分区化开关 模块可裁剪、可按硬件能力启停 双 HCS 并存带来理解成本

知识点依赖与跨章连接

本章知识点 依赖 下一跳
HCS 参数来源方法 第2章(DTS/驱动基线) 第4章(会话门禁如何消费这些能力)
OpenCamera 上电链 第1章(全链路时序) 第6章(函数级失败点)
Extend/Basic 优先级 第1章(能力解析时序) 第5章(ArkTS 输出创建失败机制)

信号 -> 判断 -> 动作

信号 判断 动作
GetCameraIds 正常但预览创建失败 映射轨大概率正常,能力轨异常 extend/basic + ParseCapability
camera powerup failed 物理映射或硬件枚举不一致 对齐 physicsCameraIdsproject_hardware.h
前后摄展示错位 metadata 位置标签与 DTS 不一致 对齐 cameraPosition/lensFacing 与 DTS facing
KHDF 报 not supported 对应分区 mode=0 或解析失败 camera_config.hcs 分区开关与解析日志

四函数流程卡(每一步都有说明)

1) DealMetadata 流程

步骤 做什么 为什么重要 下一跳/失败信号
Step 1 创建 CameraMetadata(ENTRY_CAPACITY, DATA_CAPACITY) 建立能力容器,后续字段都写入这里 失败返回 RC_ERROR
Step 2 顺序调用各 DealXXX 子函数(AE/AWB/FPS/position/basic/extend...) 把 HCS 每个字段转成标准 metadata tag 某字段解析失败会留下“部分能力”风险
Step 3 执行 DealAvaliableBasicConfigurations 注入 basic 流能力(格式/分辨率) basic 错会导致 profile 稀疏
Step 4 执行 DealAvaliableExtendConfigurations 注入 mode/stream/fps 细粒度能力 extend 错会优先污染解析路径
Step 5 cameraMetadataMap_.insert(cameraId, metadata) 这是能力真正对外可见的落点 未插入则上层拿不到能力

2) DealAvaliableBasicConfigurations 流程

步骤 做什么 为什么重要 下一跳/失败信号
Step 1 读取 basicAvailableConfigurations 原始数组 拿到 HCS 的 basic 输入 数组为空或脏数据会影响后续
Step 2 按每 3 个为一组遍历(format,width,height 维持 basic 语义一致 长度异常会造成维度错位
Step 3 对格式位做 formatArray[value-1] 映射 HCS 格式号转 framework 可识别枚举 格式不在映射内会导致 profile 异常
Step 4 宽高位原样写入 保留真实尺寸参数 尺寸超驱动能力会在后续失败
Step 5 addEntry(OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS, ...) 完成 basic 能力注入 写入失败返回 RC_ERROR

3) ParseCapability 流程

步骤 做什么 为什么重要 下一跳/失败信号
Step 1 先查 OHOS_ABILITY_AVAILABLE_PROFILE_LEVEL 最高优先级解析入口 命中则直接 ParseProfileLevel
Step 2 未命中时查 OHOS_ABILITY_STREAM_AVAILABLE_EXTEND_CONFIGURATIONS extend 优先于 basic 命中则走 ParseExtendCapability
Step 3 再未命中时查 OHOS_ABILITY_STREAM_AVAILABLE_BASIC_CONFIGURATIONS basic 兜底路径 命中则走 ParseBasicCapability
Step 4 三者都不命中则报错 表示主流能力标签缺失 Failed get stream info
Step 5 额外独立检查 OHOS_ABILITY_DEPTH_DATA_PROFILES 深度流与主流并行解析 命中则走 ParseDepthCapability

4) ParseExtendCapability 流程

步骤 做什么 为什么重要 下一跳/失败信号
Step 1 getModeInfo(item.data.i32, item.count, extendInfo) 把原始 int32 数组按 -1 语义拆成结构 分隔错会导致 mode/stream/detail 乱序
Step 2 modeName == VIDEO,先扫 HIGH_FRAME_RATE 视频模式特有补充分支 该分支可解释 video profile 差异
Step 3 ConvertMetaToFwkMode 做 mode 映射 元数据 mode 需转 framework scene mode 映射失败会打印错误并跳过
Step 4 找到目标 mode 后遍历 streamType 锁定当前会话模式可用输出流 找不到 mode 会导致 profile 为空
Step 5 CreateProfile4StreamType 生成 profile 这是 preview/photo/video 产出点 异常常表现为 ValidateOutputProfile ... fail

一页速记卡(现场排障可直接照抄)

主题 速记
首查顺序 GetCameraIds -> OpenCamera(powerup) -> ParseCapability
能力优先级 ProfileLevel > Extend > Basic(不是 Basic 优先)
basic 三元组 format,width,height,格式位会做 formatArray 映射
extend 结构 mode -> streamType -> detail,靠 -1 分隔
朝向双证据 HCS cameraPosition/lensFacing + DTS camera-module-facing
映射双证据 HCS physicsCameraIds + project_hardware.h
分辨率/FPS 双证据 HCS basic/extend + ov5648_modes[]/frame_interval
Linux 工具 media-ctl -p(拓扑)/ v4l2-ctl --list-formats-ext(格式)/ --list-subdev-frameintervals(fps)
典型错误1 camera powerup failed -> 先核 physicsCameraIds
典型错误2 ValidateOutputProfile ... fail -> 先核 extend 分隔与 mode 映射
典型错误3 前后摄错位 -> 先核 HCS 朝向与 DTS 朝向一致性

本章最小动作(10分钟)

  1. 对照 camera_host_config.hcs 抽查 4 项:physicsCameraIdscameraPositionbasicextend
  2. 用源码确认读取点和生效点:drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/hcs_deal.cpp + drivers/peripheral/camera/vdi_base/v4l2/src/camera_host/camera_host_vdi_impl.cpp + foundation/multimedia/camera_framework/frameworks/native/camera/src/input/camera_manager.cpp
  3. 再对照 DTS/驱动:device/board/gkhbd/nt_backclip_5cun_v1/kernel/dts/nt_backclip_vendor/rk3568-gkh-nt_backclip_5cun.dtsikernel/linux/linux-6.6-nt_backclip_5cun_v1/drivers/media/i2c/ov5648.c,确认参数值来源有证据。

一句话小结

这章的核心不是“背字段”,而是把每个参数放进“来源 -> 读取函数 -> 生效函数 -> 失败信号”的闭环里做双证据验证。


发布后补链

全章导航

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐