这几篇文章是之前学习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().
节约篇幅再开一篇