百度seo sem南京seo優(yōu)化培訓(xùn)
系列文章目錄
ExoPlayer架構(gòu)詳解與源碼分析(1)——前言
ExoPlayer架構(gòu)詳解與源碼分析(2)——Player
ExoPlayer架構(gòu)詳解與源碼分析(3)——Timeline
ExoPlayer架構(gòu)詳解與源碼分析(4)——整體架構(gòu)
ExoPlayer架構(gòu)詳解與源碼分析(5)——MediaSource
文章目錄
- 系列文章目錄
- 前言
- MediaSource
- MediaSource的實現(xiàn)
- BaseMediaSource
- CompositeMediaSource
- WrappingMediaSource
- MaskingMediaSource
- ProgressiveMediaSource
- 總結(jié)
前言
上篇說完整體架構(gòu),這里開始分析其中的各個組件,先從MediaSource看起,繼續(xù)拿運載火箭做對比,MediaSource在整個運載火箭中的角色就類似于燃料系統(tǒng),確?;鸺樌?#xff0c;燃料系統(tǒng)是其中重要的一環(huán),需要能在運行過程從持續(xù)穩(wěn)定的提供燃料。ExoPlayer也一樣,為了保證能夠持續(xù)的渲染出媒體內(nèi)容,就得保證MediaSource持續(xù)穩(wěn)定提供需要的數(shù)據(jù)。
MediaSource
繼續(xù)擴充下我們的版圖
MediaSource定義了媒體信息以及提供媒體數(shù)據(jù)給播放器,主要有2個職責(zé):
- 為播放器提供定義其媒體時序結(jié)構(gòu)的Timeline,并在媒體時序結(jié)構(gòu)發(fā)生變化時提供新的Timeline。初始化是提供一個PlaceholdTimeline,當prepareSource 完成時一般就能獲取到真實的Timeline,然后調(diào)用傳遞給prepareSource 的MediaSourceCallers 上的onSourceInfoRefreshed 來更新這些新的Timeline。
- 為其Timeline中的Period提供 MediaPeriod 實例。 MediaPeriods是通過調(diào)用createPeriod獲得的,并為播放器提供加載和讀取媒體的方式。
應(yīng)用代碼不應(yīng)該直接調(diào)用MediaSource 里的方法,而應(yīng)該讓ExoPlayer在合適的時間調(diào)用。
MediaSource實例可以重復(fù)使用,但只能同時用于一個 ExoPlayer 實例。
不同MediaSource 方法只能在應(yīng)用程序線程或內(nèi)部播放線程其中一個上調(diào)用。每個方法文檔上都明確了可以調(diào)用的線程。
看下幾個重要的方法定義
- getInitialTimeline主線程調(diào)用,當真實Timeline未知時立即返回初始PlaceholderTimeline,或者為返回null 讓播放器創(chuàng)建初始Timeline。
- getMediaItem主線程調(diào)用,返回當前的MediaItem,可以看到MediaSource里也可能保存了MediaItem。
- prepareSource內(nèi)部播放線程調(diào)用,注冊 MediaSourceCaller,主要用來為播放器提供一個回調(diào),獲取最新的Timeline。另外,在播放某些播放資源需要先獲取真實的媒體源時,這里會提前解析媒體資源(如播放HLS時這個時候會去獲取解析M3U8文件),prepareSource完成后會立即刷新Timeline。
void prepareSource(MediaSourceCaller caller,@Nullable TransferListener mediaTransferListener,PlayerId playerId);interface MediaSourceCaller {void onSourceInfoRefreshed(MediaSource source, Timeline timeline);}
- createPeriod在內(nèi)部播放線程調(diào)用,返回一個由periodId區(qū)分的新的MediaPerods對象,只能在真實的源已經(jīng)準備好后再調(diào)用,也就是上面的prepareSource確保源已經(jīng)準備完成,參數(shù)id就是MediaPerods唯一區(qū)分,startPositionUs想要播放的開始位置,allocator是一個緩存分配器這個后面講MediaPerods會提到,MediaPerods創(chuàng)建完成后也會perpare,完成后一般就可以獲取媒體的基本數(shù)據(jù),如時長、軌道等,這個時候會反過來通知MediaSource刷新Timeline。
MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs);
MeidiaSource大致工作流程就是創(chuàng)建時初始化出一個Timeline,然后prepareSource準備數(shù)據(jù)源,之后createPeriod創(chuàng)建Period,然后講工作交給Period,整個過程都在刷新Timeline。
MediaSource的實現(xiàn)
BaseMediaSource
MediaSource虛函數(shù)實現(xiàn),主要用于多個MediaSourceEventListener的處理分發(fā),觸發(fā)多個MediaSourceCaller的onSourceInfoRefreshed,還保存上一次的Timeline。
CompositeMediaSource
由多個子MediaSource組成的復(fù)合MediaSource,將所有方法調(diào)用轉(zhuǎn)發(fā)給各個子的MediaSource
WrappingMediaSource
繼承自CompositeMediaSource,實現(xiàn)只包含了一個子MediaSource的MediaSource 。
MaskingMediaSource
一個MediaSource ,主要作用是當實際媒體結(jié)果未知時,用一個PlaceholderTimeline來表示Timeline ,當獲取實際的媒體結(jié)構(gòu)時采用實際的Timeline替換PlaceholderTimeline。
public MaskingMediaSource(MediaSource mediaSource, boolean useLazyPreparation) {super(mediaSource);this.useLazyPreparation = useLazyPreparation && mediaSource.isSingleWindow();window = new Timeline.Window();period = new Timeline.Period();@Nullable Timeline initialTimeline = mediaSource.getInitialTimeline();if (initialTimeline != null) {timeline =MaskingTimeline.createWithRealTimeline(initialTimeline, /* firstWindowUid= */ null, /* firstPeriodUid= */ null);hasRealTimeline = true;} else {timeline = MaskingTimeline.createWithPlaceholderTimeline(mediaSource.getMediaItem());}}
ProgressiveMediaSource
繼承自BaseMediaSource,主要用于漸進式媒體文件的播放,如本地或遠程的單個視頻文件
@Override//prepareprotected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {transferListener = mediaTransferListener;drmSessionManager.setPlayer(/* playbackLooper= */ checkNotNull(Looper.myLooper()), getPlayerId());drmSessionManager.prepare();notifySourceInfoRefreshed();}@Override//ProgressiveMediaPeriod在獲取到Timeline相關(guān)信息后會回調(diào)更新Timelinepublic void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean isLive) {// 優(yōu)先實現(xiàn)之前的durationUs durationUs = durationUs == C.TIME_UNSET ? timelineDurationUs : durationUs;if (!timelineIsPlaceholder&& timelineDurationUs == durationUs&& timelineIsSeekable == isSeekable&& timelineIsLive == isLive) {// 沒有發(fā)生變更return;}timelineDurationUs = durationUs;timelineIsSeekable = isSeekable;timelineIsLive = isLive;timelineIsPlaceholder = false;notifySourceInfoRefreshed();}//刷新TimeLineprivate void notifySourceInfoRefreshed() {Timeline timeline =new SinglePeriodTimeline(timelineDurationUs,timelineIsSeekable,/* isDynamic= */ false,/* useLiveConfiguration= */ timelineIsLive,/* manifest= */ null,mediaItem);if (timelineIsPlaceholder) {timeline =new ForwardingTimeline(timeline) {@Overridepublic Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {super.getWindow(windowIndex, window, defaultPositionProjectionUs);window.isPlaceholder = true;return window;}@Overridepublic Period getPeriod(int periodIndex, Period period, boolean setIds) {super.getPeriod(periodIndex, period, setIds);period.isPlaceholder = true;return period;}};}//觸發(fā)監(jiān)聽refreshSourceInfo(timeline);}
總結(jié)
沒了就這么多,燃料系統(tǒng)這么簡陋的嗎?當然不會,因為它把除了Timeline的管理維護之外的幾乎所有的工作都交給別人來完成了,它就是下面要重點講的MediaPeriod,MediaSource只管創(chuàng)建出就好了,ExoPlayer也是主要通過MediaSource關(guān)聯(lián)的MediaPeriod控制媒體的加載釋放等。
版權(quán)聲明 ?
本文為CSDN作者山雨樓原創(chuàng)文章
轉(zhuǎn)載請注明出處
原創(chuàng)不易,覺得有用的話,收藏轉(zhuǎn)發(fā)點贊支持