高通camx Node相关

一、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是如何启用的

        一个node会被编译成一个.so文件。在开机过程中系统会加载很多东西,比如各种应用程序、so文件等等,在加载HAL进程时,会一起加载node。

具体实现如下: 

 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

// 此方法的作用是获取.so链接库hLibrary里面的名为pProcName的函数

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

因此在函数camxchicomponent.cpp里面会获取函数chiNodeEntry 函数,并将地址赋值给pNodeEntry。然后把对应node的回调信息放到&pExternalComponentInfo[index].nodeCallbacks。


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

获取node方法总体解释: 也就是:CamX通过GetFilesFromPath遍历camera/components目录下的所有so,调用dlopen()来打开目标库获取handle(定位库文件的地址),然后使用dlsym()来得到符号函数名字为"ChiNodeEntry"的地址,因为所有Node都有一个入口方法ChiNodeEntry,这样便可以加载所有的Node。

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之后,如何使用node中的方法呢? 

        通过调用pNodeEntry对pExternalComponentInfo[index].nodeCallbacks参数进行取地址赋值,这样就可以使用Node中的方法,其他的节点类似就好。

       总结:node 的加载是通过编译成.so文件使用,当程序起来的时候,就可以使用.so文件,加载node节点,每个node中存在一个ChiNodeEntry,将chiNodeEntry导入,就可以加载node里面的方法。

四、针对chinodecallbacks分析回调中的各个函数大致分析

CDK_VISIBILITY_PUBLIC VOID ChiNodeEntry(
    CHINODECALLBACKS* pNodeCallbacks)
{
    if (NULL != pNodeCallbacks)
    {
        if ((ChiNodeMajorVersion == pNodeCallbacks->majorVersion) &&
            (sizeof(CHINODECALLBACKS) <= pNodeCallbacks->size))
        {
            pNodeCallbacks->majorVersion                = ChiNodeMajorVersion;
            pNodeCallbacks->minorVersion                = ChiNodeMinorVersion;
            pNodeCallbacks->pGetCapabilities            = GpuNodeGetCaps;
            pNodeCallbacks->pQueryVendorTag             = GpuNodeQueryVendorTag;
            pNodeCallbacks->pCreate                     = GpuNodeCreate;
            pNodeCallbacks->pDestroy                    = GpuNodeDestroy;
            pNodeCallbacks->pQueryBufferInfo            = GpuNodeQueryBufferInfo;
            pNodeCallbacks->pSetBufferInfo              = GpuNodeSetBufferInfo;
            pNodeCallbacks->pProcessRequest             = GpuNodeProcRequest;
            pNodeCallbacks->pChiNodeSetNodeInterface    = GpuNodeSetNodeInterface;
            pNodeCallbacks->pPostPipelineCreate         = GpuNodePostPipelineCreate;
            pNodeCallbacks->pFlushRequest               = GpuNodeFlushRequest;
            pNodeCallbacks->pGetFlushResponse           = GpuNodeGetFlushResponse;
        }
        else
        {
            LOG_ERROR(CamxLogGroupChi, "Chi API major version doesn't match (%d:%d) vs (%d:%d)",
                      pNodeCallbacks->majorVersion,
                      pNodeCallbacks->minorVersion,
                      ChiNodeMajorVersion,
                      ChiNodeMinorVersion);
        }
    }
    else
    {
        LOG_ERROR(CamxLogGroupChi, "Invalid Argument: %p", pNodeCallbacks);
    }
}
/// @brief Callback Interface for Chi to call into custom node.
typedef struct ChiNodeCallbacks
{
    UINT32                          size;                       ///< Size of this structure
    UINT32                          majorVersion;               ///< Major version
    UINT32                          minorVersion;               ///< Minor version
    PFNNODEGETCAPS                  pGetCapabilities;           ///< Get Node Capabilities
    PFNCHIQUERYVENDORTAG            pQueryVendorTag;            ///< Optional function to get the vendor tags
                                                                ///< supported by node
    PFNNODECREATE                   pCreate;                    ///< Mandatory function to create an instance of the node
    PFNNODEDESTROY                  pDestroy;                   ///< Mandatory function to destroy an instance of the node
    PFNNODEQUERYBUFFERINFO          pQueryBufferInfo;           ///< Mandatory function called to query input buffer
                                                                ///< requirements
    PFNNODESETBUFFERINFO            pSetBufferInfo;             ///< Mandatory function called to set the buffer properties
    PFNNODEPROCREQUEST              pProcessRequest;            ///< Mandatory function to process a request by node
    PFCHINODESETNODEINTERFACE       pChiNodeSetNodeInterface;   ///< Mandatory function to set the node interface functions
    PFNPIPELINECREATED              pPipelineCreated;           ///< Notify pipeline created. Deprecated
    PFNPOSTPIPELINECREATE           pPostPipelineCreate;        ///< Indication of Post pipeline creation
    PFNCHIPREPARESTREAMON           pPrepareStreamOn;           ///< Notify pipeline for preparing stream on
    PFNCHIONSTREAMON                pOnStreamOn;                ///< Notify pipeline stream on
    PFNCHIONSTREAMOFF               pOnStreamOff;               ///< Notify pipeline stream off
    PFNNODEQUERYMETADATAPUBLISHLIST pQueryMetadataPublishList;  ///< Mandatory function called to query metadata list
                                                                ///< published by the node
    PFNNODEFLUSH                    pFlushRequest;              ///< Free up node resources allocated for a request
    PFNNODEFLUSHRESPONSEINFO        pGetFlushResponse;          ///< Get worst case response time for flush call
    PFNNODEFILLPERREQUESTHWDATA     pFillHwdata;                ///< Fill per request hardware data
} CHINODECALLBACKS;

回调函数指针对应实现函数功能与作用调用时机
pGetCapabilitiesGpuNodeGetCaps获取节点能力
返回节点支持的硬件特性(如旋转/缩放/滤镜等)
节点初始化时
pQueryVendorTagGpuNodeQueryVendorTag查询供应商标签
声明节点自定义的元数据标签(如调试参数/控制参数)
流水线构建前
pCreateGpuNodeCreate创建节点实例
分配节点私有数据,初始化硬件资源
每个节点实例化时
pDestroyGpuNodeDestroy销毁节点实例
释放资源,清理状态
节点不再使用时
pQueryBufferInfoGpuNodeQueryBufferInfo查询缓冲区需求
声明节点对输入/输出缓冲区的尺寸/格式/对齐要求
流水线缓冲区分配前
pSetBufferInfoGpuNodeSetBufferInfo设置缓冲区信息
接收实际分配的缓冲区属性(如 stride/scanline)
缓冲区分配完成后
pProcessRequestGpuNodeProcRequest处理请求
核心函数,执行图像处理(如 GPU 滤镜/旋转/缩放)
每帧数据处理时
pChiNodeSetNodeInterfaceGpuNodeSetNodeInterface设置节点接口
获取 CHI 框架服务(如日志/元数据访问)
节点创建后立即调用
pPostPipelineCreateGpuNodePostPipelineCreate流水线创建后处理
执行依赖完整流水线的初始化(如跨节点依赖解析)
整个相机流水线构建完成后
pFlushRequestGpuNodeFlushRequest刷新请求
中止正在处理的请求(如相机模式切换时)
流水线需要重置时
pGetFlushResponseGpuNodeGetFlushResponse获取刷新响应
确认所有请求已终止

以GPU为例:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值