您的位置:首页 > 运维架构

libstagefright openmax编解码数据流向分析

2014-03-04 19:52 441 查看
OMXCodec::read第一次调用时,mInitialBufferSubmit值为true,这个标志就是用来标识OMXCodec::read是否是第一次调用的。

在if (mInitialBufferSubmit) { },中

1、把标志mInitialBufferSubmit置为false,

2、调用drainInputBuffers,把输入通道中的所有输入缓存区,逐个传递给drainInputBuffer

3、在drainInputBuffer中会从调用mSource->read读取原始数据,填充到缓存区中,然后调用mOMX->emptyBuffer发消息给openmax。

4、调用fillOutputBuffers把输出通道中的输出缓冲区,逐个传递给fillOutputBuffer。

5、在fillOutputBuffer中调用mOMX->fillBuffer发消息给openmax,相当于把缓冲区传递给openmax

6、

while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {

if ((err = waitForBufferFilled_l()) != OK) {

return err;

}

}

等待输出缓冲区的数据,如果有数据就往下走,读取数据输出。

等OMXCodec::read后续调用时,就直接到上述第6步,等待输出缓冲区数据。

PS: 有两个点说明一下

1、mBufferFilled,是Condition类型。在上述第6步会等待这个信号,这个信号主要是在omx_message::FILL_BUFFER_DONE处理流程中发送,这个事件是openmax解码数据后把一个输出缓冲区填充满了就触发这个事件。

2、mFilledBuffers数据类型是List<size_t>,它存储的不是缓冲区地址而是输出缓冲区索引。在omx_message::FILL_BUFFER_DONE处理流程中有下面两行代

mFilledBuffers.push_back(i);

mBufferFilled.signal();

即把已经填充好的输出缓冲区索引保存到mFilledBuffers中,然后再发信号。

OMXCodec::read第6步检查到有数据可读了,就从mFilledBuffers读取头部的缓冲区索引,同时把这个索引从List中删除,然后根据索引找到缓冲区,再把缓冲区地址赋值给输出指针输出,这个缓存区的引用计数会加1,上层使用完会释放。

输入缓冲区更新:

如果一个输入缓冲区数据被读取完了,openmax会触发事件omx_message::EMPTY_BUFFER_DONE通知上层,在这个事件处理流程中,会根据发送来的bufferid找到对应的输入缓冲区,然后把这个缓冲区传递给drainInputBuffer,执行上面的第3步流程。

输出缓冲区更新:

输出缓冲区会被传出交给上层使用(传递个渲染器使用),使用完后需要把这个缓存区重新交给openmax,(个人推测openmax把一个缓存填充满后,就把这个缓冲区置为不可用,所以上层使用完后,需要重新发消息给openmax通知它这个缓冲区可以用了,输入缓冲区也是这样处理的),上层使用完输出缓冲区后会调用MediaBuffer::release进行销毁,在这个接口中会把输出缓冲区的引用计数减1,然后调用signalBufferReturned,实际对应OMXCodec::signalBufferReturned接口,再下一层调用fillOutputBuffer,把这个缓冲区重新交给openmax。

总结:这样就是通过第一次调用drainInputBuffers触发openmax,然后后面依靠openmax的事件驱动来完成数据的读取、解码操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: