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