在 android 4.0.3 SF和Openmax关系
awesomplayer.cpp 中 awesomeplay有一个成员 OMXClient mClient;
这个mClient是通过MediaPlayerService的getOmx()方法创建(new OMX),代码如下
sp<IOMX> MediaPlayerService::getOMX() {
Mutex::Autolock autoLock(mLock);
if (mOMX.get() == NULL) {
mOMX = new OMX;
}
return mOMX;
}
可以跟综OMX.cpp这个文件,查看创建过程
OMX::OMX()
: mMaster(new OMXMaster),
mNodeCounter(0) {
}
mNodeCounter:omxnode 计数器,在OmxCodec.cpp中返回nodeid
mMaster 这个对象是omx核心 可以理解为服务器端,之后在Omxcodec.cpp中create时传入的mOmx是mclient,它的所有调用都会通过IOMX.cpp转到Omx.cpp中。
下面我们来重点分析一下 OMXMaster
OMXMaster::OMXMaster()
: mVendorLibHandle(NULL) {
addVendorPlugin();
addPlugin(new SoftOMXPlugin);
}
通过addPlugin添加openmax外挂的插件,可以拿 addPlugin(new SoftOMXPlugin)为例,在SoftOMXPlugin插件中包含了支持的所有解码器组件,在我们的系统中支持的解码组件如下:
static const struct {
const char *mName;
const char *mLibNameSuffix;
const char *mRole;
} kComponents[] = {
{ "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
{ "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
{ "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
{ "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
{ "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
{ "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
{ "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" },
{ "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },
{ "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },
{ "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },
{ "OMX.google.vpx.decoder", "vpxdec", "video_decoder.vpx" },
};
addPlugin(softomxplugin)时,会把调用SoftOmXPlugin的enumerateComponents,依次把上面这些组件添加到OMXMaster 的mPluginByComponentName中。
在omxcodec.cpp中创建组件时:
status_t err = omx->allocateNode(componentName, observer, &node);
会依次根据componentName,通过iomx.cpp(ibinder)->omx.cpp->OMXMaster.cpp中的makeComponentInstance
OMXMaster的makeComponentInstance会根据componentName名字查找到具体插件,比如componentName是OMX.google.vorbis.decoder,则会找到SoftOMXPlugin插件(vorbis这个组件包含在SoftOMXPlugin插件中,从上数据可以看出来),然后要据componentname调用插件SoftOMXPlugin->makeComponentInstance的方法,生成真正的组件(对应的解码器)。代码如下
OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
LOGV("makeComponentInstance '%s'", name);
for (size_t i = 0; i < kNumComponents; ++i) {
if (strcmp(name, kComponents[i].mName)) {
continue;
}
AString libName = "libstagefright_soft_";
libName.append(kComponents[i].mLibNameSuffix);
libName.append(".so");
void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
if (libHandle == NULL) {
LOGE("unable to dlopen %s", libName.c_str());
return OMX_ErrorComponentNotFound;
}
typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
const char *, const OMX_CALLBACKTYPE *,
OMX_PTR, OMX_COMPONENTTYPE **);
CreateSoftOMXComponentFunc createSoftOMXComponent =
(CreateSoftOMXComponentFunc)dlsym(
libHandle,
"_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
"PvPP17OMX_COMPONENTTYPE");
if (createSoftOMXComponent == NULL) {
dlclose(libHandle);
libHandle = NULL;
return OMX_ErrorComponentNotFound;
}
sp<SoftOMXComponent> codec =
(*createSoftOMXComponent)(name, callbacks, appData, component);
if (codec == NULL) {
dlclose(libHandle);
libHandle = NULL;
return OMX_ErrorInsufficientResources;
}
OMX_ERRORTYPE err = codec->initCheck();
if (err != OMX_ErrorNone) {
dlclose(libHandle);
libHandle = NULL;
return err;
}
codec->incStrong(this);
codec->setLibHandle(libHandle);
return OMX_ErrorNone;
}
return OMX_ErrorInvalidComponentName;
}
从上面代码可以看出来,SoftOMXPlugin->makeComponentInstance会根据传过来组件的名字,寻找对应的
libstagefright_soft_vorbisdec.so库,然后加载库中的CreateSoftOMXComponentFunc函数,然后调用它,来创建真正的解码器。由此可以看出,libstagefright_soft_vorbisdec.so这个库就是对应一个解码器组件。根据lcomponentname的不同加载不同的库,创建不同的解码器。好了,到现在为止大家对4.0.3中使用openmax有个大概了解。
下面强调几点
1:libstagefright_soft_vorbisdec.so 对应的解码器组件,要有标准接口。set/getparameter,set/getconfig等openmax标准接口
2:本文中说的组件和插件稍有不同,读者自已分析一下。组件可以认为涉及低层了 属于openmax的DL而之上的插件属于IL,可以这样理解,不知道对不对。
3:以ogg的setparameter为例,明确调用流程
omx.cpp(ibinder)->omx.cpp->OMXMaster.cpp->OMXNodeInstance.cpp->omx_core.h(setparameter)->具体组件的setparameter( SoftVorbis::internalSetParameter)
下面简述一下softvorbis解码器创建流程。
awesomplayer.cpp initAudioDecoder()->omxcodec:create()它会在这里调用
status_t err = omx->allocateNode(componentName, observer, &node);
if (err == OK) {
LOGV("Successfully allocated OMX node '%s'", componentName);
sp<OMXCodec> codec = new OMXCodec(
omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);
之后返回codec,至此codec创建完成。
awesomplayer.cpp得到的codec 赋值给mAudioSource.
mAudioSource = OMXCodec::Create(//此处将mAudioTrack传给codec,mAudioTrack相当于文件数据,mClient相当于OMX bp接口。
mClient.interface(), mAudioTrack->getFormat(),
false, // createEncoder
mAudioTrack);
之后awesomplayer.cpp接到收的start,read/pause等,都会转化为mAudioSource的start,read,等。
mAudioSource的read相当于读取解码器的数据,然后送给mAudioPlayer。
mAudioPlayer将pcm->HAL(Audioflinger)->alsa->kernel.
采用openmax形式的 和 SF原来不使用openmax方式类似 不采用openmax时,mAudioSource返回的直接就是解码器对应的类。