【Qcom Camera】Camx架构Chi External Node 三部曲之如何加载

一、Node简单介绍

    较官方的定义:Node节点在Camx/Chi架构中至关重要,主要用于处理pipeline下发的request,最终的数据处理都是通过封装好的Node节点来进行的。

简单来说Node用于数据处理;

同时也可以是一些特殊的算法处理,比如EIS,FD,SW Remosaic等等。

    大概了解下Node所处的具体位置,如下图:

    Node在Camx/Chi中均会存在,Camx中主要位于:android/vendor/qcom/proprietary/camx/src/(hwl/swl),例如:IFE,IPE,BPS,Sensor等。

Chi中主要位于:android/vendor/qcom/proprietary/chi-cdk/oem/qcom/node/,例如:三方EIS,memcpy等。

那两种Node之间有何差异呢?

主要体现在:Camx node是平台已经封装好的节点,一般不需要改动;而Chi node则是提供给vendor自定义实现的节点,用于自定义算法处理。

二、Node如何加载

今天讲解的是Chi Node,大概分为三类,主要关注COMPONENT NODE;

enum class ExternalComponentNodeAlgo
{
COMPONENTNODE      = 0,   ///< Node
COMPONENTALGORITHM = 1,   ///< Algorithm
COMPONENTHVX       = 2,   ///< Hvx
};


在开机过程中系统会加载很多东西,比如各种应用程序、so文件等等,在加载HAL进程时同样会一起加载Node,我们共同在以下方法中梳理Node的加载流程:
android/vendor/qcom/proprietary/camx/src/core/camxhwenvironment.cpp
//HW初始化方法
 

CamxResult HwEnvironment::Initialize()
 CAMX_ASSERT(NULL != pExternalComponent);
if ((CamxResultSuccess == result) && (NULL != pExternalComponent))
{
     result = ProbeChiComponents(pExternalComponent, &m_numExternalComponent);
}

//我们要知道External node在编译成功之后存放于以下目录
static const CHAR ExtCompPath[] = "/vendor/lib64/camera/components";
//ProbeChiComponents方法

CamxResult ProbeChiComponents(
    ExternalComponentInfo* pExternalComponentInfo,
UINT*                  pNumExternalComponent)
//返回so的文件数量
    fileCountTypeNode  = OsUtils::GetFilesFromPath(ExtCompPath,
                                                   FILENAME_MAX,
                                                   &soFilesName[0][0],
                                                   "*",      //VendorName
                                                   "node",  //CategoryName
,例如com.qti.node.memcpy.so,  com.wt.node.sat.so
                                                   "*",
                                                   "*",
                                                 &SharedLibraryExtension[0]);
//循环加载Node节点
    while (index < fileCountTypeNode + fileCountTypeStats + fileCountTypeHvx)
    {
        CamX::OSLIBRARYHANDLE handle = CamX::OsUtils::LibMap(&soFilesName[index][0]);// 1.dlopen的封装方法

        if (index < fileCountTypeNode)
        {
            pNodeEntry = reinterpret_cast<PFCHINODEENTRY>(CamX::OsUtils::LibGetAddr(handle, "ChiNodeEntry"));  // 2.dlsys的封装方法
            CAMX_ASSERT(NULL != pNodeEntry);
            pExternalComponentInfo[index].nodeCallbacks.size = sizeof(ChiNodeCallbacks);
            if (NULL != pNodeEntry)
            {
                pNodeEntry(&pExternalComponentInfo[index].nodeCallbacks);// 3.Node API’s Callbacks
            }

            if (NULL != pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag)
            {
                GetComponentTag(pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag);
            }

            pExternalComponentInfo[index].nodeAlgoType = ExternalComponentNodeAlgo::COMPONENTNODE;
        }

1.核心方法dlopen

OSLIBRARYHANDLE ChxUtils::LibMap(const CHAR* pLibraryName)
{
    OSLIBRARYHANDLE hLibrary  = NULL;
    const UINT bindFlags = RTLD_NOW | RTLD_LOCAL;
    hLibrary = dlopen(pLibraryName, bindFlags);
    if (NULL == hLibrary)
    {
        CHX_LOG_ERROR("Failed to load library %s error %s", pLibraryName, dlerror());
        CHX_ASSERT(0 == dlerror());
    }
    return hLibrary;
}


2.核心方法dlsym

VOID* ChxUtils::LibGetAddr(OSLIBRARYHANDLE hLibrary,
                           const CHAR*     pProcName)
{
    VOID* pProcAddr = NULL;
    if (hLibrary != NULL)
    {
        pProcAddr = dlsym(hLibrary, pProcName);
    }
    return pProcAddr;
}


首先要知道.so 库文件是一个 ELF 文件,可以通过 readelf -s 命令查看对应的.so文件描述,如下图可以看到其中有一个 Name 属性为 ChiNodeEntry。

也就是:CamX通过GetFilesFromPath遍历camera/components目录下的所有so,调用dlopen()来打开目标库获取handle(定位库文件的地址),然后使用dlsym()来得到符号名字为"ChiNodeEntry"的地址,因为所有Node都有一个入口方法ChiNodeEntry,这样便可以加载所有的Node。
那么加载之后如何拿到Node中的方法?
1.这里就需要查看"//ProbeChiComponents方法" 中3的pNodeEntry的数据类型
 

PFCHINODEENTRY       pNodeEntry;
typedef VOID (*PFCHINODEENTRY) (CHINODECALLBACKS* pNodeCallbacks);

函数指针类型;
通过调用pNodeEntry对pExternalComponentInfo[index].nodeCallbacks参数进行取地址赋值,这样就可以使用Node中的方法。
2.以memcpy为例看一下具体操作:
android/vendor/qcom/proprietary/chi-cdk/oem/qcom/node/memcpy/camxchinodememcpy.cpp
//Memcpynode 中的ChiNodeEntry方法
 

CDK_VISIBILITY_PUBLIC VOID ChiNodeEntry(
    CHINODECALLBACKS* pNodeCallbacks)
{
    if (NULL != pNodeCallbacks)
    {
        if (pNodeCallbacks->majorVersion == ChiNodeMajorVersion &&
            pNodeCallbacks->size >= sizeof(CHINODECALLBACKS))
        {
            pNodeCallbacks->majorVersion             = ChiNodeMajorVersion;
            pNodeCallbacks->minorVersion             = ChiNodeMinorVersion;
            pNodeCallbacks->pGetCapabilities          = MemCpyNodeGetCaps;
            pNodeCallbacks->pQueryVendorTag          = MemCpyNodeQueryVendorTag;
            pNodeCallbacks->pCreate                  = MemCpyNodeCreate;
            pNodeCallbacks->pDestroy                 = MemCpyNodeDestroy;
            pNodeCallbacks->pQueryBufferInfo         = MemCpyNodeQueryBufferInfo;
            pNodeCallbacks->pSetBufferInfo           = MemCpyNodeSetBufferInfo;
            pNodeCallbacks->pProcessRequest          = MemCpyNodeProcRequest;
            pNodeCallbacks->pChiNodeSetNodeInterface = MemCpyNodeSetNodeInterface;
        }
}

非常清楚明了,举一反三:其他类型的Node如何加载、Camx如何加载Chi、上层如何加载HAL等等,同理。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cam_Rxy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值