洞察 video 超能力系列——玩轉 mp4

用技術提高美好事物發生的機率git

Technologically, for greater probability to be happy.github


前言

只要在 HTML5 中使用過視頻播放的同窗對 video 標籤必定不會陌生,不過不少同窗只使用了 video 的基礎功能,實際上 video 擁有強大潛能的,只要姿式正確就能讓其擁有超能力。不妨從下面幾個場景來逐漸瞭解下video 不曾被髮掘的神祕空間:web

  • 清晰度無縫切換瀏覽器

  • 節省視頻流量網絡

清晰度無縫切換

點播領域裏 mp4 是最廣泛、兼容性最好的視頻容器,不過 mp4 也有它的侷限性,好比常見的清晰度切換,咱們是沒法像youtube那樣作到無縫切換的。咱們能夠看下普通的mp4播放的網絡請求和youtube視頻播放的網絡請求的區別。app


圖1.1 普通mp4的下載請求過程ide



圖1.2 Youtube視頻下載請求過程

翻譯

這兩張圖不難看出,在默認狀況下 mp4 使用一次 http 請求全部的視頻數據,Youtube 則分次請求。固然這個描述很不專業,但確實形象。形成這種差別的是 video 不支持流式的視頻數據,Youtube 採用的是流式的視頻容器 webm,而 mp4 是非流式的。那如何解釋清楚流式的視頻數據呢,從專業的角度三言兩語很難說清楚,但用大白話翻譯過來就是流式的視頻數據支持分段獨立播放,非流式的不能夠。換句話說一個10M的視頻文件,流式的視頻能夠把0~1M的數據請求回來單獨播放,可是非流式的不能夠。
3d

上面咱們描述了視頻格式的不一樣,接下來咱們要說的是第一張圖中的視頻加載是瀏覽器來控制的,經過給 video 的 src 屬性配置視頻地址,觸發播放以後瀏覽器就會開始下載了,JS干涉不了。而 Youtube 的視頻加載是經過JS來控制的,各位能夠再次看下第二張圖的網絡請求類型:xhr,足以證實這一點。cdn

上面兩點搞清楚以後咱們就該說下清晰度切換的事情了。這個需求你們都不陌生,可是直接使用 mp4 格式作無縫清晰度切換,難度還挺大的。先解釋下「無縫清晰度切換」的概念:從播放一個分辨率的視頻到另外一個分辨率且保證畫面、聲音不停頓的平滑切換過程。瞭解了這個概念,你們應該知道了用 video 無縫切換 mp4 有多難。一方面,video 是不支持流式的視頻格式的,一方面,video 的加載是不受JS控制的。經過切換 video 的 src 屬性,必然會致使畫面中斷、從新請求視頻數據等。有的同窗想到說利用兩個 video 再結合 z-index 來搞,可是當你生成另外一個video去加載視頻的時候,沒法保證兩個畫面是嚴格一致的,即便將原來的畫面暫停到一個時刻,用另外一個視頻經過 currentTime 屬性與之同步,切換仍然看到畫面閃爍,基本沒法和 Youtube 無縫切換的體驗匹敵。並且還會形成更多流量的浪費,背後的緣由你們能夠研究下 mp4 容器和 webm 容器的異同,也能夠看下視頻解碼相關的文章。

還有一種方法就是將 mp4 格式通通轉碼到流式的視頻格式好比 hls、webm 等。不過這種看上去可行的方式實際上會帶來很大的成本開銷,如將大量視頻作轉碼會消耗高昂的機器資源、雙倍存儲的費用、CDN的雙倍費用等等。其實咱們也是在這種背景下研究出來新的技術問題解決清晰度無縫切換的。

首先,咱們改變對 mp4 視頻的播放流程,再也不直接使用 video 的 src 來播放,由於咱們沒有任何能夠操做的空間。video不只支持 src 屬性還支持 Blob 對象,咱們就是利用後者。播放的流程以下:

圖1.3 mp4 視頻新播放流程


  1. 來請求 mp4 視頻數據,這樣能夠結合視頻 Range 服務,作到精確加載。

  2. 編寫解析器將加載回來的部分 mp4 視頻數據進行解複用

  3. 將解複用的視頻數據轉成 fmp4 格式並傳遞給 MediaSource

  4. 使用 video 進行解碼完成播放

而後在作清晰度切換的時候流程以下:

圖1.4 mp4視頻清晰度切換原理示意圖


  1. 播放視頻A,過程同上

  2. 在某個時刻,用戶切換到播放視頻B,首先解析B的索引文件(moov),反向計算mp4的range區間

  3. 加載B的視頻區間數據

  4. 解複用

  5. 把數據轉換成fmp4格式並傳遞給MediaSource

  6. 刪除A的部分Buffer

  7. 在下一個關鍵幀自動完成畫質的切換


圖1.5 mp4視頻清晰度切換流程示意圖

這個過程看上去比較繁瑣,可是全部的操做都是在瀏覽器端完成,也就是說都是JS來實現的。這樣以前說的全部成本問題都不存在,還能作到youtube相同體驗的無縫切換。若是你們也想使用這個功能不須要本身再去實現一遍上述流程,可使用以下代碼:

若是對這段代碼有什麼疑惑,或者想深刻了解下它背後是如何實現的,能夠參考github.com/bytedance/x…

長按識別二維碼 ⬇️


節省視頻流量

使用 video 的同窗基本上都是這樣用的,以下:

  1. 利用src屬性

  2. 利用source標籤

這樣就能夠播放視頻了,不過前面咱們講過這樣使用 video ,視頻的加載是受瀏覽器控制的,能夠看下瀏覽器在視頻剛開始播放的時候下載了多少數據:

圖2.1 video默認下載截圖


我隨便找了個視頻,你們看下視頻總長度是 02:08,在播放到 00:05 的時候,瀏覽器已經下載到 01:30 了,若是用戶終止觀看,下載的視頻就這樣被浪費掉了。固然,若是不斷的 seek 也會形成較多的流量浪費。按照咱們以前的統計在短視頻領域,用戶 seek 的頻率在 80%,因此這部分流量是能夠節省掉的。具體原理以下:

圖2.2 播放器加載視頻原理


  1. 設置每次加載的數據包大小

  2. 設置預加載時長

  3. 開啓加載隊列,完成第一次數據包下載,判斷緩衝時間和預加載時長是否知足,不知足請求下一個數據包

具體實現代碼以下:

這樣就實現了視頻在播放過程當中永遠只預加載10秒的數據,進而保證節省流量。


瞭解超能力西瓜播放器是如何煉成的: h5player.bytedance.com

相關文章
相關標籤/搜索