前言
這篇總結其實是去年公司每週技術分享會輪到我的時候寫的。那時候公司正在大刀闊斧地準備直播業務,私以為主管會委以重任,就翻了不少論壇,做了一次簡單的技術分享。後來直播業務讓另一位同事承擔了,自己也就沒了實踐直播的機會,有點可惜吧。好了,廢話不多說,開始我們的理論篇~
技術背景
可以看到,直播從 PC 到一直髮展到移動端,越來越多的直播類 App 上線,同時移動直播進入了前所未有的爆發階段,但是對於大多數移動直播來說,還是要以 Native 客戶端實現為主,但是 H5 在移動直播端也承載著不可替代的作用,例如 H5 有著傳播快,易釋出的優勢,同時最為關鍵的是 H5 同樣可以播放直播視訊。2016年是直播元年,一是由於各大寬頻提供商順應民意增寬降價,二是大量資本流進了直播板塊,促進了技術的更新迭代。市面上,最常用的是 Apple 推出的 HLS 直播協議(原始支援 H5 播放),當然,還有 RTMP、HTTP-FLV、RTP等。
視訊檔案格式和直播協議
視訊檔案格式
視訊檔案格式實際上,我們常常稱作為容器格式,也就是,我們一般生活中最經常談到的格式,flv,mp4,ogg 格式等。它就可以理解為將位元流按照一定順序放進特定的盒子裡。那選用不同格式來裝視訊有什麼問題嗎?
答案是,沒有任何問題,但是你需要知道如何將該盒子解開,並且能夠找到對應的解碼器進行解碼。那如果按照這樣看的話,對於這些 mp4,ogv,webm等等視訊格式,只要我有這些對應的解碼器以及播放器,那麼就沒有任何問題。那麼將視訊位元流放進一個盒子裡面,如果其中某一段出現問題,那麼最終生成的檔案實際上是不可用的,因為這個盒子本身就是有問題的。
不過,上面有一個誤解的地方在於,我只是將視訊理解為一個靜態的流。試想一下,如果一個視訊需要持續不斷的播放,例如,直播,現場播報等。這裡,我們就拿 TS/PS 流來進行講解。
-
PS(Program Stream): 靜態檔案流
-
TS(Transport Stream): 動態檔案流
針對於上面兩種容器格式,實際上是對一個視訊位元流做了不一樣的處理。
- PS: 將完成視訊位元流放到一個盒子裡,生成固定的檔案
- TS: 將接受到的視訊,分成不同的盒子裡。最終生成帶有多個盒子的檔案。
那麼結果就是,如果一個或多個盒子出現損壞,PS 格式無法觀看,而 TS 只是會出現跳幀或者馬賽克效應。兩者具體的區別就是:對於視訊的容錯率越高,則會選用 TS,對視訊容錯率越低,則會選用 PS。
直播協議HLS
HTTP Live Streaming(簡稱 HLS)是一個基於 HTTP 的視訊流協議。這是 Apple 提出的直播流協議。目前,IOS 和 高版本 Android 都支援 HLS。那什麼是 HLS 呢?HLS 主要的兩塊內容是 .m3u8 檔案和 .ts 播放檔案。
HLS 協議基於 HTTP,而一個提供 HLS 的伺服器需要做兩件事:
編碼:以 H.263 格式對影象進行編碼,以 MP3 或者 HE-AAC 對聲音進行編碼,最終打包到 MPEG-2 TS(Transport Stream)容器之中;
分割:把編碼好的 TS 檔案等長切分成字尾為 ts 的小檔案,並生成一個 .m3u8 的純文字索引檔案;
瀏覽器使用的是 m3u8 檔案。m3u8 跟音訊列表格式 m3u 很像,可以簡單的認為 m3u8 就是包含多個 ts 檔案的播放列表。播放器按順序逐個播放,全部放完再請求一下 m3u8 檔案,獲得包含最新 ts 檔案的播放列表繼續播,周而復始。整個直播過程就是依靠一個不斷更新的 m3u8 和一堆小的 ts 檔案組成,m3u8 必須動態更新,ts 可以走 CDN。
這裡,我們著重介紹一下客戶端的過程。首先,直播之所以是直播,在於它的內容是實時更新的。那 HLS 是怎麼完成呢?
我們使用 HLS 直接就用一個 video 進行包括即可:
<video autoplay controls>
<source src="xxx.m3u8" type="application/vnd.apple.mpegurl" />
<p class="warning">Your browser doesn't support video</p>
</video>
複製程式碼
根據上面的描述,它實際上就是去請求一個 .m3u8 的索引檔案。該檔案包含了對 .ts 檔案的相關描述,例如:
不過,這只是一個非常簡單,不涉及任何功能的直播流。實際上,HLS 的整個架構,可以分為: masterplaylist 主要乾的事就是根據, 當前使用者的頻寬,解析度,解碼器等條件決定使用哪一個流。所以,master playlist 是為了更好的使用者體驗而存在的。當填寫了 master playlist URL,那麼使用者只會下載一次該 master playlist。接著,播放器根據當前的環境決定使用哪一個 media playlist(就是 子 m3u8 檔案)。如果,在播放當中,使用者的播放條件發生變化時,播放器也會切換對應的 media playlist。
當然,HLS 支援的功能,並不只是分片播放(專門適用於直播),它還包括其他應有的功能。
-
使用 HTTPS 加密 ts 檔案
-
快/倒放
-
廣告插入
-
不同解析度視訊切換
可以看到 HLS 協議本質還是一個個的 HTTP 請求 / 響應,所以適應性很好,不會受到防火牆影響。但它也有一個致命的弱點:延遲現象非常明顯。如果每個 ts 按照 5 秒來切分,一個 m3u8 放 6 個 ts 索引,那麼至少就會帶來 30 秒的延遲。如果減少每個 ts 的長度,減少 m3u8 中的索引數,延時確實會減少,但會帶來更頻繁的緩衝,對服務端的請求壓力也會成倍增加。所以只能根據實際情況找到一個折中的點。
注意:HLS 在 PC 端僅支援safari瀏覽器,類似chrome瀏覽器使用HTML5 video標籤無法播放 m3u8 格式,可直接採用網上一些比較成熟的方案,如:sewise-player、MediaElement、videojs-contrib-hls、jwplayer。
直播協議RTMP
Real Time Messaging Protocol(簡稱 RTMP)是 Macromedia 開發的一套視訊直播協議,現在屬於 Adobe。和 HLS 一樣都可以應用於視訊直播,區別是 RTMP 基於 flash 無法在 iOS 的瀏覽器裡播放,但是實時性比 HLS 要好。所以一般使用這種協議來上傳視訊流,也就是視訊流推送到伺服器。
下面是 HLS 和 RTMP 的對比:
直播協議HTTP-FLV
HTTP-FLV 和 RTMP 類似,都是針對於 FLV 視訊格式做的直播分發流。但,兩者有著很大的區別。
- 直接發起長連線,下載對應的 FLV 檔案
- 頭部資訊簡單
現在市面上,比較常用的就是 HTTP-FLV 進行播放。但,由於手機端上不支援,所以,H5 的 HTTP-FLV 也是一個痛點。不過,現在 flv.js 可以幫助高版本的瀏覽器,通過 mediaSource 來進行解析。HTTP-FLV 的使用方式也很簡單。和 HLS 一樣,只需要新增一個連線即可:
<object type="application/x-shockwave-flash" src="xxx.flv"></object>
複製程式碼
直播基本架構
目前較為成熟的直播產品,大致都是以 Server 端和 H5 和 Native(android,ios)搭配實現直播,基本是下圖這個套路:
完整的直播可以分為以下幾塊:-
視訊錄製端:一般是電腦上的音視訊輸入裝置或者手機端的攝像頭或者麥克風,目前以移動端的手機視訊為主。
-
視訊播放端:可以是電腦上的播放器,手機端的 Native 播放器,還有就是 H5 的 video 標籤等,目前還是已手機端的 Native 播放器為主。
-
視訊伺服器端:一般是一臺 nginx 伺服器,用來接受視訊錄製端提供的視訊源,同時提供給視訊播放端流服務。
-
彈幕實時性,可以利用 webscoket 來實時傳送和接收新的彈幕並渲染出來。
-
對於不支援 webscoket 的瀏覽器來說,只能降級為長輪詢或者前端定時器傳送請求來獲取實時彈幕。
-
彈幕渲染時的動畫和碰撞檢測(即彈幕不重疊)等等
H5直播方案
使用flv.js做直播
- 簡介
flv.js是來自Bilibli的開源專案。它解析FLV檔案餵給原生HTML5 Video標籤播放音視訊資料,使瀏覽器在不借助Flash的情況下播放FLV成為可能。
- 優勢
由於瀏覽器對原生Video標籤採用了硬體加速,效能很好,支援高清。同時支援錄播和直播。去掉對Flash的依賴。
- 瀏覽器依賴
flv.js依賴的瀏覽器特性相容列表
1、HTML5 Video
2、Media Source Extensions
3、WebSocket
4、HTTP FLV: fetch 或 stream
- 原理
flv.js只做了一件事,在獲取到FLV格式的音視訊資料後通過原生的JS去解碼FLV資料,再通過Media Source Extensions API 餵給原生HTML5 Video標籤。(HTML5 原生僅支援播放 mp4/webm 格式,不支援 FLV)
flv.js 為什麼要繞一圈,從伺服器獲取FLV再解碼轉換後再餵給Video標籤呢?原因如下:
1、相容目前的直播方案:目前大多數直播方案的音視訊服務都是採用FLV容器格式傳輸音視訊資料。
2、FLV容器格式相比於MP4格式更加簡單,解析起來更快更方便。
- 相容方案
PC端
1、優先使用 HTTP-FLV,因為它延遲小,效能也不差1080P都很流暢。
2、不支援 flv.js 就使用 Flash播放器播 RTMP 流。Flash相容性很好,但是效能差預設被很多瀏覽器禁用。
3、不想用Flash相容也可以用HLS,但是PC端只有Safari支援HLS
移動端
1、優先使用 HTTP-FLV,因為它延遲小,支援HTTP-FLV的裝置效能執行 flv.js 足夠了。
2、不支援 flv.js 就使用 HLS,但是 HLS延遲非常大。
3、HLS 也不支援就沒法直播了,因為移動端都不支援Flash。
好了,畢竟是入門理論篇,後續如果有業務實踐我會更新的,感覺閱讀至此,比心~