android 视频框架

由于stagefrightopenmax运行在两个不同的进程上,所以他们之间的通讯要经过openBinder进行处理,openBinder这一块还没有了解,所以恕stagefrightopenmax之间的通信不能做分析,还有就是本小结不考虑音频这一块,假设视频为MP4封装的AVC编码文件.

最早看的是opencore,opencore兼顾了多平台的移植性而过于复杂,后来就改看stagefright,stagefright使用的OMX ILopencore中的代码........所以我蛮期待google什么时候能重写一个OMX IL框架来全面替代opencore

 先简单的看一下stagefright是怎么工作的, stagefright使用event来进行驱动,event调度器和event运行在同一个线程中,播放器向队列插入event来驱动整个解码流程,event调度器的工作抽象流程如下:
1
 检测队列是否为空,为空则等待event的插入

2
 获取队列中的第一个event
3
 计算event所要求的delay time后进行延时操作

4
 event从队列中剔除后执行该event
event
调度器通过不断循环这样的过程来进行调度,在具体代码中还会根据特殊情况进而改变调度过程,目前event事件有如下几种
:
1
 onVideoEvent
2
 onStreamDone
3
 onBufferingUpdate
4
 onCheckAudioStatus
5
 onPrepareAsyncEvent

stagefright的播放器类为AwesomePlayer,这个类主要有以下几个成员(排除Audio部分):
1. mVideoSource(
解码视频
)
2. mVideoTrack(
从多媒体文件中读取视频数据
)
3. mVideoRenderer(
对解码好的视频进行格式转换,android使用的格式为
RGB565)
4. mISurface(
重绘图层
)
5. mQueue(event
事件队列)

stagefright运行时的抽象流程如下:

android 视频框架_第1张图片

下面以一个mp4文件(avc编码)来分析AwesomePlayer的抽象工作流程(排除 Audio部分)
1) 
设置mUrixxxx.MP4的绝对路径

2) 
启动mQueue,这会创建一个线程来运行 threadEntry,并命名为TimedEventQueue,这个线程就是event调度器
3) 
打开mUri所指定的文件,xxxx.MP4文件的头部为(....ftypisom....),则会选择MPEG4Extractor来作为分离器
4) 
使用 MPEG4ExtractorMP4进行音视频轨道的分离,并返回MPEG4Source类型的视频轨道给mVideoTrack
5) 
根据 mVideoTrack中的编码类型来选择解码器,avc的编码类型会选择AVCDecoder (假设不使用OMX),并返回给mVideoSource,并设置mVideoSource中的mSource
mVideoTrack
6) 
插入onVideoEventQueue,开始解码播放

7) 
通过mVideoSource对象来读取解析好的视频buffer
8) 
如果解析好的buffer还没到AV时间戳同步的时刻,则推迟到下一轮操作

9) mVideoRenderer
为空,则进行初始化,如果不使用 OMX会将mVideoRenderer设置为AwesomeLocalRenderer
10) 
通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式并发给display模块进行图像绘制

11) 
onVideoEvent重新插入event调度器来循环

OMX IL作为底层解码部件的集合层,为上层多媒体框架提供了统一的接口,Android2.2stagefright, stagefright使用的是opencore中的OMX IL实现,使用该OMX IL框架需要将mVideoSource设置为OMXCodec,OMX IL层的对外接口主要有以下几种:
1) stagefright
使用 OMX_MasterInit初始化OMX框架,加载
component
2) stagefright
使用 OMX_MasterGetHandle匹配OMX中的component,匹配成功则返回OMX_HANDLETYPE用于OMXCodec component之间进行通信

3) OMXCodec
使用OMX_SendCommand来设置component的状态,操作 componentport
4) OMXCodec
使用EventHandler通知OMXCodecCommand执行结果

5) OMXCodec
使用OMX_GetParameterOMX_SetParameter来获取和设置component的属性参数
6) OMXCodec
使用 OMX_UseBuffer设置compoment使用的bufferOMXCodec分配的buffer
7) OMXCodec
使用 OMX_EmptyThisBuffer传递未解码的buffercomponent,用于解码

8) OMXCodec
使用 OMX_FillThisBuffer传递空的bffercomponent用于存储解码后的帧
9) compoment
使用 EmptyBufferDone通知OMXCodec已完成inputport buffer的读取
10) compoment
使用 FillBufferDone通知OMXCodec已完成outputport buffer的填充
初始化流程如下:

 android 视频框架_第2张图片

OMX component的数据主要通过port来进行交互,port分为inputoutput , port通过和OMXCodec共享buffer来进行编解码,如下图:

 android 视频框架_第3张图片

buffer的处理主要由以下4个命令来进行驱动:
l OMXCodec使用 OMX_EmptyThisBuffer传递未解码的buffercomponent,component收到该命令后会读取input port buffer中的数据,将其组装成帧进行解码,读取buffer中的数据完成后会调用EmptyBufferDone通知
OMXCodec
l compoment 使用EmptyBufferDone通知OMXCodec已完成inputport buffer的读取, OMXCodec收到该命令后会通过mVideoTrack读取新的视频bufferinput portbuffer,并调用OMX_EmptyThisBuffer通知
component
l OMXCodec使用 OMX_FillThisBuffer传递空的bffercomponent用于存储解码后的帧,component收到该命令后将解码好的帧数据复制到该buffer,然后调用FillBufferDone通知
OMXCodec
l compoment 使用FillBufferDone通知OMXCodec已完成outputport buffer的填充, OMXCodec收到该命令后将解码好的帧传递给mISurface进行图像绘制,绘制完毕后使用OMX_FillThisBuffer通知 component有空的buffer可填充

抽象图如下:

android 视频框架_第4张图片

OMX IL中的解码分成了两个部分,AVC的解码为例:
1) 
使用AssemblePartialFramesinput portbuffer组装成帧

2) 
将帧传递给AvcDecoder_OMX进行解码后输出到output portbuffer
如下图:

 android 视频框架_第5张图片

假设input port buffer中有2buffer,分别为buffer_1buffer_2,并且这两个buffer所携带的数据可构成1, AssemblePartialFrames首先申请一块内存区域tmp_buffer_1,buffer_1的有效数据拷贝到 tmp_buffer_1,然后再申请一块内存区域tmp_buffer_2,申请完后第一步将tmp_buffer_1的数据拷贝到自身的前半部,第二步将buffer_2的有效数据拷贝到后半部来组合成为1.
组合完成后将tmp_buffer_2output portbuffer交给AvcDecoder_OMX进行解码, AvcDecoder_OMX将解码后的帧数据拷贝到output port buffer.

你可能感兴趣的:(android)