• Android音视频——OMX 中 Nodeinstance 列表的管理与节点的操作


    在我们创建Componentinstance (OMX组件实例)后,需要对它里面的Nodelnstance列表 进行管理。

    • OMX对解码器组件Component的使用,是通过OMXNodelnstance来实现的。 OMXNodelnstance
      自身的动作包括 Nodeinstance 的生成(allocateNode )和删除
      (freeNode)o其实就是对niDispatchers和mNode】DToInstance进行添加和删除。
    • mNodelDToInstance 就是一个 key 为 node id» value 为 Nodeinstance 的键/值对列表。而
      niDispatchers 就是一个 key 为 node id, value 为 OMX::CallbackDispatcher
      的键/值对列 表。并且,每个 Nodeinstance 都拥有一个 0MX::CalIbackDispatchero
    • CallbackDispatcher的主要作用是在解码器组件Component发出回调动作后,将message
      分发给对应的OMXCodec客户端。

    在我们了解到OMXNodelnstance列表管理后,每个OMXNodelnstance中都有Node节 点,若你需要给这些Node节点分配一些Buffer,下面看看对Node节点的操作过程。
    在/frameworks/av/media/libstagefright/include/OMXNodeInstance.h 中:

    struct OMXNodeInstance {
        OMXNodeInstance(
                OMX *owner, const sp<IOMXObserver> &observer, const char *name);
                 void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
     status_t prepareForAdaptivePlayback(
                OMX_U32 portIndex, OMX_BOOL enable,
               OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight);
        status_t useBuffer(
               OMX_U32 portIndex, const sp<IMemory> &params,
                OMX::buffer_id *buffer, OMX_U32 allottedSize);
    //OMX: :Client通过此鹵数将已分配好的Buffer传给OMX服务器端组件,让其使用
    
     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<IMemory> &params,
               OMX::buffer_id *buffer, OMX_U32 allottedSize);
     status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
     //Client通过调用此函数让Component释放allocateBuffer分配的Buffer
     status_t fillBuffer(OMX::buffer_id buffer, int fenceFd);
     //Client通过调用此函数传递空的Buffer给Component»让其将处理好的
    //数据填入其中。此函数会调用OMX标准接口 OMX_FillThisBuffer 
    
     static OMX_ERRORTYPE OnEmptyBufferDone(
               OMX_IN OMX_HANDLETYPE hComponent,
                OMX_IN OMX_PTR pAppData,
             OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
    //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 消息
    
    sp<GraphicBufferSource> getGraphicBufferSource();
       void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
    
        // 处理| msg 124;,并可以对其进行修改。返回true iff完全处理并 
        // |msg| does not need to be sent to the event listener.
        bool handleMessage(omx_message &msg);
        OMXNodeInstance(const OMXNodeInstance &);
        OMXNodeInstance &operator=(const OMXNodeInstance &);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    当执行这些函数时,都是先通过findinstance在mNodelDToInstance列表中找到对应的 Nodeinstance,然后调用Nodelnstance对应的方法。
    OMXCodec对具体的component函数的操作,是通过OMXNodelnstance来实现的,如 filIBuffer> emptyBuffer> sendCommand等,它们都是通过OMX Core.h中的宏定义间接调用 OMX_Component.h 的 OMX_COMPONENTTYPE 中的相应函数指针来完成的。OMX_Core.h 和OMX_Compoiient.h都是OpenMAX标准头文件。

    OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
    };
    它把3个OMXNodelnstance类的静态方法注册给了 kCallbacks。kCallbacks实际就是struct OMX COMPONENTTYPE和struct OMX_CALLBACKTYPE的具体实现,而这两者就是在 OMX Core.h 和 OMX_Component.h 中定义的。
    在哪里使用kCallbacks呢?下面看看OMX.cpp中的allocateNode函数:

    status_t OMX::allocateNode(
            const char *name, const sp<IOMXObserver> &observer, node_id *node) {
       Mutex::Autolock autoLock(mLock);
    
       *node = 0;
    
        OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
    
        OMX_COMPONENTTYPE *handle;
        OMX_ERRORTYPE err = mMaster->makeComponentInstance(
               name, &OMXNodeInstance::kCallbacks,
                instance, &handle);
    
        if (err != OMX_ErrorNone) {
            ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
    
           instance->onGetHandleFailed();
    
           return StatusFromOMXError(err);
        }
    
        *node = makeNodeID(instance);
        mDispatchers.add(*node, new CallbackDispatcher(instance));
    
        instance->setHandle(*node, handle);
    
        mLiveNodes.add(IInterface::asBinder(observer), instance);
        IInterface::asBinder(observer)->linkToDeath(this);
    
        return OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    事件处理函数传给了组件Componentinstance,也就是传给了具体芯片平台相关的OMX IL 层。
    当组件有事件发生时,就会调用OMXNodelnstance中这几个注册过的事件处理函数:

    OMX_ERRORTYPE OMXNodelnstance::OnEmptyBufferDone
    OMX_ERRORTYPE OMXNodelnstance::OnFillBufferDone
    OMX_ERRORTYPE OMXNodelnstance::OnEvent
    而这几个函数又会调用OMX中对应的函数,也就是下面这3个函数:
    OMX_ERRORTYPE OMX::OnEmptyBufferDone
    OMX_ERRORTYPE OMX::OnFillBufferDone
    OMX_ERRORTYPE OMX::OnEvent
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    总结一下,这儿个函数都采用相同的方式,即根据n odeid找到Cal I back Dispatcher,并把 事件信息传递出去,也就是findDispatcher(node)->post(msg)o
    进一步地,需要了解CallbackDispatcher的实现机制。它内部开启了一个线程,使用了信 号量(signal)机制。
    findDispatcher(node)->post(msg)是一个异步操作,只把消息传递过去,不会等待事件处理 完毕就返回。
    问题来了,那么CallbackDispatcher是怎么处理接收到的消息的呢?查看以下代码:

    bool OMX::CallbackDispatcher::loop() {
        for (;;) {
            std::list<omx_message> messages;
            {
                Mutex::Autolock autoLock(mLock);
               while (!mDone && mQueue.empty()) {
                    mQueueChanged.wait(mLock);
                }
                if (mDone) {
                    break;
                }
               messages.swap(mQueue);
            }
            dispatch(messages);
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这样事件最终还是跨Binder传到OMXCodec里面,交给OMXCodecObserver 了« •旦有 关于回调的过程,再从OMX服务器端发送到OMX客户端。我们又知道AwesomePlayer类中 持有OMX客户端,所以这些从OMX组件通知上来的消息就可以到达AwesomePlayer中。这 样就完成了 AwesomePlayer和OMX组件之间的通信。

  • 相关阅读:
    文件逻辑结构与物理结构对比(从用户,操作系统的角度)
    GAMES101复习:光栅化
    静态类和非静态类的区别
    Codeforces Round #808 (Div. 2) C【二分】【贪心】【反向贪心】
    docker在java项目中打成tar包
    从0到1:CTFer成长之路——死亡 Ping 命令
    2017年某高校848数据结构真题复习
    SQL查询语句之查询数据
    NSSCTF第12页(3)
    深度学习理论知识入门【EM算法、VAE算法、GAN算法】和【RBM算法、MCMC算法、HMC算法】
  • 原文地址:https://blog.csdn.net/qq_25749749/article/details/126088694