所有在線內容播放,都面臨一些共同的問題:啟播慢,seek慢,碼率切換慢。而隨著互聯網的發展,用戶對這些方面的要求越來越高,對慢的容忍度越來越差,如何解決這些問題,就成了MXPlayer 在線業務初期優化的重點。
本次分享將分為四個部分:第一部分介紹MXPlayer 如何解決起播慢,seek慢;第二部分介紹如何解決碼率切換慢的問題;第三部分介紹緩存面臨的問題,以及緩存是如何為前兩部分服務的;最后一個部分介紹在復雜業務下,多播放器實例是如何管理的,通過以上幾個部分為大家介紹MXPlayer 對在線內容播放優化的經驗。
大家好,我是趙琳琳,來自MX Player。我的分享主題是:MX Player在線播放優化。
首先簡單介紹一下業務背景:MX Player起初是一款比較純粹的本地播放器,其體積小,但功能強大,在全球各個地區都有不少的活躍用戶。隨著時間推移,公司在產品策略上也進行升級,引入了在線化的內容如影視劇、短視頻、直播等。
雖然全球都有MX Player的用戶,但其中主要用戶來自于印度地區。印度地區的用戶比較有特色,第一是語言(有十幾種主流語言);第二是網絡(4G網絡占多數,家庭有線寬帶較少);第三是設備(偏低端機型,存儲空間小)。
隨著在線內容的引入,也出現了一些問題。例如啟播慢、seek慢、碼率切換慢、緩存命中率低、代碼復雜度高等。
今天的分享內容主要圍繞以上的問題展開,首先介紹秒開、快速seek是如何實現的;之后是平滑碼率切換的技術細節;然后是緩存面臨的挑戰;最后是多播放器事例是如何管理的。
-01-
秒開
第一部分,秒開。如何讓用戶盡可能快地看到視頻內容,是所有在線播放面臨的難題。有數據表明,等待時間越長,用戶流失越嚴重。
根據統計,熱度視頻平均啟播時長在2.5秒左右。
經過進一步的分析,發現其中絕大多數時間用于下載數據。
那么如何減少用戶的等待時間呢?我們分析了幾個優化方向,首先解碼占用時間是較少的,優化空間有限;啟播緩沖區大概需要2秒等待時間,我們認為這個時間已經很短了,所以不選擇減小以優化;最終我們經過分析對比選擇了預加載方案。
預加載的流程是:首先服務端根據一些策略判定哪些視頻需要預加載,并且把信息告訴客戶端。客戶端收到請求后,會啟動預加載程序。預加載程序會在視頻沒有播放的情況下啟動預加載,把需要加載的視頻頭2秒放到緩存內。
策略上線后,熱度視頻的平均啟播時長由2.5秒降到1.8秒。如果預加載的緩存命中,啟播時長可以達到0.5秒,收益非常可觀。
那么如何決策哪些視頻需要預加載?服務端會根據視頻的標簽(新劇/推廣/熱度)等進行打分,最終做出決策并告知客戶端,啟動預加載程序。
-02-
快速seek
接下來介紹快速seek。和啟播一樣,等待時間越長,用戶流失越嚴重。
我們先看一下優化之前的seek過程。假設用戶要seek到A點,播放器首先會進入暫停狀態,并緩沖接下來6秒的數據,完成之后開始播放。
經過分析,發現用戶seek平均等待時間是3.4秒
那如何減少seek時間呢?
前文有提到預加載方案,是否適用于seek呢?答案是No,因為并不知道用戶要seek到什么位置,除非緩存整個視頻,顯然這是不合適的。
另外一個方案是減小緩沖區,例如從6秒調整到4秒或更短。但這種方法比較簡單粗暴,無法預知其是否有負面的用戶體驗影響,所以這個方案也被否定。
那么如何解決呢?經過分析和觀察,我們發現當播放器當前的下載速度大于播放速度,不論緩沖區有多少數據,播放都是流暢的。
根據以上結論,我們得出一個快速seek方案:用戶seek到A點,播放器暫停并緩沖1秒,得出當前下載速度D和常量播放速度P,如果D》=P,則直接開始播放;如果D《P,就會執行緩沖6秒數據再開始播放。
策略上線后,數據統計分析顯示平均等待時長由原先的3.4秒降為2.5秒。
-03-
平滑碼率切換
接下來講平滑碼率切換,首先看一下優化前的流程。
箭頭所指為當前播放器進度,藍色為已緩沖內容。如果開始切換,播放器會暫停,并丟棄當前的緩沖區,接著緩沖對應碼率的6秒數據,再開始播放。
經過數據統計,碼率切換平均等待時間為2.8秒。
如何減小切換等待時間呢?同樣的,減小緩沖區的方案比較簡單粗暴,直接pass。
可以注意到,圖中紅色的丟棄緩沖區,原本是可以正常播放的,只是因為用戶需要切換碼率,所以丟棄。那么是否可以重用該緩沖區呢?答案是肯定的。
如圖是優化后的平滑碼率切換方案:當播放器進行碼率切換時,并不會進入暫停,而是繼續播放當前碼率上已經緩沖好的數據,并開辟一個新的緩沖區來緩沖對應碼流的6秒數據,同時當舊緩沖區數據播放完,進行緩沖區切換。
業務上線后經數據統計,優化后的碼率切換平均等待時間由原來的2.8秒降為0.4秒。
-04-
緩存面臨的挑戰
接下來介紹緩存面臨的挑戰以及對應的解決方法。
前述提到MX Player在線用戶主要分布在印度,他們的設備偏低端,內存空間普遍都非常小。在業務上線之初,我們給緩存空間定了一個上限為2G。上線后,后臺收到了大量的用戶反饋,說App占用空間過大。經過我們的討論和決策,把緩存下調到500M,這帶來了一個直接的問題:命中率降低。
如圖是優化前的緩存布局,在容量不變的情況下,分片越小,個數越多,命中率就會越高。
基于上述結論,我們得出一個方案:兩段緩存。
我們把一個完整的分片拆為頭尾兩部分,頭部優先級高,尾部優先級低,并放入緩存空間。當空間滿了之后,會先清理掉所有尾部數據。
這是優化后的緩存布局。左圖為裝滿6個分為頭尾的分片數據,當用戶繼續使用一段時間后,緩存空間布局就會變成右圖的樣子,只留下了各個分片的頭部數據。
這時如果播放器需要播放內容,到緩沖區查找數據,就會發現右圖的命中率一定是比左圖布局要高的。
這時回顧一下預加載和快速seek:預加載方案是緩存視頻頭2秒,和兩段緩存中的頭部分片數據是吻合的。在快速seek中,如果在1秒緩沖內可以命中緩存的頭部數據,并且下載速度大于播放速度,就可以直接啟播。
兩段緩存方案在后臺默默地為其他功能進行支持,這些方案是相輔相成的關系。
-05-
多播放器如何管理
接下來介紹多播放器如何管理。
隨著業務發展,播放場景也越來越多。這些播放場景之間并不是彼此孤立的,如PIP播放和音樂播放就是互斥關系。當PIP正在播放,用戶需要切換音樂播放,就需要暫停PIP,反之亦然。
另外,feed流播放需要和PIP播放以及音樂播放共存。因為feed流播放是無聲和自動播放,我們并不希望這種播放打擾用戶行為。
隨著在線業務高速發展,隨之而來的是一系列問題。
經過討論決定,我們選擇重構部分代碼以解決問題,同時定下幾條重構原則:
第一,業務代碼彼此獨立:業務之間無需互相知道;增加新業務無需修改其他業務;啟動播放無需判斷是否有其他播放。
第二,環境變化自我感知:當App失去聲音焦點,自動暫停;程序進入后臺,播放器按需暫停;進入音樂播放后,自動暫停PIP。
基于以上原則,我們重構了代碼,結構如圖所示。Player代表底層播放器,并抽象出來PlayerContext的概念。每一個Player必須和Context進行attach,才能播放。Context有一個屬性為ready,只有在ready情況下,才能夠讓播放器啟動,否則會暫停。
Context有幾個具體的實例,首先是Activity,它是一個安卓標準組件,只有在unReceived的時候才是ready狀態;Fragment和Activity類似,只有unReceived才是ready狀態;Screen在鎖屏時為非ready狀態,其他時候都為ready;Global永遠都是ready狀態。
Activity和Fragment主要用于詳情頁播放和feed流播放;Screen用于PIP播放;Global用于后臺播放。
Player和PlayerContext之間不直接交互,而是通過PlayerManager進行管理。它會監聽和維護所有PlayerContext的狀態,并根據其狀態改變來控制播放器的生命周期變化。同時,Manager會維護Player和Context之間的映射關系。
經過這樣的結構重構,我們的業務代碼基本實現了解耦,新增業務不需要改動已有業務,并且樣本代碼不需要出現在具體業務中,PlayerManager可以感知并通知Player進行操作。 以上就是我的全部分享,謝謝大家!
-
播放器
+關注
關注
5文章
397瀏覽量
37409 -
視頻
+關注
關注
6文章
1942瀏覽量
72884 -
互聯網
+關注
關注
54文章
11148瀏覽量
103230
原文標題:MX Player在線播放優化
文章出處:【微信號:livevideostack,微信公眾號:LiveVideoStack】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論