在《Android開發(fā)OpenMAX接口規(guī)范》一文中,我們了解到OpenMAX IL集成層的重要性。OpenMAX IL(Integration Layer)作為在嵌入式和移動設(shè)備中使用的音頻、視頻、圖像等編解碼器的底層接口,使得應(yīng)用和多媒體框架可以以統(tǒng)一的方式訪問多媒體編解碼器和支持組件,這就使得OpenMAX擁有跨平臺的能力。在OpenMAX IL的接口規(guī)范中,有些接口是廠商必須提供的,必須提供的方法如下:
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(…);
除以上方法必須實現(xiàn)外,為了使OpenCORE能夠獲悉OpenMAX Core的配置信息,OMXConfigParser()被強(qiáng)烈推薦實現(xiàn)。OMXConfigParser()的定義位于pv_omx_config_parser.h文件中。
在OpenCORE中,關(guān)于OpenMAX Core的實現(xiàn)位于pv_omxcore.cpp文件中?紤]在實際開發(fā)中,可能存在由多個廠商開發(fā)的OpenMAX Core實現(xiàn)的可能,為了避免造成靜態(tài)編譯時的鏈接問題,廠商在實現(xiàn)OpenMAX Core時,應(yīng)考慮增加一個簡單的封裝層。以封裝OpenMAX Core的標(biāo)準(zhǔn)接口。如在OpenCORE中,OMX_Init()接口的實現(xiàn)為:
OSCL_EXPORT_REF OMX_ERRORTYPE OMX_MasterInit()
{
return OMX_Init(); // OMX_Init()的具體實現(xiàn)位于同文件中
}
在OpenCORE中,為上層提供的封裝接口為OMXInterface。由于采用的是動態(tài)加載的方法,考慮到可能存在多家廠商的OpenMAX Core情況,OpenMAX Core必須以動態(tài)庫的方式出現(xiàn)。在OpenCORE中,提供了兩種編譯模式。
一種編譯模式是封裝器和OpenMAX Core共享庫分別編譯。在OpenMAX Core動態(tài)庫中并不包含封裝器。該編譯模式的實現(xiàn)位于OpenCORE\codecs_v2\omx\ omx_core_ plugins\template\src\pv_omx_interface.cpp中。在PVOMXInterface類的構(gòu)造函數(shù)中,利用dlopen()函數(shù)以RTLD_NOW模式打開OpenMAX Core共享庫。為OpenMAX IL接口利用dlsym()函數(shù)查找對應(yīng)的符號進(jìn)行賦值。具體實現(xiàn)為:
代碼:封裝器和共享庫分別編譯
#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動態(tài)庫中包含封裝器。該編譯模式的實現(xiàn)位于OpenCORE\codecs_v2\omx\ omx_ sharedlibrary\interface\src\ pv_omx_interface.cpp中。在該編譯模式下,只能同時編譯一個OpenMAX Core動態(tài)庫。具體實現(xiàn)為:
代碼:封裝器和共享庫同時編譯
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;
};
};
需要注意的是,不管是何種編譯模式,實現(xiàn)上均采用了單子模式(Singleton Pattern)的設(shè)計方法。在運行期間,PVOMXInterface僅有唯一對象出現(xiàn)。
為了使集成的編解碼器能夠在系統(tǒng)中運行,必須對編解碼器進(jìn)行注冊,在OpenCORE中,已經(jīng)提供了AVC、M4V(Apple公司開發(fā))、H.263、WMA、AAC、AMR、MP3、WMA、RV、RA等格式的解碼器,提供了AVC、M4V、H.263、AMR、AAC等格式的編碼器。在OpenMAX IL層中,編解碼器均是在Open Core的OMX_Init()函數(shù)中進(jìn)行注冊的,該函數(shù)的實現(xiàn)位于external\opencore\codecs_v2\omx\omx_common\src\pv_omxcore.cpp文件中,而編解碼器的注冊函數(shù)則位于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; //角色數(shù)量
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);//創(chuàng)建組件
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];
}
}
//用于動態(tài)加載
OMX_STRING SharedLibraryName; //共享庫名
OMX_PTR SharedLibraryPtr; //共享庫指針
OMX_PTR SharedLibraryOsclUuid; //共享庫UUID
OMX_U32 SharedLibraryRefCounter; //共享庫引用計數(shù)
};
為了進(jìn)行注冊,首先需要創(chuàng)建一個ComponentRegistrationType對象,對其成員進(jìn)行賦值,然后將其添加到OMXGlobalDatad的ipRegTemplateList[MAX_SUPPORTED_COMPONENTS]成員中。需要說明的是,在組件庫中的每個組件均有唯一的一個UUID來標(biāo)識,以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; //角色數(shù)量
pCRT->SharedLibraryOsclUuid=NULL;
#if USE_DYNAMIC_LOAD_OMX_COMPONENTS
//構(gòu)造組件
pCRT->FunctionPtrCreateComponent=&OmxComponentFactoryDynamicCreate;
//析構(gòu)組件
pCRT->FunctionPtrDestroyComponent=&OmxComponentFactoryDynamicDestructor;
//共享庫名
pCRT->SharedLibraryName=(OMX_STRING)"libomx_mp3dec_sharedlibrary";
pCRT->SharedLibraryPtr=NULL;
//UUID
OsclUuid *temp=(OsclUuid *) oscl_malloc(sizeof(OsclUuid));
if (temp==NULL)
{
//釋放已分配內(nèi)存
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中都對應(yīng)唯一的一個 UUID標(biāo)識符。這些UUID標(biāo)識符定義位于pv_omxcore.h文件中。