鬥魚直播相信大家都聽說過,打開鬥魚官網就可以直接在瀏覽器中觀看直播。那麼鬥魚是如何實現瀏覽器視頻直播的呢?本篇文章就來解析鬥魚是如何實現直播的,以及它是如何節省 80% 的 CDN 流量,要知道視頻直播流量費並不便宜,鬥魚每個月光這些流量費都要支付幾個億,節省 CDN 流量就是省錢。 直播技術方案 ...
鬥魚直播相信大家都聽說過,打開鬥魚官網就可以直接在瀏覽器中觀看直播。那麼鬥魚是如何實現瀏覽器視頻直播的呢?本篇文章就來解析鬥魚是如何實現直播的,以及它是如何節省 80% 的 CDN 流量,要知道視頻直播流量費並不便宜,鬥魚每個月光這些流量費都要支付幾個億,節省 CDN 流量就是省錢。
直播技術方案
在實際去鬥魚直播間調試視頻直播之前,我就猜它肯定是使用 HTTP-FLV 方案來實現視頻直播,因為國內幾乎所有直播平臺都是使用 HTTP-FLV 方案。
但是去鬥魚直播間並沒有找到 .flv
的網路請求,而是找到了 .xs
的網路請求,如下圖所示。
不過 .xs
網路請求的響應的 Content-Type
是 video/x-flv
,原來只是尾碼不同,看來我猜的果真沒錯,鬥魚就是用的 HTTP-FLV。
HTTP+P2P FLV 拉流
不過為什麼尾碼是 .xs
而不是 .flv
呢?其實這裡是因為鬥魚預設並不完全使用 HTTP 去拉流,而是採用 CDN 和 P2P 兩種方式同時去拉流,.xs
並不是一個完整的 FLV 流,而是一個子 FLV 流。
進入鬥魚直播間,鬥魚首先會去請求一個完整的 FLV 流,等 P2P 連接好了再去切換成子流。這是因為 P2P 連接比較慢,如果走來就走 P2P,那麼視頻起播速度會非常慢。
上圖中第二個連接就是一個完整的 FLV 流,等 P2P 連接成功後會斷開連接去拉子流。
在 P2P 連接成功後,還可以在網路面板看到一個 WebSocket 連接,如下圖所示,它是鬥魚用來推送其他正在觀看當前流的用戶的,這樣播放器就可以直接從推送的用戶這裡拉流。
鬥魚 P2P 是基於 WebRTC 的 DataChannel,可以打開 chrome 的 WebRTC 的調試頁面,可以看到有很多 WebRTC 連接,它可以接收其他用戶分享的視頻數據,自己也會共用當前下載到的視頻數據給其他用戶。
鬥魚將一個完整的直播流進行切片,分成一個個小的視頻分片併進行編號(這樣方便用戶之間共用)然後將這些小分片分為多個子流,通過 HTTP 從 CDN 拉一路子流,然後通過 P2P 去其他用戶那裡拉其他的子流。
但是通過 P2P 從其他用戶那裡拉流並不是很穩定,例如其他用戶可以能退出了直播間,或者網路出了問題,這樣就會導致接收它分享的用戶直播斷流。為了提升直播穩定性,如果在一定時間內沒有收到其他用戶分享的數據,鬥魚播放器就會立刻從 CDN 去拉對應的子流,並且 WebSocket 也會推薦新的用戶給播放器。
可以發現,加上 P2P 拉流,大大增加了直播的複雜度。但是它帶來的好處也非常的明顯,就是可以省錢,省到就是賺到!因為流量費非常的貴,鬥魚每個月光直播帶寬都得花好幾個億。利用 P2P 從其他用戶那裡拉流可以節省大量流量,例如一個直播流分為兩個子流,一個從 CDN 拉,一個從其他用戶那裡拉,這樣理論上就可以節省 50% 的流量,而鬥魚將一個直播流分成 6 個子流,一個從 CDN 拉,其餘 5 個全部從其他用戶那裡拉,理論上可以節省超過 80% 的直播流量!
當然 P2P 拉流也有一些缺點,例如直播延遲較高,不適用於低延遲直播場景,對用戶電腦和帶寬有一定消耗,因為除了從其他用戶那裡拉流,當前用戶自己還要上傳視頻數據給其他用戶。
如果你想關閉 P2P,也比較簡單,可以在網路面板屏蔽下圖中的地址即可。
屏蔽之後,鬥魚就只會從 CDN 拉流,不走 P2P,如下圖所示,可以發現流的地址變成正常的 .flv
尾碼。
無論是只使用 HTTP,還是使用 HTTP + P2P,它們的最終目的是獲取 FLV 視頻數據。
FLV 格式
FLV 視頻格式是由 Adobe 公司開發,在 2003 年發佈,用於視頻文件在網路上傳輸。在 Flash 時代幾乎所有流媒體平臺都在使用 FLV 格式,但是隨著 Flash 技術的淘汰,FLV 也跟著沒落了,目前國外已經沒有流媒體平臺在使用 FLV 了,但是在國內 FLV 卻廣泛用於網路直播場景。
不像 Flash,H5 的 video 元素是無法播放 FLV 視頻的,我們需要藉助 MSE 來自己控制視頻播放,具體原理是將 FLV 轉封裝成 FMP4 視頻格式,然後交給 MSE 播放即可。
MSE 全稱是 Media Source Extensions API,它是 Web 流媒體的基礎,所有 Web 流媒體平臺最終都會用到它,如果對它感興趣,歡迎查看 流媒體視頻基礎 MSE 入門 & FFmpeg 製作視頻預覽縮略圖和 fmp4
目前有開源的 flv.js 來幫我們完成這件事,查看鬥魚 dist 後代碼,鬥魚也是使用的 flv.js,不過在之上加了很多自定義的代碼,例如加上了 h265 編碼的支持,flv.js 是不支持 h265 編碼的,FLV 官方規範也不支持,但是業務又有這種需求,所以一般將 FLV 視頻編碼 ID 等於 12 當作 h265 的流。在鬥魚直播中如果發現直播流是 h265 編碼並且瀏覽器不支持 h265,鬥魚會利用 WASM 來軟解播放視頻。
直播時移
對於賽事直播鬥魚是支持直播時移的,如下圖所示。
但是這個播放器的進度條體驗不是很好,進度條的高度只有 3px,滑鼠非要精準的放上去,才能有 Hover 的效果,這是沒那麼容易做到的。這裡推薦個好用開源的播放器進度條 ppbar,你可以把它集成到任何播放器中去,非常的好用。
鬥魚直播時移是基於 HLS 的,如果點擊一下進度條,鬥魚播放器會黑一下,將 FLV 切換成 HLS。
在剛開始進入直播間拉流的時候,鬥魚播放器可以獲取到伺服器返回的一個時間戳,單位是秒,當用戶點擊進度條跳轉到前 10 分鐘時,就直接用當前時間減去 600 秒就得到了前 10 分鐘視頻的時間戳,然後會用這個時間戳去請求請求一個 getVodStream
介面獲取到 HLS 時移流地址,獲取到 HLS 過後,就和普通 HLS 直播一樣去播放即可。
和 FLV 一樣,要在瀏覽器中播放 HLS 流,同樣需要 MSE API 來播放,目前可以藉助開源的 hls.js 來在瀏覽器中播放 HLS 流。查看鬥魚 dist 過後的代碼,鬥魚應該沒有使用 hls.js,而是自己實現在瀏覽器中播放 HLS。
總結
這篇文章介紹了鬥魚 H5 直播技術的原理,鬥魚不僅使用國內常用的 HTTP-FLV 方案,還加入了 P2P 拉流,從而節省 CDN 流量。對於賽事直播,鬥魚還支持直播時移,直播時移是使用 HLS 來實現的,用戶在 seek 後會通過 seek 到的時間點去伺服器換取對應的時移 HLS 流地址,然後走 HLS 拉流即可。