因为这段时间工作的时候老是看到各种metadata,真的时烦死了。对这个东西之前简单的了解了一下,对这个东西了解的还不是很系统,所以接下来的这段时间打算好好的整理一下这个metada。前期的时候我会把我整理的这些东西简单的整理成比较碎片的文档,等后面完全通的时候再把这些东西顺下来。
前期学习的时候真的是一件很痛苦的事情,但是学习就是这样的在痛苦中成长。我就不写学习计划了,我学到了什么就先写什么,比较碎片化。
把hal所有的metadata放在一起
主要就是这个AppendVendorTagInfo函数,代代表三类的meta。hw和core这两类是高通自己定义的,正常情况下我们是不会去改动这些的。我自己加的meta属于componentVendorTag这个类别里面。
//单例模式
VendorTagManager* VendorTagManager::GetInstance()
{
static VendorTagManager s_VendorTagManagerSingleton;
return &s_VendorTagManagerSingleton;
}
VendorTagManager::VendorTagManager()
{
CamxResult result = InitializeVendorTagInfo();
}
CamxResult VendorTagManager::InitializeVendorTagInfo()
{
VendorTagInfo hwVendorTagInfo = { 0 };
ComponentVendorTagsInfo componentVendorTagsInfo = { 0 };
VendorTagInfo coreVendorTagInfo = { g_CamXVendorTagSections, CAMX_ARRAY_SIZE(g_CamXVendorTagSections) };
// Query the vendor tag information from HW
result = pHwEnvironment->GetHwStaticEntry()->QueryVendorTagsInfo(&hwVendorTagInfo);
result = AppendVendorTagInfo(&hwVendorTagInfo);
result = AppendVendorTagInfo(&coreVendorTagInfo);
// Query the vendor tag information from External Component
for (UINT32 i = 0; i < componentVendorTagsInfo.numVendorTagInfo ; i++)
{
result = AppendVendorTagInfo(&componentVendorTagsInfo.pVendorTagInfoArray[i]);
}
}
1.hwVendorTagInfo
这是对应结构体的定义
struct VendorTagInfo
{
VendorTagSectionData* pVendorTagDataArray; ///< An array of vendor tag section
UINT32 numSections; ///< The number of vendor tag section in pVendorTagDataArray
};
struct VendorTagSectionData
{
const CHAR* pVendorTagSectionName; ///< The string representing the vendor tag section name
VendorTag firstVendorTag; ///< The first vendor tag in the vendor tag section
UINT32 numTags; ///< The number of vendor tags in the section
VendorTagData* pVendorTagaData; ///< An array of vendor tag data arrays
TagSectionVisibility visbility; ///< Visibility of this tag section
};
typedef UINT32 VendorTag;
struct VendorTagData
{
const CHAR* pVendorTagName; ///< The string representation of the vendor tag name
VendorTagType vendorTagType; ///< The type of the vendor tag
SIZE_T numUnits; ///< The number of units of vendorTagType needed to program this tag
};
enum class VendorTagType : UINT8
{
Byte = 0, ///< Unsigned 8-bit integer
Int32 = 1, ///< Signed 32-bit integer
Float = 2, ///< 32-bit float
Int64 = 3, ///< Signed 64-bit integer
Double = 4, ///< 64-bit float
Rational = 5, ///< A 64-bit fraction
Error = 255, ///< Complies with COMMON API if an invalid vendor tag specified
};
enum TagSectionVisibility : UINT32
{
TagSectionVisibleToOEM = 0x1, ///< VenderTag section visible to OEM
TagSectionVisibleToFramework = 0x2, ///< VenderTag section visible to Android framework
TagSectionVisibleToAll = 0xFFFFFFFF, ///< VenderTag section visible to All
};
接下来看下hwVendorTagInfo是怎么获取到的
result = pHwEnvironment->GetHwStaticEntry()->QueryVendorTagsInfo(&hwVendorTagInfo);
CamxResult Titan17xContext::QueryVendorTagsInfo(VendorTagInfo* pVendorTagInfo)
{
pVendorTagInfo->pVendorTagDataArray = g_HwVendorTagSections;
pVendorTagInfo->numSections = CAMX_ARRAY_SIZE(g_HwVendorTagSections);
}
可以说只要找到g_HwVendorTagSections 是怎么来的就找到了hwVendorTagInfo,这个正好是高通定义的一个数组。
static VendorTagSectionData g_HwVendorTagSections[] =
{
......
{
"xxx.xxx.xxx", //pVendorTagSectionName
0, //firstVendorTag
CAMX_ARRAY_SIZE(g_VendorTagSectionSharpness), //numTags
g_VendorTagSectionSharpness, //pVendorTagaData
TagSectionVisibility::TagSectionVisibleToAll //visbility
}
......
}
static VendorTagData g_VendorTagSectionSharpness[] =
{
{
"strength", //pVendorTagName
VendorTagType::Int32, //vendorTagType
1 //numUnits
}
}
2.coreVendorTagInfo
这个类型跟g_HwVendorTagSections差不多,我就随便找一个例子分析下,因为有些还是有差异的
static VendorTagSectionData g_CamXVendorTagSections[] =
{
{
"org.codeaurora.qcamera3.internal_private",
VendorTagPrivate,
CAMX_ARRAY_SIZE(g_VendorTagSectionInernalPrivate),
g_VendorTagSectionInernalPrivate,
TagSectionVisibility::TagSectionVisibleToOEM
},
}
static const UINT32 NumOfVendorTagOffsetBit = 16;
MetadataSectionVendorSection = 0x8000
VendorTagSectionPrivate = MetadataSectionVendorSection
static const VendorTag VendorTagPrivate = static_cast<VendorTag>(VendorTagSectionPrivate << NumOfVendorTagOffsetBit);
static VendorTagData g_VendorTagSectionInernalPrivate[] =
{
{
"private_property",
VendorTagType::Byte,
PropertyBlobSize
} // tagId + value + number of tags
}
static const UINT PropertyBlobSize = sizeof(MainPropertyBlob) + sizeof(MainPropertyLinearLUT) + sizeof(UINT32);
这两个是个数组,几乎把所有的tagid否枚举出来了到时候研究一下
3. componentVendorTagsInfo
可以看到这个是对hwVendorTagInfo的进一步封装
struct ComponentVendorTagsInfo
{
VendorTagInfo* pVendorTagInfoArray; ///< An array of vendor tag info
UINT32 numVendorTagInfo; ///< The number of vendortag info section in pVendorTagInfoArray
};
pHwEnvironment->GetHwStaticEntry()->QueryExternalComponentVendorTagsInfo(&componentVendorTagsInfo);
CamxResult Titan17xContext::QueryExternalComponentVendorTagsInfo(ComponentVendorTagsInfo* pComponentVendorTagsInfo)
{
pComponentVendorTagsInfo->pVendorTagInfoArray = g_componentVendorTagsInfo.pVendorTagInfoArray;
pComponentVendorTagsInfo->numVendorTagInfo = g_componentVendorTagsInfo.numVendorTagInfo;
}
这个主要是找到g_componentVendorTagsInfo被赋值的地方就可以找到这一类是怎么来的了。
这里就要从开启动的流程开始说起了
//这是一个典型的单例模式实现方式可以学习一下
HwEnvironment* HwEnvironment::GetInstance()
{
static HwEnvironment s_HwEnvironmentSingleton;
if (InitCapsInitialize == s_HwEnvironmentSingleton.m_initCapsStatus)
{
s_HwEnvironmentSingleton.InitCaps();
}
return &s_HwEnvironmentSingleton;
}
//开机启动的时候会调用这个函数
HwEnvironment::HwEnvironment()
: m_initCapsStatus(InitCapsInvalid)
, m_pNCSObject(NULL) {
Initialize(); }
CamxResult HwEnvironment::Initialize()
{
ExternalComponentInfo* pExternalComponent = GetExternalComponent();
CAMX_ASSERT(NULL != pExternalComponent);
if ((CamxResultSuccess == result) && (NULL != pExternalComponent))
{
result = ProbeChiComponents(pExternalComponent, &m_numExternalComponent);//主要是这个函数比较重要
}
}
CAMX_INLINE ExternalComponentInfo* GetExternalComponent() const
{
return (ExternalComponentInfo*)&m_externalComponent[0];//感觉这里就是单纯的传递一个地址
}
从下面开始就是重头戏了,这个看明白就知道为什么我们客制化要在node或者chi里面定义tag的原因了。
这是传入的参数的数据结构
struct ExternalComponentInfo
{
CHAR* pComponentName; ///< External Component name
union
{
CHINODEINTERFACE nodeInterface; ///< node Interface for custom node to call into Chi.
CHIALGORITHMINTERFACE algoInterface; ///< algo Interface for custom node to call into Chi.
};
union
{
CHINODECALLBACKS nodeCallbacks; ///< Node Callback Interface for Chi to call into custom node.
CHIHISTALGORITHMCALLBACKS histAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIAECALGORITHMCALLBACKS AECAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIAFALGORITHMCALLBACKS AFAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIAWBALGORITHMCALLBACKS AWBAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIAFDALGORITHMCALLBACKS AFDAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIASDALGORITHMCALLBACKS ASDAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIPDLIBRARYCALLBACKS PDLibCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHIISPHVXALGORITHMCALLBACKS HVXAlgoCallbacks; ///< Algo Callback Interface for Chi to call into custom node.
CHITRACKERALGORITHMCALLBACKS trackerAlgoCallbacks; ///< Algo Callback Interface for chi to call into custom code.
};
ExternalComponentNodeAlgo nodeAlgoType; ///< 0 for node and 1 for algo
BOOL inUse; ///< 1 for inUse and 0 for free
ExternalComponentStatsAlgo statsAlgo; ///< stats algo type
};
enum class ExternalComponentNodeAlgo {
COMPONENTNODE = 0, ///< Node
COMPONENTALGORITHM = 1, ///< Algorithm
COMPONENTHVX = 2, ///< Hvx };
enum class ExternalComponentStatsAlgo
{
ALGOAEC = 0, ///< AEC
ALGOAF, ///< AF
ALGOAWB, ///< AWB
ALGOAFD, ///< AFD
ALGOASD, ///< ASD
ALGOPD, ///< PD
ALGOHIST = 7, ///< Histogram Algo
ALGOTRACK, ///< Track
};
这是对应的处理流程
CamxResult ProbeChiComponents(
ExternalComponentInfo* pExternalComponentInfo,
UINT* pNumExternalComponent)
{
UINT16 fileCountTypeNode = 0;
UINT16 fileCountTypeStats = 0;
UINT16 fileCountTypeOverride = 0;
UINT16 fileCountTypeHvx = 0;
//这是在用通配符计算对应的so的数量
fileCountTypeOverride = OsUtils::GetFilesFromPath(CHIOverrideModulePath,
FILENAME_MAX,
&chiOverrideSoFileName[0],
"*",
"chi",
"*",
"*",
&SharedLibraryExtension[0]);
fileCountTypeNode = OsUtils::GetFilesFromPath(ExtCompPath,
FILENAME_MAX,
&soFilesName[0][0],
"*",
"node",
"*",
"*",
&SharedLibraryExtension[0]);
fileCountTypeStats = OsUtils::GetFilesFromPath(ExtCompPath,
FILENAME_MAX,
&soFilesName[fileCountTypeNode][0],
"*",
"stats",
"*",
"*",
&SharedLibraryExtension[0]);
fileCountTypeHvx = OsUtils::GetFilesFromPath(ExtCompPath,
FILENAME_MAX,
&soFilesName[fileCountTypeNode+fileCountTypeStats][0],
"*",
"hvx",
"*",
"*",
&SharedLibraryExtension[0]);
//这就是我们传过来的第二个参数在这里被赋值的
*pNumExternalComponent = fileCountTypeNode + fileCountTypeStats + fileCountTypeHvx;
while (index < fileCountTypeNode + fileCountTypeStats + fileCountTypeHvx)
{
if (index < fileCountTypeNode)
{
CamX::OSLIBRARYHANDLE handle = CamX::OsUtils::LibMap(&soFilesName[index][0]);
pNodeEntry = reinterpret_cast<PFCHINODEENTRY>(CamX::OsUtils::LibGetAddr(handle, "ChiNodeEntry"));
pNodeEntry(&pExternalComponentInfo[index].nodeCallbacks);
if (NULL != pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag)
{
//这一句很重要
GetComponentTag(pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag);
}
}
else if (index < (fileCountTypeNode+fileCountTypeStats))
{
pExternalComponentInfo[index].nodeAlgoType = ExternalComponentNodeAlgo::COMPONENTALGORITHM;
if (OsUtils::GetFileNameToken(&soFilesName[index][0], 4, outTokenString, FILENAME_MAX) == TRUE)
{
if (0 == OsUtils::StrNICmp(outTokenString, AECToken, OsUtils::StrLen(AECToken)))
{
......
//这一句很重要
GetAECAlgorithmCallback(&soFilesName[index][0], pExternalComponentInfo, index);
pExternalComponentInfo[index].statsAlgo = ExternalComponentStatsAlgo::ALGOAEC;
}
......
}
}
else
{
pExternalComponentInfo[index].nodeAlgoType = ExternalComponentNodeAlgo::COMPONENTHVX;
GetHVXAlgorithmCallback(&soFilesName[index][0], pExternalComponentInfo, index);
}
}
if (0 < fileCountTypeOverride)
{
PFNCHIQUERYVENDORTAG pQueryVendorTag;
pQueryVendorTag = reinterpret_cast<PFNCHIQUERYVENDORTAG>(CamX::OsUtils::LibGetAddr(CamX::OsUtils::LibMap(&chiOverrideSoFileName[fileIndex]), "chi_hal_query_vendertag"));
GetComponentTag(pQueryVendorTag);
}
}
上面的逻辑主要分成两个,一个是while循环里面,另外一个是fileCountTypeOverride
首先分析while循环里面的内容
pNodeEntry = reinterpret_cast<PFCHINODEENTRY>(CamX::OsUtils::LibGetAddr(handle, "ChiNodeEntry"));
VOID* OsUtils::LibGetAddr(
OSLIBRARYHANDLE hLibrary,
const CHAR* pProcName)
{
VOID* pProcAddr = NULL;
if (hLibrary != NULL)
{
pProcAddr = dlsym(hLibrary, pProcName);
}
return pProcAddr;
}
//dlsym是一个计算机函数,功能是根据动态链接库操作句柄与符号,返回符号对应的地址,不但可以获取函数地址,也可以获取变量地址
//所以上面就相当于拿到了node的这个函数的句柄
pNodeEntry(&pExternalComponentInfo[index].nodeCallbacks);
//在每个node中都会有一个ChiNodeEntry函数,里面会定义所有的函数接口
//这里就相当于拿到了node的所有的函数。
CDK_VISIBILITY_PUBLIC VOID ChiNodeEntry(
CHINODECALLBACKS* pNodeCallbacks)
{
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;
pNodeCallbacks->pFlushRequest = MemCpyNodeFlushRequest;
pNodeCallbacks->pGetFlushResponse = MemCpyNodeGetFlushResponseTime;
}
可以看到这是这个node所有的函数接口,pNodeCallbacks->pQueryVendorTag = MemCpyNodeQueryVendorTag;只要拿到对应的callback就可以调用到对应的接口。
CDKResult MemCpyNodeQueryVendorTag(
CHIQUERYVENDORTAG* pQueryVendorTag)
{
CDKResult result = CDKResultSuccess;
result = ChiNodeUtils::QueryVendorTag(pQueryVendorTag, g_VendorTagInfoMemCpy);
return result;
}
g_VendorTagInfoMemCpy这个变量定义的就是这个node相关的tag
GetComponentTag(pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag);
pExternalComponentInfo[index].nodeCallbacks.pQueryVendorTag这里就可以调用到上面看的那个node对应的接口。
接下来看GetComponentTag()这个接口。
void GetComponentTag(
PFNCHIQUERYVENDORTAG pfnQueryVendorTag)
{
CHIQUERYVENDORTAG queryVendorTag = {0};
queryVendorTag.size = sizeof(CHIQUERYVENDORTAG);
pfnQueryVendorTag(&queryVendorTag);//这就是node中的接口
AddComponentTag(&queryVendorTag); //这里把node获取到的tag传进去
}
CamxResult AddComponentTag(
CHIQUERYVENDORTAG* pQueryVendorTag)
{
// Append to the global vendor tag info list
UINT32 index = g_componentVendorTagsInfo.numVendorTagInfo;
g_componentVendorTagsInfo.pVendorTagInfoArray[index].numSections =
pQueryVendorTag->pVendorTagInfo->numSections;
g_componentVendorTagsInfo.pVendorTagInfoArray[index].pVendorTagDataArray =
reinterpret_cast<VendorTagSectionData *>(pQueryVendorTag->pVendorTagInfo->pVendorTagDataArray);
g_componentVendorTagsInfo.numVendorTagInfo = g_componentVendorTagsInfo.numVendorTagInfo + 1;
}
g_componentVendorTagsInfo //这个是不是很眼熟,我们最开始的目的就是为了找这个变量赋值的地方。现在终于找到咯
后面还有相关的AEC、AF、HVX这些地方去获取meta。跟这个获取node都是类似的可以追一下流程都是这种通过获取到对应的接口,然后获取到对应的tag。
到这里也可以明白为什么我们这些第三方加tag要加在chi和对应的nde里面了,这里也对高通说chi是开放给第三方的做客制化流程的节点有进一步的理解了。