1. Create a new UUID
In ANDROID_DIR/external/opencore/codecs_v2/omx/omx_common/include/pv_omxcore.h
#if USE_DYNAMIC_LOAD_OMX_COMPONENTS
#define PV_OMX_MP3DEC_UUID OsclUuid(0x1d4769f0,0xca0c,0x11dc,0x95,0xff,0x08,0x00,0x20,0x0c,0x9a,0x
70)
#define PV_OMX_AACENC_UUID OsclUuid(0x1d4769f0,0xca0c,0x11dc,0x95,0xff,0x08,0x00,0x20,0x0c,0x9a,0x76)
2. Add in your decoder library and interface head file
In fold ANDROID_DIR/external/opencore/codecs_v2/, create a new directory and put your decoder files in. Here we take the mp3 decoder as an example.The mp3 decoder is put in the fold audio/mp3/dec/ and the head file will be used by us are:(you can get this in Android.mk)
LOCAL_COPY_HEADERS := \
include/pvmp3_decoder.h \
include/pvmp3decoder_api.h \
include/pvmp3_audio_type_defs.h
The decoder library will be compiled to be a static library named libpvmp3.a
3. Intergrate the decoder library into openmax in opencore
Create a new directory in codecs_v2/omx. Here we take the mp3 decoder as an example. The mp3 omx component is placed in the fold omx/omx_mp3/. From the Android.mk file you can know the most imp
ortant files are:
LOCAL_SRC_FILES := \
src/mp3_dec.cpp \
src/omx_mp3_component.cpp \
src/mp3_timestamp.cpp
LOCAL_COPY_HEADERS := \
include/mp3_dec.h \
include/omx_mp3_component.h \
include/mp3_timestamp.h
We can get a snap from the head files. In the file mp3_dec.h, a new class named Mp3Decoder will be created to use the mp3 decoder.
CPvMP3_Decoder* iAudioMp3Decoder; // defined in pvmp3_decoder.h
tPVMP3DecoderExternal* iMP3DecExt; //defined in pvmp3decoder_api.h
Some import interfaces will be created here:
Mp3Decoder();
OMX_BOOL Mp3DecInit(OMX_AUDIO_CONFIG_EQUALIZERTYPE* aEqualizerType);
void Mp3DecDeinit();
Int Mp3DecodeAudio(OMX_S16* aOutBuff,
OMX_U32* aOutputLength, OMX_U8** aInputBuf,
OMX_U32* aInBufSize,
OMX_S32* aFrameCount,
OMX_AUDIO_PARAM_PCMMODETYPE* aAudioPcmParam,
OMX_AUDIO_PARAM_MP3TYPE* aAudioMp3Param,
OMX_BOOL aMarkerFlag,
OMX_BOOL* aResizeFlag);
void ResetDecoder(); // for repositioning
If your decoder is an audio decoder you should create a class which inherits from OmxComponentAudio. If your decoder is a video decoder you should create a class which inherits from OmxComponentVideo.
The OmxComponetAudio class:
class OmxComponentAudio : public OmxComponentBase
{
public:
OmxComponentAudio();
virtual ~OmxComponentAudio() {}
OMX_ERRORTYPE GetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_INOUT OMX_PTR ComponentParameterStructure);
OMX_ERRORTYPE SetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_IN OMX_PTR ComponentParameterStructure);
virtual void UpdateAACPlusFlag(OMX_BOOL aAacPlusFlag)
{
OSCL_UNUSED_ARG(aAacPlusFlag);
}
};
The OmxComponentVideo class:
class OmxComponentVideo : public OmxComponentBase
{
public:
OmxComponentVideo();
virtual ~OmxComponentVideo() {}
OMX_ERRORTYPE GetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_INOUT OMX_PTR ComponentParameterStructure);
OMX_ERRORTYPE SetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_IN OMX_PTR ComponentParameterStructure);
};
In the base class OmxComponentBase you can see there are 5 pure virtual interfaces:
virtual OMX_ERRORTYPE GetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_INOUT OMX_PTR ComponentParameterStructure) = 0;
virtual OMX_ERRORTYPE SetParameter(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nParamIndex,
OMX_IN OMX_PTR ComponentParameterStructure) = 0;
virtual void ProcessData() = 0;
virtual OMX_ERRORTYPE ComponentInit() = 0;
virtual OMX_ERRORTYPE ComponentDeInit() = 0;
So these interfaces must have a definition in derived components. The first two will be derived in OmxComponent Audio and OmxComponentVideo. So our component must define the left 3 functions.
And here in our mp3 componet(named OpenmaxMp3AO in the file omx_mp3_component.h)
OpenmaxMp3AO();
~OpenmaxMp3AO();
OMX_ERRORTYPE ConstructComponent(OMX_PTR pAppData, OMX_PTR pProxy);
OMX_ERRORTYPE DestroyComponent();
OMX_ERRORTYPE ComponentInit();
OMX_ERRORTYPE ComponentDeInit();
static void ComponentGetRolesOfComponent(OMX_STRING* aRoleString);
void ProcessData();
void SyncWithInputTimestamp();
void ProcessInBufferFlag();
void ResetComponent();
OMX_ERRORTYPE GetConfig(
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_INDEXTYPE nIndex,
OMX_INOUT OMX_PTR pComponentConfigStructure);
And we will use the Mp3Decoder to implement the component OpenmaxMp3AO
Mp3Decoder* ipMp3Dec;
Sometimes we need a timestamp
Mp3TimeStampCalc iCurrentFrameTS;
In omx_mp3_component.cpp we can know the Mp3OmxSharedLibraryInterface will be implemented as a singleton because we need mp3 deocoder at time. And here the UUID will be used to judge whether this library is the right.
OsclAny *QueryOmxComponentInterface(const OsclUuid& aOmxTypeId, const OsclUuid& aInterfaceId)
{
if (PV_OMX_MP3DEC_UUID == aOmxTypeId)
{
if (PV_OMX_CREATE_INTERFACE == aInterfaceId)
{
return ((OsclAny*)(&Mp3OmxComponentFactory));
}
else if (PV_OMX_DESTROY_INTERFACE == aInterfaceId)
{
return ((OsclAny*)(&Mp3OmxComponentDestructor));
}
}
return NULL;
};
OsclAny *SharedLibraryLookup(const OsclUuid& aInterfaceId)
{
if (aInterfaceId == PV_OMX_SHARED_INTERFACE)
{
return OSCL_STATIC_CAST(OmxSharedLibraryInterface*, this);
}
return NULL;
};
Finally after we finished all the source code we will get a new component library,here the mp3 component will be compiled to be library named libomx_mp3_component_lib.so
4. Compile the two libs to be the shared lib
In build_config/opencore_dynamic/Android_omx_mp3dec_sharedlibrary.mk, we will compile the mp3 decoder lib and the mp3 component lib to libomx_mp3dec_sharedlibrary.so
LOCAL_WHOLE_STATIC_LIBRARIES := \
libomx_mp3_component_lib \
libpvmp3
LOCAL_MODULE := libomx_mp3dec_sharedlibrary
…..
include $(PV_TOP)/codecs_v2/omx/omx_mp3/Android.mk
include $(PV_TOP)/codecs_v2/audio/mp3/dec/Android.mk
5. Regist the shared lib in soure code
In codecs_v2/omx/omx_common/src/pv_omxregistry.cpp
#if (REGISTER_OMX_MP3_COMPONENT) || (USE_DYNAMIC_LOAD_OMX_COMPONENTS)
/////////////////////////////////////////////////////////////////////////////
OMX_ERRORTYPE Mp3Register()
{
….
pCRT->SharedLibraryName = (OMX_STRING)”libomx_mp3dec_sharedlibrary.so”;
….
OSCL_PLACEMENT_NEW(temp, PV_OMX_MP3DEC_UUID);
And this function Mp3Register will be called in omx_common/src/pv_omxcore.cpp
OSCL_EXPORT_REF OMX_ERRORTYPE OMX_Init()
{
…
if (status == OMX_ErrorNone)
{
_Try_OMX_Init(error, status);
…
}
…
}
static void _Try_OMX_Init(int32& aError, OMX_ERRORTYPE& aStatus)
{
OSCL_TRY(aError, aStatus = _OMX_Init(););
}
tatic OMX_ERRORTYPE _OMX_Init()
{
….
Status = Mp3Register();
…
}
6. At last we need to finish the PVOMXInterface in pv_omx_interface.cpp
Because the PV OpenCORE framework is utilizing dynamic loading and linking to handle
potentially multiple OMX cores simultaneously, the OMX core libraries must be built as shared
objects .
There are currently two different build methods to include the PV OMX core wrapper into the final
shared object library (.so):
6.1 If your opencore shared library and the opencore wrapper library are build seperately:
we need to modify the file omx_core_plugins/template/src/pv_omx_interface.cpp.
#define OMX_CORE_LIBRARY “libOmxCore.so” →
needs to be substituted with the following line that contains the name of the pre-built shared
library that contains OMX core methods (but does not contain OMX core wrapper):
#define OMX_CORE_LIBRAY “ “lib_prebuilt_omxcore_no_wrapper.so”
As part of dynamic loading process, the OMX core wrapper for this case must open “lib_prebuilt
omxcore_no_wrapper.so” library and link to the OMX core methods in this library explicitly (using
dlopen & dlsym calls).
In pv_omx_interface.cpp:
pOMX_Init = (tpOMX_Init)dlsym(ipHandle, “OMX_Init”);
…
The provider of the final OMX core library must ensure that makefiles that create the final OMX
library (“lib_omxcore_plus_wrapper.so”) include the OMX core library wrapper as well. The
purpose of OMX core library wrapper is to provide the PV OpenCORE framework with common
APIs to dynamically load and communicate with OMX core plugins.
6.2 OMX core methods and the OMX core wrapper interface can be built simultaneously:
The code for the OMX core wrapper interface for this case is provided in: …/codecs_v2/omx/omx_sharedlibrary/interface/src
This code needs to be copied to an appropriate place in the directory structure of vendor’s code
that will enable the creation of “lib_omxcore_and_simultaneous_wrapper.so”
In pv_omx_interface.cpp:
pOMX_Init = OMX_Init;
Aw, this was a very good post. Taking the time and actual effort
to create a superb article… but what can I say… I put
things off a whole lot and never seem to get nearly anything
done.