OpenMAX
来源:互联网 发布:b2c建站 编辑:程序博客网 时间:2024/04/20 06:26
http://www.xuebuyuan.com/2117774.html
libstagefright openmax编解码数据流向分析
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的事件驱动来完成数据的读取、解码操作。
=====================================================================================
OMXCodec是一个MediaSource,完成数据的parse和decode。而OMXCodec则主要通过IOMX跨越OpenBinder机制操作OMX来实现。
重点介绍一下OMX。OMX主要完成三个任务,NodeInstance列表的管理,针对一个NodeInstance的操作以及事件的处理。
一、NodeInstance列表的管理。
这个主要包括NodeInstance的生成(allocateNode)和删除(freeNode)。其实就是对mDispatchers和 mNodeIDToInstance进行添加和删除。mNodeIDToInstance就是一个key为node_id,value为 NodeInstance的名值对列表。而mDispatchers就是一个key为node_id,value为 OMX::CallbackDispatcher的名值对列表。并且,一个NodeInstance都拥有一个 OMX::CallbackDispatcher。
二、NodeInstance节点的操作。
主要成员函数如下:
sendCommand
getParameter
setParameter
… …
fillBuffer
emptyBuffer
getExtensionIndex
这些方法执行时,都是先通过findInstance在mNodeIDToInstance列表中找到对应的NodeInstance,然后调用NodeInstance对应的方法。
三、事件处理
先看一下OMXNodeInstance.cpp中的这样一段代码:
12345
- OMX_CALLBACKTYPE OMXNodeInstance<span style="color:#339933">::</span><span style="color:#202020">kCallbacks</span> <span style="color:#339933">=</span> <span style="color:#009900">{</span>
- <span style="color:#339933">&</span>OnEvent<span style="color:#339933">,</span> <span style="color:#339933">&</span>OnEmptyBufferDone<span style="color:#339933">,</span> <span style="color:#339933">&</span>OnFillBufferDone
- <span style="color:#009900">}</span><span style="color:#339933">;</span>
它把三个OMXNodeInstance类的静态方法注册给了kCallbacks。而kCallbacks在哪里使用呢?看一下OMX.cpp中的allocateNode方法中的代码:
12345
- OMX_ERRORTYPE err <span style="color:#339933">=</span> mMaster<span style="color:#339933">-></span>makeComponentInstance<span style="color:#009900">(</span>
- name, <span style="color:#339933">&</span>OMXNodeInstance<span style="color:#339933">::</span>kCallbacks,
- instance, <span style="color:#339933">&</span>handle<span style="color:#009900">)</span><span style="color:#339933">;</span>
事件处理函数传给了组件ComponentInstance。当组件有事件发生时,就会调用OMXNodeInstance中这几个注册过的事件处理函数,而这几个函数又会去调用OMX中对应的函数,也就是下面这三个:
OnEvent、OnEmptyBufferDone、OnFillBufferDone。
这几个方法都采用相同的路子:根据node_id找到CallbackDispatcher,并把事件信息post过去。具体点儿,就是调用findDispatcher(node)->post(msg)。
这里不得不提一下CallbackDispatcher的实现机制。它内部开启了一个线程,使用了信号量机制。可以看一下OMX::CallbackDispatcher的属性:Condition mQueueChanged;
可以看出findDispatcher(node)->post(msg)是一个异步操作,只把msg给POST过去,不会等待事件处理完毕就返回了。那么CallbackDispatcher是怎么处理接收到的msg呢?看以下代码:
12345678
- OMX<span style="color:#339933">::</span><span style="color:#202020">CallbackDispatcher</span><span style="color:#339933">::</span><span style="color:#202020">threadEntry</span><span style="color:#009900">(</span><span style="color:#009900">)</span>
- dispatch<span style="color:#009900">(</span>msg<span style="color:#009900">)</span><span style="color:#339933">;</span>
- mOwner<span style="color:#339933">-></span>onMessage<span style="color:#009900">(</span>msg<span style="color:#009900">)</span><span style="color:#339933">;</span>
- mObserver<span style="color:#339933">-></span>onMessage<span style="color:#009900">(</span>msg<span style="color:#009900">)</span><span style="color:#339933">;</span>
这个mObserver是哪来的?OMXCodec::Create中初始化IOMX时传入的。
12345
- sp<span style="color:#339933"><</span>OMXCodecObserver<span style="color:#339933">></span> observer <span style="color:#339933">=</span> new OMXCodecObserver<span style="color:#339933">;</span>
- ... ...
- <span style="color:#202020">omx</span><span style="color:#339933">-></span>allocateNode<span style="color:#009900">(</span>componentName<span style="color:#339933">,</span> observer<span style="color:#339933">,</span> <span style="color:#339933">&</span>node<span style="color:#009900">)</span><span style="color:#339933">;</span>
这样算下来,事件最终还是跨越OpenBinder又传到了OMXCodec里面去,交给OMXCodecObserver了。
对节点的操作
NodeInstance的大部分方法的实现,如sendCommand等,都是通过OMX_Core.h中的宏定义间接调用 OMX_Component.h中的OMX_COMPONENTTYPE这个struct中的相应函数指针来完成。在这里提到的OMX_Core.h和 OMX_Component.h都是OpenMAX标准头文件。
原文链接:http://blog.csdn.net/a345017062/archive/2011/02/17/6190905.aspx
- OpenMax
- OpenMAX
- openmax
- OpenMax
- OpenMAX
- OpenMAX
- OpenMAX
- OpenMAX
- OpenMAX
- OpenMax
- OpenMax
- OpenMAX介绍
- OpenMAX入门
- OpenMAX介绍
- OpenMAX简介
- OpenMax介绍
- OpenMAX简介
- Android OpenMax
- 信息学奥赛相关文章即将起航
- 从二叉搜索树(Binary Search Tree)入手,学习C++中类的构建 --(三)public\private\protected、封装\继承\多态、提供更丰富的函数接口
- 点击事件问题(点一个触发多个)
- java核心技术自学day01
- HSSFWorkBooK用法
- OpenMAX
- DecorView
- (1.2.3)串的结构定义和模式匹配
- java设计模式(一)
- Nginx负载均衡
- 2015.3.13
- APM飞控数传驱动
- [HDU 4609]3-idiots(FFT+生成函数)
- Provider