awesomeplayer_openmax 初始化分析

我们知道stagefright进行编解码的流控是基于OMX的。
首先我们总结一下OMX的初始化部分。

此文借鉴了以下几篇文章。感谢作者
http://blog.csdn.net/hellofeiya/article/details/8601168
http://blog.csdn.net/tjy1985/article/details/7926133
http://blog.csdn.net/tjy1985/article/details/7397752

一,整体结构

Android的播放器被抽象成一个叫MediaPlayer的类,播放本地视频的时候使用的是AwesomePlayer的类。

MediaPlayer初始化时,通过setdataSource 获得了mVideoTrack,mAudioTrack。
如下: 
status_t MediaPlayer::setDataSource(
        const char *url, const KeyedVector *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp& service(getMediaPlayerService());
        if (service != 0) {
            sp player(service->create(this, mAudioSessionId));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}
 status_t AwesomePlayer::setDataSource_l(const sp &extractor) {…
if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) {
            setVideoSource(extractor->getTrack(i));}
else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) {
            setAudioSource(extractor->getTrack(i));
.....
}
}
void AwesomePlayer::setVideoSource(sp source) {
    CHECK(source != NULL);
    mVideoTrack = source;
}
void AwesomePlayer::setAudioSource(sp source) {
    CHECK(source != NULL);
    mAudioTrack = source;
}
 awesomeplayer初始化的时候,在prepare中获得了mVideoSourc,mAudioSource。

会调用到下面的prepareAsync_l

status_t AwesomePlayer::prepareAsync_l() {
    if (!mQueueStarted) {
        mQueue.start();
        mQueueStarted = true;
    }
    modifyFlags(PREPARING, SET);
    mAsyncPrepareEvent = new AwesomeEvent(
            this, &AwesomePlayer::onPrepareAsyncEvent);
    mQueue.postEvent(mAsyncPrepareEvent);
    return OK;
}
mAsyncPrepareEvent被触发的时候,调用onPrepareAsyncEvent函数,继而调用beginPrepareAsync_l。
过程中会调用:
status_t AwesomePlayer::initVideoDecoder()
status_t AwesomePlayer::initAudioDecoder()
这两个函数里面会分别初始化mAudioSource,mVideoSource
如下: 
void AwesomePlayer::beginPrepareAsync_l() {
    if (mVideoTrack != NULL && mVideoSource == NULL) {
        status_t err = initVideoDecoder();
        if (err != OK) {
            abortPrepare(err);
            return;
        }
    }
    if (mAudioTrack != NULL && mAudioSource == NULL) {
        status_t err = initAudioDecoder();
        if (err != OK) {
            abortPrepare(err);
            return;
        }
    }
} 

status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 
.....
mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack,
            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
.....
}

status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 
.... 
mAudioSource = OMXCodec::Create(
                mClient.interface(), mAudioTrack->getFormat(),
                false, // createEncoder
                mAudioTrack);
....
}
android系统中用openmax来做编解码,所以android向上抽象了一层OMXCodec,提供给上层播放器AwesomePlayer用。
播放器中音视频解码器mVideosource、mAudiosource都是OMXCodec的实例。
OMXCodec::Create是解码器初始化的入口。
OMXCodec通过IOMX 依赖binder机制 获得 OMX服务,OMX服务 才是openmax 在android中 实现
 参见图一,图二:


awesomeplayer_openmax 初始化分析_第1张图片

awesomeplayer_openmax 初始化分析_第2张图片

 
二,一些初始化的流程

AwesomePlayer是如何获得OMX服务的?
在AwesomePlayer初始化的时候,会调用 AwesomePlayer::onPrepareAsyncEvent。
继而调用AwesomePlayer::initVideoDecoder以及AwesomePlayer:: initAudioDecoder。
然后开始正式的进入OMX以及硬件解码器的初始化工作。
之前的AwesomePlayer初始化的一些工作都是在跑龙套。只有这里才是开始真正核心的初始化工作。
我们知道,android中的组件都是在提供服务,有server,有client,多媒体也不例外。
AwesomePlayer 中有个变量 OMXClient  mClient;  

类定义是:

class OMXClient {   
public:   
    OMXClient();   
       status_t connect();   
    void disconnect();   
       sp interface() {   
        return mOMX;   
    }   
   private:   
    sp mOMX;   
       OMXClient(const OMXClient &);   
    OMXClient &operator=(const OMXClient &);   
};  
OMXClient 有个IOMX 的变量 mOMX ,这个就是和OMX服务进行binder通讯的。

在 AwesomePlayer 的构造函数中会调用:
CHECK_EQ(mClient.connect(), (status_t)OK);  
定义如下
status_t OMXClient::connect() {   
    sp sm = defaultServiceManager();   
    sp binder = sm->getService(String16("media.player"));   
    sp service = interface_cast(binder);   
       CHECK(service.get() != NULL);   
       mOMX = service->getOMX();   
    CHECK(mOMX.get() != NULL);   
       if (!mOMX->livesLocally(NULL /* node */, getpid())) {   
        ALOGI("Using client-side OMX mux.");   
        mOMX = new MuxOMX(mOMX);   
    }   
       return OK;   
}  
sp MediaPlayerService::getOMX() {   
    Mutex::Autolock autoLock(mLock);   
       if (mOMX.get() == NULL) {   
        mOMX = new OMX;   //实例化一个OMX
    }   
       return mOMX;   
}  
OMXClient::connect函数是通过binder机制 获得到MediaPlayerService,然后通过MediaPlayerService来创建OMX的实例。
这样OMXClient就获得到了OMX的入口,接下来就可以通过binder机制来获得OMX提供的服务。
也就是说OMXClient 是android中 openmax 的入口。

在创建音视频解码mVideoSource、mAudioSource的时候会把OMXClient中的sp mOMX的实例 传给mVideoSource、mAudioSource来共享使用这个OMX的入口。

也就是说一个AwesomePlayer对应着 一个IOMX 变量,AwesomePlayer中的音视频解码器共用这个IOMX变量来获得OMX服务。

  sp interface() {
        return mOMX;
}
status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
…………
mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack,
            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
…………..
 
  status_t err = mVideoSource->start();
}
其中重点是OMXCodec::Create函数
sp OMXCodec::Create(  
        const sp &omx,  
        const sp &meta, bool createEncoder,  
        const sp &source,  
        const char *matchComponentName,  
        uint32_t flags,  
        const sp &nativeWindow) {  
    int32_t requiresSecureBuffers;  
    const char *mime;  
    bool success = meta->findCString(kKeyMIMEType, &mime);  
    CHECK(success);  
    Vector matchingCodecs;  
    Vector matchingCodecQuirks;  
    findMatchingCodecs(  
            mime, createEncoder, matchComponentName, flags,  
            &matchingCodecs, &matchingCodecQuirks);  
  //根据mVideoTrack传进来的视频格式信息,查找相匹配的解码器。
    sp observer = new OMXCodecObserver;  
    IOMX::node_id node = 0;  
  //创建OMXCodecObserver 实例,OMXCodecObserver功能后续会详细介绍。
    for (size_t i = 0; i < matchingCodecs.size(); ++i) {  
        const char *componentNameBase = matchingCodecs[i].string();  
        uint32_t quirks = matchingCodecQuirks[i];  
        const char *componentName = componentNameBase;  
        AString tmp;  
        status_t err = omx->allocateNode(componentName, observer, &node);  
  //通过omx入口 依靠binder 机制调用OMX服务中的allocateNode(),这一步把匹配得到的解码器组件名、OMXCodecObserver实例和初始化为0的node一并传入。
  //这一步实际上是分配一个对解码器的控制结点。后续对解码器的操作,都依靠这个node
        if (err == OK) {  
            ALOGV("Successfully allocated OMX node '%s'", componentName);  
              sp 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;  
            }  
              ALOGV("Failed to configure codec '%s'", componentName);  
        }  
    }  
    return NULL;  
}  
每个AwesomePlayer实例 只有一个OMX服务的入口,但是AwesomePlayer不一定就只需要1种解码器。音视频都要有,部分场景下还有多路音频,或者多路视频。
这个时候OMX那头需要建立不同的解码器的组件来对应着AwesomePlayer中不同的解码需求。
OMX中非常重要的2个成员: OMXMaster 和 OMXNodeInstance。
OMX通过这俩个成员来创建和维护不同的openmax 解码器组件,为AwesomePlayer中不同解码需求提供服务。
OMXNodeInstance 负责创建并维护不同的实例,这些实例是根据实际的解码需求创建的,以node_id作为唯一标识。
这样解码器组件中每个OMXCodec在OMX服务端都对应有了自己的OMXNodeInstance实例。AwesomePlayer就可以根据这个OMXNodeInstance来操作相应解码器
OMXMaster 维护底层软硬件解码库,是对解码器组件的一个大管家,根据OMXNodeInstance中想要的解码器来创建解码实体组件。

所以我们要分析一下OMXMaster和OMXNodeInstance。

OMX构造函数中会进行初始化。

OMXMaster *mMaster;
OMX::OMX()   
    : mMaster(new OMXMaster),   
      mNodeCounter(0) {   
}  
OMXMaster::OMXMaster()   
    : mVendorLibHandle(NULL) {   
    addVendorPlugin();   
    addPlugin(new SoftOMXPlugin);   
} 
void OMXMaster::addVendorPlugin() {
    addPlugin("libstagefrighthw.so");
}
void OMXMaster::addPlugin(const char *libname) {
    mVendorLibHandle = dlopen(libname, RTLD_NOW);
…………………………….
    if (createOMXPlugin) {
        addPlugin((*createOMXPlugin)());-----创建OMXPlugin,并添加进我们的列表里
    }
}
OMXPluginBase *createOMXPlugin() {
    return new ExynosOMXPlugin;
}
ExynosOMXPlugin::ExynosOMXPlugin()
    : mLibHandle(dlopen("libExynosOMX_Core.so", RTLD_NOW)),
      mInit(NULL),
      mDeinit(NULL),
      mComponentNameEnum(NULL),
      mGetHandle(NULL),
      mFreeHandle(NULL),
      mGetRolesOfComponentHandle(NULL) {
    if (mLibHandle != NULL) {
        mInit = (InitFunc)dlsym(mLibHandle, "Exynos_OMX_Init");
        mDeinit = (DeinitFunc)dlsym(mLibHandle, "Exynos_OMX_Deinit");
        mComponentNameEnum =
            (ComponentNameEnumFunc)dlsym(mLibHandle, "Exynos_OMX_ComponentNameEnum");
        mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "Exynos_OMX_GetHandle");
        mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "Exynos_OMX_FreeHandle");
        mGetRolesOfComponentHandle =
            (GetRolesOfComponentFunc)dlsym(
                    mLibHandle, "Exynos_OMX_GetRolesOfComponent");
        (*mInit)();
    }
}
这样,就可以使用exynos 处理器的解码器了。
到这里,我们就明白了AwesomePlayer是如何利用具体的硬件平台上的硬件解码器。例如上面说的exynos平台的mfc decoder。

那么针对不同的文件格式,如何选择具体的解码器组件呢?
继续顺着前面的OMXCodec::Create介绍。看一下allocateNode
status_t OMX::allocateNode(  
        const char *name, const sp &observer, node_id *node) {  
    Mutex::Autolock autoLock(mLock);  
      *node = 0;  
      OMXNodeInstance *instance = new OMXNodeInstance(this, observer);  
      OMX_COMPONENTTYPE *handle;  
    OMX_ERRORTYPE err = mMaster->makeComponentInstance(  
            name, &OMXNodeInstance::kCallbacks,  
            instance, &handle);  
      if (err != OMX_ErrorNone) {  
        ALOGV("FAILED to allocate omx component '%s'", name);  
          instance->onGetHandleFailed();  
          return UNKNOWN_ERROR;  
    }  
      *node = makeNodeID(instance);  
    mDispatchers.add(*node, new CallbackDispatcher(instance));  
      instance->setHandle(*node, handle);  
      mLiveNodes.add(observer->asBinder(), instance);  
    observer->asBinder()->linkToDeath(this);  
      return OK;  
}  

可以看到,用mMaster来创建component
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    Mutex::Autolock autoLock(mLock);
     *component = NULL;
 ssize_t index = mPluginByComponentName.indexOfKey(String8(name)); 
//根据我们在media_codec.xml的解码器名字,在插件列表找到其索引
 源码路径中,./device/samsung/exynos4412/media_profiles.xml,里面定义了解码器的类型,full build 后会保存在“/etc/media_codecs.xml”,
OMXPluginBase *plugin = mPluginByComponentName.valueAt(index); 
//根据索引找到ExynosOMXPlugin
    OMX_ERRORTYPE err =
        plugin->makeComponentInstance(name, callbacks, appData, component);
       mPluginByInstance.add(*component, plugin);
     return err;
}
OMX_ERRORTYPE ExynosOMXPlugin::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    if (mLibHandle == NULL) {
        return OMX_ErrorUndefined;
    }
    return (*mGetHandle)(
            reinterpret_cast(component),
            const_cast(name),
            appData, const_cast(callbacks));
}

这样就实现了根据文件编码格式,对具体解码器的挂接
下面讲一下OMXcodec如何注册和初始化OMX所需要的回调函数。
OMX服务主要完成三个任务: NodeInstance列表的管理,NodeInstance的操作,事件的处理。

1、NodeInstance列表的管理。
前面我们介绍过,OMX对解码器组件component的使用,是通过OMXNodeInstance来实现的。
OMXNodeInstance自身的动作包括NodeInstance的生成(allocateNode)和删除(freeNode)。
其实就是对mDispatchers和 mNodeIDToInstance进行添加和删除。
mNodeIDToInstance就是一个key为node_id,value为 NodeInstance的名值对列表。
而mDispatchers就是一个key为node_id,value为 OMX::CallbackDispatcher的名值对列表。
并且,一个NodeInstance都拥有一个 OMX::CallbackDispatcher。
CallbackDispatcher的作用主要是解码器组件component发出回调动作后,将message分发给对应的OMXcodec客户端。


2、NodeInstance节点的操作。
OMXNodeInstance主要成员函数如下:
   struct OMXNodeInstance {
    OMXNodeInstance(
            OMX *owner, const sp &observer);
    void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
    status_t freeNode(OMXMaster *master);
    status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
    status_t getParameter(OMX_INDEXTYPE index, void *params, size_t size);
    status_t setParameter(OMX_INDEXTYPE index, const void *params, size_t size);
    status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
    status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
    status_t getState(OMX_STATETYPE* state);
    status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable);
    status_t getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage);
    status_t storeMetaDataInBuffers(OMX_U32 portIndex, OMX_BOOL enable);
    status_t prepareForAdaptivePlayback(
            OMX_U32 portIndex, OMX_BOOL enable,
            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
    status_t useBuffer(
            OMX_U32 portIndex, const sp ¶ms,
            OMX::buffer_id *buffer);//Client通过此函数将已分配好的Buffer传给Component,让其使用。
    status_t useGraphicBuffer(
            OMX_U32 portIndex, const sp &graphicBuffer,
            OMX::buffer_id *buffer);
    status_t updateGraphicBufferInMeta(
            OMX_U32 portIndex, const sp &graphicBuffer,
            OMX::buffer_id buffer);
    status_t createInputSurface(
            OMX_U32 portIndex, sp *bufferProducer);
    status_t signalEndOfInputStream();
    status_t allocateBuffer(
            OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
            void **buffer_data);//Client通过调用此函数让Component分配Buffer。
    status_t allocateBufferWithBackup(
            OMX_U32 portIndex, const sp ¶ms,
            OMX::buffer_id *buffer);
    status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);//Client通过调用此函数让Component释放allocateBuffer()分配的Buffer。
    status_t fillBuffer(OMX::buffer_id buffer);//Client通过调用此函数传递空的Buffer给Component,让其将处理好的数据填入其中。此函数会调用OMX标准接口OMX_FillThisBuffer()。
    status_t emptyBuffer(
            OMX::buffer_id buffer,
            OMX_U32 rangeOffset, OMX_U32 rangeLength,
            OMX_U32 flags, OMX_TICKS timestamp);//Client通过调用此函数传递输入Buffer给Component,让其读取其中的数据进行编解码等处理。此函数会调用OMX标准接口OMX_ 


    status_t emptyDirectBuffer(
            OMX_BUFFERHEADERTYPE *header,
            OMX_U32 rangeOffset, OMX_U32 rangeLength,
            OMX_U32 flags, OMX_TICKS timestamp);
    status_t getExtensionIndex(
            const char *parameterName, OMX_INDEXTYPE *index);
    status_t setInternalOption(
            OMX_U32 portIndex,
            IOMX::InternalOptionType type,
            const void *data,
            size_t size);
    void onMessage(const omx_message &msg);
    void onObserverDied(OMXMaster *master);
    void onGetHandleFailed();
    void onEvent(OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2);
    static OMX_CALLBACKTYPE kCallbacks;
        status_t useGraphicBuffer2_l(
            OMX_U32 portIndex, const sp &graphicBuffer,
            OMX::buffer_id *buffer);
    static OMX_ERRORTYPE OnEvent(
            OMX_IN OMX_HANDLETYPE hComponent,
            OMX_IN OMX_PTR pAppData,
            OMX_IN OMX_EVENTTYPE eEvent,
            OMX_IN OMX_U32 nData1,
            OMX_IN OMX_U32 nData2,
            OMX_IN OMX_PTR pEventData);
    static OMX_ERRORTYPE OnEmptyBufferDone(
            OMX_IN OMX_HANDLETYPE hComponent,
            OMX_IN OMX_PTR pAppData,
            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);// Component完成对输入buffer的读取后,调用此回调函数,向Client发送EmptyBufferDone消息。
    static OMX_ERRORTYPE OnFillBufferDone(
            OMX_IN OMX_HANDLETYPE hComponent,
            OMX_IN OMX_PTR pAppData,
            OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);//Component完成相应处理将输出数据填入输出Buffer后,调用此回调函数,向Client发送FillBufferDone消息。
    status_t storeMetaDataInBuffers_l(OMX_U32 portIndex, OMX_BOOL enable);
    sp getGraphicBufferSource();
    void setGraphicBufferSource(const sp& bufferSource);
    OMXNodeInstance(const OMXNodeInstance &);
    OMXNodeInstance &operator=(const OMXNodeInstance &);
};
这些方法执行时,都是先通过findInstance在mNodeIDToInstance列表中找到对应的NodeInstance,然后调用NodeInstance对应的方法。

3、事件处理
通过前面的分析,我们知道,OMXCodec对具体的component方法的操作,是通过OMXNodeInstance来实现的。
如fillBuffer,emptybuffer,sendCommand等,都是通过OMX_Core.h中的宏定义间接调用OMX_Component.h中的OMX_COMPONENTTYPE这个struct中的相应函数指针来完成。
在这里提到的OMX_Core.h和 OMX_Component.h都是OpenMAX标准头文件。
例如OMXNodeInstance.cpp中的这样一段代码:
OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
     &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
 };
  它把三个OMXNodeInstance类的静态方法注册给了kCallbacks。
  kCallbacks实际就是struct OMX_COMPONENTTYPE和struct OMX_CALLBACKTYPE的具体实现。
  而这两者就是在OMX_Core.h和 OMX_Component.h中定义的。
    kCallbacks在哪里使用呢?看一下OMX.cpp中的allocateNode方法中的代码:
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
             name, &OMXNodeInstance::kCallbacks,
             instance, &handle);
事件处理函数传给了组件ComponentInstance。也就是传给了具体芯片平台相关的OMX IL 层。
当组件有事件发生时,就会调用OMXNodeInstance中这几个注册过的事件处理函数:
OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone
OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone
OMX_ERRORTYPE OMXNodeInstance::OnEvent
而这几个函数又会去调用OMX中对应的函数,也就是下面这三个:
OMX_ERRORTYPE OMX::OnEmptyBufferDone
OMX_ERRORTYPE OMX::OnFillBufferDone
OMX_ERRORTYPE OMX::OnEvent
总结一下, 这几个方法都采用相同的路子:
根据node_id找到CallbackDispatcher,并把事件信息post过去。
也就是:findDispatcher(node)->post(msg)。

这里不得不提一下CallbackDispatcher的实现机制。它内部开启了一个线程,使用了信号量机制。
findDispatcher(node)->post(msg)是一个异步操作,只把msg给POST过去,不会等待事件处理完毕就返回了。
那么CallbackDispatcher是怎么处理接收到的msg呢?
看以下代码:
bool OMX::CallbackDispatcher::loop() {
    for (;;) {
        omx_message msg;
        {
            Mutex::Autolock autoLock(mLock);
            while (!mDone && mQueue.empty()) {
                mQueueChanged.wait(mLock);
            }
            if (mDone) {
                break;
            }
            msg = *mQueue.begin();
            mQueue.erase(mQueue.begin());
        }
        dispatch(msg);
    }
    return false;
} 

这样事件最终还是跨越Binder又传到了OMXCodec里面去,交给OMXCodecObserver了。也就是交给了调用OMX service的client端了。
将回调的发生,从service端发送到了client端。
至于到了client端以后再干什么事情,我们后面再讲。

最后,我们总结一下前面所讲:
1.AwesomePlayer初始化过程中,中通过initVideoDecoder / init AudioDecoder来创建video/Audio解码器mVideoSource/mAudioSource
2.mVideoSource 中通过mVideoTrack来demux 媒体文件,从中获得文件编码格式,继而得到需要的解码器类型,通过类型调用omx->allocateNode 创建OMX node实例与编码格式对应。以后都是通过node实例来操作实际的硬件解码器。
3. MediaPlayerService对象初始化的时候会创建OMX对象,OMX对象的构造函数会创建mMaster,mMaster负责获得与管理硬件平台的硬件解码器组件库。
4,在 omx->allocateNode中 通过mMaster->makeComponentInstance 来创建真正对应的解码器组件。这个解码器组件是完成之后实质的解码工作的。
5.在创建mMaster->makeComponentInstance过程中,也是通过上面mVideoTrack 过来的解码器类型名,找到相对应的解码器的库,然后实例化。
6.解码Component通过输入Port和输出Port来进行交互,通过和OMXCodec共享buffer来进行编解码。
7.AwesomePlayer中包含了mVideoSource,初始化时指向OMXCodec的实际对象。OMXCodec使用了Binder机制,实现了对OMX服务的远程调用,其中IOMX作为接口类定义了OMX的大部分接口函数。
8.OMX的具体实现时,OMXMaster类用于管理OMX的插件,OMXNodeInstance类代表OMX的具体实例,完成和Component的调用和交互,
9.CallbackDispatcher用于调度处理回调函数传回的消息。OMXNodeInstance和CallbackDispatcher一一对应,协同工作,完成不同实例的消息处理。
10.OMXNodeInstance是OMX端的概念,是service端的概念。其service端与OMX在一个进程空间中。
11.OMXObserver是OMXCodec端的概念,是client端的概念。其service端与OMXCodec在一个进程空间中。其Bn,Bp 方向和OMX,OMXNodeInstance相反。主要是用来反向通知onMessage消息
到此,我们就介绍完了awesomeplayer是如何对OMX初始化,以及如何关联到对应硬件平台上的HW decoder的。

你可能感兴趣的:(android,编解码)