前言:在上篇中,分析了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 Multimedia框架总结(四)MediaPlayer从Java层到C++层类关系及prepare及之后其他过...相关推荐

  1. Android MultiMedia框架完全解析 - 概览

    之前的工作中,一直在看Android MultiMedia的一些东西,关注我博客的同学也许知道我换工作了,以后将要从事Camera相关的工作,于是乎,将之前整理存放在有道云笔记里面的一些东西发出来,整 ...

  2. Android Multimedia框架总结(二十四)MediaMuxer实现手机屏幕录制成gif图

    原址:http://blog.csdn.net/hejjunlin/article/details/53866405 前言:上篇中,介绍是用MediaMuxer与MediaExtractor进入音视频 ...

  3. Android Multimedia框架总结(十七)音频开发基础知识

    原文链接:http://blog.csdn.net/hejjunlin/article/details/53078828 近年来,唱吧,全民K歌,QQ音乐,等成为音频软件的主流力量,音频开发一直是多媒 ...

  4. Android Multimedia框架总结(二十八)NuPlayer到OMX过程

    原址 NuPlayer是谷歌新研发的.  AwesomePlayer存在BUG,谷歌早已在android m 版本中弃用. sp<MediaPlayerBase> MediaPlayerS ...

  5. 8. Android MultiMedia框架完全解析 - prepareAsync的过程分析

    还是从mediaplayer.cpp文件开始分析: status_t MediaPlayer::prepareAsync() {ALOGV("prepareAsync");Mute ...

  6. 10. Android MultiMedia框架完全解析 - MediaExtractor::Create函数的解析和FslExtractor分析

    先来看看MediaExtractor所处的位置: (一)创建流程 在GenericSource.cpp的NuPlayer::GenericSource::initFromDataSource()函数中 ...

  7. Java程序员从笨鸟到菜鸟之(九十四)深入java虚拟机(三)——类的生命周期(下)类的初始化...

    上接深入java虚拟机--深入java虚拟机(二)--类加载器详解(上),在上一篇文章中,我们讲解了类的生命周期的加载和连接,这一篇我们接着上面往下看. 类的初始化:在类的生命周期执行完加载和连接之后 ...

  8. 1、java集合:java集合详解及类关系图

    List和Set继承自Collection接口. Set无序不允许元素重复.HashSet和TreeSet是两个主要的实现类. List有序且允许元素重复,支持null对象.ArrayList.Lin ...

  9. Android开发实践:Java层与Jni层的数组传递

    Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的Socket代码发送出去,当然,Jni ...

  10. Java层与Jni层的数组传递(转)

    源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...

最新文章

  1. 0119吧 iPhone 屏幕尺寸
  2. 一次利用位图索引进行SQL优化的案例
  3. 永远不会执行的cron表达式
  4. python字典基础知识点
  5. 三维重建16:概率图模型 模板类编程
  6. Unable to lock JVM Memory: error=12--elasticsearch
  7. 为了彻底理解乱码问题,一怒之下我把字符集历史扒了个底朝天
  8. Bootstrap 公布长期支持计划,Bootstrap 3 生命周期结束
  9. leetcode 1446 连续字符
  10. iOS Xcode Implicit declaration of function 'callbackBlock' is invalid in C99
  11. jquery设置元素的readonly和disabled
  12. 如何在CSDN删除自己上传的资源
  13. jzoj 1388. 【2012.02.25普及组】探索的奶牛
  14. 各种加速卡 异构计算
  15. 【python】hasattr()、getattr()、setattr() 函数使用详解
  16. SwiftUI脑洞大开打造实时显示当前值的Slider(滑动器)
  17. K-means 代碼
  18. 【Linux】Linux文件与文件的存储
  19. [精华]AMF的磨叽引发的血案(Step24 IMS语音特性判决)
  20. sql 同时(更新)update和(查询)select同一张表

热门文章

  1. Echarts 折线图最后一个点发光闪烁效果
  2. 一些自己使用VS2015的心得
  3. Django搭建的个人博客
  4. 有哪些激光雷达SLAM算法?
  5. Selectsort Tournamentsort Heapsort
  6. 第一章:开始启程-你的第一行Android代码
  7. python 第一课作用
  8. Wicket实战(二)hello world
  9. Junit学习笔记(二): 源码分析(2)-命令和组合模式
  10. 关于DLL中的哪段代码被执行的处理方法