zoukankan      html  css  js  c++  java
  • stagefright omx小结

    由于stagefright和openmax运行在两个不同的进程上,所以他们之间的通讯要经过Binder进行处理,本小结不考虑音频这一块,假设视频为MP4封装的AVC编码文件.

     先简单的看一下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运行时的抽象流程如下:

     

    下面以一个mp4文件(avc编码)来分析AwesomePlayer的抽象工作流程(排除Audio部分)
    1) 设置mUri为xxxx.MP4的绝对路径
    2) 启动mQueue,这会创建一个线程来运行threadEntry,并命名为TimedEventQueue,这个线程就是event调度器
    3) 打开mUri所指定的文件,xxxx.MP4文件的头部为(....ftypisom....),则会选择MPEG4Extractor来作为分离器
    4) 使用MPEG4Extractor对MP4进行音视频轨道的分离,并返回MPEG4Source类型的视频轨道给mVideoTrack
    5) 根据mVideoTrack中的编码类型来选择解码器,avc的编码类型会选择AVCDecoder (假设不使用OMX),并返回给mVideoSource,并设置mVideoSource中的mSource为mVideoTrack
    6) 插入onVideoEvent到Queue中,开始解码播放
    7) 通过mVideoSource对象来读取解析好的视频buffer
    8) 如果解析好的buffer还没到AV时间戳同步的时刻,则推迟到下一轮操作
    9) mVideoRenderer为空,则进行初始化,如果不使用OMX会将mVideoRenderer设置为AwesomeLocalRenderer
    10) 通过mVideoRenderer对象将解析好的视频buffer转换成RGB565格式并发给display模块进行图像绘制
    11) 将onVideoEvent重新插入event调度器来循环

    OMX IL作为底层解码部件的集合层,为上层多媒体框架提供了统一的接口,在Android2.2的stagefright中, 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的状态,操作component的port
    4) OMXCodec使用EventHandler通知OMXCodec的Command执行结果
    5) OMXCodec使用OMX_GetParameter和OMX_SetParameter来获取和设置component的属性参数
    6) OMXCodec使用OMX_UseBuffer设置compoment使用的buffer为OMXCodec分配的buffer
    7) OMXCodec使用OMX_EmptyThisBuffer传递未解码的buffer给component,用于解码
    8) OMXCodec使用OMX_FillThisBuffer传递空的bffer给component用于存储解码后的帧
    9) compoment使用EmptyBufferDone通知OMXCodec已完成inputport buffer的读取
    10) compoment使用FillBufferDone通知OMXCodec已完成outputport buffer的填充
    初始化流程如下:

     

     

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

     

     

     

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

     

    OMX IL中的解码分成了两个部分,以AVC的解码为例:
    1) 使用AssemblePartialFrames将input port的buffer组装成帧
    2) 将帧传递给AvcDecoder_OMX进行解码后输出到output port的buffer中
    如下图:

     

     

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

  • 相关阅读:
    .net core 在 Docker 上的部署
    js 运算的内置函数
    vux 项目的构建
    微信小程序开发资料
    HttpClient 调用WebAPI时,传参的三种方式
    jsplumb 中文教程
    MyEclipse最新版-版本更新说明及下载
    如何用VSCode调试Vue.js
    vs2017开发Node.js控制台程序
    Objc的底层并发API
  • 原文地址:https://www.cnblogs.com/shakin/p/4729534.html
Copyright © 2011-2022 走看看