Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Multimedia框架總結(四)MediaPlayer中從Java層到C++層類關系及prepare及之後其他過程

Android Multimedia框架總結(四)MediaPlayer中從Java層到C++層類關系及prepare及之後其他過程

編輯:關於Android編程

前言:在上篇中,分析了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方法也是類似,這裡不再分析。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved