這篇總結實際上是去年公司每週技術分享會輪到個人時候寫的。那時候公司正在大刀闊斧地準備直播業務,私覺得主管會委以重任,就翻了很多論壇,作了一次簡單的技術分享。後來直播業務讓另外一位同事承擔了,本身也就沒了實踐直播的機會,有點惋惜吧。好了,廢話很少說,開始咱們的理論篇~html
2016年是直播元年,一是因爲各大寬帶提供商順應民意增寬降價,二是大量資本流進了直播板塊,促進了技術的更新迭代。市面上,最經常使用的是 Apple 推出的 HLS 直播協議(原始支持 H5 播放),固然,還有 RTMP、HTTP-FLV、RTP等。前端
視頻文件格式實際上,咱們經常稱做爲容器格式,也就是,咱們通常生活中最常常談到的格式,flv,mp4,ogg 格式等。它就能夠理解爲將比特流按照必定順序放進特定的盒子裏。那選用不一樣格式來裝視頻有什麼問題嗎?android
答案是,沒有任何問題,可是你須要知道如何將該盒子解開,而且可以找到對應的解碼器進行解碼。那若是按照這樣看的話,對於這些 mp4,ogv,webm等等視頻格式,只要我有這些對應的解碼器以及播放器,那麼就沒有任何問題。那麼將視頻比特流放進一個盒子裏面,若是其中某一段出現問題,那麼最終生成的文件其實是不可用的,由於這個盒子自己就是有問題的。ios
不過,上面有一個誤解的地方在於,我只是將視頻理解爲一個靜態的流。試想一下,若是一個視頻須要持續不斷的播放,例如,直播,現場播報等。這裏,咱們就拿 TS/PS 流來進行講解。nginx
PS(Program Stream): 靜態文件流web
TS(Transport Stream): 動態文件流chrome
針對於上面兩種容器格式,其實是對一個視頻比特流作了不同的處理。瀏覽器
那麼結果就是,若是一個或多個盒子出現損壞,PS 格式沒法觀看,而 TS 只是會出現跳幀或者馬賽克效應。二者具體的區別就是:對於視頻的容錯率越高,則會選用 TS,對視頻容錯率越低,則會選用 PS。服務器
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。
Real Time Messaging Protocol(簡稱 RTMP)是 Macromedia 開發的一套視頻直播協議,如今屬於 Adobe。和 HLS 同樣均可以應用於視頻直播,區別是 RTMP 基於 flash 沒法在 iOS 的瀏覽器裏播放,可是實時性比 HLS 要好。因此通常使用這種協議來上傳視頻流,也就是視頻流推送到服務器。
下面是 HLS 和 RTMP 的對比:
HTTP-FLV 和 RTMP 相似,都是針對於 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 的瀏覽器來講,只能降級爲長輪詢或者前端定時器發送請求來獲取實時彈幕。
彈幕渲染時的動畫和碰撞檢測(即彈幕不重疊)等等
flv.js是來自Bilibli的開源項目。它解析FLV文件餵給原生HTML5 Video標籤播放音視頻數據,使瀏覽器在不借助Flash的狀況下播放FLV成爲可能。
因爲瀏覽器對原生Video標籤採用了硬件加速,性能很好,支持高清。同時支持錄播和直播。去掉對Flash的依賴。
flv.js依賴的瀏覽器特性兼容列表
一、HTML5 Video
二、Media Source Extensions
三、WebSocket
四、HTTP FLV: fetch 或 stream
flv.js只作了一件事,在獲取到FLV格式的音視頻數據後經過原生的JS去解碼FLV數據,再經過Media Source Extensions API 餵給原生HTML5 Video標籤。(HTML5 原生僅支持播放 mp4/webm 格式,不支持 FLV)
flv.js 爲何要繞一圈,從服務器獲取FLV再解碼轉換後再餵給Video標籤呢?緣由以下:
一、兼容目前的直播方案:目前大多數直播方案的音視頻服務都是採用FLV容器格式傳輸音視頻數據。
二、FLV容器格式相比於MP4格式更加簡單,解析起來更快更方便。
PC端
一、優先使用 HTTP-FLV,由於它延遲小,性能也不差1080P都很流暢。
二、不支持 flv.js 就使用 Flash播放器播 RTMP 流。Flash兼容性很好,可是性能差默認被不少瀏覽器禁用。
三、不想用Flash兼容也能夠用HLS,可是PC端只有Safari支持HLS
移動端
一、優先使用 HTTP-FLV,由於它延遲小,支持HTTP-FLV的設備性能運行 flv.js 足夠了。
二、不支持 flv.js 就使用 HLS,可是 HLS延遲很是大。
三、HLS 也不支持就無法直播了,由於移動端都不支持Flash。
好了,畢竟是入門理論篇,後續若是有業務實踐我會更新的,感受閱讀至此,比心~