开始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后,你应开始调用prepare
或prepareAsync函数。对于文件类型,调用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
函数
文章来源:https://www.toymoban.com/news/detail-435231.html
pause函数其实和start函数流程类似,也是通过mp->pause()返回对应的状态,然后通知上层来暂停的文章来源地址https://www.toymoban.com/news/detail-435231.html
到了这里,关于【学习】从零开始的Android音视频开发(3)——MediaPlayer的prepare/prepareAsync流程和start流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!