1. 程式人生 > >專案記錄: Dynamic playlists with ExoPlayer

專案記錄: Dynamic playlists with ExoPlayer

專案記錄: Dynamic playlists with ExoPlayer

翻譯一下 Dynamic playlists with ExoPlayer 2017.08.25

介紹

現在支援 Exoplayer media playlists . 使用者可以在播放器執行的過程中,任意新增和移除 playlist item .

從 Exoplayer 2.8.0 版本,通過更新 ConcatenatingMediaSourcedynamic playlist 的功能. 新的媒體資源可以通過以下簡單和直接的介面:

  • addMediaSource(mediaSource)

    : 新增一個媒體資源到 playlist 的末尾;

  • addMediaSource(index,mediaSource) : 在 index 位置插入一個新的媒體資源;

  • addMediaSource(Collection<MediaSource>) : 新增一整個媒體資源到 playlist 的末尾;

  • addMediaSources(index, Collection<MediaSource>) : 在 index 位置插入一整個媒體資源;

  • removeMediaSource(index) : 溢位 index 位置的 媒體資源;

  • moveMediaSource(fromIndex, toIndex) : 將 fromindex位置的媒體資源移動至 toindex 位置處;

    可以不需要再建立新的 MediaSource . 而且可以不打亂播放,移動當前正在播放的 item ;

  • getMediaSource(index) : 獲得index位置的媒體資源

  • getSize() : 返回當前 playlist 的長度

以上的方法,可以在播放器播放之前或者播放開始之後呼叫,而且無論哪個 item 正在播放.這些方法都是 thread-safe 執行緒安全的;

可以通過預先快取下一個 playlist

的快取來實現 gapless playback 無間隔播放.

而且, 在播放到一個新的元素,將會收到 eventListener.onPositionDiscontinuity 的通知.

如果你想要開始使用這個 playlist 的新功能,就去下載 新的 release 版本的ExoPlayer,開始碼程式碼吧.

如果你對實現細節感興趣,可以繼續看下去.


實現細節

為了理解 支援 dynamiclly changing media source 其中涉及到的困難.

先一看 How ExoPlayer works with media sources internally ,Exoplayer和MediaSource在內部是如何一起工作的. 其中,涉及到5個類和5個執行緒:

  1. APP : 執行在 app thread . 這個執行緒呼叫了 如 prepare media source 的命令來呼叫 player
  2. Player : 建立一個例項,在 PlayBack thread 播放執行緒中.
  3. Media Source : 在 app thread 中建立,是接觸到真正的媒體資源的. 在 loader threads 載入資源,而且與playback threadplayer 通訊.
  4. timeline : timelines 是一成不變的? 可以在所有執行緒訪問.
  5. media period : 負責 buffering (快取資料)和 playback of the media data (播放媒體資料). 在 playback thread 中被media source 建立, 但是真正載入資料的呢:是在 loader thread ;

在這樣的多執行緒環境下,一個很中藥的問題是: 多個執行緒可能在時間上會出現 不同的 player state (播放器狀態). 因此, 當一個命令在一個執行緒釋出而在另一個執行緒處理,第二個執行緒必須必須處在和第一個執行緒釋出命令的同一狀態,二者要保持一致這是必須的.

當實現 dynamic playlist change into the process 會帶來以下兩個:

  1. 立即反應所有執行緒的狀態變化 和 2) 等待一個非同步的過程恰當地結束 是兩個競爭的期望. 會造成以下三個難題:
  1. Lazily updating the master playlist on the playback thread while having a instantly updated playlist on the app thread

    app thread 更新了一個 playlist , playback thread 更新 playlist 延時了.(懶洋洋Lazily)

  2. Lazily waiting for new timeline information while keeping the timeline consistent with the playlist.

    緩慢地等待新的 timeline資訊 當 和 playlist 保持一致

  3. Being able to create new periods based on the playlist while waiting for the lazy timeline information

    根據 playlist 建立新的 period 當等待 timeline緩慢更新

總的來說,解決方法是非常相似的: 我們使用 mocking instances of the objects we are waiting for (模擬的等待物件,相等於建立了臨時的假的?)

這些 mocking instances 被立即建立,來儘可能地欺騙那些延遲操作. 因此呢. 整個系統的狀態會得到迅速地更新,防止進入模糊不清的情況. 一旦真實的結果變得可用,這些 mocking instances 將會停止模擬,而是開始正式地呼叫真正的例項化物件.

Update the playlist

playback thread 執行緒的master playlist 作為我們想要實現所有操作的 playlist . 會有兩個缺陷:

  1. 我們希望能夠隨時改變播放列表(即在 playback thread 這個執行緒起之前)
  2. 我們希望視覺化這播放列表的資訊來立即反應所有我們做的變化.

因此,我們將保持第二個(mocked) playlist (這個是在 app thread 執行緒上的),這個將會立即得到更新,而且它可以用來查詢 playlist 的資訊. 一旦 master playlist 是可用了,所有作應用在 這個 mocked playlist 的操作將會被使用在 playback thread 執行緒上的 playlist 來進行更新.

update playlist

keeping the timeline in syn with playlist

無論 playlist 何時變化,我們需要有一個新的 timeline 去反應新的 media structure . 有些時候,我們需要載入新新增的 media 的開始部分獲取資訊來更新 timeline. 但是呢,timeline立即反應所有 更新到playlist的所有變化是非常重要的.

  • 例如, 如果 app 添加了一個新的 source 在 index為 i 的位置, 立即 seek 到這個i位置,期望的結果是這個新的source將會被播放.如果player沒有感知到這些變化的話(由於它還在就的時間資訊上),那麼它將 seek到 另一個 item 上,而非我們剛剛新增的. 這就是為什麼立即更新 timeline是非常關鍵的.

為了解決這個問題, 當 master playlist變化時,我們立即觸發 a timeline update , 用的是 a new mocked timeline element. 這個 mocked timeline element 是未知的時長, 它被標誌位 dynamic 去告訴播放器,它應該期待發生在它屬性上的變化. 儘管這個資訊不是非常有幫助,但是,至少它保證了 timeline 和 playlist 保持一致. 當 playlist element 準備好了, 這個 mocked 的 timeline element 將會返回真實的媒體屬性.

img

Creating periods while waiting for timeline updates

第三個問題是由於第二個問題的解決方案造成的.

想想一下我們立即想要播放這個新插入的 playlist item. 播放器會叫 media source建立一個新的 media period. 但是呢,meidia source 無法完成需求,仍然在等待一個真正的 media information

相同地,我們借用了一個 mocked media period 去為 mocked timeline 建立 一個 media period . 由於沒有真實的 media, 這個 media period 將會用於保持在 緩衝模式,告訴播放器媒體還沒有做不好播放.一旦呢,timeline獲得更新真的media information ,這個 mocked media period 將建立真的media period, 推進呼叫那包裝的例項.

img

總結:

  • 這個部落格描述了 新的 ConcatenatingMediaSource 特性來新增和移除 播放器上的元素.

參考文獻

Dynamic playlists with ExoPlayer