本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email:gzzaigcn2012@gmail.com
Android源码版本Version:4.2.2; 硬件平台 全志A31
之所以单独把这块内容提炼出来,在于其具备的一定的层次性,结构上具备统一性,API函数的设计需要实现OMX架构独有的接口。
1. 在上一博文Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件 中我们提到,通过Binder架构,在MPS的线程上创建完一个实际的编解码器节点后,获取到了一个node:node_id。如下所示将会根据相关的节点信息,创建一个MPS侧的OMXCodec结构体,作为类似本地的一个编解码器。
.....
sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);//创建一个本地OMXCodec解码器,node成为后续的操作的关键IOMX::node_id
//omx为Master
observer->setCodec(codec);//将解码器交给observer
err = codec->configureCodec(meta);//根据数据源配置本地的这个解码器
........
在configureCodec对这个解码器的配置中,我们可以看到一些对之前分配的解码器节点的控制操作。我们以它其中的一个函数调用为例,进行控制流的层层分析:
setVideoOutputFormat(mMIME, meta);//设置视频输出格式
mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &def, sizeof(def))
这里看到mOMX是在创建AwesomePlayer时获取的一个匿名的BpOMX对象。最终的实现在MediaPlayerService中的中的OMX对象来实现getParameter。
2.OMX对象下的操作。
status_t OMX::getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
return findInstance(node)->getParameter(
index, params, size);
}
findInstance(node)这里就是根据这个node_id来获取之前注册的一个OMXNodeInstance对象实例:
OMXNodeInstance *OMX::findInstance(node_id node) {
Mutex::Autolock autoLock(mLock);
ssize_t index = mNodeIDToInstance.indexOfKey(node);
return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
}
最终就变成了如下的调用:
status_t OMXNodeInstance::setParameter(
OMX_INDEXTYPE index, const void *params, size_t size) {
Mutex::Autolock autoLock(mLock);
OMX_ERRORTYPE err = OMX_SetParameter(
mHandle, index, const_cast<void *>(params));
return StatusFromOMXError(err);
}
3.OMX_XXX的实现
#define OMX_GetParameter( \
hComponent, \
nParamIndex, \
ComponentParameterStructure) \
((OMX_COMPONENTTYPE*)hComponent)->GetParameter( \
hComponent, \
nParamIndex, \
ComponentParameterStructure) /* Macro End */
OMX_SetParameter等宏函数是OMX_CORE的核心所在,也是原来OpenOMx里的OMX IL层的体现。来看mHandle的类型,作为一个OMXNodeInstance对象的成员变量,他维护着之前makeComponentInstance返回的一个对底层编解码组件库的句柄。这里看上去就是一个OMX节点实例,一个句柄可操作最下层的解码组件。可以看到handle转为OMX_COMPONENTTYPE类型。里看看其的结构体类型:
typedef struct OMX_COMPONENTTYPE
{
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
OMX_COMPONENTNAMETYPE eCompName;
OMX_PTR pComponentPrivate;
OMX_ERRORTYPE (*GetParameter)(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nIndex,
OMX_IN OMX_PTR ComponentParameterStructure);...............
这个handle的获取是在之前创建解码器节点时完成的,通过需要创建的解码器的name,通过OMX插件库,再进入到libOmxCore.so(OMX IL固有结构)调用OMX_GetHandle来获取对应组件name下的平台解码库libOmxVdec.so,或者libOmxVenc.so等。这个handle通过以下完成初始化:
void* aw_omx_create_component_wrapper(OMX_PTR obj_ptr)
{
aw_omx_component *pThis = (aw_omx_component *)obj_ptr;//omx_vdec对象
OMX_COMPONENTTYPE* component = &(pThis->m_cmp);//对m_cmp进行初始化
memset(&pThis->m_cmp,0,sizeof(OMX_COMPONENTTYPE));
component->nSize = sizeof(OMX_COMPONENTTYPE);
component->nVersion.nVersion = OMX_SPEC_VERSION;
component->pApplicationPrivate = 0;
component->pComponentPrivate = obj_ptr;//保存着omx_vdec这个对象
component->AllocateBuffer = &aw_omx_component_allocate_buffer;
component->FreeBuffer = &aw_omx_component_free_buffer;
component->GetParameter = &aw_omx_component_get_parameter;
component->SetParameter = &aw_omx_component_set_parameter;
component->SendCommand = &aw_omx_component_send_command;
component->FillThisBuffer = &aw_omx_component_fill_this_buffer;
component->EmptyThisBuffer = &aw_omx_component_empty_this_buffer;
component->GetState = &aw_omx_component_get_state;
component->GetComponentVersion = &aw_omx_component_get_version;
component->GetConfig = &aw_omx_component_get_config;
component->SetConfig = &aw_omx_component_set_config;
component->GetExtensionIndex = &aw_omx_component_get_extension_index;
component->ComponentTunnelRequest = &aw_omx_component_tunnel_request;
component->UseBuffer = &aw_omx_component_use_buffer;
component->SetCallbacks = &aw_omx_component_set_callbacks;
component->UseEGLImage = &aw_omx_component_use_EGL_image;
component->ComponentRoleEnum = &aw_omx_component_role_enum;
component->ComponentDeInit = &aw_omx_component_deinit;
return (void *)component;
}
通过以上的赋值操作,我们关注这个component->pComponentPrivate = obj_ptr,他是将硬件平台的解码器实例维护到handle结构体中,因为最终的操作肯定都要回到最底层的解码器控制。这也就是OMX IL的架构给予了开发者的方便性和规划化。通过这个我们就可以总结出需要以下几个文件来衔接更底层的编解码器:
xxx_omx_core.c和omx_core_cmp.c两个源文件来完成。前者提供向上的接口用于创建编解码器实例,后者提供例如上述的xxx_omx_component_api接口的实现,而实际其实现是调用的是编解码的相关API来处理:
OMX_ERRORTYPE aw_omx_component_get_parameter(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE paramIndex,
OMX_INOUT OMX_PTR paramData)
{
OMX_ERRORTYPE eRet = OMX_ErrorBadParameter;
aw_omx_component *pThis = (hComp)? (aw_omx_component *)(((OMX_COMPONENTTYPE *)hComp)->pComponentPrivate):NULL;
DEBUG_PRINT("OMXCORE: aw_omx_component_get_parameter %x, %x , %d\n",(unsigned)hComp,(unsigned)paramData,paramIndex);
if(pThis)
{
eRet = pThis->get_parameter(hComp,paramIndex,paramData);
}
return eRet;
}
这里的pThis技术当前最底层的解码器组件的控制入口。即所谓的aw_omx_component的派生类对象。这样也就是说明了我们自己要构建的编解码需要实aw_omx_component的相关接口函数,可以看到这里我们最底层的解码器组件就是对这些函数的实现,加快了自定义一个新的组件类型,以下是几个接口的定义和实现:
OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_INDEXTYPE paramIndex, OMX_IN OMX_PTR paramData)
OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_INDEXTYPE paramIndex,
OMX_INOUT OMX_PTR paramData)
到这里我们基本走通了从OMXCodec到对最底层的编解码器组件的控制,层次分明,接口规范带给我们的是快速开发,我们需要做的核心是在自己的编解码器组件中实现相关的业务,而这和自身的硬件平台具有紧密性。
4.总结新建一个属于stagefright下OMX的编解码组件需要做的事情
我们所要做的核心工作就在libOmxCore.so和libOmxVdec.so这两个库文件的设计。但都需要符合OMX的协议即可。
分析了那么多的控制流,也已经有了所谓的OMXCodec,那么后续主要内容将是数据流的处理。