OMX组件消息回调机制详解

一、引入:
在前面分享MediaCodec和ACodec状态机的时候(MediaCodec(native)状态机分析ACodec状态机分析),有讲过各个状态机都是根据底层OMX状态机来的,而OMX的状态想要被上层ACodec和MediaCodec掌握,需要搞懂OMX的消息回调机制是怎么实现的,这篇博客将详细分析下回调函数的注册及消息上报。

二、回调函数的注册:
1.ACodec在申请omx组件时,会获取OMX服务申请组件:

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
    
    
	...
	err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
	...
}

跟进至omx.cpp:

Return<void> Omx::allocateNode(
        const hidl_string& name,
        const sp<IOmxObserver>& observer,
        allocateNode_cb _hidl_cb) {
    
    

		...
		/* 实例化Node */
        instance = new OMXNodeInstance(
              this, new LWOmxObserver(observer), name.c_str());
        OMX_COMPONENTTYPE *handle;
        /* 将Node中的回调函数注册到omxmstar中 */
        OMX_ERRORTYPE err = mMaster->makeComponentInstance(
                name.c_str(), &OMXNodeInstance::kCallbacks,
                instance.get(), &handle);
}

首先会申请Node,并且将Node中的回调函数通过OMXMaster注册到底层的OMX组件中。OMXNodeInstance::kCallbacks是一个实例化的结构体对象,其类型为OMX_CALLBACKTYPE,里面包含了三个函数指针,分别是:

typedef struct OMX_CALLBACKTYPE
{
    
    
   OMX_ERRORTYPE (*EventHandler)(
        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);
    OMX_ERRORTYPE (*EmptyBufferDone)(
        OMX_IN OMX_HANDLETYPE hComponent,
        OMX_IN OMX_PTR pAppData,
        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
    OMX_ERRORTYPE (*FillBufferDone)(
        OMX_OUT OMX_HANDLETYPE hComponent,
        OMX_OUT OMX_PTR pAppData,
        OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);

} OMX_CALLBACKTYPE;

EventHandler用于处理消息事件的回调,EmptyBufferDoneFillBufferDone用于底层OMX组件对于数据的处理,本博客只分析EventHandler,剩下的会在后面的博客进行分析。再看看OMXNodeInstance中这三个函数指针的指向:

OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    
    
    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
};

也就是说,OMX底层回调上来的信息是在OnEvent函数中去处理的。
继续跟进看一下回调函数是如何注册到OMX底层组件中的:

OMX_ERRORTYPE OMXMaster::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    
    
	...
	/* plugin即芯片平台的OMX硬解库 */
    OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
    OMX_ERRORTYPE err =
        plugin->makeComponentInstance(name, callbacks, appData, component);
	...
}

callbacks即为Node传下来的回调函数。看一下芯片平台对这个函数的实现:

OMX_ERRORTYPE MSOMXPlugin::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    
    
    ALOGV("MSOMXPlugin::makeComponentInstance");
    if (mLibHandle == NULL) {
    
    
        return OMX_ErrorUndefined;
    }

    return (*mGetHandle)(
            reinterpret_cast<OMX_HANDLETYPE *>(component),
            const_cast<char *>(name),
            appData, const_cast<OMX_CALLBACKTYPE *>(callbacks));
}

直接返回mGetHandle指针指向的函数:

OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
    OMX_OUT OMX_HANDLETYPE *pHandle,
    OMX_IN  OMX_STRING cComponentName,
    OMX_IN  OMX_PTR pAppData,
    OMX_IN  OMX_CALLBACKTYPE *pCallBacks)
{
    
    
	...
    ret = loadComponent->pOMXComponent->SetCallbacks(loadComponent->pOMXComponent, pCallBacks, pAppData);
    ....
}

这里会直接将pCallBacks注册到具体的component中:

OMX_ERRORTYPE MS_OMX_SetCallbacks (
    OMX_IN OMX_HANDLETYPE    hComponent,
    OMX_IN OMX_CALLBACKTYPE* pCallbacks,
    OMX_IN OMX_PTR           pAppData)
{
    
    
	...
	pMSComponent = (MS_OMX_BAMSOMPONENT *)pOMXComponent->pComponentPrivate;
	...
    pMSComponent->callbacks = *pCallbacks;
    pMSComponent->callbackData = pAppData;
    ...
}

也就是说,后续OMX组件有消息要通知到上层的时候,直接调用pMSComponent->callbacks.EventHandle就可以了。

三、回调过程分析:
注册的过程比较简单,而回调的过程相对复杂一些。这里以ACodec设置OMX组件为OMX_StateLoaded为例,看下状态设置完成后,是如何通知到ACodec的。当OMX组件状态设置完成后,会调用回调函数通知上去:

    if (pMSComponent->callbacks.EventHandler != NULL) {
    
    
        if (ret == OMX_ErrorNone) {
    
    
                pMSComponent->callbacks.EventHandler((OMX_HANDLETYPE)pOMXComponent,
                pMSComponent->callbackData,
                OMX_EventCmdComplete, OMX_CommandStateSet,
                destState, NULL);
        } else {
    
    
                pMSComponent->callbacks.EventHandler((OMX_HANDLETYPE)pOMXComponent,
                pMSComponent->callbackData,
                OMX_EventError, ret, 0, NULL);
        }
    }

OMX_CommandStateSet为ACodec传下来的指令,OMX_EventCmdComplete代表OMX命令执行完成。
直接定位到[email protected]

OMX_ERRORTYPE OMXNodeInstance::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) {
    
    
	...
	OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
	...
	omx_message msg;
    msg.type = omx_message::EVENT;
    msg.fenceFd = -1;
    msg.u.event_data.event = eEvent;
    msg.u.event_data.data1 = nData1;
    msg.u.event_data.data2 = nData2;

    instance->mDispatcher->post(msg, true /* realTime */);

    return OMX_ErrorNone;
}

注意,回调上来的参数会被封装到omx_message中,然后投掷出去。onMessages将会对消息进行处理:

void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
    
    
    for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) {
    
    
    	/* node先处理msg */
        if (handleMessage(*it)) {
    
    
            messages.erase(it++);
        } else {
    
    
            ++it;
        }
    }
	/* 再次投递至ACodec */
    if (!messages.empty()) {
    
    
        mObserver->onMessages(messages);
    }
}

OMXNodeInstance会首先对消息进行处理,由于不是buffer的操作,所以这里不会做什么,重点是通过mObserver将消息再次发送出去。
那么这里的mObserver是什么时候赋值的?ACodec在申请OMX组件的时候,会调用onAllocateComponent去实例化一个observer,并将其注册到node中:

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
    
    
	...
	/* 1.创建observer */
	sp<CodecObserver> observer = new CodecObserver;
	...
	/* 2.申请omx组件 */
	err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
	...
	/* 3.创建notify并注册到observer中 */
	notify = new AMessage(kWhatOMXMessageList, mCodec);
    notify->setInt32("generation", ++mCodec->mNodeGeneration);
    observer->setNotificationMessage(notify);
}

所以,mObserver->onMessages对应的就是ACodec中的observer:

virtual void onMessages(const std::list<omx_message> &messages) {
    
    
	...
	switch (omx_msg.type) {
    
    
	    sp<AMessage> msg = new AMessage;
	    msg->setInt32("type", omx_msg.type);
	    switch (omx_msg.type) {
    
    
	        case omx_message::EVENT:
	        {
    
    
	            msg->setInt32("event", omx_msg.u.event_data.event);
	            msg->setInt32("data1", omx_msg.u.event_data.data1);
	            msg->setInt32("data2", omx_msg.u.event_data.data2);
	            break;
	        }
	        ...
	}
	...
	msgList->getList().push_back(msg);
	notify->setObject("messages", msgList);
	notify->post();
}

这个函数包含了两个重要信息,首先,是将omx_message中的重要信息填入到AMessage中,便于调用ACodec的AHandler进行处理,其次,这个AMessage不是直接就post出去了,而是推入到msgList中,再“套娃”到notify投递出去的,那么,这个notify对应的是什么消息呢?notify来自于CodecObserver的成员变量mNotify,这个msg也是在创建observer的时候完成的,onAllocateComponent中的注释三便是,也就是说,我们需要看ACodec中kWhatOMXMessageList消息是怎么处理的:

case ACodec::kWhatOMXMessageList:
{
    
    
    return checkOMXMessage(msg) ? onOMXMessageList(msg) : true;
}

因为返回的是true,所以看onOMXMessageList:

bool ACodec::BaseState::onOMXMessageList(const sp<AMessage> &msg) {
    
    
    sp<RefBase> obj;
    /* 1.获取msgList */
    CHECK(msg->findObject("messages", &obj));
    sp<MessageList> msgList = static_cast<MessageList *>(obj.get());

    bool receivedRenderedEvents = false;
    for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin();
          it != msgList->getList().cend(); ++it) {
    
    
         /* 2.设置kWhatOMXMessageItem消息类型 */
        (*it)->setWhat(ACodec::kWhatOMXMessageItem);
        /* 3.处理msg */
        mCodec->handleMessage(*it);
        int32_t type;
        CHECK((*it)->findInt32("type", &type));
        if (type == omx_message::FRAME_RENDERED) {
    
    
            receivedRenderedEvents = true;
        }
    }

    if (receivedRenderedEvents) {
    
    
        // NOTE: all buffers are rendered in this case
        mCodec->notifyOfRenderedFrames();
    }
    return true;
}

函数很好理解,首先是从msg中取出msgList所在的地址,然后遍历套娃在里面的msg并设置what参数,之后统一调用mCodec->handleMessage进行处理,这里的mCodec即ACodec自己,由于ACodec继承自AHierarchicalStateMachine类且没有被复写,所以直接看AHierarchicalStateMachine中的handleMessage实现:

void AHierarchicalStateMachine::handleMessage(const sp<AMessage> &msg) {
    
    
    sp<AState> save = mState;

    sp<AState> cur = mState;
    /* 调用当前状态的onMessageReceived */
    while (cur != NULL && !cur->onMessageReceived(msg)) {
    
    
        // If you claim not to have handled the message you shouldn't
        // have called setState...
        CHECK(save == mState);

        cur = cur->parentState();
    }

    if (cur != NULL) {
    
    
        return;
    }

    ALOGW("Warning message %s unhandled in root state.",
         msg->debugString().c_str());
}

核心就是调用当前状态的onMessageReceived,由于ACodec中的各个状态都没有去单独实现ACodec::kWhatOMXMessageItem这个msg,所以,我们直接看BaseState::onMessageReceived就可以了:

case ACodec::kWhatOMXMessageItem:
{
    
    
    // no need to check as we already did it for kWhatOMXMessageList
    return onOMXMessage(msg);
}

跟进到onOMXMessage:

bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {
    
    
    int32_t type;
    CHECK(msg->findInt32("type", &type));
    switch (type) {
    
    
        case omx_message::EVENT:
        {
    
    
            int32_t event, data1, data2;
            CHECK(msg->findInt32("event", &event));
            CHECK(msg->findInt32("data1", &data1));
            CHECK(msg->findInt32("data2", &data2));

            if (event == OMX_EventCmdComplete
                    && data1 == OMX_CommandFlush
                    && data2 == (int32_t)OMX_ALL) {
    
    
                // Use of this notification is not consistent across
                // implementations. We'll drop this notification and rely
                // on flush-complete notifications on the individual port
                // indices instead.

                return true;
            }

            return onOMXEvent(
                    static_cast<OMX_EVENTTYPE>(event),
                    static_cast<OMX_U32>(data1),
                    static_cast<OMX_U32>(data2));
        }
        ...
}

由于此时的状态为LoadedToIdleState,所以这里要去ACodec::LoadedToIdleState::onOMXEvent

bool ACodec::LoadedToIdleState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
    switch (event) {
    
    
        case OMX_EventCmdComplete:
        {
    
    
            status_t err = OK;
            if (data1 != (OMX_U32)OMX_CommandStateSet
                    || data2 != (OMX_U32)OMX_StateIdle) {
    
    
                ALOGE("Unexpected command completion in LoadedToIdleState: %s(%u) %s(%u)",
                        asString((OMX_COMMANDTYPE)data1), data1,
                        asString((OMX_STATETYPE)data2), data2);
                err = FAILED_TRANSACTION;
            }
			/* 向OMX底层发送OMX_StateExecuting的CMD */
            if (err == OK) {
    
    
                err = mCodec->mOMXNode->sendCommand(
                    OMX_CommandStateSet, OMX_StateExecuting);
            }

            if (err != OK) {
    
    
                mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
            } else {
    
    
                mCodec->changeState(mCodec->mIdleToExecutingState);
            }

            return true;
        }
	
        default:
            return BaseState::onOMXEvent(event, data1, data2);
    }
}

可以看到,当ACodec确认OMX在设置OMX_StateIdle成功后,会继续向OMX发送OMX_StateExecuting的状态设置,使OMX底层的buffer运转起来。

四、消息机制详细图解:
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/achina2011jy/article/details/124665973
今日推荐