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如何解複用,解碼,渲染,已經其中涉及到的音視訊資料流轉,控制,驅動線程模型,不涉及。大圖:

上圖的文字模式:
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服務啟動起來。