本文用一個UML類圖,講解mp3檔案播放的架構流程。内容以下幾個方面:
1.UML類圖
2.stagefrightPlayer是如何建立的;
3.mp3檔案的解析和解碼的簡單介紹
4.播放mp3檔案過程中,生産者和消費者的關系;
5.openmax和stagefright架構的消息機制

對照着UML圖,看下StagefrightPlayer建立的過程。
故事的開始是Java層的MediaPlayer調用了setDataSource這個函數(參數為一個path),導緻native對應的MediaPlayer 通過Binder通信機制在MediaPlayerService中開辟了一個“戶口”,即建立Client對象,這個對象是個匿名的Binder。這個“戶口”在native MediaPlayer中表現為一個IMediaPlayer的接口。
上述過程代碼如下:
建立了IMediaPlayer對象之後,就調用其setDataSource方法。經過Binder的通信機制一番的轉換之後,調用流程來到MediaPlayerService.cpp中:
代碼路徑:frameworks/av/media/libmediaplayerservice/MediaPlayerService
上面大段的代碼和分析流程沒有關系,skim it。要建立一個合适的播放器,就要分析檔案的格式,根據檔案的格式來比對一個合适的播放器。這個工作交給了MediaPlayerFactory。在其中注冊了許多的工廠用于生産一個合适的播放器。基本原理就是讀取歌曲檔案的開頭一段位元組,根據相關的container來解析歌曲的格式,做的粗糙一點的話就直接根據字尾名來判斷了。這其中的實作取決于廠商或者元件提供商了。
不管怎麼樣,我們現在假設MediaPlayerFactory根據路徑得到了一個合适的播放器,它的基類是MediaPlayerBase。android中預設的是StagefrightPlayer,繼承了MediaPlayerBase。于是StagefrightPlayer在工廠中被生産出來了。然後調用其setDataSource。
其實StagefrightPlayer隻是一個空殼,真正的工作是AwesomePlayer去做,這個對象在StagefrightPlayer構造函數中産生。看到這裡的時候一定要記得看看UML類圖。看看他們兩個之間的關系。于是這個path最終就儲存到了AwesomePlayer内部。
Java層的MediaPlayer設定完路徑之後,還要調用prepare。調用流程和上面設定路徑一樣:MediaPlayer->Client->StagefrightPlayer->AwesomePlayer,略過不表。AwesomePlayer的prepare做了兩件事情。給AwesomePlayer的事件隊列發送一條Event,然後等待這個事件的處理完成。
事件的處理在onPrepareAsyncEvent()函數中完成。做了以下工作:
1.建立一個原始Audio Track流。從這個流中讀取壓縮資料;對應于圖中的mAudioTrack。
2.建立一個讀取pcm資料的流。對應于圖中的mAudioSource。
mAudioTrack實際指向一個Mp3Source,而mAudioSource指向一個OMXCodec。Mp3Source提供Mp3原始資料供OMXCodec解碼,然後把解碼完成之後的資料傳遞給AudioPlayer。OMXCodec的解碼工作實際上是由具體的解碼元件完成。一個OMXCodec對應一個Omx中的node instance,node instance操作解碼元件。而node instance提供calback接受元件的消息。
圖中藍色部分表示讀取原始mp3檔案流程;綠色表示元件的callback 傳遞流程;
播放過程中存在兩組生産者和消費者。
第一組:原始資料的生産者,Mp3Source;原始資料消費者OMXCodec;
第二組:pcm資料的提供者OMXCodec和pcm資料的消費者AudioPlayer。
其中AudioPlayer其實是一個中間橋梁,真正的pcm資料的消費者是AudioTrack。它不斷的通過callback機制來從AudioPlayer中讀取pcm資料。
這一部分有兩條主線:
1.OMXCodec如何操作元件;
2.元件的消息如何傳遞到StagefrightPlayer。
首先說第一條:OMXCodec的構造函數會調用omx的接口建立一個OMXNodeInstance執行個體,通過OMXNodeInstance執行個體來操作元件;在建立OMXNodeInstance的同時會傳遞給OMXNodeInstance一個觀察者OMXCodecObserver。一旦OMXNodeInstance接收到來自元件的消息,就會通過這個觀察者把消息傳遞給OMXCodec。
在解碼過程中如果OMXCodec發生了錯誤,AudioPlayer會檢測到read錯誤,會把相關的資訊通過AwesomePlayer傳遞到StagefrightPlayer中去。進而通知到native的MediaPlayer。最後透過jni會post給java的MediaPlayer。