開始prepare后的流程
在之前的流程中我們沒有從MediaPlayer生態(tài)上認(rèn)識各類庫之間的依賴調(diào)用關(guān)系
MediaPlayer部分頭文件在frameworks/base/include/media/目錄中,這個目錄和libmedia.so庫源文件的目錄frameworks/av/media/libmedia/相對應(yīng)。主要頭文件有IMediaPlayerClient.h、mediaplayer.h、IMediaPlayer.h、IMediaPlayerService.h、MediaPlayerInterface.h
。在這些頭文件中,mediaplayer.h
提供了對上層的接口,而其他的幾個頭文件提供的是一些接口類(包含了純虛函數(shù)的類),這些接口必須被實現(xiàn)類繼承才能夠使用
在運行的時候整個MediaPlayer可以大致上分成Client和Server兩個部分,它們分別在兩個進程中運行,它們之間使用Binder
機制實現(xiàn)IPC通信。從框架結(jié)構(gòu)看,IMediaPlayerService.h、IMediaPlayerClient.h和mediaplayer.h這3個頭文件中定義了MediaPlayer的接口和架構(gòu),在目錄中有專門的MediaPlayerService.cpp和mediaplayer.cpp文件對應(yīng)上面三個頭文件,用于MediaPlayer架構(gòu)的實現(xiàn)
在給播放器設(shè)置數(shù)據(jù)源且展現(xiàn)了Surface后,你應(yīng)開始調(diào)用prepare
或prepareAsync函數(shù)。對于文件類型,調(diào)用prepare函數(shù)將暫時阻塞,因為prepare是一個同步函數(shù),直到MediaPlayer已經(jīng)準(zhǔn)備好數(shù)據(jù)即將播放,也就是播放器回調(diào)了onPrepared
函數(shù),進入Prepared狀態(tài)
prepare的執(zhí)行過程
我們可以看到它調(diào)用了_prepare
,也就是native函數(shù)
在網(wǎng)絡(luò)流數(shù)據(jù)傳入MediaPlayer時我們就要用prepareAsync函數(shù)了
除了最后一句 process_media_player_call中的mp->prepareAsync()
在判斷狀態(tài)時不一樣,其它和prepare函數(shù)一樣,它的操作結(jié)果經(jīng)過回調(diào)通知Java層
查看prepareAsync()
再查看prepareAsync_l()
再分析prepareAsync(),mp->prepareAsync對應(yīng)的BnMediaPlayer操作如下
接著分析MediaPlayerService::Client::prepareAsync
這里調(diào)用了AwesomePlayer的prepareAsync函數(shù)(注意:AwesomePlayer只在老版本中存在。較新的版本中已不再使用它)
查看prepareAsync_l
首先判斷mFlags
,此時不是PREPARING。接著啟動mQueue
(類TimedEventQueue)。之后修改mFlags的狀態(tài)為PREPARING
,表示現(xiàn)在正在準(zhǔn)備處理文件的音視頻流。然后實例化一個AwesomeEvent
,放到之前啟動的mQueue中進行通知。隊列中處理的結(jié)果就是調(diào)用AwesomePlayer::onPrepareAsyncEvent
函數(shù)。后面的過程就是初始化解碼器,將流解碼出來,也能知道視頻流的寬高等屬性,然后處于Prepared狀態(tài),不再向下跟蹤,prepare的流程就完成了
我們再回到j(luò)ava層中之前的prepare函數(shù)中的scanInternalSubtitleTracks
函數(shù)
它用于掃描內(nèi)嵌字幕并進行跟蹤,接下來看看MediaPlayer的start函數(shù)
從Paused狀態(tài)變?yōu)镾tarted狀態(tài),如果playback已經(jīng)處于Stopped狀態(tài),或之前從來沒有處于過Started狀態(tài),playback將會開始start
以上的stayAwake用于對屏幕進行操作
首先執(zhí)行PowerManager pm=(PowerManager)getSystemService(Context.POWER_SERVICE);
,通過Context.getSystemService函數(shù)獲取PowerManager
實例。然后通過PowerManager的newWakeLock(int flags,String tag)
來生成WakeLock實例。int flags
指示要獲取哪種WakeLock,不同的鎖對CPU、屏幕、鍵盤燈有不同的影響。獲取WakeLock實例后通過acquire獲取相應(yīng)的鎖,然后進行其他業(yè)務(wù)邏輯的操作,最后使用release釋放(必需的)
flags類型
1.PARTIAL_WAKE_LOCK
保持CPU運轉(zhuǎn),屏幕和鍵盤燈有可能是關(guān)閉的
2.SCREEN_DIM_WAKE_LOCK
保持CPU運轉(zhuǎn),允許保持屏幕顯示但有可能是灰的,允許關(guān)閉鍵盤燈
3.SCREEN_BRIGHT_WAKE_LOCK
保持CPU運轉(zhuǎn),允許保持屏幕高亮顯示,允許關(guān)閉鍵盤燈
4.FULL_WAKE_LOCK
保持CPU運轉(zhuǎn),保持屏幕高亮顯示,鍵盤燈保持亮度
5.ACQUIRE_CAUSES_WAKEUP
正常喚醒鎖實際上并不打開照明,相反,一旦打開它們會一直保持。當(dāng)獲得WakeLock時,這個標(biāo)志會使屏幕或/和鍵盤立即打開。一個典型應(yīng)用是可以立即看到對用戶來說重要的通知
最后通過updateSurfaceScreenOn函數(shù)更新屏幕上的Surface
回到最上面的start函數(shù)中,再JNI中對應(yīng)android_media_MediaPlayer_start函數(shù)
從MediaPlayer調(diào)用start函數(shù)開始,就進入了視頻播放環(huán)節(jié),最終到C++的mediaplayer.cpp中實現(xiàn),我們先分析下mediaplayer.h。在其中實現(xiàn)了MediaPlayer的基本播放控制操作。另外一個類DeathNotifier
是在MediaPlayer類中定義的,它繼承了IBinder類中的DeathRecipient
類,這些類都是為進程間通信做準(zhǔn)備的
可以發(fā)現(xiàn)調(diào)用start函數(shù)后底層返回了一個狀態(tài)以便我們知道是否處于Started狀態(tài),這是需要用process_media_player_call
判定這個返回的狀態(tài),然后通知java層中的回調(diào)事件
接下來看看pause
函數(shù)
文章來源:http://www.zghlxwxcb.cn/news/detail-435231.html
pause函數(shù)其實和start函數(shù)流程類似,也是通過mp->pause()返回對應(yīng)的狀態(tài),然后通知上層來暫停的文章來源地址http://www.zghlxwxcb.cn/news/detail-435231.html
到了這里,關(guān)于【學(xué)習(xí)】從零開始的Android音視頻開發(fā)(3)——MediaPlayer的prepare/prepareAsync流程和start流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!