exynos SOC 平台的openmax component 运行分析

来源:互联网 发布:apache spark 版本 编辑:程序博客网 时间:2024/05/22 12:39
研究了一下exynos平台上的openmax component组件,绕来绕去的很绕。
这里总结一下。
先上个总体图:


曾经尝试把awesomeplayer,以及OMXCodec里的各种event流程,queue流程,内存使用释放路径,以及各种线程概念全画到图里,却发现东西太多太杂,导致图混乱不堪。
索性,这里重点只贴Exynos平台自己的东西,把重点放在数据流向,以及大体的函数调用关系上。其他的只一笔带过。突出重点。

整个exynos 的OMX解码流程非常绕。这里记录几个关键点。

输入端分析:
1,OMXCodec 响应EMPTY_BUFFER_DONE, drainInputBuffer 里面通过buffer id得到这个使用完毕的OMX_BUFFERHEADERTYPE,把上游VideoTrack传来的数据挂上,
然后把OMX_BUFFERHEADERTYPE挂到message->pCmdData ,把message挂到 input port queue,然后启动信号量
2,数据送到decoder之后, OMX_BUFFERHEADERTYPE就可以释放回队列了。
3,可以看出,实际上有两条队列,一条是OMX_core用的OMX_BUFFERHEADERTYPE队列。另一条是openmax component用的Exynos_OMX_MESSAGE队列。
二者关系是Exynos_OMX_MESSAGE-> pCmdData = (OMX_PTR) OMX_BUFFERHEADERTYPE
4, input端,emptythisbuffer的速度控制是这样的:
Exynos_OMX_InputBufferProcess里面就会不停的循环去尝试获取V4L2 buffer 。 例如 :ioctl(pMfcDec->MfcFd, VIDIOC_DQBUF, &qbuf);
这样,解码器里面一旦释放出来buffer,Exynos_OMX_InputBufferProcess就会获取到,
就会调用Exynos_InputBufferReturn,  
调用EmptyBufferDone,
调用EMPTY_BUFFER_DONE,
释放OMX_BUFFERHEADERTYPE被下一次EmptyThisBuffer使用
也就是说,input端的buffer速度控制,是由解码器的解码频率控制V4L2的buffer存取速度,然后进一步控制了EmptyBufferDone的触发,从而最后控制了VideoTrack的demux的执行速度。
解码器没有V4L2的buffer可用时,drainInputBuffer就会阻塞,前段VideoTrack也会阻塞

输出端分析
1,OnVideoEvent的操作包括了AV 同步和显示,只有当一帧被显示出来或者丢弃掉或者延时之后,才会返回。
2,所以fillthisbuffer这个线程的速度控制,实际上是由OnVideoEvent实现的。然后通过信号量,耦合控制了Exynos_OMX_OutputBufferProcess的速度。
2, OnVideoEvent显示完一帧后,得到一个空闲buffer,调用mVideoBuffer->release,然后reuse这个buffer,把这个buffer挂到message->pCmdData 。
再把message挂到Exynos_QUEUE output queue。然后启动信号量。
4,Exynos_OMX_OutputBufferProcess只负责产生解码信息,将解码信息挂到  Output port queue队列里扔出来就完事了。
5,当fillthisbuffer通过信号量通知Exynos_OMX_OutputBufferProcess进行下一帧获取的时候,
首先要调用
qbuf.sequence = gprevIndex[pMfcDec->eInst];
ret = ioctl(pMfcDec->MfcFd, VIDIOC_QBUF, &qbuf);
把这一帧对应index的 q_data, 从V4L2内部dec->outbuf队列里挂到队列尾部,表示这个index对应的各种资源下次可用。
其实这儿调用ioctl(pMfcDec->MfcFd, VIDIOC_QBUF, &qbuf)并不是立刻释放资源,
只是把上一次拿到的index对应q_data放在dec->outbuf的尾端。这些资源即使是被释放,
也是要dec->outbuf中前面的q_data都释放了之后才轮到它.在Exynos_MfcDec_OutputBufferProcess中,
首先就是把上次index对应的q_data放在queue的尾端,然后再通过DQBUF获取最新解码后的数据信息。
下一次再进入outprocess,重复把上次获取到的q_data放在queue尾端,再接着获取最新的解码后数据
如此循环往复。
同时,由于解码器驱动里的某种机制,也会通知到解码器可以再解一帧数据。

0 0
原创粉丝点击