【学习】从零开始的Android音视频开发(3)——MediaPlayer的prepare/prepareAsync流程和start流程

开始prepare后的流程

在之前的流程中我们没有从MediaPlayer生态上认识各类库之间的依赖调用关系

MediaPlayer部分头文件在frameworks/base/include/media/目录中,这个目录和libmedia.so库源文件的目录frameworks/av/media/libmedia/相对应。主要头文件有IMediaPlayerClient.h、mediaplayer.h、IMediaPlayer.h、IMediaPlayerService.h、MediaPlayerInterface.h。在这些头文件中,mediaplayer.h提供了对上层的接口,而其他的几个头文件提供的是一些接口类(包含了纯虚函数的类),这些接口必须被实现类继承才能够使用

在这里插入图片描述

在运行的时候整个MediaPlayer可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通信。从框架结构看,IMediaPlayerService.h、IMediaPlayerClient.h和mediaplayer.h这3个头文件中定义了MediaPlayer的接口和架构,在目录中有专门的MediaPlayerService.cpp和mediaplayer.cpp文件对应上面三个头文件,用于MediaPlayer架构的实现

在给播放器设置数据源且展现了Surface后,你应开始调用prepareprepareAsync函数。对于文件类型,调用prepare函数将暂时阻塞,因为prepare是一个同步函数,直到MediaPlayer已经准备好数据即将播放,也就是播放器回调了onPrepared函数,进入Prepared状态

prepare的执行过程

在这里插入图片描述

我们可以看到它调用了_prepare,也就是native函数

在这里插入图片描述

在网络流数据传入MediaPlayer时我们就要用prepareAsync函数了

在这里插入图片描述

除了最后一句 process_media_player_call中的mp->prepareAsync()在判断状态时不一样,其它和prepare函数一样,它的操作结果经过回调通知Java层

查看prepareAsync()

在这里插入图片描述

再查看prepareAsync_l()

在这里插入图片描述

再分析prepareAsync(),mp->prepareAsync对应的BnMediaPlayer操作如下

在这里插入图片描述

在这里插入图片描述

接着分析MediaPlayerService::Client::prepareAsync

在这里插入图片描述

这里调用了AwesomePlayer的prepareAsync函数(注意:AwesomePlayer只在老版本中存在。较新的版本中已不再使用它)

在这里插入图片描述

查看prepareAsync_l

在这里插入图片描述

首先判断mFlags,此时不是PREPARING。接着启动mQueue(类TimedEventQueue)。之后修改mFlags的状态为PREPARING,表示现在正在准备处理文件的音视频流。然后实例化一个AwesomeEvent,放到之前启动的mQueue中进行通知。队列中处理的结果就是调用AwesomePlayer::onPrepareAsyncEvent函数。后面的过程就是初始化解码器,将流解码出来,也能知道视频流的宽高等属性,然后处于Prepared状态,不再向下跟踪,prepare的流程就完成了

我们再回到java层中之前的prepare函数中的scanInternalSubtitleTracks函数

在这里插入图片描述

它用于扫描内嵌字幕并进行跟踪,接下来看看MediaPlayer的start函数

在这里插入图片描述

从Paused状态变为Started状态,如果playback已经处于Stopped状态,或之前从来没有处于过Started状态,playback将会开始start

以上的stayAwake用于对屏幕进行操作

在这里插入图片描述

首先执行PowerManager pm=(PowerManager)getSystemService(Context.POWER_SERVICE);,通过Context.getSystemService函数获取PowerManager实例。然后通过PowerManager的newWakeLock(int flags,String tag)来生成WakeLock实例。int flags指示要获取哪种WakeLock,不同的锁对CPU、屏幕、键盘灯有不同的影响。获取WakeLock实例后通过acquire获取相应的锁,然后进行其他业务逻辑的操作,最后使用release释放(必需的)

flags类型

1.PARTIAL_WAKE_LOCK

保持CPU运转,屏幕和键盘灯有可能是关闭的

2.SCREEN_DIM_WAKE_LOCK

保持CPU运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

3.SCREEN_BRIGHT_WAKE_LOCK

保持CPU运转,允许保持屏幕高亮显示,允许关闭键盘灯

4.FULL_WAKE_LOCK

保持CPU运转,保持屏幕高亮显示,键盘灯保持亮度

5.ACQUIRE_CAUSES_WAKEUP

正常唤醒锁实际上并不打开照明,相反,一旦打开它们会一直保持。当获得WakeLock时,这个标志会使屏幕或/和键盘立即打开。一个典型应用是可以立即看到对用户来说重要的通知

最后通过updateSurfaceScreenOn函数更新屏幕上的Surface

回到最上面的start函数中,再JNI中对应android_media_MediaPlayer_start函数

在这里插入图片描述

从MediaPlayer调用start函数开始,就进入了视频播放环节,最终到C++的mediaplayer.cpp中实现,我们先分析下mediaplayer.h。在其中实现了MediaPlayer的基本播放控制操作。另外一个类DeathNotifier是在MediaPlayer类中定义的,它继承了IBinder类中的DeathRecipient类,这些类都是为进程间通信做准备的

在这里插入图片描述

可以发现调用start函数后底层返回了一个状态以便我们知道是否处于Started状态,这是需要用process_media_player_call判定这个返回的状态,然后通知java层中的回调事件

接下来看看pause函数

在这里插入图片描述

在这里插入图片描述

pause函数其实和start函数流程类似,也是通过mp->pause()返回对应的状态,然后通知上层来暂停的

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值