作者|少陽
審校|泰一
短視頻作爲內容重要的承載方式,是吸引用戶的重點,短視頻的內容與體驗直接關係到用戶是否願意長時停留。因此,體驗的優化就顯得尤爲重要。
跨頁面續播
跨頁面續播是除秒播外另一個可以從體感上增加用戶體驗的能力。由於一些業務場景需要在不同頁面上播放同一個視頻內容的場景,而這些場景頁面切換往往是連續的,這就要求短視頻的播放也是連續。這樣才能使得體驗上會有連貫性,讓用戶在進入沉浸式頁面時,能流暢的過度,並無感知的繼續播放,從而產生連續不間斷的感受。
在優化前,盒馬沉浸式短視頻播放頁面的體驗與主流短視頻 App 有明顯差距。從卡片列表頁面跳轉視頻沉浸式頁面時,相同視頻無法續播,影響用戶觀賞和體驗。下面主要介紹盒馬短視頻從普通展示頁進入沉浸式頁面時跨頁面續播能力和流暢的動畫切換效果的實現過程。
環境
手機:Pixel 4
os:Android 10
播放器:淘寶播放器
效果對比
首先我們來看一下盒馬優化前後與主流短視頻 App 的效果對比
問題分析
從對比可以看出,續播的關鍵在於視頻流的複用以及頁面轉場動畫。
要解決流的複用,同時又要保證進入新的頁面時可以立即播放,不產生聲音和畫面的頓挫,這裏根據上一篇《揭祕盒馬鮮生 APP Android 短視頻秒播優化方案》的分析,必須要解決視頻下載,加載解碼的耗時。
根據《揭祕盒馬鮮生 APP Android 短視頻秒播優化方案》裏講到緩存原理,這裏可以利用播放器播放同一個視頻(注意統一 URL,盒馬全部轉爲 H.265)來避免多次下載。
加載解碼的耗時則需要播放器複用來解決。這裏涉及到實現方案,可參照下一章的續播方案選型。
◆ 轉場動畫
轉場動畫能顯著提高體感流暢度,但實現過程中需要考慮各種兼容問題。
續播方案選型
在優化前期,我們考慮了三種續播方案。
盒馬最終選擇方案 3,這裏方案 2 和 3 原理是相同的,沒有明顯的優劣之分,最終選擇方案 3 是因爲這是目前穩定性最高,成本最低的方法。後續的播放器續播、複用、管理的分析同樣適用於方案 2。
播放器續播、複用和管理
業務上,我們需要實現續播,通過問題分析,我們已經知道,通過視頻流的複用即可實現,而視頻流的複用這裏選擇通過複用 MediaPlayer 實現(也可以複用 Surface+MediaPlayer)。
將 MediaPlayer 從 TaobaoPlayerView 中拆解出來,通過 MediaPlayerManager 進行全局管理。全局管理後,所有的播放器的 MediaPlayer 都由 MediaPlayerManager 分配和控制。
各組建間關係
確保業務流程中,只需要關心業務與 VideoView 之間的交互,底層播放器複用由 MediaPlayerManager 實現。
播放器複用是管理的一個子集,所以這裏一起介紹。主要原來有以下幾個原則:
1. 全局播放器(MediaPlayer)控制最多創建 4 個。
2. 超過 4 個播放器,創建第 5 個時,先銷燬最少使用的播放器的 MediaPlayer。
3. 每個播放器隨機分配一個 token(時間戳 + 隨機數),也可以開發者指定。
4. 相同 token 的播放器,共享 MediaPlayer。
5. 一個 MediaPlayer 同時只能被 1 個播放器 Surface 所綁定和持有。
6. 存在相同 token 的播放器,當前播放器在銷燬時,保留 MediaPlayer 實例。
7. 已創建的播放器恢復播放,但 MediaPlayer 被其他後創建的播放器佔用時,解綁 MediaPlayer 並重新綁定當前播放器。
場景一:APP 共創建 4 個及以內播放器。
場景二:創建超過 4 個播放器時。
場景三:新創建的播放器 token 已存在時,複用 MediaPlayer。
場景四:存在 token 與當前即將被銷燬的播放器 token 一致時(或已被解除 MediaPlayer 的播放器播放時)。
邏輯流程圖
從場景總結,MediaPlayer 主要提供 複用、恢復、銷燬、驅逐(創建) 四個能力。
轉場動畫
目前轉場動畫有兩個方案可選:
1. Android 自帶的元素動畫
優點:動畫流暢順滑,無需實現動畫邏輯,由系統自己實現。
缺點:侵入嚴重,需要改寫 Nav 層,在 View 複用的方案下有白屏和黑屏。
2. 自定義實現屬性動畫
優點:侵入小,只需要前置頁極少的座標信息,如果是 View 複用方案,甚至不需要前置頁提供座標信息;兼容性好,適用於各種播放器複用場景。
缺點:需要自己實現動畫,有一定的閃爍感。
ps:返回動畫同理,過程相反即可。
屬性動畫原理存在一個坑。
問題描述:
假設頁面爲 A->B,方案 3 要求 B 頁面在動畫過程中是全透明的。當 B 的 theme 中 windowIsTranslucent 爲 true 時,A->B 過程 A 的生命週期無法走向 stop(即便 B 頁面動畫結束,完全遮蓋 A 頁面)。因此,A 的生命週期沒有按照預期執行,一些需要 onStop 執行的場景下,業務就無法正常執行
B Ativity 的樣式(注:示例代碼):
<style name="MyTransparent" parent="xxxx">
<item name="android:windowFullscreen">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowAnimationStyle">@style/noAnimation</item>
</style>
解決方案:
1. 進入動畫結束時,通過反射調用 Activity 的 convertFromTranslucent 方法, 使 activity 不透明。
2. 返回動畫開始時,通過反射調用 Activity 的 convertToTranslucent 方法,使 activity 透明。
後續優化展望
關於多媒體的優化工作還有很多可以做。除了續播和沉浸式秒播等場景外,我們還可以:
未優化:
操作:連續開啓 30~50 個頁面及播放器。
現象:內存飆升,手機發燙,影響手機正常使用。
優化後:
操作:每秒開啓 1 個頁面和播放器,連續開啓 100 個。
現象:內存呈鋸齒狀正常上升,無明顯飆升現象,軟件運行正常。
本文分享自微信公衆號 - 音視頻開發進階(glumes_blog)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。