當前位置:
首頁 > 知識 > ExoPlayer Talk 01 緩存策略分析與優化

ExoPlayer Talk 01 緩存策略分析與優化

操作系統:Windows8.1

顯卡:Nivida GTX965M

開發工具:Android studio 2.3.3 | ExoPlayer r2.5.1



使用 ExoPlayer 已經有一段時間了,對播放器的整體架構設計 到 具體實現 佩服至極,特別建議開發播放器的同學有機會一定要看看,相信會受益匪淺。這次分享的內容主要關於緩存策略優化

一、Default Buffer Policy


Google ExoPlayer提供了默認的AV數據的緩存策略,並通過 DefaultLoadControl組件實現。該載入器組件本身沒有問題,只不過在一些情景下,這種默認緩存策略,會減損"緩存"本身的效果。在 DefaultLoadControl中有如下代碼片段:


@Override public boolean shouldContinueLoading(long bufferedDurationUs)

{

...

isBuffering = bufferTimeState == BELOW_LOW_WATERMARK || (bufferTimeState ==
BETWEEN_WATERMARKS && isBuffering &&
!targetBufferSizeReached);

...return isBuffering;

}

該函數由於播放器調用,以確定是否應該繼續載入緩存AV數據。

/**

DEFAULT_MIN_BUFFER_MS 常量定義了播放器觸發載入AV數據的時機,即當前緩衝區AV數據 duration time 小於15秒。

DEFAULT_MAX_BUFFER_MS常量定義了播放器進行載入AV數據的上限,即當前緩衝區AV數據 duration time 小於30秒。

DEFAULT_BUFFER_FOR_PLAYBACK_MS 常量定義了播放器播放AV數據的條件,即緩衝區必須滿足AV數據 duration time 不小於2.5秒。

DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS 常量定義了播放器從 REBUFFER狀態(REBUFFER是由於運行時緩衝區耗盡觸發導致) 恢復為可播放狀態後可播放AV數據的條件,即緩衝區必須滿足AV數據 duration time 不小於5秒。

所以根據以上代碼了解,前兩個參數用於描述載入時序,後兩個參數用於描述是否有足夠的緩衝數據來播放。

我們可以概述默認載入器組件會按照如下方式工作:

  1. 載入組件持續載入,直到緩衝AV數據大於30秒,停止載入,進入等待狀態。

  2. 當緩衝AV數據小於15秒時,載入器重新執行載入邏輯。

  3. 播放器根據當前緩衝區AV數據 duration time 控制是否播放。

那麼問題來了,這樣設計的目的是什麼?很難想到一個情景應用該策略,換句話說是否可以自定義修改15秒30秒這樣的數值呢?

What about Buffering?



There are arguments that
mobile carriers prefer this kind of traffic pattern over their networks
(i.e. bursts rather than drip-feeding). Which is an important
consideration given ExoPlayer is used by some very popular services. It
may also be more battery efficient.

Whether these arguments are
still valid is something we should probably take another look at fairly
soon, since the information we used when making this decision is 3-4
years old now. We should also figure out whether we should adjust the
policy dynamically based on network type (e.g. even if the arguments are
still valid, they may only hold for mobile networks and not for WiFi).

關於此問題已經有人問詢過,其中一個ExoPlayer開發人員給出這樣的答覆,大致意為,目前主流移動運營商將作為ExoPlayer的相關實現重要考慮對象,有證據表明運營商們更傾向於這種被稱為 bursts的流量模式,而不是 drip-feeding類的流量模式。除此之外也會提升電池使用效率。無論這些證據是否有效,很快會再次的了解一下,因為做出這個決定所參考的是3-4年前的信息了。還應該確定是否有必要根據網路類型動態調整策略(即使這些參數仍然使用,它們只適用於移動網路,而不是WiFi)。

盡現在使用的默認緩存策略比較通用,但不可能滿足所有的情況。為了更好的點播體驗,增加緩衝數據 duration time 為1分鐘或者更久,接下來我們進一步分析ExoPlayer默認緩存策略的實現原理,並在最後給出一般性的優化例子。

二、Water Marks



在默認的緩存策略實現中,有一個 water marks 的概念,類似水桶盛水過程中變化的"水位",具體代碼為:

private static final int ABOVE_HIGH_WATERMARK = 0;
private static final int BETWEEN_WATERMARKS = 1;
private static final int BELOW_LOW_WATERMARK = 2;

三個級別的水位與前面提到的四個常量的關係如圖所示:

ExoPlayer Talk 01 緩存策略分析與優化

參考完整的 getBufferTimeState()shouldContinueLoad() 函數,其中 getBufferTimeState() 根據當前的緩存AV數據的 duration time 來判斷處於哪個水位。

private int getBufferTimeState(long bufferedDurationUs)

@Override

public boolean shouldContinueLoading(long bufferedDurationUs)

{

int bufferTimeState = getBufferTimeState(bufferedDurationUs);

boolean targetBufferSizeReached = allocator.getTotalBytesAllocated() >=
targetBufferSize;

boolean wasBuffering = isBuffering;

isBuffering = bufferTimeState == BELOW_LOW_WATERMARK || (bufferTimeState ==
BETWEEN_WATERMARKS && isBuffering &&
!targetBufferSizeReached);

if (priorityTaskManager != null && isBuffering != wasBuffering)

{

if (isBuffering)

{

priorityTaskManager.add(C.PRIORITY_PLAYBACK);

}

else

{

priorityTaskManager.remove(C.PRIORITY_PLAYBACK);

}

}

return isBuffering;

}

一個典型的載入行為經過 A、B、C 三個階段:

Pass A

起始階段,載入器開始連續的載入AV數據,一直達到或者超過 maxBufferUs水位為止,需要注意的是這個時候時間線為停頓在 t1 ,如下圖所示:

ExoPlayer Talk 01 緩存策略分析與優化

Pass B

t1 時間後,播放器消費緩衝區AV數據,但 isBuffering = false 並且 bufferTimeState == BETWEEN_WATERMARK,所以 shouldContinueLoading() 仍然返回 false,即不需要載入AV數據,時間線停頓在 t2 ,如下圖所示:

ExoPlayer Talk 01 緩存策略分析與優化

Pass C

來到最後一個階段,當播放器持續消費緩衝區AV數據,直到水位低於 minBufferUs ,即 bufferTimeState == BELOW_LOW_WATERMARK 時候,我們恢復載入程序,時間線停頓在 t3 ,如下圖所示:

ExoPlayer Talk 01 緩存策略分析與優化

作為一個小節,通過三個階段的圖示我們了解到,從 t1t3 之間區間內,載入器沒有做任何載入操作。因此會遇到這種情景,某時刻緩衝區中只有僅僅15秒的緩衝數據。

除此之外,對於緩衝區大小也是有限制的,一般來說當網路狀況良好時,一般都可以緩存 15 到 30 秒的AV數據,換句話說,有可能根據需求擴展緩衝區大小。

三、How to customize the buffer?



應用前面提到的 drip - feeding 滴灌方式,移除緩衝區的上線限制,代碼如下:


isBuffering = bufferTimeState == BELOW_LOW_WATERMARK

|| (bufferTimeState == BETWEEN_WATERMARKS

/*

* commented below line to achieve drip-feeding method for better caching.
once you are below maxBufferUs, do fetch immediately.

*/

/* && isBuffering */

&& !targetBufferSizeReached);

同時擴大 maxBufferUsminBufferUs

/**

* To increase buffer time and size.

*/

public static int BUFFER_SCALE_UP_FACTOR = 4;

....

minBufferUs = BUFFER_SCALE_UP_FACTOR * minBufferMs * 1000L;

maxBufferUs = BUFFER_SCALE_UP_FACTOR * maxBufferMs * 1000L;

...

可以在 shouldContinueLoading() 函數下面添加日誌,驗證修改前後的不同表現。


Log.d(CustomLoadControl.class.getSimpleName(), "current buffer durationUs:
" + bufferedDurationUs + ",max bufferUs: " + maxBufferUs + ", min bufferUs: " +
minBufferUs + " shouldContinueLoading: " + isBuffering);

中公優就業IT培訓,總有你想學的:http://xue.ujiuye.com

勤工儉學計劃,0元學IT!

http://www.ujiuye.com/zt/qgjx/?wt.bd=mmxtt

找工作太難?好漢,讓我助你一臂之力!

http://www.ujiuye.com/zt/jyfc/?wt.bd=mmxtt

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT優就業 的精彩文章:

macvlan 網路隔離和連通-每天5分鐘玩轉 Dock
ASP.NET Core Razor頁面 vs MVC
CO函數庫源碼解析
Linux IO 實時監控iostat命令詳解
.Net Reactor 5脫殼教程

TAG:IT優就業 |

您可能感興趣

TinyShop緩存文件獲取WebShell之0day
Hitachi Vantara升級Skylaking伺服器加入Optane緩存和GPU
SpringBoot:SpringDataRedis緩存改造
Flutter圖片緩存 Image.network源碼分析
緩存架構SpringBoot集成Curator實現zookeeper分散式鎖
使用RedisTemplate(JDK序列化策略)緩存實體類
spring-boot-2.0.3之redis緩存實現
英特爾推出升級版Optane Memory M15緩存SSD
python的緩存庫:cacheout
Python + Memcached: 在分散式應用程序中實現高效緩存
Python + Memcached:在分散式應用程序中實現高效緩存
Python+Memcached:在分散式應用程序中實現高效緩存
redis緩存和cookie實現Session共享
MyBatis中的緩存
Spark調優的關鍵—RDD Cache緩存使用詳解
開源分散式內存緩存系統 Memcrashed 被利用發起 DDoS 放大攻擊,峰值竟達 500 Gbps
10nm工藝!Intel全新架構Ice Lake首次現身:一二級緩存增大
杉岩數據智能緩存技術AgileCache亮相2018 Ceph亞太峰會
Bloom Filter如何解決緩存穿透
windows緩存