天天看點

ExoPlayer結構分析

最近要做音樂播放器,經過一周的調研,最終決定使用google的ExoPlayer,對ExoPlayer的架構、流程做個分析,梳理一下調用邏輯。

先做個筆記,等項目做完了寫一個多媒體播放的大型攻略。

媒體資源的擷取

MediaSource類代表媒體資源,new出這個類的執行個體需要uri,DataSourceFactory和ExtractorsFactory。

uri是資源的路徑;

DataSourceFactory的作用是建立對應的DataSource執行個體,從uri資源中讀取檔案流;

ExtractorsFactory的作用是建立Extractors執行個體,Extractor翻譯過來就是“抽出器”,在這裡就是把媒體檔案從二進制的媒體流中抽出來。這個開源項目已經實作了mp3/mp4/flv等常見格式的抽出器,如果需要解析不支援的格式,還可以自己實作,或使用ffmpeg擴充。

MediaSource是一個接口,也沒聲明幾個方法,其中最主要的一個就是createPeriod()方法,用來建立一個MediaPeriod對象,這個對象就是真正做資源處理的。

對媒體資源的使用

ExoPlayer類代表這“播放器”的概念,就是接收媒體資源,把媒體資源解析成聲音和畫面呈現出來。ExoPlayer是一個接口,它有很多實作,我們以SimpleExoPlayer為例子。new出一個SimpleExoPlayer執行個體需要RenderersFactory、TrackSelector和LoadControl三個參數。

RenderersFactory是用來生産Renderer數組的。Renderer翻譯過來就是渲染器的意思,就是把音頻、視訊、文字源顯示在畫面上或輸出成聲音。音視訊檔案的錄制都是二進制的,隻是時間間隔非常短,是以輸出時讓人感覺是連續的,而Renderer的工作就是“快速、連續地輸出這些檔案”。為什麼是數組呢,因為一個媒體檔案可能有音頻、視訊等多個軌道,一個Render對應一個軌道;

TrackSelector翻譯過來就是軌道選擇器的意思,它在這裡的作用就是軌道選擇,它有個方法selectTracks(),傳回TrackSelection數組,TrackSelection就是對軌道進行解析的。一個媒體檔案會包含多個軌道,音軌、視訊軌、文字軌等,是以需要多個TrackSelection;

LoadControl主要是解析的一些進度控制、參數控制等,主要是記錄一些position;

整個播放邏輯流程

上面分析了資源的擷取和資源的使用,現在就分析下ExoPlayer是如何啟動整個流程、控制整個流程的。

ExoPlayer通過prepare(MediaSource m,xxx,xxx)方法啟動,方法裡面調用ExoPlayerImpl的prepare方法,裡面又調用ExoPlayerImplInternal的prepare方法,這個類就是真正的邏輯實作。

ExoPlayerImplInternal裡面會通過Handler發送MSG_PREPARE消息,然後最終會調用prepareInternal方法。這個方法裡面進行一些初始化操作後,就會發送MSG_DO_SOME_WORK消息,最終調用doSomeWork方法。

doSomeWork方法裡首先會調用updatePeriods方法更新Period。播放由三個MediaPeriodHolder執行個體控制,MediaPeriodHolder是什麼呢?它持有MediaPeriod、MediaSource、Render等所有執行個體,這裡面就是真正完成所有邏輯的。這三個執行個體分别是loadingPeriodHolder、readingPeriodHolder和playingPeriodHolder。

updatePeriods方法會調用setPlayingPeriodHolder方法,設定将要播放的MediaPeriod。setPlayingPeriodHolder方法最後會調用enableRenderers方法,該方法會周遊render數組(建立ExoPlayer執行個體時傳入的參數),調用render的start方法,這裡面會執行一些狀态的重置、通知。

然後再回到doSomeWork方法,接着往下走,會調用render的render方法,這個方法就是真正的解析、渲染了。