搜索
 找回密码
 立即注册

简单一步 , 微信登陆

【stagefrightplayer】4 OMX Codec介绍

作者:果果 | 时间:2016-9-22 19:34:55 | 阅读:5340| 只看该作者
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方法并执行,这里每个解码器都应该实现此函数

收藏
收藏0
分享
分享
点赞
点赞0
反对
反对0
回复

使用道具 举报

大神点评1

沙发#
Robby.zou 发表于:2016-9-28 11:02:35
该会员没有填写今日想说内容.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版