本文節選自 Live CheatSheet | 直播技術理論基礎與實踐概論, 不少內容非做者原創,而是對 Live Links 中列舉出的多篇文章的盤點總結,更多直播相關內容能夠前往 xCompass 交互式檢索或 MushiChat 查看代碼。
音視頻直播的基本流程都是採集 → 編碼推流 → 網絡分發 → 解碼 → 播放
這五大環節,其中又會涉及平臺硬件、編解碼、網絡傳輸、服務併發、數字信號處理、在線學習等多方面技術。從交互模式上,又能夠泛分爲單對單模式與會議模式兩大類;從實時性要求上,直播又能夠分爲僞實時、準實時與真實時三個等級:前端
視頻封裝格式就是咱們一般所說的 .mp4,.flv,.ogv,.webm 等,它其實就是一個盒子,用來將實際的視頻流以必定的順序放入,確保播放的有序和完整性。視頻壓縮格式(視頻編碼)就是指可以對數字視頻進行壓縮或者解壓縮(視頻解碼)的程序或者設備。一般這種壓縮屬於有損數據壓縮。git
視頻壓縮格式和視頻格式具體的區別就是,它是將原始的視頻碼流變爲可用的數字編碼。首先,由原始數碼設備提供相關的數字信號流,而後經由視頻壓縮算法,大幅度的減小流的大小,而後交給視頻盒子,打上相應的 dts,pts 字段,最終生成可用的視頻文件。視頻編碼也能夠指經過過特定的壓縮技術,將某個視頻格式轉換成另外一種視頻格式。github
常見的視頻封裝格式(簡稱:視頻格式)包括了 AVI,MPEG,VOB 等,即至關於一種儲存視頻信息的容器,由相應的公司開發出來的。web
AVI 格式(後綴爲.AVI):它的英文全稱爲 Audio Video Interleaved,即音頻視頻交錯格式。它於 1992 年被 Microsoft 公司推出。算法
這種視頻格式的優勢是圖像質量好。因爲無損 AVI 能夠保存 alpha 通道,常常被咱們使用。缺點太多,體積過於龐大,並且更加糟糕的是壓縮標準不統一,最廣泛的現象就是高版本 Windows 媒體播放器播放不了採用早期編碼編輯的 AVI 格式視頻,而低版本 Windows 媒體播放器又播放不了採用最新編碼編輯的 AVI 格式視頻,因此咱們在進行一些 AVI 格式的視頻播放時常會出現因爲視頻編碼問題而形成的視頻不能播放或即便可以播放,但存在不能調節播放進度和播放時只有聲音沒有圖像等一些莫名其妙的問題。vim
DV-AVI 格式(後綴爲.AVI):DV 的英文全稱是 Digital Video Format,是由索尼、松下、JVC 等多家廠商聯合提出的一種家用數字視頻格式。瀏覽器
數字攝像機就是使用這種格式記錄視頻數據的。它能夠經過電腦的 IEEE 1394 端口傳輸視頻數據到電腦,也能夠將電腦中編輯好的的視頻數據回錄到數碼攝像機中。這種視頻格式的文件擴展名也是 avi。電視臺採用錄像帶記錄模擬信號,經過 EDIUS 由 IEEE 1394 端口採集卡從錄像帶中採集出來的視頻就是這種格式。安全
QuickTime File Format 格式(後綴爲.MOV):美國 Apple 公司開發的一種視頻格式,默認的播放器是蘋果的 QuickTime。服務器
具備較高的壓縮比率和較完美的視頻清晰度等特色,並能夠保存 alpha 通道。你們可能注意到了,每次安裝 EDIUS,咱們都要安裝蘋果公司推出的 QuickTime。安裝其目的就是爲了支持 JPG 格式圖像和 MOV 視頻格式導入。微信
MPEG 格式(文件後綴能夠是 .MPG .MPEG .MPE .DAT .VOB .ASF .3GP .MP4 等):它的英文全稱爲 Moving Picture Experts Group,即運動圖像專家組格式,該專家組建於 1988 年,專門負責爲 CD 創建視頻和音頻標準,而成員都是爲視頻、音頻及系統領域的技術專家。
MPEG 文件格式是運動圖像壓縮算法的國際標準。MPEG 格式目前有三個壓縮標準,分別是 MPEG-一、MPEG-二、和 MPEG-4。MPEG-一、MPEG-2 目前已經使用較少,着重介紹 MPEG-4,其制定於 1998 年,MPEG-4 是爲了播放流式媒體的高質量視頻而專門設計的,以求使用最少的數據得到最佳的圖像質量。目前 MPEG-4 最有吸引力的地方在於它可以保存接近於 DVD 畫質的小體積視頻文件。你可能必定注意到了,怎麼沒有 MPEG-3 編碼,由於這個項目本來目標是爲高分辨率電視(HDTV)設計,隨後發現 MPEG-2 已足夠 HDTV 應用,故 MPEG-3 的研發便停止。
WMV 格式(後綴爲.WMV .ASF):它的英文全稱爲 Windows Media Video,也是微軟推出的一種採用獨立編碼方式而且能夠直接在網上實時觀看視頻節目的文件壓縮格式。
WMV 格式的主要優勢包括:本地或網絡回放,豐富的流間關係以及擴展性等。WMV 格式須要在網站上播放,須要安裝 Windows Media Player(簡稱 WMP),很不方便,如今已經幾乎沒有網站採用了。
Real Video 格式(後綴爲.RM .RMVB):Real Networks 公司所制定的音頻視頻壓縮規範稱爲 Real Media。
用戶可使用 RealPlayer 根據不一樣的網絡傳輸速率制定出不一樣的壓縮比率,從而實如今低速率的網絡上進行影像數據實時傳送和播放。RMVB 格式:這是一種由 RM 視頻格式升級延伸出的新視頻格式,固然性能上有很大的提高。RMVB 視頻也是有着較明顯的優點,一部大小爲 700MB 左右的 DVD 影片,若是將其轉錄成一樣品質的 RMVB 格式,其個頭最多也就 400MB 左右。你們可能注意到了,之前在網絡上下載電影和視頻的時候,常常接觸到 RMVB 格式,可是隨着時代的發展這種格式被愈來愈多的更優秀的格式替代,著名的人人影視字幕組在 2013 年已經宣佈再也不壓制 RMVB 格式視頻。
Flash Video 格式(後綴爲.FLV):由 Adobe Flash 延伸出來的的一種流行網絡視頻封裝格式。隨着視頻網站的豐富,這個格式已經很是普及。
Matroska 格式(後綴爲.MKV):是一種新的多媒體封裝格式,這個封裝格式可把多種不一樣編碼的視頻及 16 條或以上不一樣格式的音頻和語言不一樣的字幕封裝到一個 Matroska Media 檔內。它也是其中一種開放源代碼的多媒體封裝格式。Matroska 同時還能夠提供很是好的交互功能,並且比 MPEG 的方便、強大。
視頻實際上就是一幀一幀的圖片,拼接起來進行播放;標準的圖像格式使用 RGB 三字節描述像素顏色值,會佔用較大的存儲空間與帶寬。視頻編解碼器會根據先後圖像的變化作運動檢測,經過各類壓縮把變化的結果發送到對方。
實時視頻編碼器須要考慮兩個因素:編碼計算量和碼率帶寬,實時視頻會運行在移動端上,須要保證明時性就須要編碼足夠快,碼率儘可能小。基於這個緣由現階段通常認爲 H.264 是最佳的實時視頻編碼器,並且各個移動平臺也支持它的硬編碼技術;譬如 1080P 進行過 H.264 編碼後帶寬也就在 200KB/S ~ 300KB/S 左右。
總的來講,經常使用的編碼方式分爲三種:
I,B,P 其實是從運動補償中引出來的,這裏爲了後面的方便先介紹一下。
Intra-coded picture
。也能夠叫作獨立幀。該幀是編碼器隨機挑選的參考圖像,換句話說,一個 I 幀自己就是一個靜態圖像。它是做爲 B,P 幀的參考點。對於它的壓縮,只能使用熵
和 變化編碼
這兩種方式進行幀內壓縮。因此,它的運動學補償基本沒有。Predicted picture
--前向預測幀。即,他會根據前面一張圖像,來進行圖片間的動態壓縮,它的壓縮率和 I 幀比起來要高一些。Bi-predictive picture
-- 雙向預測。它比 P 幀來講,還多了後一張圖像的預測,因此它的壓縮率更高。
考慮到不一樣幀傳輸的無序性,咱們還須要引入 PTS 與 DTS 來進行控制,使用 DTS 來解碼,PTS 來進行播放。
H.26X 系列由 ITU 國際電傳視訊聯盟主導包括, H.26一、H.26二、H.26三、H.26四、H.265 等:
H.264 是由 ITU 和 MPEG 兩個組織共同提出的標準,整個編碼器包括幀內預測編碼、幀間預測編碼、運動估計、熵編碼等過程,支持分層編碼技術(SVC)。單幀 720P 分辨率通常 PC 上的平均編碼延遲 10 毫秒左右,碼率範圍 1200 ~ 2400kpbs,同等視頻質量壓縮率是 MPEG4 的 2 倍,H.264 也提供 VBR、ABR、CBR、CQ 等多種編碼模式,各個移動平臺兼容性好。
H.264 爲了防止丟包和減少帶寬還引入一種雙向預測編碼的 B 幀,B 幀之前面的 I 或 P 幀和後面的 P 幀爲參考幀。H.264 爲了防止中間 P 幀丟失視頻圖像會一直錯誤它引入分組序列(GOP)編碼,也就是隔一段時間發一個全量 I 幀,上一個 I 幀與下一個 I 幀之間爲一個分組 GOP。
在實時視頻當中最好不要加入 B 幀,由於 B 幀是雙向預測,須要根據後面的視頻幀來編碼,這會增大編解碼延遲。
MPEG 系列由 ISO 國際標準組織機構下屬的 MPEG 運動圖象專家組開發視頻編碼方面主要有:
實時音視頻除了視頻編碼器之外還須要音頻編碼器,音頻編碼器只須要考慮編碼延遲和丟包容忍度,因此通常的 MP三、AAC、OGG 都不太適合做爲實時音頻編碼器。從如今市場上來使用來看,Skype 研發的 Opus 已經成爲實時音頻主流的編碼器。Opus 優勢衆多,編碼計算量小、編碼延遲 20ms、窄帶編碼-silk、寬帶編碼器 CELT、自帶網絡自適應編碼等。
同視頻編碼相似,將原始的音頻流按照必定的標準進行編碼,上傳,解碼,同時在播放器裏播放,固然音頻也有許多編碼標準,例如 PCM 編碼,WMA 編碼,AAC 編碼等等。
經常使用的直播協議包括了 HLS, RTMP 與 HTTP-FLV 這三種,其對好比下:
協議 | 優點 | 缺陷 | 延遲性 |
---|---|---|---|
HLS | 支持性廣 | 延時巨高 | 10s 以上 |
RTMP | 延時性好,靈活 | 量大的話,負載較高 | 1s 以上 |
HTTP-FLV | 延時性好,遊戲直播經常使用 | 只能在手機 APP 播放 | 2s 以上 |
HLS, HTTP Live Streaming 是 Apple 提出的直播流協議,其將整個流分紅一個個小的塊,並基於 HTTP 的文件來下載;HLS 由兩部分構成,一個是 .m3u8 文件,一個是 .ts 視頻文件;每個 .m3u8 文件,分別對應若干個 ts 文件,這些 ts 文件纔是真正存放視頻的數據,m3u8 文件只是存放了一些 ts 文件的配置信息和相關路徑,當視頻播放時,.m3u8 是動態改變的,video 標籤會解析這個文件,並找到對應的 ts 文件來播放,因此通常爲了加快速度,.m3u8 放在 web 服務器上,ts 文件放在 CDN 上。 HLS 協議視頻支持 H.264 格式的編碼,支持的音頻編碼方式是 AAC 編碼。
.m3u8 文件,其實就是以 UTF-8 編碼的 m3u 文件,這個文件自己不能播放,只是存放了播放信息的文本文件:
#EXTM3U m3u文件頭 #EXT-X-MEDIA-SEQUENCE 第一個TS分片的序列號 #EXT-X-TARGETDURATION 每一個分片TS的最大的時長 #EXT-X-ALLOW-CACHE 是否容許cache #EXT-X-ENDLIST m3u8文件結束符 #EXTINF 指定每一個媒體段(ts)的持續時間(秒),僅對其後面的URI有效 mystream-12.ts
HLS 協議的使用也很是便捷,將 m3u8 直接寫入到 src 中而後交與瀏覽器解析,也可使用 fetch 來手動解析而且獲取相關文件:
<video controls autoplay> <source src="http://devimages.apple.com/iphone/samples/bipbop/masterplaylist.m3u8" type="application/vnd.apple.mpegurl" /> <p class="warning">Your browser does not support HTML5 video.</p> </video>
HLS 詳細版的內容比上面的簡版多了一個 playlist,也能夠叫作 master。在 master 中,會根據網絡段實現設置好不一樣的 m3u8 文件,好比,3G/4G/wifi 網速等。好比,一個 master 文件中爲:
#EXTM3U #EXT-X-VERSION:6 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2855600,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=960x540 live/medium.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5605600,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720 live/high.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1755600,CODECS="avc1.42001f,mp4a.40.2",RESOLUTION=640x360 live/low.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=545600,CODECS="avc1.42001e,mp4a.40.2",RESOLUTION=416x234 live/cellular.m3u8
以 high.m3u8 文件爲例,其內容會包含:
#EXTM3U #EXT-X-VERSION:6 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:26 #EXTINF:9.901, http://media.example.com/wifi/segment26.ts #EXTINF:9.901, http://media.example.com/wifi/segment27.ts #EXTINF:9.501, http://media.example.com/wifi/segment28.ts
該二級 m3u8 文件也能夠稱爲 media 文件,其有三種類型:
顯而易見,HLS 的延時包含了 TCP 握手、m3u8 文件下載與解析、ts 文件下載與解析等多個步驟,能夠縮短列表的長度和單個 ts 文件的大小來下降延遲,極致來講能夠縮減列表長度爲 1,而且 ts 的時長爲 1s,可是這樣會形成請求次數增長,增大服務器壓力,當網速慢時回形成更多的緩衝,因此蘋果官方推薦的 ts 時長時 10s,因此這樣就會大改有 30s 的延遲。
RTMP,Real-Time Messaging Protocol 是由 Adobe 推出的音視頻流傳遞協議;它經過一種自定義的協議,來完成對指定直播流的播放和相關的操做。在 Web 上能夠經過 MSE(MediaSource Extensions)來接入 RTMP,基本思路是根據 WebSocket 直接創建長鏈接進行數據的交流和監聽。RTMP 協議根據不一樣的套層,也能夠分爲:
RTMP 內部是藉由 TCP 長鏈接協議傳輸相關數據,因此,它的延時性很是低。而且,該協議靈活性很是好(因此,也很複雜),它能夠根據 message stream ID 傳輸數據,也能夠根據 chunk stream ID 傳遞數據。二者均可以起到流的劃分做用。流的內容也主要分爲:視頻,音頻,相關協議包等。
RTMP 是直接將流的傳輸架在 RTMP 協議之上,而 HTTP-FLV 是在 RTMP 和客戶端之間套了一層轉碼的過程,即:
每一個 FLV 文件是經過 HTTP 的方式獲取的,因此,它經過抓包得出的協議頭須要使用 chunked 編碼:
Content-Type:video/x-flv Expires:Fri, 10 Feb 2017 05:24:03 GMT Pragma:no-cache Transfer-Encoding:chunked
單對單模式主要是怎麼經過路由路徑優化手段達到兩點之間最優,這方面 SKYPE 首先提出基於 P2P 的 Real-time Network 模型。而 單對多模式是一個分發樹模型,各個客戶端節點須要就近接入離本身最近的服務器,而後在服務器與服務器構建一個實時通訊網絡。
所謂推流,就是將咱們已經編碼好的音視頻數據發往視頻流服務器中。實時音視頻系統都是一個客戶端到其餘一個或者多個客戶端的通訊行爲,這就意味着須要將客戶端編碼後的音視頻數據傳輸到其餘實時音視頻系統都是一個客戶端到其餘一個或者多個客戶端的通訊行爲,這就意味着須要將客戶端編碼後的音視頻數據傳輸到其餘客戶端上,通常作法是先將數據實時上傳到服務器上,服務器再進行轉發到其餘客戶端,客戶端這個上傳音視頻數據行爲稱爲推流。
咱們能夠經過 Nginx 的 RTMP 擴展方便地搭建推流服務器:
rtmp { server { listen 1935; #監聽的端口 chunk_size 4000; application hls { #rtmp推流請求路徑 live on; hls on; hls_path /usr/local/var/www/hls; hls_fragment 5s; } } }
推流會受到客戶端網絡的影響,例如:wifi 信號衰減、4G 弱網、擁擠的寬帶網絡等。爲了應對這個問題,實時音視頻系統會設計一個基於擁塞控制和 QOS 策略的推流模塊。
WebRTC 是一個開源項目,旨在使得瀏覽器能爲實時通訊(RTC)提供簡單的 JavaScript 接口。說的簡單明瞭一點就是讓瀏覽器提供 JS 的即時通訊接口。這個接口所創立的信道並非像 WebSocket 同樣,打通一個瀏覽器與 WebSocket 服務器之間的通訊,而是經過一系列的信令,創建一個瀏覽器與瀏覽器之間(peer-to-peer)的信道,這個信道能夠發送任何數據,而不須要通過服務器。而且 WebRTC 經過實現 MediaStream,經過瀏覽器調用設備的攝像頭、話筒,使得瀏覽器之間能夠傳遞音頻和視頻。WebRTC 有三個重要的部分:MediaStream、RTCPeerConnection、RTCDataChannel:
在大規模實時多媒體傳輸網絡中,TCP 和 RTMP 都不佔優點。TCP 是個擁塞公平傳輸的協議,它的擁塞控制都是爲了保證網絡的公平性而不是快速到達,咱們知道,TCP 層只有順序到對應的報文才會提示應用層讀數據,若是中間有報文亂序或者丟包都會在 TCP 作等待,因此 TCP 的發送窗口緩衝和重發機制在網絡不穩定的狀況下會形成延遲不可控,並且傳輸鏈路層級越多延遲會越大。
在實時傳輸中使用 UDP 更加合理,UDP 避免了 TCP 繁重的三次握手、四次揮手和各類繁雜的傳輸特性,只須要在 UDP 上作一層簡單的鏈路 QoS 監測和報文重發機制,實時性會比 TCP 好,這一點從 RTP 和 DDCP 協議能夠證實這一點,咱們正式參考了這兩個協議來設計本身的通訊協議。
UDP 不可避免地存在抖動、亂序、丟包問題,視頻必須按照嚴格是時間戳來播放,不然的就會出現視頻動做加快或者放慢的現象,若是咱們按照接收到視頻數據就當即播放,那麼這種加快和放慢的現象會很是頻繁和明顯。也就是說網絡抖動會嚴重影響視頻播放的質量,通常爲了解決這個問題會設計一個視頻播放緩衝區,經過緩衝接收到的視頻幀,再按視頻幀內部的時間戳來播放既可。
UDP 除了小範圍的抖動之外,仍是出現大範圍的亂序現象,就是後發的報文先於先發的報文到達接收方。亂序會形成視頻幀順序錯亂,通常解決的這個問題會在視頻播放緩衝區裏作一個前後排序功能讓先發送的報文先進行播放。
UDP 在傳輸過程還會出現丟包,丟失的緣由有多種,例如:網絡出口不足、中間網絡路由擁堵、socket 收發緩衝區過小、硬件問題、傳輸損耗問題等等。在基於 UDP 視頻傳輸過程當中,丟包是很是頻繁發生的事情,丟包會形成視頻解碼器丟幀,從而引發視頻播放卡頓。這也是大部分視頻直播用 TCP 和 RTMP 的緣由,由於 TCP 底層有本身的重傳機制,能夠保證在網絡正常的狀況下視頻在傳輸過程不丟。基於 UDP 丟包補償方式通常有如下幾種:
要評估一個網絡通訊質量的好壞和延遲一個重要的因素就是 Round-Trip Time(網絡往返延遲),也就是 RTT。評估兩端之間的 RTT 方法很簡單,大體以下:
由於客戶端有可能在弱網環境下進行推流,音視頻數據若是某一時刻發多了,就會引發網絡擁塞或者延遲,若是發少了,可能視頻的清晰很差。在實時音視頻傳輸過程會設計一個自動適應本地網絡變化的擁塞控制算法,像 QUIC 中的 BBR、webRTC 中 GCC 和通用的 RUDP。思路是經過 UDP 協議反饋的丟包和網絡延遲(RTT)來計算當前網絡的變化和最大瞬時吞吐量,根據這幾個值調整上層的視頻編碼器的碼率、視頻分辨率等,從而達到適應當前網絡狀態的目的。
客戶端推流除了須要考慮網絡上傳能力之外,還須要考慮客戶端的計算能力。若是在 5 年前的安卓機上去編碼一個分辨率爲 640P 的高清視頻流,那這個過程必然會產生延遲甚至沒法工做。爲此須要針對各個終端的計算能力設計一個 QoS 策略,不一樣計算能力的終端採用不一樣的視頻編碼器、分辨率、音頻處理算法等,這個 QoS 策略會配合擁塞控制作一個狀態不可逆的查找過程,直到找到最合適的 QoS 策略位置
在實時音視頻系統中,回聲消除是一個難點,儘管 webRTC 提供了開源的回聲消除模塊,但在移動端和一些特殊的場景表現不佳。專業的實時音視頻系統會進行回聲消除的優化。回聲消除的原理描述很簡單,就是將揚聲器播放的聲音波形和麥克風錄製的波形進行抵消,達到消除回聲的做用。由於回聲的回錄時間不肯定,因此很難肯定什麼時間點進行對應聲音數據的抵消。在專業的回聲消除模塊裏面一般會設計一個逼近函數,經過不斷對輸出和輸入聲音波形進行在線學習逼近,肯定回聲消除的時間差值點。
本部分的代碼實驗參考 MushiChat。
MSE 全稱就是 Media Source Extensions。它是一套處理視頻流技術的簡稱,裏面包括了一系列 API:Media Source,Source Buffer 等。在沒有 MSE 出現以前,前端對 video 的操做,僅僅侷限在對視頻文件的操做,而並不能對視頻流作任何相關的操做。如今 MSE 提供了一系列的接口,使開發者能夠直接提供 media stream。
const vidElement = document.querySelector('video'); if (window.MediaSource) { const mediaSource = new MediaSource(); vidElement.src = URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', sourceOpen); } else { console.log('The Media Source Extensions API is not supported.'); } function sourceOpen(e) { URL.revokeObjectURL(vidElement.src); const mime = 'video/webm; codecs="opus, vp9"'; const mediaSource = e.target; const sourceBuffer = mediaSource.addSourceBuffer(mime); const videoUrl = 'droid.webm'; fetch(videoUrl) .then(function(response) { return response.arrayBuffer(); }) .then(function(arrayBuffer) { sourceBuffer.addEventListener('updateend', function(e) { if (!sourceBuffer.updating && mediaSource.readyState === 'open') { mediaSource.endOfStream(); } }); sourceBuffer.appendBuffer(arrayBuffer); }); }
其中 MediaSource 只是一系列視頻流的管理工具,它能夠將音視頻流完整的暴露給 Web 開發者來進行相關的操做和處理。因此,它自己不會形成過分的複雜性。