OMX中的回调机制分析


OMX中的回调,目的:给组件用来回调OMX,OMXNodeInstance的相应处理。
1.OMX从分配allocateNode开始时,就设置了回调。见SoftOMXPlugin_makeComponentInstance的分析过程。
status_t OMX::allocateNode(
        const char *name, const sp &observer,
        sp *nodeBinder, node_id *node) {
    Mutex::Autolock autoLock(mLock);


    *node = 0;
    if (nodeBinder != NULL) {
        *nodeBinder = NULL;
    }


    if (mNodeIDToInstance.size() == kMaxNodeInstances) {
        // all possible node IDs are in use
        return NO_MEMORY;
    }


    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_l(instance);
    mDispatchers.add(*node, new CallbackDispatcher(instance)); \\给对应的node ID生成回调处理器


    instance->setHandle(*node, handle);
    //instance,observer为binder接口,用于和ACodec进程间通信
    mLiveNodes.add(IInterface::asBinder(observer), instance);   
    IInterface::asBinder(observer)->linkToDeath(this);


    return OK;
}


2.OMXNodeInstance::kCallbacks是已经设定的静态值,OMXNodeInstance。
1)OMXNodeInstance::kCallbacks
// static
OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
    &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
};


typedef struct OMX_CALLBACKTYPE  \\保存着三个指向回调函数的指针
{
    /** The EventHandler method is used to notify the application when an
        event of interest occurs.  Events are defined in the OMX_EVENTTYPE
        enumeration.  Please see that enumeration for details of what will
        be returned for each type of event. Callbacks should not return
        an error to the component, so if an error occurs, the application
        shall handle it internally.  This is a blocking call.


        The application should return from this call within 5 msec to avoid
        blocking the component for an excessively long period of time.


        @param hComponent
            handle of the component to access.  This is the component
            handle returned by the call to the GetHandle function.
        @param pAppData
            pointer to an application defined value that was provided in the
            pAppData parameter to the OMX_GetHandle method for the component.
            This application defined value is provided so that the application
            can have a component specific context when receiving the callback.
        @param eEvent
            Event that the component wants to notify the application about.
        @param nData1
            nData will be the OMX_ERRORTYPE for an error event and will be
            an OMX_COMMANDTYPE for a command complete event and OMX_INDEXTYPE for a OMX_PortSettingsChanged event.
         @param nData2
            nData2 will hold further information related to the event. Can be OMX_STATETYPE for
            a OMX_CommandStateSet command or port index for a OMX_PortSettingsChanged event.
            Default value is 0 if not used. )
        @param pEventData
            Pointer to additional event-specific data (see spec for meaning).
      */


   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);


    /** The EmptyBufferDone method is used to return emptied buffers from an
        input port back to the application for reuse.  This is a blocking call
        so the application should not attempt to refill the buffers during this
        call, but should queue them and refill them in another thread.  There
        is no error return, so the application shall handle any errors generated
        internally.


        The application should return from this call within 5 msec.


        @param hComponent
            handle of the component to access.  This is the component
            handle returned by the call to the GetHandle function.
        @param pAppData
            pointer to an application defined value that was provided in the
            pAppData parameter to the OMX_GetHandle method for the component.
            This application defined value is provided so that the application
            can have a component specific context when receiving the callback.
        @param pBuffer
            pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
            or AllocateBuffer indicating the buffer that was emptied.
        @ingroup buf
     */
    OMX_ERRORTYPE (*EmptyBufferDone)(
        OMX_IN OMX_HANDLETYPE hComponent,
        OMX_IN OMX_PTR pAppData,
        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);


    /** The FillBufferDone method is used to return filled buffers from an
        output port back to the application for emptying and then reuse.
        This is a blocking call so the application should not attempt to
        empty the buffers during this call, but should queue the buffers
        and empty them in another thread.  There is no error return, so
        the application shall handle any errors generated internally.  The
        application shall also update the buffer header to indicate the
        number of bytes placed into the buffer.


        The application should return from this call within 5 msec.


        @param hComponent
            handle of the component to access.  This is the component
            handle returned by the call to the GetHandle function.
        @param pAppData
            pointer to an application defined value that was provided in the
            pAppData parameter to the OMX_GetHandle method for the component.
            This application defined value is provided so that the application
            can have a component specific context when receiving the callback.
        @param pBuffer
            pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
            or AllocateBuffer indicating the buffer that was filled.
        @ingroup buf
     */
    OMX_ERRORTYPE (*FillBufferDone)(
        OMX_OUT OMX_HANDLETYPE hComponent,
        OMX_OUT OMX_PTR pAppData,
        OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);


} OMX_CALLBACKTYPE;


2)OnEvent
// static
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) {
    if (pAppData == NULL) {
        ALOGE("b/25884056");
        return OMX_ErrorBadParameter;
    }
    OMXNodeInstance *instance = static_cast(pAppData);
    if (atomic_load(&instance->mDying)) {
        return OMX_ErrorNone;
    }
    return instance->owner()->OnEvent(
            instance->nodeID(), eEvent, nData1, nData2, pEventData);
}
3)OnEmptyBufferDone
// static
OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
        OMX_IN OMX_HANDLETYPE /* hComponent */,
        OMX_IN OMX_PTR pAppData,
        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    if (pAppData == NULL) {
        ALOGE("b/25884056");
        return OMX_ErrorBadParameter;
    }
    OMXNodeInstance *instance = static_cast(pAppData);
    if (atomic_load(&instance->mDying)) {
        return OMX_ErrorNone;
    }
    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    return instance->owner()->OnEmptyBufferDone(instance->nodeID(),
            instance->findBufferID(pBuffer), pBuffer, fenceFd);
}
4)OnFillBufferDone
// static
OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
        OMX_IN OMX_HANDLETYPE /* hComponent */,
        OMX_IN OMX_PTR pAppData,
        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
    if (pAppData == NULL) {
        ALOGE("b/25884056");
        return OMX_ErrorBadParameter;
    }
    OMXNodeInstance *instance = static_cast(pAppData);
    if (atomic_load(&instance->mDying)) {
        return OMX_ErrorNone;
    }
    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);
    return instance->owner()->OnFillBufferDone(instance->nodeID(),
            instance->findBufferID(pBuffer), pBuffer, fenceFd);
}


3.OMXNodeInstance的回调函数会调到OMX的相应函数
instance->owner()->OnEvent
instance->owner()->OnEmptyBufferDone
instance->owner()->OnFillBufferDone


4.OMX处理,以OMX::OnEvent为例,OnEmptyBufferDone、OnFillBufferDone类似
OMX_ERRORTYPE OMX::OnEvent(
        node_id node,
        OMX_IN OMX_EVENTTYPE eEvent,
        OMX_IN OMX_U32 nData1,
        OMX_IN OMX_U32 nData2,
        OMX_IN OMX_PTR pEventData) {
    ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
    OMXNodeInstance *instance = findInstance(node);


    if (instance == NULL) {
        return OMX_ErrorComponentNotFound;
    }


    // Forward to OMXNodeInstance.
    instance->onEvent(eEvent, nData1, nData2); \\小写的onEvent


    sp dispatcher = findDispatcher(node); \\根据node ID 找到对应的回调消息分发器
    if (dispatcher == NULL) {
       ALOGW("OnEvent Callback dispatcher NULL, skip post");
       return OMX_ErrorNone;
    }


    // output rendered events are not processed as regular events until they hit the observer
    if (eEvent == OMX_EventOutputRendered) {
        if (pEventData == NULL) {
            return OMX_ErrorBadParameter;
        }


        // process data from array
        OMX_VIDEO_RENDEREVENTTYPE *renderData = (OMX_VIDEO_RENDEREVENTTYPE *)pEventData;
        for (size_t i = 0; i < nData1; ++i) {
            omx_message msg;
            msg.type = omx_message::FRAME_RENDERED;
            msg.node = node;
            msg.fenceFd = -1;
            msg.u.render_data.timestamp = renderData[i].nMediaTimeUs;
            msg.u.render_data.nanoTime = renderData[i].nSystemTimeNs;


            dispatcher->post(msg, false /* realTime */);
        }
        return OMX_ErrorNone;
    }


    omx_message msg;
    msg.type = omx_message::EVENT;
    msg.node = node;
    msg.fenceFd = -1;
    msg.u.event_data.event = eEvent;
    msg.u.event_data.data1 = nData1;
    msg.u.event_data.data2 = nData2;


    dispatcher->post(msg, true /* realTime */); \\分发器处理消息


    return OMX_ErrorNone;
}


5.CallbackDispatcher处理消息CallbackDispatcher::post,回调分发器post消息
1)CallbackDispatcher::post,回调分发器post消息
void OMX::CallbackDispatcher::post(const omx_message &msg, bool realTime) {
    Mutex::Autolock autoLock(mLock);


    mQueue.push_back(msg);\\放入分发器的消息队列
    if (realTime) {
        mQueueChanged.signal();
    }
}
2)CallbackDispatcher启动之后一直在loop
bool OMX::CallbackDispatcher::loop() {
    for (;;) {
        std::list messages;


        {
            Mutex::Autolock autoLock(mLock);
            while (!mDone && mQueue.empty()) {
                mQueueChanged.wait(mLock); \\wait
            }


            if (mDone) {
                break;
            }


            messages.swap(mQueue);
        }


        dispatch(messages);
    }


    return false;
}
3)CallbackDispatcher::dispatch处理,进入到OMXNodeInstance的onMessages,让OMXNodeInstance继续处理消息
void OMX::CallbackDispatcher::dispatch(std::list &messages) {
    if (mOwner == NULL) {
        ALOGV("Would have dispatched a message to a node that's already gone.");
        return;
    }
    mOwner->onMessages(messages); \\OMXNodeInstance *mOwner;,还是回到OMXNodeInstance的消息处理中去
}


6.OMXNodeInstance::onMessages,把消息通过binder发给OMX的客户端ACodec
void OMXNodeInstance::onMessages(std::list &messages) {
    for (std::list::iterator it = messages.begin(); it != messages.end(); ) {
        if (handleMessage(*it)) {   \\处理消息,只对两类FILL_BUFFER_DONE和EMPTY_BUFFER_DONE感兴趣
            messages.erase(it++);
        } else {
            ++it;
        }
    }


    if (!messages.empty()) {         \\没有被处理掉的消息
        mObserver->onMessages(messages); \\继续处理没有被处理掉的消息序列,通过binder发给OMX的客户端,sp mObserver;
    }
}


7.OMXNodeInstance::handleMessage主要对两类消息非常感兴趣,
对他们进行进一步的处理,填一些数据什么的,一般返回为false,
真正的消息处理还是要通过mObserver->onMessages(binder进程间通信)发回OMX的客户端。
msg.type == omx_message::FILL_BUFFER_DONE,OMX的组件已经解码或者编码完毕的数据,放到了输出端;
msg.type == omx_message::EMPTY_BUFFER_DONE  组件已经吃到输入端输去;
bool OMXNodeInstance::handleMessage(omx_message &msg) {
    const sp& bufferSource(getGraphicBufferSource());


    if (msg.type == omx_message::FILL_BUFFER_DONE) {  \\1.处理omx_message::FILL_BUFFER_DONE
        OMX_BUFFERHEADERTYPE *buffer =
            findBufferHeader(msg.u.extended_buffer_data.buffer);
        if (buffer == NULL) {
            ALOGE("b/25884056");
            return BAD_VALUE;
        }


        {
            Mutex::Autolock _l(mDebugLock);
            mOutputBuffersWithCodec.remove(buffer);


            CLOG_BUMPED_BUFFER(
                    FBD, WITH_STATS(FULL_BUFFER(
                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));


            unbumpDebugLevel_l(kPortIndexOutput);
        }


        BufferMeta *buffer_meta =
            static_cast(buffer->pAppPrivate);


        if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset
                || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) {
            CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
                    FULL_BUFFER(NULL, buffer, msg.fenceFd));
        }
        buffer_meta->CopyFromOMX(buffer);


        if (bufferSource != NULL) {
            // fix up the buffer info (especially timestamp) if needed
            bufferSource->codecBufferFilled(buffer);


            msg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
        }
    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) { \\2.处理omx_message::EMPTY_BUFFER_DONE
        OMX_BUFFERHEADERTYPE *buffer =
            findBufferHeader(msg.u.buffer_data.buffer);


        {
            Mutex::Autolock _l(mDebugLock);
            mInputBuffersWithCodec.remove(buffer);


            CLOG_BUMPED_BUFFER(
                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
        }


        if (bufferSource != NULL) {
            // This is one of the buffers used exclusively by
            // GraphicBufferSource.
            // Don't dispatch a message back to ACodec, since it doesn't
            // know that anyone asked to have the buffer emptied and will
            // be very confused.
            bufferSource->codecBufferEmptied(buffer, msg.fenceFd);
            return true;
        }
    }


    return false;
}


8.最终的消息mObserver->onMessages(messages)处理。对应到客户端CodecObserver的onMessages处理。
即客户端(ACodec)处理OMX返回来的消息。CodecObserver里面dup出kWhatOMXMessageList消息,发往ACodec处理。
注意这个mObserver是ACodec在onAllocateComponent中omx->allocateNode传进binder的。
struct CodecObserver : public BnOMXObserver {
    CodecObserver() {}


    void setNotificationMessage(const sp &msg) {
        mNotify = msg;
    }


    // from IOMXObserver
    virtual void onMessages(const std::list &messages) {
        if (messages.empty()) {
            return;
        }


        sp notify = mNotify->dup();\\这个消息会发给ACodec处理,kWhatOMXMessageList
        bool first = true;
        sp msgList = new MessageList();
        for (std::list::const_iterator it = messages.cbegin();
              it != messages.cend(); ++it) {
            const omx_message &omx_msg = *it;
            if (first) {
                notify->setInt32("node", omx_msg.node);
                first = false;
            }


            sp 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;
                }


                case omx_message::EMPTY_BUFFER_DONE:
                {
                    msg->setInt32("buffer", omx_msg.u.buffer_data.buffer);
                    msg->setInt32("fence_fd", omx_msg.fenceFd);
                    break;
                }


                case omx_message::FILL_BUFFER_DONE:
                {
                    msg->setInt32(
                            "buffer", omx_msg.u.extended_buffer_data.buffer);
                    msg->setInt32(
                            "range_offset",
                            omx_msg.u.extended_buffer_data.range_offset);
                    msg->setInt32(
                            "range_length",
                            omx_msg.u.extended_buffer_data.range_length);
                    msg->setInt32(
                            "flags",
                            omx_msg.u.extended_buffer_data.flags);
                    msg->setInt64(
                            "timestamp",
                            omx_msg.u.extended_buffer_data.timestamp);
                    msg->setInt32(
                            "fence_fd", omx_msg.fenceFd);
                    break;
                }


                case omx_message::FRAME_RENDERED:
                {
                    msg->setInt64(
                            "media_time_us", omx_msg.u.render_data.timestamp);
                    msg->setInt64(
                            "system_nano", omx_msg.u.render_data.nanoTime);
                    break;
                }


                default:
                    ALOGE("Unrecognized message type: %d", omx_msg.type);
                    break;
            }
            msgList->getList().push_back(msg);
        }
        notify->setObject("messages", msgList);
        notify->post();
    }


protected:
    virtual ~CodecObserver() {}


private:
    sp mNotify;


    DISALLOW_EVIL_CONSTRUCTORS(CodecObserver);
};


ACodec中onAllocateComponent给observer设置了一个通知消息
{
    ......
    notify = new AMessage(kWhatOMXMessageList, mCodec);
    observer->setNotificationMessage(notify);
......
}




0.组件保存回调函数指针,当使用回调时,走OMX的回调机制
SoftOMXComponent::SoftOMXComponent(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component)
    : mName(name),
      mCallbacks(callbacks),\\保存回调
      mComponent(new OMX_COMPONENTTYPE),
      mLibHandle(NULL) {
    mComponent->nSize = sizeof(*mComponent);
    mComponent->nVersion.s.nVersionMajor = 1;
    mComponent->nVersion.s.nVersionMinor = 0;
    mComponent->nVersion.s.nRevision = 0;
    mComponent->nVersion.s.nStep = 0;
    mComponent->pComponentPrivate = this;
    mComponent->pApplicationPrivate = appData;


    mComponent->GetComponentVersion = NULL;
    mComponent->SendCommand = SendCommandWrapper;
    mComponent->GetParameter = GetParameterWrapper;
    mComponent->SetParameter = SetParameterWrapper;
    mComponent->GetConfig = GetConfigWrapper;
    mComponent->SetConfig = SetConfigWrapper;
    mComponent->GetExtensionIndex = GetExtensionIndexWrapper;
    mComponent->GetState = GetStateWrapper;
    mComponent->ComponentTunnelRequest = NULL;
    mComponent->UseBuffer = UseBufferWrapper;
    mComponent->AllocateBuffer = AllocateBufferWrapper;
    mComponent->FreeBuffer = FreeBufferWrapper;
    mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;
    mComponent->FillThisBuffer = FillThisBufferWrapper;
    mComponent->SetCallbacks = NULL;
    mComponent->ComponentDeInit = NULL;
    mComponent->UseEGLImage = NULL;
    mComponent->ComponentRoleEnum = NULL;


    *component = mComponent;\\component
}


1.对OMX的回调机制的使用从ACodec开始,以ACodec中onInputBufferFilled为例,
其中有mCodec->mOMX->emptyBuffer。
void ACodec::BaseState::onInputBufferFilled(const sp &msg) {
    ......
    mCodec->mOMX->emptyBuffer
......
}


2.OMX::emptyBuffer
status_t OMX::emptyBuffer(
        node_id node,
        buffer_id buffer,
        OMX_U32 range_offset, OMX_U32 range_length,
        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    OMXNodeInstance *instance = findInstance(node);


    if (instance == NULL) {
        return NAME_NOT_FOUND;
    }


    return instance->emptyBuffer(
            buffer, range_offset, range_length, flags, timestamp, fenceFd);
}


3.OMXNodeInstance::emptyBuffer
status_t OMXNodeInstance::emptyBuffer(
        OMX::buffer_id buffer,
        OMX_U32 rangeOffset, OMX_U32 rangeLength,
        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
    Mutex::Autolock autoLock(mLock);


    OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
    if (header == NULL) {
        ALOGE("b/25884056");
        return BAD_VALUE;
    }
    BufferMeta *buffer_meta =
        static_cast(header->pAppPrivate);
    sp backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
    sp codec = buffer_meta->getBuffer(header, false /* backup */, false /* limit */);


    // convert incoming ANW meta buffers if component is configured for gralloc metadata mode
    // ignore rangeOffset in this case
    if (mMetadataType[kPortIndexInput] == kMetadataBufferTypeGrallocSource
            && backup->capacity() >= sizeof(VideoNativeMetadata)
            && codec->capacity() >= sizeof(VideoGrallocMetadata)
            && ((VideoNativeMetadata *)backup->base())->eType
                    == kMetadataBufferTypeANWBuffer) {
        VideoNativeMetadata &backupMeta = *(VideoNativeMetadata *)backup->base();
        VideoGrallocMetadata &codecMeta = *(VideoGrallocMetadata *)codec->base();
        CLOG_BUFFER(emptyBuffer, "converting ANWB %p to handle %p",
                backupMeta.pBuffer, backupMeta.pBuffer->handle);
        codecMeta.pHandle = backupMeta.pBuffer != NULL ? backupMeta.pBuffer->handle : NULL;
        codecMeta.eType = kMetadataBufferTypeGrallocSource;
        header->nFilledLen = rangeLength ? sizeof(codecMeta) : 0;
        header->nOffset = 0;
    } else {
        // rangeLength and rangeOffset must be a subset of the allocated data in the buffer.
        // corner case: we permit rangeOffset == end-of-buffer with rangeLength == 0.
        if (rangeOffset > header->nAllocLen
                || rangeLength > header->nAllocLen - rangeOffset) {
            CLOG_ERROR(emptyBuffer, OMX_ErrorBadParameter, FULL_BUFFER(NULL, header, fenceFd));
            if (fenceFd >= 0) {
                ::close(fenceFd);
            }
            return BAD_VALUE;
        }
        header->nFilledLen = rangeLength;
        header->nOffset = rangeOffset;


        buffer_meta->CopyToOMX(header);
    }


    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer, fenceFd);
}


status_t OMXNodeInstance::emptyBuffer_l(
        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp,
        intptr_t debugAddr, int fenceFd) {
    header->nFlags = flags;
    header->nTimeStamp = timestamp;


    status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexInput);
    if (res != OK) {
        CLOG_ERROR(emptyBuffer::storeFenceInMeta, res, WITH_STATS(
                FULL_BUFFER(debugAddr, header, fenceFd)));
        return res;
    }


    {
        Mutex::Autolock _l(mDebugLock);
        mInputBuffersWithCodec.add(header);


        // bump internal-state debug level for 2 input frames past a buffer with CSD
        if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
            bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);
        }


        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header, fenceFd)));
    }


    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header); \\宏展开
    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header, fenceFd));


    {
        Mutex::Autolock _l(mDebugLock);
        if (err != OMX_ErrorNone) {
            mInputBuffersWithCodec.remove(header);
        } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
            unbumpDebugLevel_l(kPortIndexInput);
        }
    }


    return StatusFromOMXError(err);
}




4.OMX_Core.h中的宏展开
/** The OMX_EmptyThisBuffer macro will send a buffer full of data to an
    input port of a component.  The buffer will be emptied by the component
    and returned to the application via the EmptyBufferDone call back.
    This is a non-blocking call in that the component will record the buffer
    and return immediately and then empty the buffer, later, at the proper
    time.  As expected, this macro may be invoked only while the component
    is in the OMX_StateExecuting.  If nPortIndex does not specify an input
    port, the component shall return an error.


    The component should return from this call within 5 msec.


    @param [in] hComponent
        Handle of the component to be accessed.  This is the component
        handle returned by the call to the OMX_GetHandle function.
    @param [in] pBuffer
        pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
        or AllocateBuffer.
    @return OMX_ERRORTYPE
        If the command successfully executes, the return code will be
        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
    @ingroup comp buf
 */
#define OMX_EmptyThisBuffer(                                \
        hComponent,                                         \
        pBuffer)                                            \
    ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer(      \
        hComponent,                                         \
        pBuffer)                        /* Macro End */


5.SoftOMXComponent构造函数
((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer见SoftOMXComponent初始化时,保存的对应函数指针
mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;


6.SoftOMXComponent::EmptyThisBufferWrapper
// static
OMX_ERRORTYPE SoftOMXComponent::EmptyThisBufferWrapper(
        OMX_HANDLETYPE component,
        OMX_BUFFERHEADERTYPE *buffer) {
    SoftOMXComponent *me =
        (SoftOMXComponent *)
            ((OMX_COMPONENTTYPE *)component)->pComponentPrivate;


    return me->emptyThisBuffer(buffer);\\调用父类的emptyThisBuffer
}


7.SimpleSoftOMXComponent::emptyThisBuffer
OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer(
        OMX_BUFFERHEADERTYPE *buffer) {
    sp msg = new AMessage(kWhatEmptyThisBuffer, mHandler);
    msg->setPointer("header", buffer);
    msg->post();


    return OMX_ErrorNone;
}


8.SimpleSoftOMXComponent处理消息
void SimpleSoftOMXComponent::onMessageReceived(const sp &msg) {
    Mutex::Autolock autoLock(mLock);
    uint32_t msgType = msg->what();
    ALOGV("msgType = %d", msgType);
    switch (msgType) {
        case kWhatSendCommand:
        {
            int32_t cmd, param;
            CHECK(msg->findInt32("cmd", &cmd));
            CHECK(msg->findInt32("param", ¶m));


            onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param);
            break;
        }


        case kWhatEmptyThisBuffer:
        case kWhatFillThisBuffer:
        {
            OMX_BUFFERHEADERTYPE *header;
            CHECK(msg->findPointer("header", (void **)&header));


            CHECK(mState == OMX_StateExecuting && mTargetState == mState);


            bool found = false;
            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
                    header->nInputPortIndex: header->nOutputPortIndex;
            PortInfo *port = &mPorts.editItemAt(portIndex);


            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
                BufferInfo *buffer = &port->mBuffers.editItemAt(j);


                if (buffer->mHeader == header) {
                    CHECK(!buffer->mOwnedByUs);


                    buffer->mOwnedByUs = true;


                    CHECK((msgType == kWhatEmptyThisBuffer
                            && port->mDef.eDir == OMX_DirInput)
                            || (port->mDef.eDir == OMX_DirOutput));


                    port->mQueue.push_back(buffer);
                    onQueueFilled(portIndex);


                    found = true;
                    break;
                }
            }


            CHECK(found);
            break;
        }


        default:
            TRESPASS();
            break;
    }
}


9.子类SoftMP3必须要实现的onQueueFilled方法,
已经有新的输入给组件codec的数据/已经取走组件codec的输出数据。
void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
    if (mSignalledError || mOutputPortSettingsChange != NONE) {
        return;
    }


    List &inQueue = getPortQueue(0);
    List &outQueue = getPortQueue(1);
    int64_t tmpTime = 0;
    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
        BufferInfo *inInfo = NULL;
        OMX_BUFFERHEADERTYPE *inHeader = NULL;
        if (!inQueue.empty()) {
            inInfo = *inQueue.begin();
            inHeader = inInfo->mHeader;
        }


        BufferInfo *outInfo = *outQueue.begin();
        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
        outHeader->nFlags = 0;


        if (inHeader) {
            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
                // use new input buffer timestamp as Anchor Time if its
                //    a) first buffer or
                //    b) first buffer post seek or
                //    c) different from last buffer timestamp
                //If input buffer timestamp is same as last input buffer timestamp then
                //treat this as a erroneous timestamp and ignore new input buffer
                //timestamp and use last output buffer timestamp as Anchor Time.
                if ((mLastAnchorTimeUs != inHeader->nTimeStamp)) {
                    mAnchorTimeUs = inHeader->nTimeStamp;
                    mLastAnchorTimeUs = inHeader->nTimeStamp;
                } else {
                    mAnchorTimeUs = mNextOutBufferTimeUs;
                }


                mNumFramesOutput = 0;
            }


            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
                mSawInputEos = true;
            }


            mConfig->pInputBuffer =
                inHeader->pBuffer + inHeader->nOffset;


            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
        } else {
            mConfig->pInputBuffer = NULL;
            mConfig->inputBufferCurrentLength = 0;
        }
        mConfig->inputBufferMaxLength = 0;
        mConfig->inputBufferUsedLength = 0;


        mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
        if ((int32)outHeader->nAllocLen < mConfig->outputFrameSize) {
            ALOGE("input buffer too small: got %u, expected %u",
                outHeader->nAllocLen, mConfig->outputFrameSize);
            android_errorWriteLog(0x534e4554, "27793371");
            notify(OMX_EventError, OMX_ErrorUndefined, OUTPUT_BUFFER_TOO_SMALL, NULL);
            mSignalledError = true;
            return;
        }


        mConfig->pOutputBuffer =
            reinterpret_cast(outHeader->pBuffer);


        ERROR_CODE decoderErr;
        if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
                != NO_DECODING_ERROR) {
            ALOGV("mp3 decoder returned error %d", decoderErr);


            if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
                        && decoderErr != SIDE_INFO_ERROR) {
                ALOGE("mp3 decoder returned error %d", decoderErr);


                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                mSignalledError = true;
                return;
            }


            if (mConfig->outputFrameSize == 0) {
                mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
            }


            if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
                if (!mIsFirst) {
                    // pad the end of the stream with 529 samples, since that many samples
                    // were trimmed off the beginning when decoding started
                    outHeader->nOffset = 0;
                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);


                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
                }
                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                mSignalledOutputEos = true;
            } else {
                // This is recoverable, just ignore the current frame and
                // play silence instead.


                // TODO: should we skip silence (and consume input data)
                // if mIsFirst is true as we may not have a valid
                // mConfig->samplingRate and mConfig->num_channels?
                ALOGV_IF(mIsFirst, "insufficient data for first frame, sending silence");
                memset(outHeader->pBuffer,
                       0,
                       mConfig->outputFrameSize * sizeof(int16_t));


                if (inHeader) {
                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
                }
            }
        } else if (mConfig->samplingRate != mSamplingRate
                || mConfig->num_channels != mNumChannels) {
            mSamplingRate = mConfig->samplingRate;
            mNumChannels = mConfig->num_channels;


            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
            mOutputPortSettingsChange = AWAITING_DISABLED;
            return;
        }


        if (mIsFirst) {
            mIsFirst = false;
            // The decoder delay is 529 samples, so trim that many samples off
            // the start of the first output buffer. This essentially makes this
            // decoder have zero delay, which the rest of the pipeline assumes.
            outHeader->nOffset =
                kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);


            outHeader->nFilledLen =
                mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
        } else if (!mSignalledOutputEos) {
            outHeader->nOffset = 0;
            outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
        }


        outHeader->nTimeStamp =
            mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
        tmpTime = outHeader->nTimeStamp;
        if (inHeader) {
            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);


            inHeader->nOffset += mConfig->inputBufferUsedLength;
            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;




            if (inHeader->nFilledLen == 0) {
                inInfo->mOwnedByUs = false;
                inQueue.erase(inQueue.begin());
                inInfo = NULL;
                notifyEmptyBufferDone(inHeader);
                inHeader = NULL;
            }
        }


        mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;


        outInfo->mOwnedByUs = false;
        outQueue.erase(outQueue.begin());
        outInfo = NULL;
        notifyFillBufferDone(outHeader);\\关键调用
        outHeader = NULL;
    }


    if (tmpTime > 0) {
        mNextOutBufferTimeUs = tmpTime;
    }
}


10.最后使用OMX的回调机制,闭环发送消息到OMX客户端ACodec
void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) {
    (*mCallbacks->FillBufferDone)(
            mComponent, mComponent->pApplicationPrivate, header);
}

你可能感兴趣的:(android多媒体)