一、引言:
OMX组件的标准接口(OMX_Core.h
)中,OMX_FillThisBuffer
和OMX_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;
EmptyBufferDone
和FillBufferDone
就是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组件的标准回调消息EmptyBufferDone
及FillBufferDone
配合使用。
回到前面看回调的设置,当ACodecBufferChannel实例化完成后,MediaCodec为了能和ACodec同步获知OMX对buffer的更新情况,会设置一个BufferCallback
(主要是一个msg)到ACodecBufferChannel中:
BufferCallback::BufferCallback(const sp<AMessage> ¬ify)
: 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的所有信息。下面看下OMXNodeInstance
中OnFillBufferDone
的实现:
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;
}
{