android StageFright框架解读

android多媒体框架

MediaPlayerService Stagefright OpenCore

底层openmax

1、JAVA类的路径:
frameworks/base/media/java/android/media/MediaPlayer.java
JAVA本地调用部分(JNI):
frameworks/base/media/jni/android_media_MediaPlayer.cpp
内容将被编译成为目标库libmedia_jni.so。
2、多媒体客户端部分:
一个服务端的代理,对应用层提供相关的接口,和服务端交互
frameworks/base/media/libmedia
将被编译成库libmedia.so
3、多媒体服务端部分:
//服务端库
frameworks/base/media/libmediaplayerservice
文件为mediaplayerservice.h和mediaplayerservice.cpp
将被编译成库libmediaplayerservice.so。

MediaPlayerService底层框架:
1、opencore
2、stagefright在MediaPlayerService这一层加入的(与opencore并列),android默认选择stagefright。
Stagefright在 Android中是以shared library的形式存在(libstagefright.so),AwesomePlayer可用来播放video/audio。 AwesomePlayer提供许多API,可以让上层的应用程序(Java/JNI)来调用。
二者都基于openmax框架

MediaPlayerService底层框架演变:
最早期OpenCore => StageFright => 现在NuPlayerDriver
现在Android中使用的是Stagefright + NuPlayer并存的方式:
1、Stagefright负责播放本地的媒体文件
2、NuPlayer用于播放网络流媒体文件
从Android L开始NuPlayeri渐渐开始替代了Stagefright,目前本地播放已切换到NuPlayer上了(Android N已移除了Stagefright)

Stagefight的MediaPLayer框架

MediaPlayerService基本调用流程:
1、Java层通过JNI调用Native侧的mediaplayer相关接口
2、mediaPlayerService中创建服务器端客户端,分别实例化相关播放器,把接口事件调用应 用到具体的播放器:
本地媒体调用stagefright,
流媒体调用NuPlayerDriver
3、stagefright会调用AwesomePlayer相应接口, 其实流媒体侧和本地媒体类似的,最后会调用Nuplayer.
AwesomePlayer的几个成员:
mVideoTrack(从多媒体文件中读取视频数据)
mVideoSource(解码视频)
mVideoRenderer(对解码好的视频进行格式转换,android使用的格式为RGB565)
mISurface(重绘图层)
mQueue(event事件队列)

AwesomePlyaer调用其它组件(如MPEG4Extractor)完成,参数mVideoBuffer即为解码后的帧图像,decode则是调用OMXCodec的服务接口. 也就是解码时又通过Binder做了一次跨进程通信. OMXCodec Service文件:
接口定义:
IOMX.h
客户端类:
OMXCodec.cpp
OMXClient.cpp
IOMX.cpp (BpOMX类/BnOMX类)
服务端类:
OMX.cpp
OMXNodeInstance.cpp
说明:
1、 android系统中只用openmax来做code,所以android向上抽象了一层OMXCodec,提供给上层播放器用。 播放器中音视频解码器mVideosource、mAudiosource都是OMXCodec的实例。
2、OMXCodec通过IOMX 依赖binder机制 获得 OMX服务,OMX服务 才是openmax 在android中 实现。
3、 OMX把软编解码和硬件编解码统一看作插件的形式管理起来

StageFrightPlayer.cpp

StagefrightPlayer::StagefrightPlayer()  : mPlayer(new AwesomePlayer) {  ALOGV("StagefrightPlayer");  mPlayer->setListener(this);
}  

数据读取、解码流程:

数据由源到最终解码的流程:
DataSource(URI,FD) => MediaExtractor => mVideoTrack => mVideoSource => mVideoBuffer
DataSource(URI,FD) => MediaExtractor => mAudioTrack => mAudioSource => mAudioPlayer
1、MediaPlayerService调用Stagefright相应的接口
2、Stagefright调用AwesomePlayer相应的接口
3、AwesomePlayer调用OMXCode读取ES数据,并且进行解码的处理
4、OMXCodec调用MediaSource的read函数来获取音视频的数据
5、OMXCodec调用Android的IOMX接口,其实就是Stagefrightde中的 OMX实现
6、OMX调用OMXMaster,而OMXMaster调用OMXPluginBase的接口,这里也可以获取外部的Codec的插件,最终调用对应的解码组建来完成解码,不同解码组件不太相同,后面会做介绍
7、解码完成后,通过OMXcodec返回的裸码流数据会在Awesomeplayer中调用Render模块,实现渲染,从而给用户提供了画面

具体操作步骤:
1、设置DataSource,数据源可以两种URI和FD。
URI可以http://,rtsp://等。
FD是一个本地文件描述符,能过FD,可以找到对应的文件。
2、由DataSource生成MediaExtractor。通过sp extractor = MediaExtractor::Create(dataSource)来实现。
MediaExtractor::Create(dataSource)会根据不同的数据内容创建不同的数据读取对象。
3、通过调用setVideoSource由MediaExtractor分解生成音频数据流(mAudioTrack)和视频数据流(mVideoTrack)。
onPrepareAsyncEvent()如果DataSource是URL的话,根据地址获取数据,并开始缓冲,直到获取到mVideoTrack和mAudioTrack。
mVideoTrack和mAudioTrack通过调用initVideoDecoder()和initAudioDecoder()来生成 mVideoSource和mAudioSource这两个音视频解码器。
然后调用postBufferingEvent_l()提交事件开启缓冲。
4、数据缓冲的执行函数是onBufferingUpdate()。缓冲区有足够的数据可以播放时,调用play_l()开始播放。play_l()中关键是调用了postVideoEvent_l(),提交了 mVideoEvent。
这个事件执行时会调用函数onVideoEvent(),内部执行mVideoSource->read(&mVideoBuffer, &options)进行视频解码。
音频解码通过mAudioPlayer实现。
5、视频解码器解码后通过mVideoSource->read读取一帧帧的数据,放到mVideoBuffer中,mVideoRenderer->render(mVideoBuffer)把视频数据发送到显示模块。
当需要暂停或停止时,调用cancelPlayerEvents来提交事件用来停止解码,还可以选择是否继续缓冲数据。

步骤解读:
1、由数据源DataSource生成MediaExtractor。
通过MediaExtractor::Create(dataSource)来实现。Create方法通过两步来生成相应的 MediaExtractor(MediaExtractor.cpp):

    通过dataSource->sniff来探测数据类型生成相应的Extractor:if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)|| !strcasecmp(mime, "audio/mp4")) {return new MPEG4Extractor(source);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {return new MP3Extractor(source, meta);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {return new AMRExtractor(source);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {return new WAVExtractor(source);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {return new OggExtractor(source);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {return new MatroskaExtractor(source);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {return new MPEG2TSExtractor(source);}

2、音视频轨道分离,生成mVideoTrack和mAudioTrack两个MediaSource。代码如下(AwesomePlayer.cpp):

if (!haveVideo && !strncasecmp(mime, "video/", 6)) {setVideoSource(extractor->getTrack(i));haveVideo = true;
} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {setAudioSource(extractor->getTrack(i));haveAudio = true;
}

得到的这两个MediaSource,只具有parser功能,没有decode功能。还需要对这两个MediaSource做进一步的包装,获取了两个MediaSource(具有parse和decode功能):

mVideoSource = OMXCodec::Create(mClient.interface(), mVideoTrack->getFormat(),false, // createEncodermVideoTrack,NULL, flags);
mAudioSource = OMXCodec::Create(mClient.interface(), mAudioTrack->getFormat(),false, // createEncodermAudioTrack);

3、StageFright的Decode

从流中read packet,parse,decode .都在mVideoSource->read(&mVideoBuffer, &options)函数完成

当调用MediaSource.start()方法后,它的内部就会开始从数据源获取数据并解析,等到缓冲区满后便停止。在AwesomePlayer里就可以调用MediaSource的read方法读取解码后的数据。
a: 对于mVideoSource来说,读取的数据:
mVideoSource->read(&mVideoBuffer, &options)交给显示模块进行渲染,mVideoRenderer->render(mVideoBuffer);
b: 对mAudioSource来说,用mAudioPlayer对mAudioSource进行封装,然后由mAudioPlayer负责读取数据和播放控制。

经过“数据流的封装”得到的两个MediaSource,其实是两个OMXCodec。AwesomePlayer和mAudioPlayer都是从MediaSource中得到数据进行播放。AwesomePlayer得到的是最终需要渲染的原始视频数据, 而mAudioPlayer读取的是最终需要播放的原始音频数据。也就是说,从OMXCodec中读到的数据已经是原始数据了。
(1)、
OMXCodec是怎么把数据源经过parse、decode两步以后转化成原始数据的。从OMXCodec::Create这个构造方法开始,它的参数:
IOMX &omx //指的是一个OMXNodeInstance对象的实例。
MetaData &meta //由MediaSource.getFormat获取得到。这个对象的主要成员就是一个KeyedVector<uint32_t, typed_data> mItems,里面存放了一些代表MediaSource格式信息的名值对。
bool createEncoder //指明OMXCodec是编码还是解码。
MediaSource &source //一个MediaExtractor。
char *matchComponentName //指定一种Codec用于生成这个OMXCodec。

a: findMatchingCodecs寻找对应的Codec,找到以后为当前IOMX分配节点并注册事件监听器:omx->allocateNode(componentName, observer, &node)。
b: 把IOMX封装进一个OMXCodec:

sp<OMXCodec> codec = new OMXCodec(omx, node, quirks,createEncoder, mime, componentName,source);

AwesomePlayer中得到这个OMXCodec后,首先调用mVideoSource->start()进行初始化。 OMXCodec初始化主要是做两件事:
a: 向OpenMAX发送开始命令。mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle)
b: 调用allocateBuffers()分配两个缓冲区,存放在Vector mPortBuffers[2]中,分别用于输入和输出。
(2)、
AwesomePlayer开始播放后,通过mVideoSource->read(&mVideoBuffer, &options)读取数据,实际调用OMXCodec.read来读取数据。而OMXCodec.read主要分两步来实现数据的读取:
a:通过调用drainInputBuffers()对mPortBuffers[kPortIndexInput]进行填充,这一步完成 parse。由OpenMAX从数据源把demux后的数据读取到输入缓冲区,作为OpenMAX的输入。
b:通过fillOutputBuffers()对mPortBuffers[kPortIndexOutput]进行填充,这一步完成 decode。由OpenMAX对输入缓冲区中的数据进行解码,然后把解码后可以显示的视频数据输出到输出缓冲区。
(3)、
AwesomePlayer通过mVideoRenderer->render(mVideoBuffer)对经过parse和decode 处理的数据进行渲染。一个mVideoRenderer其实就是一个包装了IOMXRenderer的AwesomeRemoteRenderer:

mVideoRenderer = new AwesomeRemoteRenderer(mClient.interface()->createRenderer(mISurface, component,(OMX_COLOR_FORMATTYPE)format,decodedWidth, decodedHeight,mVideoWidth, mVideoHeight,rotationDegrees));

android StageFright框架解读相关推荐

  1. android stagefright 框架

    原文:[转]android stagefright 框架 链接:http://blog.chinaunix.net/uid-9838896-id-2976618.html 在Android上,预设的多 ...

  2. android stagefright框架

    http://blog.csdn.net/mirkerson/article/details/38520135 stagefright框架(一)Video Playback的流程 在Android上, ...

  3. Android游戏框架解读之总体结构

    Android游戏开发的框架图无偿奉上. 大小: 55.7 KB 查看图片附件

  4. Stagefright框架解读(—)音视频Playback流程

    转载请注明出处:http://blog.csdn.net/itachi85/article/details/7216639 从Android 2.0,Google引进了Stagefright,并在an ...

  5. StageFright框架流程解读

    1.    StageFright介绍 Android froyo版本多媒体引擎做了变动,新添加了stagefright框架,并且默认情况android选择stagefright,并没有完全抛弃ope ...

  6. Android 开源框架Universal-Image-Loader学习

    Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二)--- 图片 ...

  7. android多媒体框架学习 详解

    原址 一:多媒体框架概述 jellybean 的多媒体跟以前的版本,通过对比没啥变化,最大的变化是google终于舍得给multimedia建个独立的git了(framework/av),等你好久了! ...

  8. android多媒体框架学习 详解 最新版本

    一:多媒体框架概述 jellybean 的多媒体跟以前的版本,通过对比没啥变化,最大的变化是google终于舍得给multimedia建个独立的git了(framework/av),等你好久了!也体现 ...

  9. android 课程大纲,Android课程大纲解读.doc

    Android课程大纲解读 Android课程大纲 Android-Java基础(25天)Java开发环境搭建基础知识 JAVA环境的搭建 Hello World 小程序JAVA语法基础基本语法掌握关 ...

  10. 详解Android主流框架不可或缺的基石

    探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架 ...

最新文章

  1. Android修改包名
  2. mysql 新建子查询_Mysql创建SQL子查询ALIAS
  3. java的知识点13——多态、对象的转型(casting)、final关键字、抽象方法和抽象类、接口的作用、如何定义和使用接口?、接口的多继承、面向接口编程
  4. Bzoj4503 两个串
  5. office2016中插入公式心得
  6. unzip不能解压mysql的zip_Linux中zip压缩和unzip解压缩命令详解
  7. “2019大数据与实体经济深度融合全国行”盛大启动
  8. 计算机小知识分享,分享几小个计算机操作技巧
  9. arduino蜂鸣器音乐代码青花瓷_教你用 Arduino 制造简易金属探测器
  10. SAP License:2021年度最新FICO面试题目
  11. 以前收集到的PHP总结笔记
  12. intellij idea 汉化包
  13. 测试用例的设计方法:等价类划分法
  14. 数据分析师工资高达50万,正在进入每一个行业!
  15. html插入mkv,mkv导入到PR中该怎么做?
  16. ARFoundation系列讲解 - 57 3D物体识别一
  17. 计算机专业有非全日制研究生,计算机专业有双证在职研究生吗?
  18. 介绍一些比较方便好用的爬虫工具和服务
  19. 李永乐团队2021数学基础过关660题勘误表
  20. php 提取文字,如何使用PHP从word文档中提取文本内容?

热门文章

  1. js调用数科阅读器_多种方式实现JS调用后台方法进行数据交互
  2. 思科CISCO ASA 5521 防火墙 Ipsec 配置详解
  3. 3dmax 计算机中丢失,3dmax材质丢失怎么快速找回-解决3dmax材质不见了的方法 - 河东软件园...
  4. 将数据类型为列表中的内容复制粘贴到 SAP 或 Excel
  5. 流氓软件卸载神器geek
  6. anaconda 安装Mosek
  7. android镜子app,Android镜子应用 一面可编程的镜子
  8. struct dirent
  9. 用户研究:用户行为分析
  10. 2018年 数据挖掘“泰迪杯” C题 第二问