HAL3对camera的控制是通过metadata进行控制的。在相机初始化的时候会获取一个默认设置,然后在请求每一帧的时候,把需要设置的参数在metadata中更新,再参数也下发下去。
那么带来了两个问题:

  1. 如何对接上层,告诉它我有相应的接口,如果你想要实现某个功能,就设置metadata就行了。
    其次如何在CHI节点中又获取到上层设置的接口呢?

  2. CHI之间的3A,人脸识别等统计信息也是通过metadata传递的,在CHI之间如何获取呢?

本文从这两个方面去解答。

设置和获取上层的metadata

元数据标签可以是预定义的Android标签,也可以是定制的供应商标签。供应商标签在HAL中定义,以支持Camx和Chi所需的附加元数据。供应商标签信息有三种类型:hwVendorTagInfo、componentVendorTagsInfo和coreVendorTagInfo。我们需要添加相应的vendor标签。

hwVendorTagInfo: 在camxtitan17xcontext.cpp中定义,被Core、HWL、SWL等使用。这些厂商标签大多不属于HWL,它们是HW独立的。

componentVendorTagsInfo:这些厂商标签依赖于CHI节点,并在每个CHI组件中相应地定义。

coreVendorTagInfo:在核心层(camxvendortag .cpp)中定义,并由核心层或其他层使用。

接下来详细讲解操作步骤:

  1. 在hwVendorTagInfo增加厂商标签信息

    //Path: vendor/qcom/proprietary/camx/src/hwl/titan17x/camxtitan17xcontext.cpp 
    static VendorTagData g_VendorTagSectionDemo[] =
    {
    { "demoTag", VendorTagType::Byte, 1 },
    };
    static VendorTagSectionData g_HwVendorTagSections[] =
    {
    ......

    {
    "org.quic.camera.DemoSection", 0,
    CAMX_ARRAY_SIZE(g_VendorTagSectionDemo), g_VendorTagSectionDemo,
    TagSectionVisibility::TagSectionVisibleToAll
    },
    };
  2. 在骁龙相机中设置metadata标签

    路径:packages/apps/SnapdragonCamera/src/com/android/camera/CaptureModule.java

    1. 定义key

      public static final CaptureRequest.Key demoKey = 
      new CaptureRequest.Key<>("org.quic.camera.DemoSection.demoTag", byte.class);
    2. 定义默认值

      private boolean mDemoKeyValue = true; 

      private void applyDemoKey(CaptureRequest.Builder request) {
      try {
      request.set(CaptureModule.demoKey, (byte) (mDemoKeyValue? 0xFF : 0x00));
      } catch (IllegalArgumentException e) {
      e.printStackTrace();
      }
      }
    3. 应用key到每帧请求

      private void applyCommonSettings(CaptureRequest.Builder builder, int id) { 
      ……
      applyDemoKey(builder);
      ……
      }
  3. 获取metadata

    1. camx session

      //Path: vendor/qcom/proprietary/camx/src/core/camxsession.cpp 
      CamxResult Session::ProcessCaptureRequest(
      const ChiPipelineRequest* pPipelineRequests)
      {
      ……..
      MetadataSlot* pMetadataSlot =
      pPerFrameInputPool->GetSlot(m_requestBatchId[pipelinIndex]);
      if (pMetadataSlot != NULL) {
      UINT32 metaTag = 0;
      result = VendorTagManager::QueryVendorTagLocation("org.quic.camera.DemoSection", "demoTag", &metaTag);
      if (CamxResultSuccess == result)
      {
      UINT8* demoData = static_cast(pMetadataSlot->GetMetadataByTag(metaTag));
      }
      }
    2. camx pipeline

      //Path: vendor/qcom/proprietary/camx/src/core/camxpipeline.cpp
      CamxResult Pipeline::ProcessRequest(
      PipelineProcessRequestData* pPipelineRequestData)
      {
      ……
      UINT32 metaTag = 0;
      result = VendorTagManager::QueryVendorTagLocation("org.quic.camera.DemoSection", "demoTag", &metaTag);
      if (CamxResultSuccess == result)
      {
      UINT8* demoData = static_cast(pInputSlot->GetMetadataByTag(metaTag));
      }
      ……
    3. SWL/HWL

      //Path: vendor/qcom/proprietary/camx/src/swl/sensor/camxsensornode.cpp
      CamxResult SensorNode::ExecuteProcessRequest(
      ExecuteProcessRequestData* pExecuteProcessRequestData)
      {
      ……
      UINT32 metaTag[1] = { 0 };
      UINT8* demoData[1] = { 0 };
      UINT length = CAMX_ARRAY_SIZE(metaTag);
      UINT64 configDataOffset[1] = { 0 };

      result = VendorTagManager::QueryVendorTagLocation("org.quic.camera.DemoSection", "demoTag", &metaTag[0]);
      metaTag[0] |= InputMetadataSectionMask;
      GetDataList(metaTag, reinterpret_cast(demoData), configDataOffset, length);
      ……
    4. CHI 节点

      //Path: vendor/qcom/proprietary/chi-cdk/vendor/node/memcpy/camxchinodememcpy.cpp 
      CDKResult ChiMemCpyNode::ProcessRequest(
      CHINODEPROCESSREQUESTINFO* pProcessRequestInfo)
      {
      ……
      CHIVENDORTAGBASEINFO vendorTagBase = {0};
      vendorTagBase.size = sizeof(CHIVENDORTAGBASEINFO);
      vendorTagBase.pComponentName = "org.quic.camera.DemoSection";
      vendorTagBase.pTagName = "demoTag";

      g_ChiNodeInterface.pGetVendorTagBase(&vendorTagBase);
      UINT8* demoData = static_cast(ChiNodeUtils::GetMetaData(
      pProcessRequestInfo->frameNum, vendorTagBase.vendorTagBase
      |InputMetadataSectionMask, ChiMetadataDynamic, &g_ChiNodeInterface,
      m_hChiSession));
      ……

CHI节点之间获取metadata

我们在CHI节点之间需要获取metadata,那么如何获取呢,就以获取人脸检测配置为例

  1. 找到你需要获取的vendor tag

    vendor\qcom\proprietary\chi-cdk\cdk\fd\chifdproperty.h

    static const CHAR* VendorTagSectionOEMFDConfig  = "org.quic.camera2.oemfdconfig"; ///< OEM FD config vendor tag section
    static const CHAR* VendorTagNameOEMFDConfig = "OEMFDConfig"; ///< OEM FD config vendor tag name
  2. 找到相关的数据结构体

    vendor\qcom\proprietary\chi-cdk\cdk\common\chistatspropertydefines.h

    /// @brief Structure describing the rectangle coordinates
    typedef struct
    {
    UINT32 left; ///< x coordinate of the ROI
    UINT32 top; ///< y coordinate of the ROI
    UINT32 width; ///< Width of the ROI
    UINT32 height; ///< Height of the ROI
    } RectangleCoordinate;
    /// @brief Describes Face ROI
    typedef struct
    {
    UINT32 id; ///< Id used to track a face in the scene
    UINT32 confidence; ///< Confidence of this face
    RectangleCoordinate faceRect; ///< Detected Face rectangle
    } FaceROIData;
    /// @brief Structure describing Face ROI data
    typedef struct
    {
    UINT64 requestId; ///< Request ID corresponding to this results
    UINT32 ROICount; ///< Number of ROIs
    FaceROIData unstabilizedROI[MaxFaceROIs]; ///< Unstabilized Face ROI data
    FaceROIData stabilizedROI[MaxFaceROIs]; ///< Stabilized Face ROI data
    } FaceROIInformation;
  3. 检查需要读取的供应商标记的依赖。如果尚未发布,则增加依赖项计数。

    如果Chi节点的处理依赖于其他标签并且标签尚未发布,则Chi节点可以在pProcessRequestInfo中设置依赖关系并立即返回。 一旦满足依赖关系,框架将再次调用ExecuteProcessRequest。

    +       // Check OEMFDResults dependency 
    + CHIVENDORTAGBASEINFO vendorTagBase = {0};
    + vendorTagBase.size = sizeof(CHIVENDORTAGBASEINFO);
    + vendorTagBase.pComponentName = VendorTagSectionOEMFDResults;
    + vendorTagBase.pTagName = VendorTagNameOEMFDResults;
    + g_ChiNodeInterface.pGetVendorTagBase(&vendorTagBase);
    +
    + tag = vendorTagBase.vendorTagBase;
    +
    + pData = ChiNodeUtils::GetMetaData(pProcessRequestInfo->frameNum, tag,
    ChiMetadataDynamic,
    + &g_ChiNodeInterface, m_hChiSession);
    + if (NULL == pData)
    + {
    + pDependencyInfo->properties[dependencyCount] = tag;
    + pDependencyInfo->offsets[dependencyCount] = 0;
    + dependencyCount++;
    + }
    +
    if (dependencyCount > 0)
    {
    pDependencyInfo->count = dependencyCount;
  4. 在处理请求的函数中获取厂商标签

    +VOID ChiMemCpyNode::GetFDResults(UINT64 requestId) 
    +{
    + VOID* pData = NULL;
    + UINT32 tag;
    + CHIVENDORTAGBASEINFO vendorTagBase = {0};
    + vendorTagBase.size = sizeof(CHIVENDORTAGBASEINFO);
    + vendorTagBase.pComponentName = VendorTagSectionOEMFDResults;
    + vendorTagBase.pTagName = VendorTagNameOEMFDResults;
    + g_ChiNodeInterface.pGetVendorTagBase(&vendorTagBase);
    +
    + tag = vendorTagBase.vendorTagBase;
    +
    + pData = ChiNodeUtils::GetMetaData(requestId, tag, ChiMetadataDynamic,
    + &g_ChiNodeInterface, m_hChiSession);
    + if(pData){
    + LOG_ERROR(CamxLogGroupChi, "pData %p tag 0x%x",pData,tag);
    + FaceROIInformation* pFaceROIInfo = (FaceROIInformation *)pData;
    + LOG_ERROR(CamxLogGroupChi, "ROICount %d", pFaceROIInfo->ROICount);
    + for (UINT32 i = 0; i < pFaceROIInfo->ROICount; i++){
    + LOG_ERROR(CamxLogGroupChi,"faceID=%d, confidence=%d, top-left(%d, %d), width=%d, height=%d",
    + pFaceROIInfo->unstabilizedROI[i].id, pFaceROIInfo->unstabilizedROI[i].confidence,
    + pFaceROIInfo->unstabilizedROI[i].faceRect.left, pFaceROIInfo->unstabilizedROI[i].faceRect.top,
    + pFaceROIInfo->unstabilizedROI[i].faceRect.width, pFaceROIInfo->unstabilizedROI[i].faceRect.height);
    + }
    + for (UINT32 i = 0; i < pFaceROIInfo->ROICount; i++){
    + LOG_ERROR(CamxLogGroupChi,"faceID=%d, confidence=%d, top-left(%d, %d), width=%d, height=%d",
    + pFaceROIInfo->stabilizedROI[i].id, pFaceROIInfo->stabilizedROI[i].confidence,
    + pFaceROIInfo->stabilizedROI[i].faceRect.left, pFaceROIInfo->stabilizedROI[i].faceRect.top,
    + pFaceROIInfo->stabilizedROI[i].faceRect.width, pFaceROIInfo->stabilizedROI[i].faceRect.height);
    + }
    + }else{
    + LOG_ERROR(CamxLogGroupChi, "OEMFDResults pData is NULL!");
    + }
    +}
    +
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ChiMemCpyNode::ProcessRequest
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    @@ -550,6 +603,7 @@ CDKResult ChiMemCpyNode::ProcessRequest(

    if (TRUE == satisfied)
    {
    + GetFDResults(pProcessRequestInfo->frameNum);
    for (UINT32 i = 0; i < pProcessRequestInfo->outputNum; i++)
    {
    // This is memcpy dummy RTB node
  5. 最后打开人脸检测的打印进行检查

    adb root  
    adb remount
    adb shell "echo logVerboseMask=0x100000 >> /vendor/etc/camera/camxoverridesettings.txt"
    adb reboot