OMX标准接口OMX_FillThisBuffer机制详解

一、引言:
OMX组件的标准接口(OMX_Core.h)中,OMX_FillThisBufferOMX_EmptyThisBuffer共同完成了OMX的buffer运转。OMX_FillThisBuffer是操作解码完后数据(PCM/YUV)的,OMX_EmptyThisBuffer是操作解码前(es)数据的。本博客将分析OMX_FillThisBuffer,下篇博客再分析OMX_EmptyThisBuffer。
整个buffer机制的分析需要从两个方面进行,一方面是OMX回调通知ACodec和MediaCodec,另一方面是MediaCodec使用完buffer后通知OMX这个过程,两个过程组合起来实际上就是生产者与消费者的关系。对于OMX_FillThisBuffer而言,MediaCodec是消费者,OMX组件是生产者。
之前讲OMX消息机制的时候,说过OMXNodeInstance会实例化一个OMX_CALLBACKTYPE的结构体,指向了三个函数:

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

OMX_CALLBACKTYPE就是OMX_Core.h中的标准接口:

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;

EmptyBufferDoneFillBufferDone就是OMX通知给ACodec回调接口。

二、ACodecBufferChannel介绍:
ACodecBufferChannel这个类是供ACodec用于更新buffer信息的,类的实例化操作是在MediaCodec的init函数中完成:

status_t MediaCodec::init(const AString &name) {
   
	...
	/* 1.实例化ACodecBufferChannel */
    mBufferChannel = mCodec->getBufferChannel();
    /* 2.设置ACodecBufferChannel的回调函数 */
    mBufferChannel->setCallback(
            std::unique_ptr<CodecBase::BufferCallback>(
                    new BufferCallback(new AMessage(kWhatCodecNotify, this))));	
	...
}

看一下ACodec中getBufferChannel函数的操作:

std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() {
   
    if (!mBufferChannel) {
   
        mBufferChannel = std::make_shared<ACodecBufferChannel>(
                new AMessage(kWhatInputBufferFilled, this),
                new AMessage(kWhatOutputBufferDrained, this));
    }
    return mBufferChannel;
}

构造函数中实例化了两个msg,分别和OMX组件的标准回调消息EmptyBufferDoneFillBufferDone配合使用。
回到前面看回调的设置,当ACodecBufferChannel实例化完成后,MediaCodec为了能和ACodec同步获知OMX对buffer的更新情况,会设置一个BufferCallback(主要是一个msg)到ACodecBufferChannel中:

BufferCallback::BufferCallback(const sp<AMessage> &notify)
    : mNotify(notify) {
   }

notify就是上面的kWhatCodecNotify,有了这个msg之后,ACodecBufferChannel中的消息就可以由MediaCodec来处理了。

三、OMX通过FillBufferDone通知至MediaCodec:
不论是vdec组件还是adec组件,当某个buffer的数据填充完之后,OMX组件会调用callbacks.FillBufferDone通知至上层,下面看下芯片平台的具体实现:

pMSComponent->callbacks.FillBufferDone(pOMXComponent, pMSComponent->callbackData, bufferHeader);

参数中bufferHeader包括了解码完后buffer的所有信息。下面看下OMXNodeInstanceOnFillBufferDone的实现:

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<OMXNodeInstance *>(pAppData);
    if (instance->mDying) {
   
        return OMX_ErrorNone;
    }
    int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);

    omx_message msg;
    msg.type = omx_message::FILL_BUFFER_DONE;
    msg.fenceFd = fenceFd;
    msg.u.extended_buffer_data.buffer = instance->findBufferID(pBuffer);
    msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
    msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
    msg.u.extended_buffer_data.flags = pBuffer->nFlags;
    msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
    instance->mDispatcher->post(msg);

    return OMX_ErrorNone;
}

OnFillBufferDone的函数实现比较简单,就是将buffer的相关信息填充到omx_message结构体中并发送出去。下面看下omx_message::FILL_BUFFER_DONE的消息处理:

void OMXNodeInstance::onMessages(std::list<omx_message> &messages) {
   
    for (std::list<omx_message>::iterator it = messages.begin(); it != messages.end(); ) {
   
    	/* OMXNodeInstance的消息处理 */
        if (handleMessage(*it)) {
   
            messages.erase(it++);
        } else {
   
            ++it;
        }
    }
	/* ACodec的消息处理 */
    if (!messages.empty()) {
   
        mObserver->onMessages(messages);
    }
}

先看handleMessage

if (msg.type == omx_message::FILL_BUFFER_DONE) {
   
	/* 1.获取buffer信息 */
    OMX_BUFFERHEADERTYPE *buffer =
        findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
    if (buffer == NULL) {
   
        ALOGE("b/25884056");
        return false;
    }

    {
   
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值