这个 drainInputBuffers函数从输入端口的buffers中取出之前分配好的BufferInfo,然后交给drainInputBuffer (info)函数来处理,函数实现如下:
bool OMXCodec::drainInputBuffer(BufferInfo *info) {
//comment by Alan, this buffer has only codec config informations
status_t err = mOMX->emptyBuffer( mNode, info->mBuffer, 0, size,
OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG, 0);
for (;;) {
?....
MediaBuffer *srcBuffer; ?...
err = mSource->read(&srcBuffer); ?...
memcpy((uint8_t *)info->mData + offset,
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(), srcBuffer->range_length()); ?.....
err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, offset, flags, timestampUs); ?.... }
这个函数比较复杂,主要的关键代码如上,在这个函数中,首先会把一些和编解码组件相关的specific data送给omx框架来调
用一次emptybuffer,然后会进入一个for(;;)循环,在这个for循环内,会通过mSource->read(&srcBuffer)网
srcBuffer中填充一些原始的流数据(从XXXExtractor解析出来未解码的数据),这里mSource就是前面XXXExtractor在
文件解析的过程中new 的XXXSource这里假定是MPEG4Source。函数的大致实现如下:
status_t MPEG4Source::read(MediaBuffer **out, const ReadOptions *options) { ?...
err = mGroup->acquire_buffer(&mBuffer);
if (usesDRM) {
num_bytes_read =
mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size); } else {
num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size); }
?...
*out = mBuffer; mBuffer = NULL; return OK; }
这个函数的实现很复杂,在read的时候不但考虑了seek的问题,而且还涉及到了不少多媒体容器格式方面的一些问题。但是关于
数据流向的函数就是两个,首先acquire_buffer,这个acquire_buffer和前面的add_buffer对应,在MPEG4Source::
start中会被调用到。获得一个mBuffer后就可以通过mDataSource->readAt来往这个buffer上填充数据了。这里的
mDataSource实际上可以对应到一个FileSource或者来之网络的CacheSource。mBuffer数据填充完后赋值给调用函数的
srcBuffer,这样就相当于给 drainInputBuffer(BufferInfo *info)中的info填充了数据,然后回到
drainInputBuffer函数,接着emptyBuffer。实际上这里的BufferInfo *info的数据填充过程还有一些细节需要弄清楚,
BufferInfo的结构体各个字段的意义还有待进一步弄明白。
到了mOMX->emptyBuffer()基本就进入OMX框架了,无非是OMX那一套消息机制,之前已经说过,这里就不在赘述了。
如果还有不清楚的话,其在openMax文档的时候我画的一张时序图。还有一点需要明确,在emptyBuffer的时候会将App Data
copyToOMX,将来之Appcation的数据copy到OMX框架中,而在OMXNodeInstance::onMessage FILL_BUFFER_DONE
的时候,会将数据从OMX框架中copy到Appcation空间,即copyFromOMX。Appcation<-- data --->OMX
来看看其中一个函数的实现,
void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) { if (!mIsBackup) { return; }
memcpy(header->pBuffer + header->nOffset,
(const OMX_U8 *)mMem->pointer() + header->nOffset, header->nFilledLen); }
注意以下,mMem这个成员变量具体指什么,我们看看emptyBuffer这个函数的实现:
status_t OMXNodeInstance::emptyBuffer( OMX::buffer_id buffer,
OMX_U32 rangeOffset, OMX_U32 rangeLength, OMX_U32 flags, OMX_TICKS timestamp) { Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; header->nFilledLen = rangeLength; header->nOffset = rangeOffset; header->nFlags = flags;
header->nTimeStamp = timestamp;
BufferMeta *buffer_meta =
static_cast
OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
return StatusFromOMXError(err); }
去看一下BufferMeta的构造函数就可以发现,上面mMem实际上指的是head->pAppPrivate。
那么具体的解码过程什么时候开始呢?
在OMX框架中所有的软解部分,最终都会通过OMX的消息机制走到SimpleSoftOMXComponent::
onMessageReceived,函数的实现如下:
void SimpleSoftOMXComponent::onMessageReceived(const sp
Mutex::Autolock autoLock(mLock);
switch (msg->what()) { case kWhatSendCommand: {
int32_t cmd, param;
CHECK(msg->findInt32(\
CHECK(msg->findInt32(\
onSendCommand((OMX_COMMANDTYPE)cmd, (OMX_U32)param); break; }
case kWhatEmptyThisBuffer: case kWhatFillThisBuffer: {
OMX_BUFFERHEADERTYPE *header;
CHECK(msg->findPointer(\
CHECK(mState == OMX_StateExecuting && mTargetState == mState);
bool found = false;
for (size_t i = 0; i < mPorts.size(); ++i) {
PortInfo *port = &mPorts.editItemAt(i);
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((msg->what() == kWhatEmptyThisBuffer && port->mDef.eDir == OMX_DirInput)
|| (port->mDef.eDir == OMX_DirOutput));
port->mQueue.push_back(buffer); onQueueFilled(i);
found = true; break;
} } }
CHECK(found); break; }