OMX Codec是stagefrightplayer中负责解码的模块。 由于遵循openmax接口规范,因此结构稍微有点负责,这里就依照awesomeplayer中的调用顺序来介绍。 主要分如下几步: 1 mClient->connect 2 InitAudioDecoder & InitVideoDecoder 3 消息通信机制模型的介绍 4 解码过程介绍 先看下类图 这里OMX Codec是以service的方式提供服务的。Awesomeplayer中通过mOmx(IOMX) 作为客户端通过binder方式与OMX 通信完成解码的工作 下面一句具体代码分析 1 mClient->connect
在awesomeplayer的构造函数中调用,具体代码如下 [html] view plaincopy
- AwesomePlayer::AwesomePlayer()
- {
- ******
- CHECK_EQ(mClient.connect(), (status_t)OK);
- ******
- }
看下具体实现 [html] view plaincopy
- status_t OMXClient::connect() {
- sp<</span>IServiceManager> sm = defaultServiceManager();
- sp<</span>IBinder> binder = sm->getService(String16("media.player"));
- sp<</span>IMediaPlayerService> service = interface_cast<</span>IMediaPlayerService>(binder);
-
- CHECK(service.get() != NULL);
-
- mOMX = service->getOMX();
- CHECK(mOMX.get() != NULL);
-
- if (!mOMX->livesLocally(NULL , getpid())) {
- ALOGI("Using client-side OMX mux.");
- mOMX = new MuxOMX(mOMX);
- }
-
- return OK;
- }
这里主要就是通过binder机制与mediaplayerservice通信来完成,具体实现看mediaplayerservice [html] view plaincopy
- sp<</span>IOMX> MediaPlayerService::getOMX() {
- Mutex::Autolock autoLock(mLock);
- if (mOMX.get() == NULL) {
- mOMX = new OMX;
- }
- return mOMX;
- }
主要就是构造一个OMX对象返回给上层保存在mClient的IOMX对象mOmx中 看下构造函数都做了啥 [html] view plaincopy
- OMX::OMX()
- : mMaster(new OMXMaster),
- mNodeCounter(0) {
- }
在构造函数中又调用了OMXMaster的构造函数,代码如下 [html] view plaincopy
- OMXMaster::OMXMaster()
- : mVendorLibHandle(NULL) {
- addVendorPlugin();
- addPlugin(new SoftOMXPlugin);
- }
这里OMXMaster可以看成是解码器的入口,通过makeComponentInstance建立解码器的实例,之后就可以进行解码操作了。 这里我们以软件解码器插件为例来看整个流程,主要是addPlugin(newSoftOMXPlugin);先看SoftOMXPlugin构造函数 [html] view plaincopy
- SoftOMXPlugin::SoftOMXPlugin() {
- }
是空的~~ 再看下addPlugin代码 [html] view plaincopy
- void OMXMaster::addPlugin(OMXPluginBase *plugin) {
- Mutex::Autolock autoLock(mLock);
-
- mPlugins.push_back(plugin);
-
- OMX_U32 index = 0;
-
- char name[128];
- OMX_ERRORTYPE err;
- while ((err = plugin->enumerateComponents(
- name, sizeof(name), index++)) == OMX_ErrorNone) {
- String8 name8(name);
-
- if (mPluginByComponentName.indexOfKey(name8) >= 0) {
- ALOGE("A component of name '%s' already exists, ignoring this one.",
- name8.string());
-
- continue;
- }
-
- mPluginByComponentName.add(name8, plugin);
- }
-
- if (err != OMX_ErrorNoMore) {
- ALOGE("OMX plugin failed w/ error 0xx after registering %d "
- "components", err, mPluginByComponentName.size());
- }
- }
这里传入的plugin参数时上面SoftOMXPlugin 构造函数产生的实例 从代码可以看出主要是将enumerateComponents枚举出来的各种解码器存放在成员变量mPluginByComponentName中,类型为 KeyedVector 看下enumerateComponents实现 [html] view plaincopy
- static c**t struct {
- c**t char *mName;
- c**t char *mLibNameSuffix;
- c**t char *mRole;
-
- } kComponents[] = {
- { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
- { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
- { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
- { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
- { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
- { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
- { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
- { "OMX.google.h264.encoder", "h264enc", "video_encoder.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.h263.encoder", "mpeg4enc", "video_encoder.h263" },
- { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" },
- { "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.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" },
- { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },
- { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },
- };
[html] view plaincopy
- OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents(
- OMX_STRING name,
- size_t size,
- OMX_U32 index) {
- if (index >= kNumComponents) {
- return OMX_ErrorNoMore;
- }
-
- strcpy(name, kComponents[index].mName);
-
- return OMX_ErrorNone;
- }
这里enumerateComponents主要就是将数组kComponents中的以为index下标的plugin传递出来 这里只是将插件名字返回最终存储在mPluginByComponentName列表中 后面还会通过makeComponentInstance产生实际的解码器实例,后面再详细看 至此mClient->connect()就结束了。 这里的主要工作就是通过getOMX()在mediaplayerservice端构造一个OMX实例,并返回给mClient的IOMX成员mOmx中 而且在OMX的构造函数中调用OMXMaster的构造函数,可以通过makeComponentInstance 建立实际的解码器实例。 2 InitAudioDecoder & InitVideoDecoder
awesomeplayer构造函数结束后,在setDataSource之后会调用prepare方法,其实现中会调用initAudioDecoder和initVideoDecoder 由于在setDataSource中已经拿到了对应的解码器信息,因此此处initAudioDecoder 便可以构造实际的解码器了。以audio为例 [html] view plaincopy
- status_t AwesomePlayer::initAudioDecoder() {
- mAudioSource = OMXCodec::Create(
-
- mClient.interface(), mAudioTrack->getFormat(),
- false, // createEncoder
-
- mAudioTrack);}
-
- status_t err = mAudioSource->start();
-
- return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
-
- }
这里只列出的主要操作,下面依次来看OMXCodec::Create和mAudioSource->start的主要工作 代码比较多,我们这里主要将重要的代码列出,无关代码省略 [html] view plaincopy
- sp<</span>MediaSource> OMXCodec::Create(*)
- {
-
- findMatchingCodecs(
- mime, createEncoder, matchComponentName, flags, &matchingCodecs);
-
- sp<</span>OMXCodecObserver> observer = new OMXCodecObserver;
- IOMX::node_id node = 0;
-
- status_t err = omx->allocateNode(componentName, observer, &node);
-
- sp<</span>OMXCodec> codec = new OMXCodec(
- omx, node, quirks, flags,
- createEncoder, mime, componentName,
- source, nativeWindow);
-
- observer->setCodec(codec);
-
- err = codec->configureCodec(meta);
-
- }
下面依次来看每个过程 2.1 findMatchingCodecs 先看下代码 [html] view plaincopy
- void OMXCodec::findMatchingCodecs(
- c**t char *mime,
- bool createEncoder, c**t char *matchComponentName,
- uint32_t flags,
- Vector<</span>CodecNameAndQuirks> *matchingCodecs) {
- matchingCodecs->clear();
-
- c**t MediaCodecList *list = MediaCodecList::getInstance();
- if (list == NULL) {
- return;
- }
-
- size_t index = 0;
- for (;;) {
- ssize_t matchIndex =
- list->findCodecByType(mime, createEncoder, index);
-
- if (matchIndex <</span> 0) {
- break;
- }
-
- index = matchIndex + 1;
-
- c**t char *componentName = list->getCodecName(matchIndex);
-
- // If a specific codec is requested, skip the non-matching ones.
- if (matchComponentName && strcmp(componentName, matchComponentName)) {
- continue;
- }
-
- // When requesting software-only codecs, only push software codecs
- // When requesting hardware-only codecs, only push hardware codecs
- // When there is request neither for software-only nor for
- // hardware-only codecs, push all codecs
- if (((flags & kSoftwareCodecsOnly) && IsSoftwareCodec(componentName)) ||
- ((flags & kHardwareCodecsOnly) && !IsSoftwareCodec(componentName)) ||
- (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
-
- ssize_t index = matchingCodecs->add();
- CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);
- entry->mName = String8(componentName);
- entry->mQuirks = getComponentQuirks(list, matchIndex);
-
- ALOGV("matching '%s' quirks 0xx",
- entry->mName.string(), entry->mQuirks);
- }
- }
-
- if (flags & kPreferSoftwareCodecs) {
- matchingCodecs->sort(CompareSoftwareCodecsFirst);
- }
- }
从代码可以看到主要就是从MediaCodecList找到与传入的matchComponentName对应的解码器 MediaCodecList 的实现不看了,感兴趣的看下,主要就是从/etc/media_codecs.xml解析出支持的解码器并匹配出对应的解码器 举例: 这里需要注意的是在前面我们看到 kComponents 数组定义了支持的解码器,这里/etc/media_codecs.xml 也列出了对应的解码器,这里名字要对应上 这里找到符合条件的解码器便通过matchingCodecs->add()添加一个项,并将各个成员赋值,主要是name 最终符合条件的插件便都放在了matchingCodecs列表中 2.2 allocateNode 这里主要有如下重要代码 sp observer = new OMXCodecObserver;
IOMX::node_id node = 0; status_t err = omx->allocateNode(componentName, observer, &node); observer的作用主要用于消息传递。 这里allocateNode主要是调用service端的OMX类来完成工作(省略中间的binder操作) [html] view plaincopy
- status_t OMX::allocateNode(
- c**t char *name, c**t sp<</span>IOMXObserver> &observer, node_id *node) {
- Mutex::Autolock autoLock(mLock);
-
- *node = 0;
-
- OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
-
- OMX_COMPONENTTYPE *handle;
- OMX_ERRORTYPE err = mMaster->makeComponentInstance(
- name, &OMXNodeInstance::kCallbacks,
- instance, &handle);
-
- if (err != OMX_ErrorNone) {
- ALOGV("FAILED to allocate omx component '%s'", name);
-
- instance->onGetHandleFailed();
-
- return UNKNOWN_ERROR;
- }
-
- *node = makeNodeID(instance);
- mDispatchers.add(*node, new CallbackDispatcher(instance));
-
- instance->setHandle(*node, handle);
-
- mLiveNodes.add(observer->asBinder(), instance);
- observer->asBinder()->linkToDeath(this);
-
- return OK;
- }
首先构造了OMXNodeInstance,封装了传入的observer参数,作为消息传递的载体 调用mMaster->makeComponentInstance生成实际的解码器实例 生成node_id 将node_id与实际的解码器handle保存在instance中,最终instance会保存在OMX的mLiveNodes列表中 这样OMXCodec就可以通过OMXNodeInstance与解码器通信了,具体参考下面通信模型。 后面会介绍通信过程。这里重点讲解一下与解码器的操作 上面代码中通过mMaster->makeComponentInstance创建了解码器的实例,这里我们以android自带的mp3 解码器为例来讲解 通过上面介绍mp3解码器对应的项为(/etc/media_codecs.xml): 而findMatchingCodecs 传入的字符串为:audio/mpeg 以此为依据进行匹配 这里找到对应的解码器后,解码器的名字为:OMX.google.mp3.decoder 这样便可以通过查表(数组kComponents )得到实际的解码器了 实际的mp3解码器代码文件为:framework/av/media/libstagefright/codecs/mp3dec/SoftMP3.cpp 调用的方法为:mMaster->makeComponentInstance 实际代码是 [html] view plaincopy
- OMX_ERRORTYPE OMXMaster::makeComponentInstance(
- c**t char *name,
- c**t OMX_CALLBACKTYPE *callbacks,
- OMX_PTR appData,
- OMX_COMPONENTTYPE **component) {
- Mutex::Autolock autoLock(mLock);
-
- *component = NULL;
-
- ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
-
- if (index <</span> 0) {
- return OMX_ErrorInvalidComponentName;
- }
-
- OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
- OMX_ERRORTYPE err =
- plugin->makeComponentInstance(name, callbacks, appData, component);
-
- if (err != OMX_ErrorNone) {
- return err;
- }
-
- mPluginByInstance.add(*component, plugin);
-
- return err;
- }
主要是调用插件的makeComponentInstance方法 这里插件是通过OMXMaster构造函数addPlugin(new SoftOMXPlugin);加载的插件,因此这里makeComponentInstance 是SoftOMXPlugin 的方法 看下具体实现 [html] view plaincopy
- OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
- c**t char *name,
- c**t OMX_CALLBACKTYPE *callbacks,
- OMX_PTR appData,
- OMX_COMPONENTTYPE **component) {
- ALOGV("makeComponentInstance '%s'", name);
-
- for (size_t i = 0; i <</span> kNumComponents; ++i) {
- if (strcmp(name, kComponents.mName)) {
- continue;
- }
-
- AString libName = "libstagefright_soft_";
- libName.append(kComponents.mLibNameSuffix);
- libName.append(".so");
-
- void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
-
- if (libHandle == NULL) {
- ALOGE("unable to dlopen %s", libName.c_str());
-
- return OMX_ErrorComponentNotFound;
- }
-
- typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
- c**t char *, c**t 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<</span>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;
- }
这里主要是通过枚举kComponents找到对应的解码器记录 { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" }, 这里可以看到每个库都是以.so的方式提供的,命名符合如下规则:libstagefright_soft_mp3dec.so 通过dlopen加载后通过dlsym找到createSoftOMXComponent方法并执行,这里每个解码器都应该实现此函数
|