Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程
转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/52420803
前言:在上篇中,分析了MediaPlayer的从创建到setDataSource过程,尽管看了代码,但是没有从MediaPlayer生态上认识各类库之间依赖调用关系,在本篇中将作一个补充整体上的认识。看下今天的Agenda:
- MediaPlayer各个so库之间关系结构图
- MediaPlayer各个具体类之间依赖关系图
- prepare的执行过程
- prepareAsync执行过程
- prepare和prepareAsync区别
- start执行过程
- pause执行过程
MediaPlayer各个so库之间关系结构图
在各个so中,libmedia.so位于核心的位置,它对上层的提供的jni主要是Java中MediaPlayer类,类libmedia_jni.so通过调用MediaPlayer类提供对Java的接口,并且实现了Android.media.MediaPlayer类。
libmediaplayerservice.so是Media的服务器,它通过继承libmedia.so的类实现服务器的功能,而libmedia.so中的另外一部分内容则通过IPC和libmediaplayerservice.so进行通信。libmediaplayerservice.so的真正功能通过调用OpenCore Player来完成解码。OpenCore是一个多媒体的框架,从宏观上来看,它主要包含了两大方面的内容:
- PVPlayer:提供媒体播放器的功能,完成各种音频(Audio)、视频(Video)流的回放(Playback)功能
- PVAuthor:提供媒体流记录的功能,完成各种音频(Audio)、视频(Video)流的以及静态图像捕获功能
- PVPlayer和PVAuthor以SDK的形式提供给开发者,可以在这个SDK之上构建多种应用程序和服务。在移动终端中常常使用的多媒体应用程序,例如媒体播放器、照相机、录像机、录音机等等。
- OpenCore组织了codec等一些组建,统一接口,MediaPlayer调用OpenCore的东西,不用太关心下层的codec是什么,这个库在6.0上已经不用,代替它的是Stagefright,比OpenCore简洁很多。
MediaPlayer部分的头文件在frameworks/base/include/media/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/media/libmedia/相对应的。主要的头文件有以下几个:- IMediaPlayerClient.h
- mediaplayer.h
- IMediaPlayer.h
- IMediaPlayerService.h
- MediaPlayerInterface.h
在这些头文件mediaplayer.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。
MediaPlayer各个具体类之间依赖关系图
整个MediaPlayer在运行的时候,可以分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通信。从框架结构上来看,IMediaPlayerService.h、IMediaPlayerClient.h和MediaPlayer.h三个类定义了MeidaPlayer的接口和架构,MediaPlayerService.cpp和mediaplayer.cpp两个文件用于MeidaPlayer架构的实现,MeidaPlayer的具体功能在PVPlayer(库libopencoreplayer.so)中的实现。
prepare的执行过程
prepare播放器为playback,这是个同步方法,当setDataSource且展现了surface,你应当开始调用prepare或prepareAsync方法,对于文件类型,调用prepare方法将暂时block,直到MediaPlayer已经为playback准备好。接着调用native层android_media_MediaPlayer_prepare方法:
上述1,2,3 我们在上一篇中,曾结介绍过,1中getVideoSurfaceTexture是获取一个IGraphicBufferProducer类型指针,2中是setVideoSurfaceTexture,这个xxx中最后的部分介绍过,这里不再细说。3中是个判定并且notify的方法,这里是送进mp->prepare的方法调用的状态送入,如果不ok,就notify相关error或者抛出异常。我们知道还有一个prepareAsync方法,我们前面的思路都是顺着MediaPlayer中create方法来的。
prepareAsync的执行过程
如果是下面这种场景,一个网络url送过来,视频非常大:这时就要用到异步prepare
看下MediaPlayer中prepareAsync方法: 准备好播放器为接下来playback,这是个异步方法,当setDataSource且展现了surface,你应当开始调用prepare或prepareAsync方法了,对于流类型,你应该调用prepareAsync方法能立马返回,而不是在没有足够的流数据被缓冲时一直block
本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52420803
这是个native方法,我们看android_media_MediaPlayer_prepareAsync方法:
从代码上看,除了最后process_media_player_call中mp->prepareAsync()判断状态时,不一样,其他和prepare都是一样。它的操作结果经过回调通知给Java层。
看下media/mediaplayer.h中prepareAsync函数,c++代码:
上面代码总结为:首先判断mFlags,此时不是preparing。接着启动mQueue(类TimedEventQueue)。之后修改mFlags的状态为PREPARING,表示现在正在准备处理文件的音视频流。然后通过实例一个AwesomeEvent,然后放到之前启动的mQueue中进行通知出去。
queue中处理的结果就是调用AwesomePlayer::onPrepareAsyncEvent函数。后面的过程就是初始化解码器,将流解码出来,也能知道视频流的宽高等属性,然后通知prepared.不再向下跟踪。prepare的流程就完成了。
接下来,我们再回到java层中之前prepare方法中的scanInternalSubtitleTracks()方法
这个方法是扫描内嵌字幕并进行跟踪.
start的执行过程
接下来分析看下MediaPlayer中start过程:
以上代码总结为:start方法用于start或者重新恢复播放,如果playback先前已暂停,playback将开始从paused状态变成在start状态,如果playback已经是stopped,或之前从来没有started过,playback将会开始start。
3中执行stayAwake()中是对屏幕进行操作:
- 首先PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
- 通过 Context.getSystemService().方法获取PowerManager实例。
- 然后通过PowerManager的newWakeLock((int flags, String tag)来生成WakeLock实例。int flags指示要获取哪种WakeLock,不同的Lock对CPU、屏幕、键盘灯有不同影响。获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他业务逻辑的操作,最后使用release()释放(释放是必须的)。
关于int flags,各种锁的类型对CPU 、屏幕、键盘的影响:- PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
- SCREEN_DIM_WAKE_LOCK:保持CPU运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
- SCREEN_BRIGHT_WAKE_LOCK:保持CPU运转,允许保持屏幕高亮显示,允许关闭键盘灯
- FULL_WAKE_LOCK:保持CPU运转,保持屏幕高亮显示,键盘灯也保持亮度
- ACQUIRE_CAUSES_WAKEUP:正常唤醒锁实际上并不打开照明。相反,一旦打开他们会一直仍然保持。当获得wakelock,这个标志会使屏幕或/和键盘立即打开。一个典型的使用就是可以立即看到那些对用户重要的通知。
最后通过updateSurfaceScreenOn()进行,更新屏幕上的Surface.我们还是回到最上面start方法中。最后会调用_start方法到native jni中。
从中间的mp-start开始,就调到底层c++,在native中引入media/mediaplayer.h,我们进入这个头文件看看:
从接口中可以看出MediaPlayer类实现了一个MediaPlayer的基本playback操作,播放(start)、停止(stop)、暂停(pause), 重置(reset)等。
另外的一个类DeathNotifier在MediaPlayer类中定义,它继承了IBinder类中的DeathRecipient类,这些作用都是为了进程间通信准备:
以下过程就是和mediaplayerservice通过IPC进行通信,不再向下分析。
可以发现start后,底层来返回一个状态,是ok还是不ok的。这就回到process_media_player_call中判定这个返回的状态,然后notify java层中的回调函数。
pause的执行过程
接下来,再看下pause方法,
在对应的jni中找到android_media_MediaPlayer_pause方法
pause方法,可以看到和start的流程类似,也是通过 mp->pause()返回对应的状态,然后notify上层去pause
还有一个stop方法也是类似,这里不再分析。
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程的更多相关文章
- Android Multimedia框架总结(七)C++中MediaPlayer的C/S架构补充及MediaService介绍
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼,文章链接: http://blog.csdn.net/hejjunlin/article/details/52465168 前面一篇主要介绍 ...
- Android Multimedia框架总结(六)C++中MediaPlayer的C/S架构
转载请把头部出处链接和尾部二维码一起转载,本文出自: http://blog.csdn.net/hejjunlin/article/details/52435789 前面几节中,都是通过java层调用 ...
- Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期
请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52349221 前言:从本篇开始,将进入Multimedia框架,包含 ...
- Android Multimedia框架总结(十五)Camera框架之Camera2补充
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...
- Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882 前言:上篇文< ...
- Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085 不知不觉到第九篇了,感觉还有 ...
- Myeclipse中把java代码导成UML类图
Myeclipse中把java代码导成UML类图 1.右键点击项目名称,选择New-------àUML2 Model 2.给类图命名 3.导成类图 1)如果要把整个项目导成类图,则把整个项目拖到类图 ...
- Android Multimedia框架总结(十四)Camera框架初识及自定义相机案例
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52738492 前言:国庆节告一段 ...
- Android Multimedia框架总结(十三)CodeC部分之OpenMAX框架初识及接口与适配层实现
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629598 前言:上篇中介绍O ...
随机推荐
- [JS]手动实现一个横屏滚动公告js插件
前言 工作中要用到.在github上找的大部分都是竖屏滚动没办法只能自己手动写. 本来只是想随便实现一下的,结果一时兴起把它弄成了一个简单的小插件,开了个github仓库(希望路过点个星) JS横屏滚 ...
- spark-shell报错:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/fs/FSDataInputStream
环境: openSUSE42.2 hadoop2.6.0-cdh5.10.0 spark1.6.0-cdh5.10.0 按照网上的spark安装教程安装完之后,启动spark-shell,出现如下报错 ...
- [SDOI2014]重建
题目描述 T国有N个城市,用若干双向道路连接.一对城市之间至多存在一条道路. 在一次洪水之后,一些道路受损无法通行.虽然已经有人开始调查道路的损毁情况,但直到现在几乎没有消息传回. 辛运的是,此前T国 ...
- [SHOI2008]cactus仙人掌图
[题目描述] 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例 ...
- [USACO14DEC]后卫马克Guard Mark
题目描述 FJ将飞盘抛向身高为H(1 <= H <= 1,000,000,000)的Mark,但是Mark 被N(2 <= N <= 20)头牛包围.牛们可以叠成一个牛塔,如果 ...
- 51nod 1686 第k大区间
1686 第K大区间 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 定义一个区间的值为其众数出现的次数.现给出n个数,求将所有区间的值排序后,第K大的值为多少. ...
- UVA12186
给出一个树状关系图,公司里只有一个老板编号为0,其他人员从1开始编号.除了老板,每个人都有一个直接上司,没有下属的员工成为工人. 工人们想写一份加工资的请愿书,只有当不少于员工的所有下属的T%人递交请 ...
- 51Nod 1125 交换机器的最小代价
题目描述: 有N台机器重量各不相等,现在要求把这些机器按照重量排序,重量从左到右依次递增.移动机器只能做交换操作,但交换机器要花费一定的费用,费用的大小就是交换机器重量的和.例如:3 2 1,交换1 ...
- bzoj5100 [POI2018]Plan metra 构造
5100: [POI2018]Plan metra Time Limit: 40 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 189 Sol ...
- java continue与break区别
在循环体中跳出循环语句有continue与break语句 continue:跳出本次循环,包括本次循环continue后面的语句, break:跳出循环体,就是说一遇到break循环就结束. 代码: ...