海外高性能視頻你得這麼玩

做者:忘語 轉載自:公衆號 方凳雅集html

1、流媒體與RangeRequest

1. 流媒體

對於通常的數據請求,咱們要等整個請求數據徹底返回才能作後續的處理,可是對於視頻這種大文件,等整個響應結束再處理顯然不合理。流媒體就是對文件按時間緯度進行切片並順序存儲,網絡傳輸時,客戶端能夠接收一個切片展現一個切片。
image.png
視頻的流媒體編碼格式有不少,其中瀏覽器支持最好的是 mp4,它獲得了 PC / 無線端全部主流瀏覽器的支持:
image.png
通常的視頻文件,爲了畫面連續,一秒會採集30幀的畫面;在這麼短的時間內,每幀的畫面變化其實不多。mp4文件針對視頻的這種特性,會將畫面中連續差異不大的幀分爲一組,分組開始的幀稱爲關鍵幀(I幀),對關鍵幀只作常規的圖像壓縮,保存完整的圖像信息;而後在分組中的其它幀裏取幾個斷點做爲P幀,P幀不保存完整的圖像信息,只保留當前幀跟關鍵幀(或者上一個P幀)之間的差別信息;分組內其它幀(B幀)在關鍵幀和P幀之間,保存當前幀跟先後兩幀之間的差別信息;這樣能夠在不影響畫面質量的狀況下,獲得很是高的壓縮率,這也是 mp4 文件可以這麼普及的主要緣由。
image.png
mp4很好,可是這個協議並不開源,商業使用須要專利受權;爲此apple開發了mov格式,chrome則直接推出了開源的webm格式,兩個格式都在mp4的壓縮原理基礎上作了進一步的優化,有更好的清晰度和壓縮率。前端

2. RangeRequests

對於視頻播放來講,還有一個很重要的就是要支持用戶調整播放進度,支持讓用戶選擇直接跳到中間部分開始播放。這就須要 HTTP Range Requests 協議了,這個協議很簡單,支持客戶端在 http 請求時經過 Range 請求頭指定要請求文件的起始和結束位置。android

curl http://test.video -H "Range: bytes=0-1023"

若是服務器支持 Range Requests 協議,會讀取 test.video 文件,並將他的第 0~1023 字節提取出來,並以狀態碼 206 響應請求;
若是服務器不支持,直接忽略 Range 頭,讀取整個文件內容,以狀態碼 200 響應便可。
當咱們在 html 中放一個 video 標籤,瀏覽器會直接發起一個 Range: bytes=0- 的請求,向服務器請求從開始到結尾的完整文件,若是服務器不支持 Range Requests,響應碼爲 200,瀏覽器會正常按流式加載整個視頻文件;
若是服務器支持 Range Requests,響應碼爲 206,則瀏覽器會在接收到足夠字節(通常是比當前播放進度日後推20s)時結束掉請求,以節省網絡流量;當播放進度繼續往前,緩存不夠時,瀏覽器會發起一個新的 Range Requests 請求,請求的 Range 直接從緩存結尾的字節開始,只加載剩餘的部分文件;
image.png
相似的,在咱們調整播放進度,跳過一部份內容時,瀏覽器會把當前的 Range Requests 結束,從選擇的播放進度開始從新發起新的 Range Requests,接收到分段內容後直接重新的進度開始播放。ios

2、視頻按流量計費與防盜流

1. 視頻按流量計費

咱們前面提到,若是服務器支持 Range Requests,瀏覽器會在緩存足夠時提早結束請求而不是加載整個視頻文件。這主要是由於通常視頻服務器都是按流量計費的,流量套餐跟咱們手機的網絡流量套餐相似,你能夠選擇一個保底的月流量總量,超過總量的,每G加多少錢,下面是咱們 icbu 跟 akamai 簽定的流量套餐,你們能夠感覺一下:
image.pngweb

2. 防盜鏈

既然視頻流量這麼金貴,咱們必須限制視頻只在咱們本身的網站上播放。防盜鏈也比較簡單,視頻的 cdn 地址裏會有一段按期失效的加密串,加密串校驗失敗時,cdn 不返回內容。咱們在網站上不直接使用視頻 cdn 地址,而是一個帶視頻 id 的鑑權連接,鑑權成功後 302 到實時生成的帶加密串的 cdn 地址。
image.pngchrome

3、視頻性能指標

1. 有效播放率

前面咱們已經介紹了視頻相關的一些基礎知識,在開始進行視頻性能優化以前,先要肯定好能反應視頻性能的幾個關鍵指標。
首先,咱們看的最根本的指標是視頻的有效播放率,icbu 這邊定義視頻正常播放 3s 爲一個有效播放(這個還有寬窄口徑之分,窄口徑下在可視區域的播放纔算),同個視頻 有效播放的 uv / 開始播放 uv 稱爲視頻的有效播放率瀏覽器

2. 首幀播放時間

有效播放率是一個偏業務的指標,很大程度上受視頻質量的影響,首幀播放時間則是實打實的純性能指標了。這個計算比較簡單,視頻在播放中或者進度信息調整時會觸發 timeupdate 事件,當視頻在播放狀態時,第一個 timeupdate 事件跟上一個播放事件的時間差就是首幀播放時間了。
對於自動播放的視頻,能夠將視頻節點插入 dom 的時間做爲起始時間,這樣能夠避免視頻預加載的影響,也能夠把鑑權,302跳轉等時間計算在一塊兒,衡量整個鏈路的加載時間。緩存

3. 卡頓率

除了首幀的加載速度,還有一個很是影響體驗的是視頻的流暢度。卡頓率的計算稍微複雜一些,不能簡單計算視頻的卡頓次數,由於一個小時的視頻卡頓 10 次跟 10s 的視頻卡頓 10 次體驗是徹底不同的。通常的計算方法是:性能優化

(總卡頓時長 / 總播放時長)* (卡頓次數 * 權重)

打點的時候注意要分段打點,每次卡頓都要記錄卡頓先後的播放片斷時長和卡頓時長。最終數據統計的時候再按視頻 id 和 session 進行加合。服務器

4. 錯誤率

這個不用多解釋,咱們要儘可能將視頻的加載錯誤率降到最低。視頻出錯通常有幾種狀況:客戶網絡問題、視頻源問題和 cdn 回源超時。
視頻源問題,通常是視頻源被用戶刪除,致使視頻不可用。這一類問題服務器通常會返回 404 等錯誤;注意咱們在 html 中插入 video 時最好使用 <source> 標籤指定視頻地址並監聽 <source> 元素自己的錯誤事件,直接經過 <video> 的 src 屬性指定視頻地址時,對於資源 404 的錯誤,<video> 元素沒法捕獲到。

4、視頻性能優化

1. 流媒體 CDN 支持

通過以上的分析,咱們能夠開始進行視頻的性能優化了。與其它前端資源同樣,第一步要經過 cdn 提高資源的加載速度。不一樣於普通的靜態資源 cdn,流媒體須要專門的 cdn 支持,他與普通的cdn主要有兩方面的差異:
1)流媒體 cdn 回源超時時間更長

因爲流媒體文件廣泛很大,回源時間會很長

2)流媒體 cdn 支持分段 cache 和回源

好比客戶端請求一個視頻文件的 0~1024 字節,而 cdn 節點上已經有完整文件的時候,節點直接從緩存文件中取對應字節返回而不會回源到源站;另外一方面,若是節點上只有 0~512 字節的緩存,節點會只向節點請求 512~1024 分段的內容,而不會總體回源;

2. 鑑權服務和源站本地化部署

爲了防盜鏈,用戶不能直接訪問 cdn 連接,而是要通過一層鑑權服務;這層鑑權服務必須本地化部署,不然首幀播放時間會慢不少。另外一方面,視頻文件的緩存命中率很低(ICBU這邊的視頻緩存命中率只有65.5%),會有大量的客戶請求回源,咱們必須把視頻源站也進行本地化部署。
image.png
19年初,ICBU這邊在淘寶視頻同窗的大力支持下,將全部視頻源文件進行了中美OSS同步,將鑑權服務部署到了美國機房,採購了海外的 akamai cdn,整個視頻播放流程改造以下:
image.png
美國部署改造後整個海外視頻的首幀播放時間提高了1s+

image.png

3. 視頻內容壓縮

3.1 使用壓縮率更高的文件格式

mov 和 webm 格式壓縮率更好,並且 ios 和 android 端分別支持兩種格式,對於移動端場景能夠嘗試使用。不過格式不統一會讓 cdn 命中率進一步下降,具體效果咱們也還在測試驗證中。

3.2 視頻分辨率

視頻分辨率指視頻的寬高尺寸,相似圖片的尺寸,1920x1080 表明視頻寬 1920 像素,高1080像素;常見的幾種視頻分辨率有:1280x720(別名720P)、1920x1080(別名1080P)、2048x1080(別名2K)、4096x2160(別名4K)
若是咱們的視頻播放窗口只有350像素,而賣家上傳的視頻是 1080P 的,這無疑會浪費大量的帶寬,視頻性能也會不好。目前淘寶視頻會在視頻上傳完成後進行簡單的處理,生成低清、標清和高清三種分辨率的視頻,分別對應720、540 和 360 三個尺寸斷點。例如一個 1920x1080 的視頻,轉出高清視頻時會限制視頻寬或者高爲720像素,這樣轉換獲得的高清視頻分辨率爲 1280x720;相似的轉出標清視頻爲 960x540,低清視頻爲 640x360。這樣咱們根據不一樣的播放須要選擇加載不一樣清晰度的視頻便可。

3.3 視頻幀率

咱們知道視頻是利用人眼的視覺暫留現象,經過一張張圖片來實現動態效果的:
image.png
每秒展現多少張圖片(幀),叫作視頻的幀率(FPS),fps越高,視頻看起來就越順暢:
image.png
對於通常的視頻,24~30 的幀率已經足夠,人眼基本看不出卡頓,事實上 24FPS 已是 80 多年的電影幀率標準。目前淘視頻尚未專門處理視頻幀率,線上也有一些賣家上傳的高幀率視頻文件。

3.4 音、視頻內容分離

另外一個能有效壓縮視頻體積的辦法是將音、視頻文件分離,由於咱們有不少場景是把視頻做爲底圖或者 gif 來用的,加載音頻文件很是浪費

4. 分段請求優化

瀏覽器內置的視頻播放器只能知足基本的視頻播放需求,咱們沒法經過 js 來控制分段請求的大小或者操做視頻緩存。好比咱們拖放視頻進度到第 3s 開始播放,瀏覽器加載到第 5s 時,咱們又將進度跳回第 1s 開始播放,這時第 3~5s 的內容已經緩存完畢,可是瀏覽器內置播放器發起的分段請求是請求從第 1s 直到文件結束的全部數據信息。
經過 H5 的 MediaSource API,能夠很方便地經過 js 來控制視頻的加載與播放:

// 1. video 的 src 不是某個特定的 url,而是 mediaSource 對象的內存地址
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

// 2. 經過 mediaSource 建立一個 mp4 編碼的視頻緩存區
const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');

// 3. 請求所需的視頻分段,將數據放入緩存中
fetch('/video', {
    headers: {
        'Range': 'bytes=1024-2048',
    }
})
.then(response => response.blob())
.then(buffer => sourceBuffer.appendBuffer(buffer));

// 視頻有足夠的緩衝後便可以開始播放視頻了
video.play();
相關文章
相關標籤/搜索