在《Android开发OpenMAX接口规范》一文中,我们了解到OpenMAX IL集成层的重要性。OpenMAX IL(Integration Layer)作为在嵌入式和移动设备中使用的音频、视频、图像等编解码器的底层接口,使得应用和多媒体框架可以以统一的方式访问多媒体编解码器和支持组件,这就使得OpenMAX拥有跨平台的能力。在OpenMAX IL的接口规范中,有些接口是厂商必须提供的,必须提供的方法如下:
1)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void);
2)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void);
3)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(…);
4)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(…);
5)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(...);
6)OMX_API OMX_ERRORTYPE OMX_GetRolesOfComponent (…);
7)OMX_API OMX_ERRORTYPE OMX_GetComponentsOfRole (…);
8)OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(…);
9)OMX_API OMX_ERRORTYPE OMX_GetContentPipe(…);
除以上方法必须实现外,为了使OpenCORE能够获悉OpenMAX Core的配置信息,OMXConfigParser()被强烈推荐实现。OMXConfigParser()的定义位于pv_omx_config_parser.h文件中。
在OpenCORE中,关于OpenMAX Core的实现位于pv_omxcore.cpp文件中。考虑在实际开发中,可能存在由多个厂商开发的OpenMAX Core实现的可能,为了避免造成静态编译时的链接问题,厂商在实现OpenMAX Core时,应考虑增加一个简单的封装层。以封装OpenMAX Core的标准接口。如在OpenCORE中,OMX_Init()接口的实现为:
OSCL_EXPORT_REF OMX_ERRORTYPE OMX_MasterInit()
{
return OMX_Init(); // OMX_Init()的具体实现位于同文件中
}
在OpenCORE中,为上层提供的封装接口为OMXInterface。由于采用的是动态加载的方法,考虑到可能存在多家厂商的OpenMAX Core情况,OpenMAX Core必须以动态库的方式出现。在OpenCORE中,提供了两种编译模式。
一种编译模式是封装器和OpenMAX Core共享库分别编译。在OpenMAX Core动态库中并不包含封装器。该编译模式的实现位于OpenCORE\codecs_v2\omx\ omx_core_ plugins\template\src\pv_omx_interface.cpp中。在PVOMXInterface类的构造函数中,利用dlopen()函数以RTLD_NOW模式打开OpenMAX Core共享库。为OpenMAX IL接口利用dlsym()函数查找对应的符号进行赋值。具体实现为:
代码:封装器和共享库分别编译
#ifndef OMX_CORE_LIBRARY
#define OMX_CORE_LIBRARY "libOmxCore.so"
#endif
class PVOMXInterface : public OMXInterface
{
public:
……
private:
PVOMXInterface()
{
ipHandle=dlopen(OMX_CORE_LIBRARY, RTLD_NOW);//打开共享库
if (NULL==ipHandle)
{
pOMX_Init=NULL;
pOMX_Deinit=NULL;
pOMX_ComponentNameEnum=NULL;
pOMX_GetHandle=NULL;
pOMX_FreeHandle=NULL;
pOMX_GetComponentsOfRole=NULL;
pOMX_GetRolesOfComponent=NULL;
pOMX_SetupTunnel=NULL;
pOMX_GetContentPipe=NULL;
pOMXConfigParser=NULL;
const char* pErr=dlerror();
if (NULL==pErr)
{
……
}
else
{
……
}
}
else
{
//加载OMX core符号
pOMX_Init=(tpOMX_Init)dlsym(ipHandle, "OMX_Init");
pOMX_Deinit=(tpOMX_Deinit)dlsym(ipHandle, "OMX_Deinit");
pOMX_ComponentNameEnum=(tpOMX_ComponentNameEnum)dlsym(ipHandle,
"OMX_ComponentNameEnum");
pOMX_GetHandle=(tpOMX_GetHandle)dlsym(ipHandle, "OMX_GetHandle");
pOMX_FreeHandle=(tpOMX_FreeHandle)dlsym(ipHandle, "OMX_FreeHandle");
pOMX_GetComponentsOfRole=(tpOMX_GetComponentsOfRole)dlsym(ipHandle,
"OMX_GetComponentsOfRole");
pOMX_GetRolesOfComponent=(tpOMX_GetRolesOfComponent)dlsym(ipHandle,
"OMX_GetRolesOfComponent");
pOMX_SetupTunnel=(tpOMX_SetupTunnel)dlsym(ipHandle, "OMX_SetupTunnel");
pOMX_GetContentPipe=(tpOMX_GetContentPipe)dlsym(ipHandle,"OMX_GetContentPipe");
pOMXConfigParser=(tpOMXConfigParser)dlsym(ipHandle, "OMXConfigParser");
}
};
}
另一种编译模式是封装器和OpenMAX Core共享库同时编译。在OpenMAX Core动态库中包含封装器。该编译模式的实现位于OpenCORE\codecs_v2\omx\ omx_ sharedlibrary\interface\src\ pv_omx_interface.cpp中。在该编译模式下,只能同时编译一个OpenMAX Core动态库。具体实现为:
代码:封装器和共享库同时编译
class PVOMXInterface : public OMXInterface
{
public:
……
private:
PVOMXInterface()
{
//直接赋值
pOMX_Init=OMX_Init;
pOMX_Deinit=OMX_Deinit;
pOMX_ComponentNameEnum=OMX_ComponentNameEnum;
pOMX_GetHandle=OMX_GetHandle;
pOMX_FreeHandle=OMX_FreeHandle;
pOMX_GetComponentsOfRole=OMX_GetComponentsOfRole;
pOMX_GetRolesOfComponent=OMX_GetRolesOfComponent;
pOMX_SetupTunnel=OMX_SetupTunnel;
pOMX_GetContentPipe=OMX_GetContentPipe;
pOMXConfigParser=OMXConfigParser;
};
};
需要注意的是,不管是何种编译模式,实现上均采用了单子模式(Singleton Pattern)的设计方法。在运行期间,PVOMXInterface仅有唯一对象出现。
为了使集成的编解码器能够在系统中运行,必须对编解码器进行注册,在OpenCORE中,已经提供了AVC、M4V(Apple公司开发)、H.263、WMA、AAC、AMR、MP3、WMA、RV、RA等格式的解码器,提供了AVC、M4V、H.263、AMR、AAC等格式的编码器。在OpenMAX IL层中,编解码器均是在Open Core的OMX_Init()函数中进行注册的,该函数的实现位于external\opencore\codecs_v2\omx\omx_common\src\pv_omxcore.cpp文件中,而编解码器的注册函数则位于external\opencore\codecs_v2\omx\omx_common\src\ pv_omxregistry.cpp文件中。编解码器注册的信息位于ComponentRegistrationType的对象中,ComponentRegistrationType的定义如下:
代码:ComponentRegistrationType
class ComponentRegistrationType
{
public:
OMX_STRING ComponentName; //组件名
OMX_STRING RoleString[MAX_ROLES_SUPPORTED];
OMX_U32 NumberOfRolesSupported; //角色数量
OMX_ERRORTYPE(*FunctionPtrCreateComponent)(OMX_OUT OMX_HANDLETYPE* pHandle,OMX_IN OMX_PTR pAppData,OMX_PTR pProxy,OMX_STRING aOmxLibName,OMX_PTR &aOmxLib, OMX_PTR aOsclUuid,OMX_U32 &aRefCount);//创建组件
OMX_ERRORTYPE(*FunctionPtrDestroyComponent)(OMX_IN OMX_HANDLETYPE pHandle,OMX_PTR &aOmxLib, OMX_PTR aOsclUuid, OMX_U32 &aRefCount);//销毁组件
void GetRolesOfComponent(OMX_STRING* aRole_string)
{
for (OMX_U32 ii=0; ii< NumberOfRolesSupported; ii++)
{
aRole_string[ii]=RoleString[ii];
}
}
//用于动态加载
OMX_STRING SharedLibraryName; //共享库名
OMX_PTR SharedLibraryPtr; //共享库指针
OMX_PTR SharedLibraryOsclUuid; //共享库UUID
OMX_U32 SharedLibraryRefCounter; //共享库引用计数
};
为了进行注册,首先需要创建一个ComponentRegistrationType对象,对其成员进行赋值,然后将其添加到OMXGlobalDatad的ipRegTemplateList[MAX_SUPPORTED_COMPONENTS]成员中。需要说明的是,在组件库中的每个组件均有唯一的一个UUID来标识,以MP3解码器为例的注册过程如下:
代码:MP3Register
OMX_ERRORTYPE Mp3Register(OMXGlobalData *data)
{
OMX_S32 ii;
ComponentRegistrationType *pCRT=(ComponentRegistrationType *) oscl_malloc(sizeof (ComponentRegistrationType));
if (pCRT)
{
pCRT->ComponentName=(OMX_STRING)"OMX.PV.mp3dec"; //组件名
pCRT->RoleString[0]=(OMX_STRING)"audio_decoder.mp3"; //角色名
pCRT->NumberOfRolesSupported=1; //角色数量
pCRT->SharedLibraryOsclUuid=NULL;
#if USE_DYNAMIC_LOAD_OMX_COMPONENTS
//构造组件
pCRT->FunctionPtrCreateComponent=&OmxComponentFactoryDynamicCreate;
//析构组件
pCRT->FunctionPtrDestroyComponent=&OmxComponentFactoryDynamicDestructor;
//共享库名
pCRT->SharedLibraryName=(OMX_STRING)"libomx_mp3dec_sharedlibrary";
pCRT->SharedLibraryPtr=NULL;
//UUID
OsclUuid *temp=(OsclUuid *) oscl_malloc(sizeof(OsclUuid));
if (temp==NULL)
{
//释放已分配内存
oscl_free(pCRT);
return OMX_ErrorInsufficientResources;
}
OSCL_PLACEMENT_NEW(temp, PV_OMX_MP3DEC_UUID);
pCRT->SharedLibraryOsclUuid=(OMX_PTR) temp;
pCRT->SharedLibraryRefCounter=0;
#endif
#if REGISTER_OMX_MP3_COMPONENT
#if (DYNAMIC_LOAD_OMX_MP3_COMPONENT==0)
pCRT->FunctionPtrCreateComponent=&Mp3OmxComponentFactory;
pCRT->FunctionPtrDestroyComponent=&Mp3OmxComponentDestructor;
pCRT->SharedLibraryName=NULL;
pCRT->SharedLibraryPtr=NULL;
if (pCRT->SharedLibraryOsclUuid)oscl_free(pCRT->SharedLibraryOsclUuid);
pCRT->SharedLibraryOsclUuid=NULL;
pCRT->SharedLibraryRefCounter=0;
#endif
#endif
}
else
{
return OMX_ErrorInsufficientResources;
}
for (ii=0; ii< MAX_SUPPORTED_COMPONENTS; ii++) //注册组件
{
if (NULL==data->ipRegTemplateList[ii])
{
data->ipRegTemplateList[ii]=pCRT;
break;
}
}
if (MAX_SUPPORTED_COMPONENTS==ii)
{
return OMX_ErrorInsufficientResources;
}
return OMX_ErrorNone;
}
每一个编解码器在OpenMAX中都对应唯一的一个 UUID标识符。这些UUID标识符定义位于pv_omxcore.h文件中。