The OMX Plug-in and Code Component of A31 in Stagefright Multimedia Architecture under Android 4.2.2

Keywords: Attribute codec Google xml

This article is a summary of my own reading source code. Please indicate the origin of the transfer. Thank you.

Welcome to communicate with you. qq:1037701636 email: gzzaigcn2012@gmail.com

 

 

As mentioned in the previous blog post, AwesomePlayer::onPrepareAsyncEvent() begins to acquire and create Codec decoder components, which we share with you here.

1. Take the example of decoder as the breakthrough point.

  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(),//Extract the format of video stream, mClient:BpOMX  
  7.             false// createEncoder  
  8.             mVideoTrack,  
  9.             NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);//Create a decoder 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();//Start decoder OMXCodec  
  21.   
  22.         if (err != OK) {  
  23.             ALOGE("failed to start video source");  
  24.             mVideoSource.clear();  
  25.             return err;  
  26.         }  
  27.     }  
  28. ......  
  29. }  

Here I have to explain the contents of the following member variables to facilitate the follow-up analysis:

MClinet: OMXClient (inherited) class object. As a member variable of AwesomePlayer, we can find some traces of him here.

  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, maintain a mOMX:BpOMX after connect

Looking at the connect ion process here, let's look at what it has accomplished:

  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);//Get the MPS service BpMedia Player Service
  5.   
  6.     CHECK(service.get() != NULL);  
  7.   
  8.     mOMX = service->getOMX();//Get an omx local interface and pass it to 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. }  

The Binder driver between threads is processed here. Get the interface of an OMX component to mOMX. We have to look at the implementation of getOMX on the MediaPlayService side:

  1. sp<IOMX> MediaPlayerService::getOMX() {  
  2.     Mutex::Autolock autoLock(mLock);  
  3.   
  4.     if (mOMX.get() == NULL) {  
  5.         mOMX = new OMX;//Create a new local anonymous OMX  
  6.     }  
  7.   
  8.     return mOMX;  
  9. }  

A new OMX component class is constructed, which inherits BnOMX. After the Binder driver returns, it eventually creates an anonymous driver like BpOMX.

After returning to BpOMX, a MuxOMX class mOMX is created on the OMXClient side, which exists as a member variable of the OMXClient.

The analysis shows that mClient.interace is the mOMX component created by connect.

b.

SetVideo Source (extractor - > getTrack (i); // Set video source mVideoTrack;

SetAudio Source (extractor - > getTrack (i); // Set audio source mAudioTrack;

mVideoTrack and mAudioTrack are member functions of the created AwesomePlay, whose type is MPEG4Source and inherits MediaSource.

Then mVideoTrack - > getFormat () is the format for obtaining the corresponding video information source.

 

2. Creation of OMXCodec

All decoders, whether soft or hard, are mounted under OMX and used as a Component. Let's look at a Codec creation process.

  1. sp<MediaSource> OMXCodec::Create(  
  2.         const sp<IOMX> &omx,  
  3.         const sp<MetaData> &meta, bool createEncoder,  
  4.         const sp<MediaSource> &source,  
  5.         const char *matchComponentName,  
  6.         uint32_t flags,  
  7.         const sp<ANativeWindow> &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<CodecNameAndQuirks> matchingCodecs;  
  22.     findMatchingCodecs(  
  23.             mime, createEncoder, matchComponentName, flags, &matchingCodecs);//Find available decoders such as 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<OMXCodecObserver> 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();//Name of OMX component  
  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) {//Soft decoder createEncoder = 1;  
  49.             sp<MediaSource> 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);//Request mediaplayerservice to create a node where the real decoder is  
  77.         if (err == OK) {  
  78.             ALOGV("Successfully allocated OMX node '%s'", componentName);  
  79.   
  80.             sp<OMXCodec> codec = new OMXCodec(  
  81.                     omx, node, quirks, flags,  
  82.                     createEncoder, mime, componentName,  
  83.                     source, nativeWindow);//Create a local OMXCodec decoder  
  84.   
  85.             observer->setCodec(codec);//Give the decoder to 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 Find Decoders Supported by Platform

Bool success = meta - > find CString (kKeyMIMEType, & mime); firstly, mime is extracted from the incoming video source trace. Then we continue to search for a decoder for the decoding of the current video source.

Find Matching Codecs (); // Find available decoders such as OMX.allwinner.video.decoder.avc, which I think is the core of finding the required decoders:

  1. void OMXCodec::findMatchingCodecs(  
  2.         const char *mime,  
  3.         bool createEncoder, const char *matchComponentName,  
  4.         uint32_t flags,  
  5.         Vector<CodecNameAndQuirks> *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);//Get the name of the decoder  
  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. }  

Here we are familiar with the creation of a single column mode called MediaCodecList, a list of multimedia decoders. Here we need to look at his construction process, because it reflects the Android 4.2.2 codec maintenance is different from the previous 2.3 and so on. It's also one of the manifestations of his closer approach to mobile interconnection.

 

2.2 Construction of MediaCodecList

  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()//Create a single column mode, parse xml to complete the current mCodecInfos maintenance, support codec  
  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);//Parsing xml files to extract codec supported in them  
  21.   
  22.     if (mInitCheck == OK) {  
  23.         // These are currently still used by the video editing suite.  
  24. /* 
  25.             <MediaCodec name="OMX.allwinner.video.decoder.avc" type="video/avc" /> 
  26.            <MediaCodec name="OMX.allwinner.video.decoder.mpeg2" type="video/mpeg2" /> 
  27.  
  28.         */  
  29.         addMediaCodec(true /* encoder */"AACEncoder""audio/mp4a-latm");//Hard decoder  
  30.   
  31.         addMediaCodec(  
  32.                 false /* encoder */"OMX.google.raw.decoder""audio/raw");//Soft decoder  
  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 is characterized by its parsing of a / etc/media_codecs.xml, which makes it easy to see the features of the Internet. Let's take a look at the content of this configuration file under GLOBAL A31. It's obvious that the top priority is GLOBAL's own hardware and software decoder.

  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>  

The parse of this file is completed by parseXMLFile, and the decoder property is maintained in mCodecInfos. The parsing process of xml file is not very familiar, but the core is to extract the name and type fields and then add MediaCodec.
Of course, we can also add by manually addMedia Codec, where ture represents the encoder and vice versa, the decoder.

Through the above means, we finally get all the types of codec supported by the hardware platform, that is, all kinds of Component components under OMX.

 

2.3

With this so-called codec list, everything becomes easier, which is processed as follows:

  1. ssize_t matchIndex = list->findCodecByType(mime, createEncoder, index);  
  1. const char *componentName = list->getCodecName(matchIndex);//Get the name of the decoder.

CompoonentName will be the key to further processing.
 

3. Create a Node node belonging to the OMX decoder

  1. status_t err = omx->allocateNode(componentName, observer, &node);//Request mediaplayerservice to create a node where the real decoder is  

The omx here has been analyzed at the time of its introduction, and the variable type is an anonymous Binder service class BpOMX. Back at the BnOMX of MediaPlayService, it is estimated that the creation of the core decoder will still be handed over to MPS.

  1. status_t OMX::allocateNode(  
  2.         const char *name, const sp<IOMXObserver> &observer, node_id *node) {  
  3.     Mutex::Autolock autoLock(mLock);  
  4.   
  5.     *node = 0;  
  6.   
  7.     OMXNodeInstance *instance = new OMXNodeInstance(this, observer);//Create a new OMXNodeInstance instance  
  8.   
  9.     OMX_COMPONENTTYPE *handle;  
  10.     OMX_ERRORTYPE err = mMaster->makeComponentInstance(  
  11.             name, &OMXNodeInstance::kCallbacks,  
  12.             instance, &handle);//Create a component and get its operation 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 Create a New Real OMXNodeInstance Example

3.2 mMaster - > makeComponentInstance () Really Acquires Control of a Multi-Next Layer Decoder
Here we want to analyze mMaster as a variable:

When acquiring BpOMX, new OMX is implemented in getOMX on the MPS side:

  1. OMX::OMX()  
  2.     : mMaster(new OMXMaster),//New mMaster  
  3.       mNodeCounter(0) {  
  4. }  

Here you see the sub-member mMaster of the mOMX member in MPS.

  1. OMXMaster::OMXMaster()  
  2.     : mVendorLibHandle(NULL) {  
  3.     addVendorPlugin();//Insert device manufacturer's codec plug-in libstage frighthw  
  4.     addPlugin(new SoftOMXPlugin);  
  5. }  

Seeing this, I think OMXMaster is the administrator of all the underlying codecs. Therefore, the creation of components and so on need to be completed through him.

 

4. The Role of OMXMaster Manager

  1. void OMXMaster::addVendorPlugin() {  
  2.     addPlugin("libstagefrighthw.so");//Manufacturer's Hardware Codec  
  3. }  

See the addition of the so-called device vendor plug-in here, see that it is the addition of a libstage frighthw. so library. Let's see how he handles this so file:

  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)());//Add the current lib plug-in to Component  
  18.     }  
  19. }  

Here we do the typical lib library operation, dlopen load library, dlsym get the operation function handle in the library. * createOMXPLugin () is a function that calls the so library and returns a type of OMXPluginBase *.

At this point, I think it is necessary and necessary to analyze the basic structure of the plug-in under OMX, because only by meeting the required structure can we become a reasonable plug-in under OMX. and

 

5. Magic libstage fighthw.so

This is called a component plug-in designed by platform vendors. In A31 we can see his source code: / home / A31_Android 4.2.2/ Android/hardware/aw/libstagefrighthw

Let me take a look at the function createOMXPlugin in the library that was called before. After obtaining its entry address, I directly invoked it and created an OMX plug-in belonging to AW.

  1. extern "C" OMXPluginBase* createOMXPlugin()  
  2. {  
  3.     return new AwOMXPlugin;//Create a decoder plug-in  
  4. }  
  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. }  

The AwOMXPlugin class inherits the OMXPluginBase class and implements its related interfaces.

An OmxCore lib is opened here, and the interfaces of the above functions are obtained in turn, which will be further used by AwOMXPlugin. We see the execution of the mInit () function, and other similar function sources are located at: / home/A31_Android 4.2.2/android/hardware/aw/omx core/src/aw_omx_core.c.

 

6. Maintenance of OMX Plugin

Back to the processing flow in 4, continue to analyze the implementation of OMXMaster::addPluginOMXPluginBase *plugin() function.

  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);//Add plug-ins to 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. }  

We can see that we first look for the components currently supported by this plug-in. Let's look at their implementation in AwOMXPlugin.

  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. }  

See what is called here in the libOMXCore.so library:

  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. }  

Here is a global variable of Core, which is structured as follows

  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. }  

Through the layer-by-layer analysis of the above functions, the name of the codec and the corresponding Lib Library in core are extracted.

Finally, after each name is obtained, the codec component of different names is added to the mPluginByComponentName variable through mPluginByComponentName. add (name 8, plugin), and the ownership of the variable is maintained by mMaster.

Here we have basically analyzed the OMX plug-ins and codec extraction. Specific components for specific video sources have not been built yet. So we have to go back to No. 3 and create a Node node that belongs to the OMX decoder.

 

7. OMXMaster:: MakeComponent Instance Processing

  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));//Get the component index based on the name of the incoming decoder  
  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);//Create hardware, complete initialization, return handle to component  
  19.   
  20.     if (err != OMX_ErrorNone) {  
  21.         return err;  
  22.     }  
  23.   
  24.     mPluginByInstance.add(*component, plugin);//Maintain plug-ins  
  25.   
  26.     return err;  
  27. }  

This name is after we found the codec supported by the platform (obtained by parsing media_codec.xml), then according to this name, we find the index value and locate the plugin where the decoder is located. Here, for example, the name is OMX.allwinner.video.decoder.avc. The acquired component is libStragefighthw.so plugin AwOXPlugin.

  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<OMX_HANDLETYPE *>(component),  
  12.                          const_cast<char *>(name),  
  13.                          appData,  
  14.                          const_cast<OMX_CALLBACKTYPE *>(callbacks));  
  15. }  

A component created here has become a handle, so you can see that you are gaining access to this component. mGetHandle corresponds to OMX_GetHandle, which is located in the libOmxCore.so library.

  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() retrieves its index in core based on the name of the incoming component

7.2 omx_core_load_cmp_library

  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.   .....  

Assuming that the component corresponding to "OMX.allwinner.video.decoder.avc" is captured here, the lib library for its operation is "libOmxVdec.so". Complete the loading and get the handle of the library. In addition, the address of the function get_omx_component_factory_fn is returned here for subsequent operations on the decoding library.

 

7.3 Then look at void* pThis = (*fn_ptr)();
Call the get_omx_component_factory_fn function entry returned in 7.2.

  1. void *get_omx_component_factory_fn(void)  
  2. {  
  3.     return (new omx_vdec);  
  4. }  

Here you see that a new omx_vdec object is created, as follows:

  1. class omx_vdec: public aw_omx_component  
  2. {  
  3. public:  
  4.     omx_vdec();           // constructor  
  5.     virtual ~omx_vdec();  // destructor  

Follow-up content is mainly related to the standard construction of OMX component construction, I have to learn before digestion, first share with you here, and eventually will extract a large framework and processing diagram between modules, to facilitate a better understanding of the OMX component construction process.

Here's a diagram. A simple flow chart is redrawn. It contains the encoding and decoding plug-in of A31.


 


 

 


 

Posted by Stuie_b on Thu, 27 Dec 2018 08:24:09 -0800