Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件

在前面的博文中提到,AwesomePlayer::onPrepareAsyncEvent()开始进行Codec解码器组件的获取以及创建,这里和大家分享。

1.以解码器实例作为切入点

[cpp]  view plain copy
  1. status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {  
  2.     ATRACE_CALL();  
  3. ......  
  4.     ALOGV("initVideoDecoder flags=0x%x", flags);  
  5.     mVideoSource = OMXCodec::Create(  
  6.             mClient.interface(), mVideoTrack->getFormat(),//提取视频流的格式, mClient:BpOMX  
  7.             false// createEncoder  
  8.             mVideoTrack,  
  9.             NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);//创建一个解码器mVideoSource  
  10.   
  11.     if (mVideoSource != NULL) {  
  12.         int64_t durationUs;  
  13.         if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {  
  14.             Mutex::Autolock autoLock(mMiscStateLock);  
  15.             if (mDurationUs < 0 || durationUs > mDurationUs) {  
  16.                 mDurationUs = durationUs;  
  17.             }  
  18.         }  
  19.   
  20.         status_t err = mVideoSource->start();//启动解码器OMXCodec  
  21.   
  22.         if (err != OK) {  
  23.             ALOGE("failed to start video source");  
  24.             mVideoSource.clear();  
  25.             return err;  
  26.         }  
  27.     }  
  28. ......  
  29. }  

这里不得不先说明以下几个成员变量的相关内容,方便后续的分析:

a. mClinet:OMXClient(继承于)类对象。做为AwesomePlayer的成员变量,在这里能找到他的一些踪迹。

[html]  view plain copy
  1. AwesomePlayer::AwesomePlayer()  
  2.     : mQueueStarted(false),  
  3.       mUIDValid(false),  
  4.       mTimeSource(NULL),  
  5.       mVideoRenderingStarted(false),  
  6.       mVideoRendererIsPreview(false),  
  7.       mAudioPlayer(NULL),  
  8.       mDisplayWidth(0),  
  9.       mDisplayHeight(0),  
  10.       mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),  
  11.       mFlags(0),  
  12.       mExtractorFlags(0),  
  13.       mVideoBuffer(NULL),  
  14.       mDecryptHandle(NULL),  
  15.       mLastVideoTimeUs(-1),  
  16.       mTextDriver(NULL) {  
  17.     CHECK_EQ(mClient.connect(), (status_t)OK);//OMXClient,connect后维护一个mOMX:BpOMX  

看到这里进行了connect的处理,我们来看看其所完成的工作:

[html]  view plain copy
  1. status_t OMXClient::connect() {  
  2.     sp<IServiceManager> sm = defaultServiceManager();  
  3.     sp<IBinder> binder = sm->getService(String16("media.player"));  
  4.     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);//获取MPS服务BpMediaPlayerService  
  5.   
  6.     CHECK(service.get() != NULL);  
  7.   
  8.     mOMX = service->getOMX();//获取一个omx在本地的接口传给videosource, BpOMX  
  9.     CHECK(mOMX.get() != NULL);  
  10.   
  11.     if (!mOMX->livesLocally(NULL /* node */, getpid())) {  
  12.         ALOGI("Using client-side OMX mux.");  
  13.         mOMX = new MuxOMX(mOMX);  
  14.     }  
  15.   
  16.     return OK;  
  17. }  

这里进行线程间的Binder驱动处理。获取一个OMX组件的接口到mOMX。我们不得不去看MediaPlayService端的getOMX的实现:

[cpp]  view plain copy
  1. sp MediaPlayerService::getOMX() {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.   
  4.     if (mOMX.get() == NULL) {  
  5.         mOMX = new OMX;//新建一个本地匿名的OMX  
  6.     }  
  7.   
  8.     return mOMX;  
  9. }  

新构建了一个OMX组件类,该类继承了BnOMX。使得Binder驱动返回后最终创建的是一个BpOMX这么个匿名驱动。

返回BpOMX后在OMXClient侧创建一个MuxOMX类mOMX,其作为OMXClient的成员变量而存在。

分析可知mClient.interace即是connect创建的mOMX组件。

b.

setVideoSource(extractor->getTrack(i));//设置视频源mVideoTrack ;

setAudioSource(extractor->getTrack(i));//设置音频源mAudioTrack;

mVideoTrack和mAudioTrack的做为创建的AwesomePlay的成员函数,其类型为MPEG4Source,继承了MediaSource。

那么mVideoTrack->getFormat(),是获取对应视频信息源的格式。

 

2.OMXCodec的创建

所有的解码器无论是软解还是硬解,都是挂载OMX下面,作为其的一个Component来使用。下面来看一个Codec的创建过程。

[cpp]  view plain copy
  1. sp OMXCodec::Create(  
  2.         const sp &omx,  
  3.         const sp &meta, bool createEncoder,  
  4.         const sp &source,  
  5.         const char *matchComponentName,  
  6.         uint32_t flags,  
  7.         const sp &nativeWindow) {  
  8.     int32_t requiresSecureBuffers;  
  9.     if (source->getFormat()->findInt32(  
  10.                 kKeyRequiresSecureBuffers,  
  11.                 &requiresSecureBuffers)  
  12.             && requiresSecureBuffers) {  
  13.         flags |= kIgnoreCodecSpecificData;  
  14.         flags |= kUseSecureInputBuffers;  
  15.     }  
  16.   
  17.     const char *mime;  
  18.     bool success = meta->findCString(kKeyMIMEType, &mime);  
  19.     CHECK(success);  
  20.   
  21.     Vector matchingCodecs;  
  22.     findMatchingCodecs(  
  23.             mime, createEncoder, matchComponentName, flags, &matchingCodecs);//寻找可用的解码器如OMX.allwinner.video.decoder.avc  
  24.   
  25.     if (matchingCodecs.isEmpty()) {  
  26.         ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "  
  27.                 "matchComponentName: %s, flags: 0x%x)",  
  28.                 mime, createEncoder ? "true" : "false", matchComponentName, flags);  
  29.         return NULL;  
  30.     }  
  31.   
  32.     sp observer = new OMXCodecObserver;  
  33.     IOMX::node_id node = 0;  
  34.   
  35.     for (size_t i = 0; i < matchingCodecs.size(); ++i) {  
  36.         const char *componentNameBase = matchingCodecs[i].mName.string();//OMX组件的名字  
  37.         uint32_t quirks = matchingCodecs[i].mQuirks;  
  38.         const char *componentName = componentNameBase;  
  39.   
  40.         AString tmp;  
  41.         if (flags & kUseSecureInputBuffers) {  
  42.             tmp = componentNameBase;  
  43.             tmp.append(".secure");  
  44.   
  45.             componentName = tmp.c_str();  
  46.         }  
  47.   
  48.         if (createEncoder) {//软解码器createEncoder = 1;  
  49.             sp softwareCodec =  
  50.                 InstantiateSoftwareEncoder(componentName, source, meta);  
  51.   
  52.             if (softwareCodec != NULL) {  
  53.                 ALOGV("Successfully allocated software codec '%s'", componentName);  
  54.   
  55.                 return softwareCodec;  
  56.             }  
  57.         }  
  58.   
  59.         ALOGV("Attempting to allocate OMX node '%s'", componentName);  
  60.   
  61.         if (!createEncoder  
  62.                 && (quirks & kOutputBuffersAreUnreadable)  
  63.                 && (flags & kClientNeedsFramebuffer)) {  
  64.             if (strncmp(componentName, "OMX.SEC.", 8)) {  
  65.                 // For OMX.SEC.* decoders we can enable a special mode that  
  66.                 // gives the client access to the framebuffer contents.  
  67.   
  68.                 ALOGW("Component '%s' does not give the client access to "  
  69.                      "the framebuffer contents. Skipping.",  
  70.                      componentName);  
  71.   
  72.                 continue;  
  73.             }  
  74.         }  
  75.   
  76.         status_t err = omx->allocateNode(componentName, observer, &node);//请求mediaplayerservice创建一个节点,真正的解码器所在  
  77.         if (err == OK) {  
  78.             ALOGV("Successfully allocated OMX node '%s'", componentName);  
  79.   
  80.             sp codec = new OMXCodec(  
  81.                     omx, node, quirks, flags,  
  82.                     createEncoder, mime, componentName,  
  83.                     source, nativeWindow);//创建一个本地OMXCodec解码器  
  84.   
  85.             observer->setCodec(codec);//将解码器交给observer  
  86.   
  87.             err = codec->configureCodec(meta);  
  88.   
  89.             if (err == OK) {  
  90.                 if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {  
  91.                     codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;  
  92.                 }  
  93.   
  94.                 return codec;  
  95.             }  
  96.   
  97.             ALOGV("Failed to configure codec '%s'", componentName);  
  98.         }  
  99.     }  
  100.   
  101.     return NULL;  
  102. }  

 

2.1 查找平台支持的解码器

bool success = meta->findCString(kKeyMIMEType, &mime);首先对传入的视频源track进行mime的提取。然后是继续一个解码器的查找,为当前视频源的解码所用:

findMatchingCodecs();//寻找可用的解码器如OMX.allwinner.video.decoder.avc, 个人认为这是查找到所需要的解码器的核心所在:

[cpp]  view plain copy
  1. void OMXCodec::findMatchingCodecs(  
  2.         const char *mime,  
  3.         bool createEncoder, const char *matchComponentName,  
  4.         uint32_t flags,  
  5.         Vector *matchingCodecs) {  
  6.     matchingCodecs->clear();  
  7.   
  8.     const MediaCodecList *list = MediaCodecList::getInstance();  
  9.     if (list == NULL) {  
  10.         return;  
  11.     }  
  12.   
  13.     size_t index = 0;  
  14.     for (;;) {  
  15.         ssize_t matchIndex =  
  16.             list->findCodecByType(mime, createEncoder, index);  
  17.   
  18.         if (matchIndex < 0) {  
  19.             break;  
  20.         }  
  21.   
  22.         index = matchIndex + 1;  
  23.   
  24.         const char *componentName = list->getCodecName(matchIndex);//获取解码器的名字  
  25.   
  26.         // If a specific codec is requested, skip the non-matching ones.  
  27.         if (matchComponentName && strcmp(componentName, matchComponentName)) {  
  28.             continue;  
  29.         }  
  30.   
  31.         // When requesting software-only codecs, only push software codecs  
  32.         // When requesting hardware-only codecs, only push hardware codecs  
  33.         // When there is request neither for software-only nor for  
  34.         // hardware-only codecs, push all codecs  
  35.         if (((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||  
  36.             ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||  
  37.             (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {  
  38.   
  39.             ssize_t index = matchingCodecs->add();  
  40.             CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);  
  41.             entry->mName = String8(componentName);  
  42.             entry->mQuirks = getComponentQuirks(list, matchIndex);  
  43.   
  44.             ALOGV("matching '%s' quirks 0x%08x",  
  45.                   entry->mName.string(), entry->mQuirks);  
  46.         }  
  47.     }  
  48.   
  49.     if (flags & kPreferSoftwareCodecs) {  
  50.         matchingCodecs->sort(CompareSoftwareCodecsFirst);  
  51.     }  
  52. }  

在这里很熟悉的看到一个单列模式的创建MediaCodecList,一个多媒体解码器列表的创建。在这里我们很有必要看一下他的构造过程,因为这里体现出android4.2.2的编解码器维护和之前2.3等的不同。也是他更接近移动互联的表现之一。

 

2.2 MediaCodecList的构建

[cpp]  view plain copy
  1. const MediaCodecList *MediaCodecList::getInstance() {  
  2.     Mutex::Autolock autoLock(sInitMutex);  
  3.   
  4.     if (sCodecList == NULL) {  
  5.         sCodecList = new MediaCodecList;  
  6.     }  
  7.   
  8.     return sCodecList->initCheck() == OK ? sCodecList : NULL;  
  9. }  
  10.   
  11. MediaCodecList::MediaCodecList()//单列模式的创建,解析xml完成当前mCodecInfos的维护,支持的编解码器  
  12.     : mInitCheck(NO_INIT) {  
  13.     FILE *file = fopen("/etc/media_codecs.xml""r");  
  14.   
  15.     if (file == NULL) {  
  16.         ALOGW("unable to open media codecs configuration xml file.");  
  17.         return;  
  18.     }  
  19.   
  20.     parseXMLFile(file);//解析xml文件提取其中支持的codec  
  21.   
  22.     if (mInitCheck == OK) {  
  23.         // These are currently still used by the video editing suite.  
  24. /* 
  25.              
  26.             
  27.  
  28.         */  
  29.         addMediaCodec(true /* encoder */"AACEncoder""audio/mp4a-latm");//硬解码器  
  30.   
  31.         addMediaCodec(  
  32.                 false /* encoder */"OMX.google.raw.decoder""audio/raw");//软解码器  
  33.     }  
  34.   
  35. #if 0  
  36.     for (size_t i = 0; i < mCodecInfos.size(); ++i) {  
  37.         const CodecInfo &info = mCodecInfos.itemAt(i);  
  38.   
  39.         AString line = info.mName;  
  40.         line.append(" supports ");  
  41.         for (size_t j = 0; j < mTypes.size(); ++j) {  
  42.             uint32_t value = mTypes.valueAt(j);  
  43.   
  44.             if (info.mTypes & (1ul << value)) {  
  45.                 line.append(mTypes.keyAt(j));  
  46.                 line.append(" ");  
  47.             }  
  48.         }  
  49.   
  50.         ALOGI("%s", line.c_str());  
  51.     }  
  52. #endif  
  53.   
  54.     fclose(file);  
  55.     file = NULL;  
  56. }  

 MediaCodecList的特点在于它对一个/etc/media_codecs.xml进行了解析,很容易看到xml让人感觉到了互联网的特色所在。我们来看看在全志A31下的这个配置文件部分内容,显然放在最前面的是全志自己的软硬件解码器:

[html]  view plain copy
  1.  <MediaCodecs>  
  2.  93     <Decoders>  
  3.  94         <MediaCodec name="OMX.allwinner.video.decoder.avc" type="video/avc" />  
  4.  95         <MediaCodec name="OMX.allwinner.video.decoder.mpeg2" type="video/mpeg2" />  
  5.  96         <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es" />  
  6.  97         <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp" />  
  7.  98         <MediaCodec name="OMX.google.vpx.decoder" type="video/x-vnd.on2.vp8" />  
  8.  99   
  9. 100         <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg" />  
  10. 101         <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp" />  
  11. 102         <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb" />  
  12. 103         <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm" />  
  13. 104         <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw" />  
  14. 105         <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" />  
  15. 106         <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" />  
  16. 107         <MediaCodec name="OMX.google.raw.decoder" type="audio/raw" />  
  17. 108   
  18. 109     Decoders>  
  19. 110   
  20. 111     <Encoders>  
  21. 112         <MediaCodec name="OMX.allwinner.video.encoder.avc" type="video/avc" />  
  22. 113   
  23. 114         <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp" />  
  24. 115         <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es" />  
  25. 116         <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp" />  
  26. 117         <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb" />  
  27. 118         <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm" />  
  28. 119         <MediaCodec name="OMX.google.flac.encoder" type="audio/flac" />  
  29. 120     Encoders>  
  30. 121 MediaCodecs>  

而这个文件的解析通过parseXMLFile来完成,最终解码器属性维护在了mCodecInfos,这其中xml文件的解析过程不是很熟悉,但核心是提取name和type这两个字段后进行addMediaCodec的操作。
当然,我们也可以通过手动addMediaCodec来完成添加,其中ture代表的是编码器,反之则为解码器。

通过以上的手段,最终我们获取到了硬件平台所支持的所有编解码器的类型,也就是OMX下的各种Component组件。

 

2.3

有了这个所谓的编解码器list,一切的变得更加的轻松,分别经过如下处理:

[html]  view plain copy
  1. ssize_t matchIndex = list->findCodecByType(mime, createEncoder, index);  
[html]  view plain copy
  1. const char *componentName = list->getCodecName(matchIndex);//获取解码器的名字  

componentName将成为后续的进一步处理的关键
 

 3. 创建一个属于OMX解码器的Node节点

[cpp]  view plain copy
  1. status_t err = omx->allocateNode(componentName, observer, &node);//请求mediaplayerservice创建一个节点,真正的解码器所在  

这里的omx在传入时已经分析过,变量类型为一个匿名Binder服务类BpOMX.回到在MediaPlayService的BnOMX处,估计核心的创建解码器等还是要交给MPS来完成的。

[cpp]  view plain copy
  1. status_t OMX::allocateNode(  
  2.         const char *name, const sp &observer, node_id *node) {  
  3.     Mutex::Autolock autoLock(mLock);  
  4.   
  5.     *node = 0;  
  6.   
  7.     OMXNodeInstance *instance = new OMXNodeInstance(this, observer);//新建一个OMXNodeInstance实例  
  8.   
  9.     OMX_COMPONENTTYPE *handle;  
  10.     OMX_ERRORTYPE err = mMaster->makeComponentInstance(  
  11.             name, &OMXNodeInstance::kCallbacks,  
  12.             instance, &handle);//创建一个组件,并获取其操作句柄  
  13.   
  14.     if (err != OMX_ErrorNone) {  
  15.         ALOGV("FAILED to allocate omx component '%s'", name);  
  16.   
  17.         instance->onGetHandleFailed();  
  18.   
  19.         return UNKNOWN_ERROR;  
  20.     }  
  21.   
  22.     *node = makeNodeID(instance);  
  23.     mDispatchers.add(*node, new CallbackDispatcher(instance));  
  24.   
  25.     instance->setHandle(*node, handle);  
  26.   
  27.     mLiveNodes.add(observer->asBinder(), instance);  
  28.     observer->asBinder()->linkToDeath(this);  
  29.   
  30.     return OK;  
  31. }  

 

3.1 新建一个真正的OMXNodeInstance实例

3.2 mMaster->makeComponentInstance()真正获取一个多下一层解码器的控制权
这里要和大家分析mMaster这个变量:

在获取BpOMX时,在MPS侧的getOMX里实现了new OMX:

[cpp]  view plain copy
  1. OMX::OMX()  
  2.     : mMaster(new OMXMaster),//新建一个mMaster  
  3.       mNodeCounter(0) {  
  4. }  

这里看到MPS中的mOMX成员的子成员mMaster。

[cpp]  view plain copy
  1. OMXMaster::OMXMaster()  
  2.     : mVendorLibHandle(NULL) {  
  3.     addVendorPlugin();//插入设备厂商的编解码器插件libstagefrighthw  
  4.     addPlugin(new SoftOMXPlugin);  
  5. }  

看到这里我会觉得OMXMaster是所有底层编解码的管理者吧。因此组件的创建等都需要通过他来完成。

 

4.OMXMaster管理者的角色扮演

[cpp]  view plain copy
  1. void OMXMaster::addVendorPlugin() {  
  2.     addPlugin("libstagefrighthw.so");//厂商的硬件编解码器  
  3. }  

看到这里添加了所谓的设备厂商的插件,看到其是添加了一个libstagefrighthw.so库。我们看看他是如何对这个so文件做处理的:

[cpp]  view plain copy
  1. void OMXMaster::addPlugin(const char *libname) {  
  2.     mVendorLibHandle = dlopen(libname, RTLD_NOW);  
  3.   
  4.     if (mVendorLibHandle == NULL) {  
  5.         return;  
  6.     }  
  7.   
  8.     typedef OMXPluginBase *(*CreateOMXPluginFunc)();  
  9.     CreateOMXPluginFunc createOMXPlugin =  
  10.         (CreateOMXPluginFunc)dlsym(  
  11.                 mVendorLibHandle, "createOMXPlugin");  
  12.     if (!createOMXPlugin)  
  13.         createOMXPlugin = (CreateOMXPluginFunc)dlsym(  
  14.                 mVendorLibHandle, "_ZN7android15createOMXPluginEv");  
  15.   
  16.     if (createOMXPlugin) {  
  17.         addPlugin((*createOMXPlugin)());//将当前的lib插件加入到Component中去  
  18.     }  
  19. }  

这里做了典型的lib库的操作,dlopen加载库,dlsym获取库中的操作函数handle。*createOMXPLugin()是调用这个so库中的函数,这个函数返回的是一个OMXPluginBase*的类型。

到这里,我觉得和有必要和大家分析下OMX下的插件的基本结构了,因为只有满足这个规定的结构,才能成为一个合理的OMX下的插件。而

 

5. 神奇的libstagefighthw.so

这个被称之为平台厂商所设计的组件插件。在A31里面我们可以看到他的源码:/home/A31_Android4.2.2/android/hardware/aw/libstagefrighthw

我来看看之前调用该库里面的函数createOMXPlugin,获取其入口地址后,直接调用后是创建了属于AW的一个OMX插件

[cpp]  view plain copy
  1. extern "C" OMXPluginBase* createOMXPlugin()  
  2. {  
  3.     return new AwOMXPlugin;//创建一个解码器插件  
  4. }  
[cpp]  view plain copy
  1. AwOMXPlugin::AwOMXPlugin()  
  2.     : mLibHandle(dlopen("libOmxCore.so", RTLD_NOW)),  
  3.       mInit(NULL),  
  4.       mDeinit(NULL),  
  5.       mComponentNameEnum(NULL),  
  6.       mGetHandle(NULL),  
  7.       mFreeHandle(NULL),  
  8.       mGetRolesOfComponentHandle(NULL)  
  9. {  
  10.     if (mLibHandle != NULL)  
  11.     {  
  12.         mInit                      = (InitFunc)dlsym(mLibHandle, "OMX_Init");  
  13.         mDeinit                    = (DeinitFunc)dlsym(mLibHandle, "OMX_Deinit");  
  14.         mComponentNameEnum         = (ComponentNameEnumFunc)dlsym(mLibHandle, "OMX_ComponentNameEnum");  
  15.         mGetHandle                 = (GetHandleFunc)dlsym(mLibHandle, "OMX_GetHandle");  
  16.         mFreeHandle                = (FreeHandleFunc)dlsym(mLibHandle, "OMX_FreeHandle");  
  17.         mGetRolesOfComponentHandle = (GetRolesOfComponentFunc)dlsym(mLibHandle, "OMX_GetRolesOfComponent");  
  18.   
  19.         (*mInit)();  
  20.     }  
  21. }  

AwOMXPlugin类继承了OMXPluginBase类,实现了其相关接口

这里又打开了一个OmxCore这个lib,依次获取了以上几个函数的接口,将会被AwOMXPlugin来进一步使用。我们看到mInit()函数的执行,其他类似的函数源码位于:/home/A31_Android4.2.2/android/hardware/aw/omxcore/src/aw_omx_core.c

 

6. OMX Plugin的维护

回到4中的处理流程,继续分析OMXMaster::addPluginOMXPluginBase *plugin()函数的实现。

[cpp]  view plain copy
  1. void OMXMaster::addPlugin(OMXPluginBase *plugin) {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.   
  4.     mPlugins.push_back(plugin);  
  5.   
  6.     OMX_U32 index = 0;  
  7.   
  8.     char name[128];  
  9.     OMX_ERRORTYPE err;  
  10.     while ((err = plugin->enumerateComponents(  
  11.                     name, sizeof(name), index++)) == OMX_ErrorNone) {  
  12.         String8 name8(name);  
  13.   
  14.         if (mPluginByComponentName.indexOfKey(name8) >= 0) {  
  15.             ALOGE("A component of name '%s' already exists, ignoring this one.",  
  16.                  name8.string());  
  17.   
  18.             continue;  
  19.         }  
  20.   
  21.         mPluginByComponentName.add(name8, plugin);//增加stragefright里面的插件  
  22.     }  
  23.   
  24.     if (err != OMX_ErrorNoMore) {  
  25.         ALOGE("OMX plugin failed w/ error 0x%08x after registering %d "  
  26.              "components", err, mPluginByComponentName.size());  
  27.     }  
  28. }  

我们可以看到先查找当前的这个插件支持的组件,我们来看其在AwOMXPlugin中的实现。

[cpp]  view plain copy
  1. OMX_ERRORTYPE AwOMXPlugin::enumerateComponents(OMX_STRING name, size_t size, OMX_U32 index)  
  2. {  
  3.     if (mLibHandle == NULL)  
  4.     {  
  5.         return OMX_ErrorUndefined;  
  6.     }  
  7.   
  8.     OMX_ERRORTYPE res = (*mComponentNameEnum)(name, size, index);  
  9.   
  10.     if (res != OMX_ErrorNone)  
  11.     {  
  12.         return res;  
  13.     }  
  14.   
  15.     return OMX_ErrorNone;  
  16. }  

看到这里调用的是libOMXCore.so库里面的内容:

[cpp]  view plain copy
  1. OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(OMX_OUT OMX_STRING componentName, OMX_IN OMX_U32 nameLen, OMX_IN OMX_U32 index)  
  2. {  
  3.     OMX_ERRORTYPE eRet = OMX_ErrorNone;  
  4.     ALOGV("OMXCORE API - OMX_ComponentNameEnum %x %d %d\n",(unsigned) componentName, (unsigned)nameLen, (unsigned)index);  
  5.     if(index < SIZE_OF_CORE)  
  6.     {  
  7.         strlcpy(componentName, core[index].name, nameLen);  
  8.     }  
  9.     else  
  10.     {  
  11.         eRet = OMX_ErrorNoMore;  
  12.     }  
  13.   
  14.     return eRet;  
  15. }  

这里有一个Core的全局变量,其具体的结构如下

[cpp]  view plain copy
  1. omx_core_cb_type core[] =  
  2. {  
  3.     {  
  4.         "OMX.allwinner.video.decoder.avc",  
  5.         NULL, // Create instance function  
  6.         // Unique instance handle  
  7.         {  
  8.             NULL,  
  9.             NULL,  
  10.             NULL,  
  11.             NULL  
  12.         },  
  13.         NULL,   // Shared object library handle  
  14.         "libOmxVdec.so",  
  15.         {  
  16.             "video_decoder.avc"  
  17.         }  
  18.     },  
  19. ....  
  20. }  

通过以上函数的层层分析,提取到了core中的编解码器name以及对应的Lib库。

最终是获取了各个name之后,通过mPluginByComponentName.add(name8, plugin),添加不同name的编解码器component到mPluginByComponentName变量中,而这个变量的所有权归mMaster维护。

到这里我们基本分析完了OMX插件和codec的提取。还没有完成针对特定的视频源,构建出专门的组件。这样我们得回归到3中创建一个属于OMX解码器的Node节点处。

 

7.OMXMaster::makeComponentInstance的处理

[cpp]  view plain copy
  1. OMX_ERRORTYPE OMXMaster::makeComponentInstance(  
  2.         const char *name,  
  3.         const OMX_CALLBACKTYPE *callbacks,  
  4.         OMX_PTR appData,  
  5.         OMX_COMPONENTTYPE **component) {  
  6.     Mutex::Autolock autoLock(mLock);  
  7.   
  8.     *component = NULL;  
  9.   
  10.     ssize_t index = mPluginByComponentName.indexOfKey(String8(name));//根据传入的解码器的名字,获取组件索引  
  11.   
  12.     if (index < 0) {  
  13.         return OMX_ErrorInvalidComponentName;  
  14.     }  
  15.   
  16.     OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);  
  17.     OMX_ERRORTYPE err =  
  18.         plugin->makeComponentInstance(name, callbacks, appData, component);//创建硬件,完成初始化,返回handle到component  
  19.   
  20.     if (err != OMX_ErrorNone) {  
  21.         return err;  
  22.     }  
  23.   
  24.     mPluginByInstance.add(*component, plugin);//将插件维护起来  
  25.   
  26.     return err;  
  27. }  

这个name是之前我们查找到平台支持的codec后(通过解析media_codec.xml获得)后,再根据这个name,找到这个index值,定位到这个解码器所在的插件plugin.这里比如name是OMX.allwinner.video.decoder.avc,这个获取的组件就是libStragefighthw.so这个插件AwOXPlugin

[cpp]  view plain copy
  1. OMX_ERRORTYPE AwOMXPlugin::makeComponentInstance(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData, OMX_COMPONENTTYPE** component)  
  2. {  
  3.     ALOGV("step 1.");  
  4.     if (mLibHandle == NULL)  
  5.     {  
  6.         return OMX_ErrorUndefined;  
  7.     }  
  8.   
  9.     ALOGV("step 2.");  
  10.   
  11.     return (*mGetHandle)(reinterpret_cast(component),  
  12.                          const_cast<char *>(name),  
  13.                          appData,  
  14.                          const_cast(callbacks));  
  15. }  

这里的创建的一个组件,变成了handle,可见是获取对这个组件的操作权。而mGetHandle对应的是OMX_GetHandle其位于libOmxCore.so库之中。

[cpp]  view plain copy
  1. OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(OMX_OUT OMX_HANDLETYPE* handle, OMX_IN OMX_STRING componentName, OMX_IN OMX_PTR appData, OMX_IN OMX_CALLBACKTYPE* callBacks)  
  2. {  
  3.      OMX_ERRORTYPE  eRet = OMX_ErrorNone;  
  4.      int cmp_index = -1;  
  5.      int hnd_index = -1;  
  6.   
  7.      create_aw_omx_component fn_ptr = NULL;  
  8.   
  9.      ALOGV("OMXCORE API :  Get Handle %x %s %x\n",(unsigned) handle, componentName, (unsigned) appData);  
  10.   
  11.      if(handle)  
  12.      {  
  13.           cmp_index = get_cmp_index(componentName);  
  14.   
  15.           if(cmp_index >= 0)  
  16.           {  
  17.                ALOGV("getting fn pointer\n");  
  18.   
  19.                // dynamically load the so  
  20.   
  21.                // ALOGV("core[cmp_index].fn_ptr: %x", core[cmp_index].fn_ptr);  
  22.   
  23.                fn_ptr = omx_core_load_cmp_library(cmp_index);                      
  24.             
  25.                if(fn_ptr)  
  26.                {  
  27.                     // Construct the component requested  
  28.                     // Function returns the opaque handle  
  29.   
  30.                     void* pThis = (*fn_ptr)();  
  31.                     if(pThis)  
  32.                     {  
  33.                          void *hComp = NULL;  
  34.                          hComp = aw_omx_create_component_wrapper((OMX_PTR)pThis);  
  35.                          if((eRet = aw_omx_component_init(hComp, componentName)) != OMX_ErrorNone)  
  36.                          {  
  37.                               ALOGE("Component not created succesfully\n");  
  38.                               return eRet;  
  39.                          }  
  40.   
  41.                          aw_omx_component_set_callbacks(hComp, callBacks, appData);  
  42.                            
  43.                          hnd_index = set_comp_handle(componentName, hComp);  
  44.                          if(hnd_index >= 0)  
  45.                          {  
  46.                               *handle = (OMX_HANDLETYPE) hComp;  
  47.                          }  
  48.                          else  
  49.                          {  
  50.                               ALOGE("OMX_GetHandle:NO free slot available to store Component Handle\n");  
  51.                               return OMX_ErrorInsufficientResources;  
  52.                          }  
  53.   
  54.    .......  
  55.   
  56.      return eRet;  
  57. }  

 

7.1 get_cmp_index()根据传入的组件name获取其在core中的索引

7.2 omx_core_load_cmp_library

[cpp]  view plain copy
  1. static create_aw_omx_component omx_core_load_cmp_library(int idx)  
  2. {  
  3.      create_aw_omx_component fn_ptr = NULL;  
  4.   
  5.      pthread_mutex_lock(&g_mutex_core_info);  
  6.   
  7.   
  8.      if(core[idx].so_lib_handle == NULL)  
  9.      {  
  10.           ALOGV("Dynamically Loading the library : %s\n",core[idx].so_lib_name);  
  11.   
  12.           core[idx].so_lib_handle = dlopen(core[idx].so_lib_name, RTLD_NOW);  
  13.      }  
  14.   
  15.      if(core[idx].so_lib_handle)  
  16.      {  
  17.           if(core[idx].fn_ptr == NULL)  
  18.           {  
  19.                core[idx].fn_ptr = dlsym(core[idx].so_lib_handle, "get_omx_component_factory_fn");  
  20.   
  21.   .....  

假设这里获取的是  "OMX.allwinner.video.decoder.avc"对应的组件,则其操作的lib库为"libOmxVdec.so"。完成加载,获取库的handle。此外这里返回的是一个函数get_omx_component_factory_fn的地址,用于后续的对这个解码库的操作。

 

7.3 接着看    void* pThis = (*fn_ptr)();
就是调用7.2中返回的get_omx_component_factory_fn函数入口。

[cpp]  view plain copy
  1. void *get_omx_component_factory_fn(void)  
  2. {  
  3.     return (new omx_vdec);  
  4. }  

这里看到是新建了一个omx_vdec对象,如下所示:

[cpp]  view plain copy
  1. class omx_vdec: public aw_omx_component  
  2. {  
  3. public:  
  4.     omx_vdec();           // constructor  
  5.     virtual ~omx_vdec();  // destructor  

后续内容的主要是涉及相关OMX组件构造的标准构造,自己也要学习后才能消化,先和大家分享到这里,最终会提炼出一个大的框架和模块间的处理图,方便更好的理解这个OMX组件的构建过程。

来图了,重新整理画了一个简单的流程图,内部含有A31的编解码器插件:

Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件_第1张图片
 


原文地址:http://blog.csdn.net/gzzaigcnforever/article/details/26405739?utm_source=tuicool 


你可能感兴趣的:(Android底层开发与调试)