這幾篇文章是之前學習openmax的輸出,記錄在這裏,希望不要誤導菜鳥的同時又能得到牛牛們的指導。
android_ics openmax_in_stagefright 再次學習 /* *在學習android源代碼的工程中,一點要時刻牢記C/S架構 *任何時刻都要搞清除,這個時候的代碼是運行在客戶端, *還是服務端,這個對象來之,客戶端還是服務端的代理。 */ <---以下的討論,目的都在於弄清楚,stagefright框架內,OpenMaXIL和各個編解碼的組件是如何通信的---> At first: OpenMax是事實上的標準,也是android上多媒體編解碼框架未來的趨勢。 分析的比較凌亂,後面在做整理。 ///////////////////////////////////////////// //1,OMX 從何開始? //////////////////////////////////////////// 看下awesomeplayer的構造函數 AwesomePlayer::AwesomePlayer() : mQueueStarted(false), ... mTextPlayer(NULL) { /*mClient是一個OMXClient類型的成員變量*/ CHECK_EQ(mClient.connect(), (status_t)OK); DataSource::RegisterDefaultSniffers(); mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); ... mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); mVideoEventPending = false; mCheckAudioStatusEvent = new AwesomeEvent( this, &AwesomePlayer::onCheckAudioStatus); ... } /*connect函數的定義*/ status_t OMXClient::connect() { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16("media.player")); sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); CHECK(service.get() != NULL); mOMX = service->getOMX(); CHECK(mOMX.get() != NULL); return OK; } 上面的函數,通過binder取請求MediaPlayerService的getOmx然後反回一個OMX實例,事實上這個時候在awesomePlayer 中的mOMX是一個來之服務端的實例。打通了一條Client->Service的通道。個人認爲這就是OpenMax框架的入口。 /*OMX的構造函數如下,@OMX.cpp*/ OMX::OMX():mMaster(new OMXMaster),mNodeCounter(0) { } -------------------------以下是插曲,首次看請忽略---------------------------------------------------------> /*下面完整的貼出OMX的結構,其中有些成員的作用,在後面的學習中,會慢慢的揭開其真面目*/ class OMX : public BnOMX, public IBinder::DeathRecipient { public: OMX(); virtual bool livesLocally(pid_t pid); virtual status_t listNodes(List<ComponentInfo> *list); virtual status_t allocateNode( const char *name, const sp<IOMXObserver> &observer, node_id *node); virtual status_t freeNode(node_id node); virtual status_t sendCommand( node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param); virtual status_t getParameter( node_id node, OMX_INDEXTYPE index, void *params, size_t size); virtual status_t setParameter( node_id node, OMX_INDEXTYPE index, const void *params, size_t size); virtual status_t getConfig( node_id node, OMX_INDEXTYPE index, void *params, size_t size); virtual status_t setConfig( node_id node, OMX_INDEXTYPE index, const void *params, size_t size); virtual status_t getState( node_id node, OMX_STATETYPE* state); virtual status_t enableGraphicBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable); virtual status_t getGraphicBufferUsage( node_id node, OMX_U32 port_index, OMX_U32* usage); virtual status_t storeMetaDataInBuffers( node_id node, OMX_U32 port_index, OMX_BOOL enable); virtual status_t useBuffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer); virtual status_t useGraphicBuffer( node_id node, OMX_U32 port_index, const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer); virtual status_t allocateBuffer( node_id node, OMX_U32 port_index, size_t size, buffer_id *buffer, void **buffer_data); virtual status_t allocateBufferWithBackup( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer); virtual status_t freeBuffer( node_id node, OMX_U32 port_index, buffer_id buffer); virtual status_t fillBuffer(node_id node, buffer_id buffer); virtual status_t emptyBuffer( node_id node, buffer_id buffer, OMX_U32 range_offset, OMX_U32 range_length, OMX_U32 flags, OMX_TICKS timestamp); virtual status_t getExtensionIndex( node_id node, const char *parameter_name, OMX_INDEXTYPE *index); virtual void binderDied(const wp<IBinder> &the_late_who); OMX_ERRORTYPE OnEvent( node_id node, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData); OMX_ERRORTYPE OnEmptyBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); OMX_ERRORTYPE OnFillBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer); void invalidateNodeID(node_id node); protected: virtual ~OMX(); private: struct CallbackDispatcherThread; //關注下 struct CallbackDispatcher; //關注下 Mutex mLock; OMXMaster *mMaster; int32_t mNodeCounter; KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes; KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance; KeyedVector<node_id, sp<CallbackDispatcher> > mDispatchers; node_id makeNodeID(OMXNodeInstance *instance); OMXNodeInstance *findInstance(node_id node); sp<CallbackDispatcher> findDispatcher(node_id node); void invalidateNodeID_l(node_id node); OMX(const OMX &); OMX &operator=(const OMX &); }; } // namespace android #endif // ANDROID_OMX_H_ <-------------------------以上是插曲,首次看請忽略--------------------------------------------------------- 可以看到,在構造OMX的時候,會new一個OMXMaster給成員變量mMaster,這個mMaster是對OMXPluginBase(基類) 類型的插件的管理,其中各個插件在ICS的框架中就是軟硬件編解碼的插件。 #ifndef OMX_MASTER_H_ #define OMX_MASTER_H_ #include <media/stagefright/OMXPluginBase.h> #include <utils/threads.h> #include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/String8.h> namespace android { struct OMXMaster : public OMXPluginBase { OMXMaster(); virtual ~OMXMaster(); virtual OMX_ERRORTYPE makeComponentInstance( //符合OpenMAX標準的接口 const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component); virtual OMX_ERRORTYPE destroyComponentInstance( //符合OpenMAX標準的接口 OMX_COMPONENTTYPE *component); virtual OMX_ERRORTYPE enumerateComponents( //符合OpenMAX標準的接口 OMX_STRING name, size_t size, OMX_U32 index); virtual OMX_ERRORTYPE getRolesOfComponent( //符合OpenMAX標準的接口 const char *name, Vector<String8> *roles); private: Mutex mLock; List<OMXPluginBase *> mPlugins; KeyedVector<String8, OMXPluginBase *> mPluginByComponentName; KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> mPluginByInstance; void *mVendorLibHandle; void addVendorPlugin(); void addPlugin(const char *libname); void addPlugin(OMXPluginBase *plugin); void clearPlugins(); OMXMaster(const OMXMaster &); OMXMaster &operator=(const OMXMaster &); }; } // namespace android #endif // OMX_MASTER_H_ -----到目前爲止,android2.3和ICS在該部分沒有明顯區別----- 在OMXMaster的構造函數中,就開始不同了。 ////2.3//// OMXMaster::OMXMaster() : mVendorLibHandle(NULL) { addVendorPlugin(); #ifndef NO_OPENCORE addPlugin(new OMXPVCodecsPlugin); #endif } 2.3中,硬解部分還是使用原來OMX的標準來進行即addVendorPlugin(),然後軟件部分的話,在這裏沒有說明, 事實上軟件部分,2.3之間返回了XXXDecoder ////4.0//// OMXMaster::OMXMaster() : mVendorLibHandle(NULL) { addVendorPlugin(); addPlugin(new SoftOMXPlugin); } 4.0上對於軟硬編解碼,都使用OMX標準,掛載plugins的方式來進行。軟解部分使用addPlugin(new SoftOMXPlugin)。
///////////////////////////////////////////// //2,一個重要的類OMXCodecObserver ///////////////////////////////////////////// OMXCodecObserver是一個OMXCodec的內部類,它在OMXCodec的Create函數中會實例化一個,並且使用observer->setCodec(codec) 接口,對一個OMXCodec進行管理。OMXCodecObserver還有一個接口onMessage,其作用是對由observer管理的codec進行消息處理, 這個位於OMXCodecObserver的onMessage函數是一個統一的入口,具體的消息處理,由被observer管理的codec自己實現。 ///////////////////////////////////////////// //3,在OMXCodec的create中還做了些什麼 ///////////////////////////////////////////// 現在看看相關的代碼片段 sp<MediaSource> OMXCodec::Create( const sp<IOMX> &omx, const sp<MetaData> &meta, bool createEncoder, const sp<MediaSource> &source, const char *matchComponentName, uint32_t flags, const sp<ANativeWindow> &nativeWindow) { int32_t requiresSecureBuffers; if (source->getFormat()->findInt32( kKeyRequiresSecureBuffers, &requiresSecureBuffers) && requiresSecureBuffers) { flags |= kIgnoreCodecSpecificData; flags |= kUseSecureInputBuffers; flags |= kEnableGrallocUsageProtected; } else { flags &= ~kEnableGrallocUsageProtected; } const char *mime; bool success = meta->findCString(kKeyMIMEType, &mime); CHECK(success); Vector<String8> matchingCodecs; findMatchingCodecs( mime, createEncoder, matchComponentName, flags, &matchingCodecs); if (matchingCodecs.isEmpty()) { return NULL; } sp<OMXCodecObserver> observer = new OMXCodecObserver; IOMX::node_id node = 0; for (size_t i = 0; i < matchingCodecs.size(); ++i) { const char *componentNameBase = matchingCodecs[i].string(); const char *componentName = componentNameBase; AString tmp; if (flags & kUseSecureInputBuffers) { tmp = componentNameBase; tmp.append(".secure"); componentName = tmp.c_str(); } ... status_t err = omx->allocateNode(componentName, observer, &node); ... sp<OMXCodec> codec = new OMXCodec( omx, node, quirks, flags, createEncoder, mime, componentName, source, nativeWindow); observer->setCodec(codec); err = codec->configureCodec(meta); if (err == OK) { if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) { codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime; } return codec; ... return NULL; } 從OMXCodec::Create的代碼中可以看到,這個Create函數主要做了一下幾件事: //這裏,根據mime的類型,先找到對應的容器格式,然後把這個ComponentName放到matchingCodecs中。如果有指定的容器話,作爲實參傳遞給matchComponentName。 1,findMatchingCodecs(mime, createEncoder, matchComponentName, flags, &matchingCodecs); //實例化一個OMXCodecObserver,作用上面有提到,然後給即將創建的node分配一個node_id,id號被初始化爲0 2,sp<OMXCodecObserver> observer = new OMXCodecObserver; IOMX::node_id node = 0; //allocateNode函數會通過binder調用到服務端的OMX::allocateNode,函數的具體實現如下 3,status_t err = omx->allocateNode(componentName, observer, &node); status_t OMX::allocateNode( const char *name, const sp<IOMXObserver> &observer, node_id *node) { Mutex::Autolock autoLock(mLock); *node = 0; //OMXNodeInstance,與node_id一一對應,指的是OMX標準下node的實例,這個OMXNodeInstance內部封裝了一下對不同實例的操作,以及回調。 OMXNodeInstance *instance = new OMXNodeInstance(this, observer); OMX_COMPONENTTYPE *handle; //這裏會一直調用具體的OMXPlugins的的的makeComponentInstance函數,假設這裏的具體OMX plugin是SoftOMXPlugin,那麼 //SoftOMXPlugin的makeComponentInstance函數會根據容器名來動態的打開一個名爲llibstagefright_soft_XXX.so的的動態庫 //然後使用ddlopen和dlsym來來調用這個so中的函數。這個操作完成之後,會在底層對應一個具體的編解碼組件,例如SoftMPEG4,並對 //這個編解碼組件進行初始化,例如initPorts(),initDecoder()...... OMX_ERRORTYPE err = mMaster->makeComponentInstance( name, &OMXNodeInstance::kCallbacks, instance, &handle); if (err != OMX_ErrorNone) { LOGV("FAILED to allocate omx component '%s'", name); instance->onGetHandleFailed(); return UNKNOWN_ERROR; } *node = makeNodeID(instance); //首先由node_id來區分不同的node,然後給各個不同的node實例化一個CallbackDispatcher來與之對應,這個CallbackDispatcher //靠OMXNodeInstance instance來區分。CallbackDispatcher在實例化之後,內部會開啓一個線程,這個線程循環的監聽List<omx_message> mQueue; //看看是否有新的omx_message被分派過來。如果有就dispatch(msg)。 mDispatchers.add(*node, new CallbackDispatcher(instance)); //給這個OMXNodeInstance綁定一個node_id,和handler,這個handler是上面mMaster->makeComponentInstance傳出的。 instance->setHandle(*node, handle); mLiveNodes.add(observer->asBinder(), instance); observer->asBinder()->linkToDeath(this); return OK; } //在框架層實例化一個OOMXCodec 4,sp<OMXCodec> codec = new OMXCodec( omx, node, quirks, flags, createEncoder, mime, componentName, source, nativeWindow); //將前面的codec拉入observer的管理 observer->setCodec(codec); //根據媒體流的format對codec進行一些配置 err = codec->configureCodec(meta); 下面來看張圖: 從上面的時序圖看一看出omx在stagefright框架中的條用關係, 1,在awesomeplayer中,有一個OMXClient成員變量mClient,作用與服務端OMX交互的代理。 2,stagefright框架通過OMXCodec進入到OMX(即OMX的服務端) 3,通過服務端的OMX去和具體的OMXNodeInstance還有編解碼Components打交道。 4,回調機制可以從圖中看出來,是通過CallbackDispatcher分派消息,然後一層一層的往上調用onMessage().
節約篇幅再開一篇