視訊直播技術乾貨:一文讀懂主流視訊直播系統的推拉流架構、傳輸協議等
本文由蘑菇街前端開發工程師“三體”分享,原題“蘑菇街雲端直播探索——啟航篇”,有修訂。
1、引言
隨著行動網路網速的提升與資費的降低,視訊直播作為一個新的娛樂方式已經被越來越多的使用者逐漸接受。特別是最近這幾年,視訊直播已經不僅僅被運用在傳統的秀場、遊戲類板塊,更是作為電商的一種新模式得到迅速成長。
本文將通過介紹實時視訊直播技術體系,包括常用的推拉流架構、傳輸協議等,讓你對現今主流的視訊直播技術有一個基本的認知。
2、蘑菇街的直播架構概覽
目前蘑菇街直播推拉流主流程依賴於某雲直播的服務。
雲直播提供的推流方式有兩種:
- 1)一是通過整合SDK的方式進行推流(用於手機端開播);
- 2)另一種是通過RTMP協議向遠端伺服器進行推流(用於PC開播端或專業控臺裝置開播)。
除去推拉流,該雲平臺也提供了雲通訊(IM即時通訊能力)和直播錄製等雲服務,組成了一套直播所需要的基礎服務。
3、推拉流架構1:廠商SDK推拉流
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150201825-1077247028.png)
如上題所示,這一種推拉流架構方式需要依賴騰訊這類廠商提供的手機互動直播SDK,通過在主播端APP和使用者端APP都整合SDK,使得主播端和使用者端都擁有推拉流的功能。
這種推拉流架構的邏輯原理是這樣的:
- 1)主播端和使用者端分別與雲直播的互動直播後臺建立長連線;
- 2)主播端通過UDT私有協議向互動直播後臺推送音視訊流;
- 3)互動直播後臺接收到音視訊流後做轉發,直接下發給與之建立連線的使用者端。
這種推拉流方式有幾點優勢:
- 1)只需要在客戶端中整合SDK:通過手機就可以開播,對於主播開播的要求比較低,適合直播業務快速鋪開;
- 2)互動直播後臺僅做轉發:沒有轉碼,上傳CDN等額外操作,整體延遲比較低;
- 3)主播端和使用者端都可以作為音視訊上傳的發起方:適合連麥、視訊會話等場景。
4、推拉流架構2:旁路推流
之前介紹了通過手機SDK推拉流的直播方式,看起來在手機客戶端中觀看直播的場景已經解決了。
那麼問題來了:如果我想要在H5、小程式等其他場景下觀看直播,沒有辦法接入SDK,需要怎麼處理呢?
這個時候需要引入一個新的概念——旁路推流。
旁路推流指的是:通過協議轉換將音視訊流對接到標準的直播 CDN 系統上。
目前雲直播開啟旁路推流後,會通過互動直播後臺將音視訊流推送到雲直播後臺,雲直播後臺負責將收到音視訊流轉碼成通用的協議格式並且推送到CDN,這樣H5、小程式等端就可以通過CDN拉取到通用格式的音視訊流進行播放了。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150209579-1149426147.png)
目前蘑菇街直播旁路開啟的協議型別有HLS、FLV、RTMP三種,已經可以覆蓋到所有的播放場景,在後續章節會對這幾種協議做詳細的介紹。
5、推拉流架構3:RTMP推流
隨著直播業務發展,一些主播逐漸不滿足於手機開播的效果,並且電商直播需要高保真地將商品展示在螢幕上,需要通過更加高清專業的裝置進行直播,RTMP推流技術應運而生。
我們通過使用OBS等流媒體錄影程式,對專業裝置錄製的多路流進行合併,並且將音視訊流上傳到指定的推流地址。由於OBS推流使用了RTMP協議,因此我們稱這一種推流型別為RTMP推流。
我們首先在雲直播後臺申請到推流地址和祕鑰,將推流地址和祕鑰配置到OBS軟體當中,調整推流各項引數,點選推流以後,OBS就會通過RTMP協議向對應的推流地址推送音視訊流。
這一種推流方式和SDK推流的不同之處在於音視訊流是直接被推送到了雲直播後臺進行轉碼和上傳CDN的,沒有直接將直播流轉推到使用者端的下行方式,因此相比SDK推流延遲會長一些。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150218958-584446642.png)
總結下來RTMP推流的優勢和劣勢比較明顯。
優勢主要是:
- 1)可以接入專業的直播攝像頭、麥克風,直播的整體效果明顯優於手機開播;
- 2)OBS已經有比較多成熟的外掛,比如目前蘑菇街主播常用YY助手做一些美顏的處理,並且OBS本身已經支援濾鏡、綠幕、多路視訊合成等功能,功能比手機端強大。
劣勢主要是:
- 1)OBS本身配置比較複雜,需要專業裝置支援,對主播的要求明顯更高,通常需要一個固定的場地進行直播;
- 2)RTMP需要雲端轉碼,並且本地上傳時也會在OBS中配置GOP和緩衝,延時相對較長。
6、高可用架構方案:雲互備
業務發展到一定階段後,我們對於業務的穩定性也會有更高的要求,比如當雲服務商服務出現問題時,我們沒有備用方案就會出現業務一直等待服務商修復進度的問題。
因此雲互備方案就出現了:雲互備指的是直播業務同時對接多家雲服務商,當一家雲服務商出現問題時,快速切換到其他服務商的服務節點,保證業務不受影響。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150228435-1983594253.png)
直播業務中經常遇到服務商的CDN節點下行速度較慢,或者是CDN節點儲存的直播流有問題,此類問題有地域性,很難排查,因此目前做的互備雲方案,主要是備份CDN節點。
目前蘑菇街整體的推流流程已經依賴了原有云平臺的服務,因此我們通過在雲直播後臺中轉推一路流到備份雲平臺上,備份雲在接收到了直播流後會對流轉碼並且上傳到備份雲自身的CDN系統當中。一旦主平臺CDN節點出現問題,我們可以將下發的拉流地址替換成備份雲拉流地址,這樣就可以保證業務快速修復並且觀眾無感知。
7、視訊直播資料流解封裝原理
介紹流協議之前,先要介紹我們從雲端拿到一份資料,要經過幾個步驟才能解析出最終需要的音視訊資料。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150239583-1533792161.png)
如上圖所示,總體來說,從獲取到資料到最終將音視訊播放出來要經歷四個步驟。
第一步:解協議。
協議封裝的時候通常會攜帶一些頭部描述資訊或者信令資料,這一部分資料對我們音視訊播放沒有作用,因此我們需要從中提取出具體的音視訊封裝格式資料,我們在直播中常用的協議有HTTP和RTMP兩種。
第二步:解封裝。
獲取到封裝格式資料以後需要進行解封裝操作,從中分別提取音訊壓縮流資料和視訊壓縮流資料,封裝格式資料我們平時經常見到的如MP4、AVI,在直播中我們接觸比較多的封裝格式有TS、FLV。
第三步:解碼音視訊。
到這裡我們已經獲取了音視訊的壓縮編碼資料。
我們日常經常聽到的視訊壓縮編碼資料有H.26X系列和MPEG系列等,音訊編碼格式有我們熟悉的MP3、ACC等。
之所以我們能見到如此多的編碼格式,是因為各種組織都提出了自己的編碼標準,並且會相繼推出一些新的議案,但是由於推廣和收費問題,目前主流的編碼格式也並不多。
獲取壓縮資料以後接下來需要將音視訊壓縮資料解碼,獲取非壓縮的顏色資料和非壓縮的音訊抽樣資料。顏色資料有我們平時熟知的RGB,不過在視訊的中常用的顏色資料格式是YUV,指的是通過明亮度、色調、飽和度確定一個畫素點的色值。音訊抽樣資料通常使用的有PCM。
第四步:音視訊同步播放。
最後我們需要比對音視訊的時間軸,將音視訊解碼後的資料交給顯示卡音效卡同步播放。
PS:如果你對上述流程還不太理解,建議進一步閱讀以下系列文章:
- 《移動端實時音視訊直播技術詳解(一):開篇》
- 《移動端實時音視訊直播技術詳解(二):採集》
- 《移動端實時音視訊直播技術詳解(三):處理》
- 《移動端實時音視訊直播技術詳解(四):編碼和封裝》
- 《移動端實時音視訊直播技術詳解(五):推流和傳輸》
- 《移動端實時音視訊直播技術詳解(六):延遲優化》
另外:有關音視訊編解碼技術的文章,也可以詳細學習以下文章:
- 視訊編解碼之:《理論概述》、《數字視訊介紹》、《編碼基礎》、《預測技術介紹》
- 《認識主流視訊編碼技術H.264》
- 《如何開始音訊編解碼技術的學習》
- 《音訊基礎及編碼原理入門》
- 《常見的實時語音通訊編碼標準》
- 《實時視訊編碼H.264的特點與優勢》、《視訊編碼H.264、VP8的前世今生》
- 《詳解音訊編解碼的原理、演進和應用選型》、《零基礎,史上最通俗視訊編碼技術入門》
8、視訊直播傳輸協議1:HLS
首先介紹一下HLS協議。HLS是HTTP Live Streaming的簡寫,是由蘋果公司提出的流媒體網路傳輸協議。
從名字可以明顯看出:這一套協議是基於HTTP協議傳輸的。
說到HLS協議:首先需要了解這一種協議是以視訊切片的形式分段播放的,協議中使用的切片視訊格式是TS,也就是我們前文提到的封裝格式。
在我們獲取TS檔案之前:協議首先要求請求一個M3U8格式的檔案,M3U8是一個描述索引檔案,它以一定的格式描述了TS地址的指向,我們根據M3U8檔案中描述的內容,就可以獲取每一段TS檔案的CDN地址,通過載入TS地址分段播放就可以組合出一整段完整的視訊。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150252292-2109844620.png)
使用HLS協議播放視訊時:首先會請求一個M3U8檔案,如果是點播只需要在初始化時獲取一次就可以拿到所有的TS切片指向,但如果是直播的話就需要不停地輪詢M3U8檔案,獲取新的TS切片。
獲取到M3U8後:我們可以看一下里面的內容。首先開頭是一些通用描述資訊,比如第一個分片序列號、片段最大時長和總時長等,接下來就是具體TS對應的地址列表。如果是直播,那麼每次請求M3U8檔案裡面的TS列表都會隨著最新的直播切片更新,從而達到直播流播放的效果。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150304280-537249326.png)
HLS這種切片播放的格式在點播播放時是比較適用的,一些大的視訊網站也都有用這一種協議作為播放方案。
首先:切片播放的特性特別適用於點播播放中視訊清晰度、多語種的熱切換。比如我們播放一個視訊,起初選擇的是標清視訊播放,當我們看了一半覺得不夠清晰,需要換成超清的,這時候只需要將標清的M3U8檔案替換成超清的M3U8檔案,當我們播放到下一個TS節點時,視訊就會自動替換成超清的TS檔案,不需要對視訊做重新初始化。
其次:切片播放的形式也可以比較容易地在視訊中插入廣告等內容。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150315058-1079356.png)
在直播場景下,HLS也是一個比較常用的協議,他最大的優勢是蘋果大佬的加持,對這一套協議推廣的比較好,特別是移動端。將M3U8檔案地址餵給video就可以直接播放,PC端用MSE解碼後大部分瀏覽器也都能夠支援。但是由於其分片載入的特性,直播的延遲相對較長。比如我們一個M3U8有5個TS檔案,每個TS檔案播放時長是2秒,那麼一個M3U8檔案的播放時長就是10秒,也就是說這個M3U8播放的直播進度至少是10秒之前的,這對於直播場景來說是一個比較大的弊端。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150324307-475563795.png)
HLS中用到的TS封裝格式,視訊編碼格式是通常是H.264或MPEG-4,音訊編碼格式為AAC或MP3。
一個ts由多個定長的packtet組成,通常是188個位元組,每個packtet有head和payload組成,head中包含一些識別符號、錯誤資訊、包位置等基礎資訊。payload可以簡單理解為音視訊資訊,但實際上下層還有還有兩層封裝,將封裝解碼後可以獲取到音視訊流的編碼資料。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150334290-687797759.png)
9、視訊直播傳輸協議2:HTTP-FLV
HTTP-FLV協議,從名字上就可以明顯看出是通過HTTP協議來傳輸FLV封裝格式的一種協議。
FLV是Flash Video的簡寫,是一種檔案體積小,適合在網路上傳輸的封包方式。FlV的視訊編碼格式通常是H.264,音訊編碼是ACC或MP3。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150342517-455989605.png)
HTTP-FLV在直播中是通過走HTTP長連線的方式,通過分塊傳輸向請求端傳遞FLV封包資料。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150351795-336773215.png)
在直播中,我們通過HTTP-FLV協議的拉流地址可以拉取到一段chunked資料。
開啟檔案後可以讀取到16進位制的檔案流,通過和FLV包結構對比,可以發現這些資料就是我們需要的FLV資料。
首先開頭是頭部資訊:464C56轉換ASCII碼後是FLV三個字元,01指的是版本號,05轉換為2進位制後第6位和第8位分別代表是否存在音訊和視訊,09代表頭部長度佔了幾個位元組。
後續就是正式的音視訊資料:是通過一個個的FLV TAG進行封裝,每一個TAG也有頭部資訊,標註這個TAG是音訊資訊、視訊資訊還是指令碼資訊。我們通過解析TAG就可以分別提取音視訊的壓縮編碼資訊。
FLV這一種格式在video中並不是原生支援的,我們要播放這一種格式的封包格式需要通過MSE對影視片的壓縮編碼資訊進行解碼,因此需要瀏覽器能夠支援MSE這一API。由於HTTP-FLV的傳輸是通過長連線傳輸檔案流的形式,需要瀏覽器支援Stream IO或者fetch,對於瀏覽器的相容性要求會比較高。
FLV在延遲問題上相比切片播放的HLS會好很多,目前看來FLV的延遲主要是受編碼時設定的GOP長度的影響。
這邊簡單介紹一下GOP:在H.264視訊編碼的過程中,會生成三種幀型別:I幀、B幀和P幀。I幀就是我們通常說的關鍵幀,關鍵幀內包括了完整的幀內資訊,可以直接作為其他幀的參考幀。B幀和P幀為了將資料壓縮得更小,需要由其他幀推斷出幀內的資訊。因此兩個I幀之間的時長也可以被視作最小的視訊播放片段時長。從視訊推送的穩定性考慮,我們也要求主播將關鍵幀間隔設定為定長,通常是1-3秒,因此除去其他因素,我們的直播在播放時也會產生1-3秒的延時。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150405491-919092371.png)
10、視訊直播傳輸協議3:RTMP
RTMP協議實際可以與HTTP-FLV協議歸做同一種類型。
他們的封包格式都是FlV,但HTTP-FLV使用的傳輸協議是HTTP,RTMP拉流使用RTMP作為傳輸協議。
RTMP是Adobe公司基於TCP做的一套實時訊息傳輸協議,經常與Flash播放器匹配使用。
RTMP協議的優缺點非常明顯。
RTMP協議的優點主要是:
- 1)首先和HTTP-FLV一樣,延遲比較低;
- 2)其次它的穩定性非常好,適合長時間播放(由於播放時借用了Flash player強大的功能,即使開多路流同時播放也能保證頁面不出現卡頓,很適合監控等場景)。
但是Flash player目前在web端屬於牆倒眾人推的境地,主流瀏覽器漸漸都表示不再支援Flash player外掛,在MAC上使用能夠立刻將電腦變成燒烤用的鐵板,資源消耗很大。在移動端H5基本屬於完全不支援的狀態,相容性是它最大的問題。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150413374-312055870.png)
11、視訊直播傳輸協議4:MPEG-DASH
MPEG-DASH這一協議屬於新興勢力,和HLS一樣,都是通過切片視訊的方式進行播放。
他產生的背景是早期各大公司都自己搞自己的一套協議。比如蘋果搞了HLS、微軟搞了 MSS、Adobe還搞了HDS,這樣使用者需要在多套協議封裝的相容問題上痛苦不堪。
於是大佬們湊到一起,將之前各個公司的流媒體協議方案做了一個整合,搞了一個新的協議。
由於同為切片視訊播放的協議,DASH優劣勢和HLS類似,可以支援切片之間多視訊位元速率、多音軌的切換,比較適合點播業務,在直播中還是會有延時較長的問題。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150420807-1417967798.png)
12、如何選擇最優的視訊直播傳輸協議
視訊直播協議選擇非常關鍵的兩點,在前文都已經有提到了,即低延時和更優的相容性。
首先從延時角度考慮:不考慮雲端轉碼以及上下行的消耗,HLS和MPEG-DASH通過將切片時長減短,延時在10秒左右;RTMP和FLV理論上延時相當,在2-3秒。因此在延時方面HLS ≈ DASH > RTMP ≈ FLV。
從相容性角度考慮:HLS > FLV > RTMP,DASH由於一些專案歷史原因,並且定位和HLS重複了,暫時沒有對其相容性做一個詳盡的測試,被推出了選擇的考慮範圍。
綜上所述:我們可以通過動態判斷環境的方式,選擇當前環境下可用的最低延遲的協議。大致的策略就是優先使用HTTP-FLV,使用HLS作為兜底,在一些特殊需求場景下通過手動配置的方式切換為RTMP。
對於HLS和HTTP-FLV:我們可以直接使用 hls.js 和 flv.js 做做解碼播放,這兩個庫內部都是通過MSE做的解碼。首先根據視訊封裝格式提取出對應的音視訊chunk資料,在MediaSource中分別對音訊和視訊建立SourceBuffer,將音視訊的編碼資料餵給SourceBuffer後SourceBuffer內部會處理完剩下的解碼和音視訊對齊工作,最後MediaSource將Video標籤中的src替換成MediaSource 物件進行播放。
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150434600-1031272087.png)
在判斷播放環境時我們可以參照flv.js內部的判斷方式,通過呼叫MSE判斷方法和模擬請求的方式判斷MSE和StreamIO是否可用:
// 判斷MediaSource是否被瀏覽器支援,H.264視訊編碼和Acc音訊編碼是否能夠被支援解碼
window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
如果FLV播放不被支援的情況下:需要降級到HLS,這時候需要判斷瀏覽器環境是否在移動端,移動端通常不需要 hls.js 通過MSE解碼的方式進行播放,直接將M3U8的地址交給video的src即可。如果是PC端則判斷MSE是否可用,如果可用就使用hls.js解碼播放。
這些判讀可以在自己的邏輯裡提前判斷後去拉取對應解碼庫的CDN,而不是等待三方庫載入完成後使用三方庫內部的方法判斷,這樣在選擇解碼庫時就可以不把所有的庫都拉下來,提高載入速度。
13、同層播放如何解決
![](http://img2022.cnblogs.com/blog/1834368/202205/1834368-20220531150444549-756843284.jpg)
電商直播需要觀眾操作和互動的部分比起傳統的直播更加多,因此產品設計的時候很多的功能模組會懸浮在直播視訊上方減少佔用的空間。這個時候就會遇到一個移動端播放器的老大難問題——同層播放。
同層播放問題:是指在移動端H5頁面中,一些瀏覽器核心為了提升使用者體驗,將video標籤被劫持替換為native播放器,導致其他元素無法覆蓋於播放器之上。
比如我們想要在直播間播放器上方增加聊天視窗,將聊天視窗通過絕對定位提升z-index置於播放器上方,在PC中測試完全正常。但在移動端的一些瀏覽器中,video被替換成了native播放器,native的元素層級高於我們的普通元素,導致聊天視窗實際顯示的時候在播放器下方。
要解決這個問題,首先要分多個場景。
首先在iOS系統中:正常情況下video標籤會自動被全屏播放,但iOS10以上已經原生提供了video的同層屬性,我們在video標籤上增加playsinline/webkit-playsinline可以解決iOS系統中大部分瀏覽器的同層問題,剩下的低系統版本的瀏覽器以及一些APP內的webview容器(譬如微博),用上面提的屬性並不管用,呼叫三方庫iphone-inline-video可以解決大部分剩餘問題。
在Android端:大部分騰訊系的APP內建的webview容器用的都是X5核心,X5核心會將video替換成原生定製的播放器已便於增強一些功能。X5也提供了一套同層的方案(該方案官方文件連結已無法開啟),給video標籤寫入X5同層屬性也可以在X5核心中實現內聯播放。不過X5的同層屬性在各個X5版本中表現都不太一樣(比如低版本X5中需要使用X5全屏播放模式才能保證MSE播放的視訊同層生效),需要注意區分版本。
在蘑菇街App中,目前整合的X5核心版本比較老,在使用MSE的情況下會導致X5同層引數不生效。但如果整合新版本的X5核心,需要對大量的線上頁面做迴歸測試,成本比較高,因此提供了一套折中的解決方案。通過在頁面URL中增加一個開關引數,容器讀取到引數以後會將X5核心降級為系統原生的瀏覽器核心,這樣可以在解決瀏覽器視訊同層問題的同時也將核心變動的影響範圍控制在單個頁面當中。
14、相關文章
[3] 實現延遲低於500毫秒的1080P實時音視訊直播的實踐分享
[5] 直播系統聊天技術(七):直播間海量聊天訊息的架構設計難點實踐
[6] 從0到1:萬人線上的實時音視訊直播技術實踐分享(視訊+PPT) [附件下載]
[10] 視訊編解碼之編碼基礎
[12] 實時音視訊面視必備:快速掌握11個視訊技術相關的基礎概念
[13] 寫給小白的實時音視訊技術入門提綱
學習交流:
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
- 開源IM框架原始碼:http://github.com/JackJiang2011/MobileIMSDK(備用地址點此)
(本文已同步釋出於:http://www.52im.net/thread-3922-1-1.html)
- IM聊天系統安全手段之傳輸內容端到端加密技術
- 基於Netty,徒手擼IM(一):IM系統設計篇
- 微信團隊分享:微信後臺在海量併發請求下是如何做到不崩潰的
- 視訊直播技術乾貨:一文讀懂主流視訊直播系統的推拉流架構、傳輸協議等
- 萬字長文:手把手教你實現一套高效的IM長連線自適應心跳保活機制
- 實時音視訊入門學習:開源工程WebRTC的技術原理和使用淺析
- 阿里IM技術分享(三):閒魚億級IM訊息系統的架構演進之路
- IM技術分享:萬人群聊訊息投遞方案的思考和實踐
- IM開發技術學習:揭祕微信朋友圈這種資訊推流背後的系統設計
- 訊息推送技術乾貨:美團實時訊息推送服務的技術演進之路
- IM開發乾貨分享:網易雲信IM客戶端的聊天訊息全文檢索技術實踐
- 融雲技術分享:全面揭祕億級IM訊息的可靠投遞機制
- 開源移動端 IM 框架 MobileIMSDK v6.0 釋出!
- 企業微信的IM架構設計揭祕:訊息模型、萬人群、已讀回執、訊息撤回等
- 喜馬拉雅億級使用者量的離線訊息推送系統架構設計實踐
- 阿里技術分享:閒魚IM基於Flutter的移動端跨端改造實踐
- 理解IM訊息“可靠性”和“一致性”問題,以及解決方案探討
- 長連線閘道器技術專題(五):喜馬拉雅自研億級API閘道器技術實踐
- 網頁端IM通訊技術快速入門:短輪詢、長輪詢、SSE、WebSocket
- 長連線閘道器技術專題(四):愛奇藝WebSocket實時推送閘道器技術實踐