天天看點

android MediaPlayer 源碼分析 1

android 在java api中播放一個音樂檔案:

MediaPlayer player = new MediaPlayer();

try {

    player.setDataSource("/storage/emulated/0/test.aac");

    player.prepare();

} catch (IOException e) {

    e.printStackTrace();

}

player.start();

上面調用如此簡單,framework層裡面可是做了非常多的工作,追一下源碼。基于android 10,api-29.本篇僅僅為了分析從MediaPlayer.java 到NuPlayer的關聯過程,主要跟蹤setDataSource 和prepare兩個函數,至于後續NuPlayer如何解複用,解碼,渲染,已經其中涉及到的音視訊資料流轉,控制,驅動線程模型,不涉及。大圖:

android MediaPlayer 源碼分析 1

 上圖的文字模式:

mediaplayer
|------MediaPlayer.java 
|    \base\media\java\android\media
|        |--static { 
|        |  System.loadLibrary("media_jni"); 
|        |  native_init(); 
|        |  }
|        |--MediaPlyer()
|        |    |--Looper.myLooper()//建立了looper線程
|        |    |    |--new EventHandler(this, looper)
|        |    |--mTimeProvider = new TimeProvider(this);
|        |    |--mOpenSubtitleSources = new Vector<InputStream>();
|        |    |--native_setup(new WeakReference<MediaPlayer>(this))
|        |    |--baseRegisterPlayer()
|        |--setDataSource()
|        |    |--nativeSetDataSource( 
|        |    | IBinder httpServiceBinder, String path, String[] keys, String[] values)
|        |    |--native void _setDataSource(FileDescriptor fd, long offset, long length)
|        |--prepare()
|-----android_media_MediaPlayer.cpp 
|    \base\media\jni
|        |--android_media_MediaPlayer_native_init()
|        |--android_media_MediaPlayer_native_setup()
|        |    |--sp<MediaPlayer> mp = new MediaPlayer();
|        |    |--sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
|        |    |--setMediaPlayer(env, thiz, mp);
|        |--android_media_MediaPlayer_setDataSourceFD()
|        |    |--mp->setDataSource(fd, offset, length)
|        |--android_media_MediaPlayer_prepare()
|             |--mp->prepare()
|------mediaplayer.cpp   
|      \av\media\libmedia
|        |--MediaPlayer()
|        |--setDataSource()
|        |    |--sp<IMediaPlayer> player(service->create(this, mAudioSessionId)
|        |    |--attachNewPlayer() 
|        |    | sp<IMediaPlayer>  mPlayer
|        |    |--player->setDataSource
|        |--prepare()
|        |    |--prepareAsync_l()
|        |    |    |--mPlayer->setParameter
|        |    |    |--mPlayer->prepareAsync()
|------IMediaPlayerService.cpp 
|      \av\media\libmedia
|        |--BpMediaPlayerService
|        |    |--create()
|        |--BnMediaPlayerService::onTransact()
|------MediaPlayerService.cpp 
    \av\media\libmediaplayerservice
        |--create()
        |    |--return  new Client()
        |    |    |--MediaPlayerService::Client
        |    |        |--setDataSource
        |    |        |    |--setDataSource_pre
        |    |        |        |--MediaPlayerFactory::getPlayerType(this, url); 
        |    |        |        |這裡,通過url來比對合适的player類型 
        |    |        |        |宏定義:GET_PLAYER_TYPE_IMPL 
        |    |        |        |其原理是 周遊  sFactoryMap ,(MediaPlayerService構造函數中就對其進行了初始,注冊了幾個内置的Factory到該表中) 
        |    |        |        |調用每一個factory的虛函數scoreFactory(), 表明這個factory對目前url的比對分數, 
        |    |        |        |選取分數最高的一個factory,也就是最比對的factory。 
        |    |        |        |是以這裡注冊的NuplayerFactory,可以很容易的替換成其他Factory,架構很靈活。
        |    |        |        |--setDataSource_pre(player_type playerType)
        |    |        |            |--mPlayer = createPlayer()
        |    |        |                |--MediaPlayerFactory::createPlayer(playerType, mListener, mPid); 
        |    |        |                MediaPlayerFactory中的靜态方法,建立Plyer, 
        |    |        |                其内部通過傳入的playerType類型,從sFactoryMap表中取對應的factory, 
        |    |        |                比如之前注冊的NuplayerFactory,來建立player
        |    |        |--sp<MediaPlayerBase> mPlayer; 
        |    |        |--sp<MediaPlayerService> mService; 
        |    |        |--sp<IMediaPlayerClient> mClient;
        |    |--在MediaPlayerService中crate 的實際上是一個client,用戶端 并且MediaPlayerService會把這個client加到 
        |     SortedVector< wp<Client> > mClients;有序向量中記錄 這個 client 自身就是一個 BnMediaPlayer,
        |     是以由 mediaplayer.cpp 中的 mPlayer的操作直接調用到這個client裡面的實作
        |--MediaPlayerService()構造函數
            |--MediaPlayerFactory::registerBuiltinFactories(); 
            |注冊内置的 player工廠
            |    new NuPlayerFactory();
            |    new TestPlayerFactory();
            |    這裡将這這兩個Factory注冊進去,加入到對象 MediaPlayerFactory 中的KeyedVector<player_type, IFactory*>  sFactoryMap 
            |    我們可以在這裡添加自己的Player, 在factory比對分數的時候對 自定義的類型給出一個高的比對分數,實作自定義的player,
            |    用以對某些特定格式使用自定義的player代替預設的Nuplayer
            |--instantiate() //在av/media/mediaserver/main_mediaserver.cpp 生成可執行檔案,被.rc啟動腳本記錄,系統啟動的時候會将這個程式運作,把media.player服務運作起來。
               defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService())
           

 T1:player 耦合點 --MediaPlayerFactory::getPlayerType(this, url); 

這裡,通過url來比對合适的player類型 宏定義:GET_PLAYER_TYPE_IMPL 

其原理是 周遊  sFactoryMap ,(MediaPlayerService構造函數中就對其進行了初始化,注冊了幾個内置的Factory到該表中,目前隻有一個Nuplayer可注冊) 

調用每一個factory的虛函數scoreFactory(), 表明這個factory對目前url的比對分數, 

選取分數最高的一個factory,也就是最比對的factory。 

是以這裡注冊的NuplayerFactory,可以很容易的替換成其他Factory,架構很靈活,哪一天google對這個Nuplayer不滿意了,可能就再整一個新的player在這裡注冊進去。

T2:主要檔案

    ------MediaPlayer.java   \base\media\java\android\media java的class

    ------android_media_MediaPlayer.cpp  \base\media\jni   java 對應的jni轉

    ------mediaplayer.cpp  \av\media\libmedia  沒什麼實在作用,一層包裝

    ------IMediaPlayerService.cpp  \av\media\libmedia android典型的 binder 實作的服務,Bp+Bn,跨程序的方法調用,弱化程序概念,代之以元件的思想 

    ------MediaPlayerService.cpp   \av\media\libmediaplayerservice Bn,真正的MediaPlayer工作的地方

    ------main_mediaserver.cpp  av\media\mediaserver  這裡有main入口函數,這個會生成可執行程式mediaserver,列在系統的啟動腳本.rc檔案中,系統啟動的時候會調用該可執行程式,把mediaPlayerserver服務啟動起來。