Android_ics openmax in stagefright 學習記錄------1

這幾篇文章是之前學習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> &params,
            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> &params,
            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().


節約篇幅再開一篇


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章