網絡協議之流媒體協議:如何在直播裏看到美女帥哥?

很多人都喜歡看直播,那一個直播系統裏面都有哪些組成部分,都使用了什麼協議呢?

無論是直播還是點播,其實都是對於視頻數據的傳輸。一提到視頻,大家都愛看,但是一提到視頻技術,大家都頭疼,因爲名詞實在是太多了。

三個名詞系列

我這裏列三個名詞系列,你先大致有個印象。

  • 名詞系列一:AVI、MPEG、RMVB、MP4、MOV、FLV、WebM、WMV、ASF、MKV。例如RMVB和MP4,看着是不是很熟悉?
  • 名詞系列二:H.261、 H.262、H.263、H.264、H.265。這個是不是就沒怎麼聽過了?彆着急,你先記住,要重點關注H.264。
  • 名詞系列三:MPEG-1、MPEG-2、MPEG-4、MPEG-7。MPEG好像聽說過,但是後面的數字是怎麼回事?是不是又熟悉又陌生?

這裏,我想問你個問題,視頻是什麼?我說,其實就是快速播放一連串連續的圖片。

每一張圖片,我們稱爲一。只要每秒鐘幀的數據足夠多,也即播放得足夠快。比如每秒30幀,以人的眼睛的敏感程度,是看不出這是一張張獨立的圖片的,這就是我們常說的幀率FPS)。

每一張圖片,都是由像素組成的,假設爲1024*768(這個像素數不算多)。每個像素由RGB組成,每個8位,共24位。

我們來算一下,每秒鐘的視頻有多大?

30幀×1024×768×24=566,231,040Bits=70,778,880Bytes

如果一分鐘呢?4,246,732,800Bytes,已經是4個G了。

是不是不算不知道,一算嚇一跳?這個數據量實在是太大,根本沒辦法存儲和傳輸。如果這樣存儲,你的硬盤很快就滿了;如果這樣傳輸,那多少帶寬也不夠用啊!

怎麼辦呢?人們想到了編碼,就是看如何用盡量少的Bit數保存視頻,使播放的時候畫面看起來仍然很精美。編碼一個壓縮的過程。

視頻和圖片的壓縮過程有什麼特點?

之所以能夠對視頻流中的圖片進行壓縮,因爲視頻和圖片有這樣一些特點。

  • 空間冗餘:圖像的相鄰像素之間有較強的相關性,一張圖片相鄰像素往往是漸變的,不是突變的,沒必要每個像素都完整地保存,可以隔幾個保存一個,中間的用算法計算出來。
  • 時間冗餘:視頻序列的相鄰圖像之間內容相似。一個視頻中連續出現的圖片也不是突變的,可以根據已有的圖片進行預測和推斷。
  • 視覺冗餘:人的視覺系統對某些細節不敏感,因此不會每一個細節都注意到,可以允許丟失一些數據。
  • 編碼冗餘:不同像素值出現的概率不同,概率高的用的字節少,概率低的用的字節多,類似霍夫曼編碼(Huffman Coding)的思路。

總之,用於編碼的算法非常複雜,而且多種多樣,但是編碼過程其實都是類似的。

點擊這裏查看更多內容

視頻編碼的兩大流派

能不能形成一定的標準呢?要不然開發視頻播放的人得累死了。當然能,我這裏就給你介紹,視頻編碼的兩大流派。

  • 流派一:ITU(International Telecommunications Union)的VECG(Video Coding Experts Group),這個稱爲國際電聯下的VCEG。既然是電信,可想而知,他們最初做視頻編碼,主要側重傳輸。名詞系列二,就是這個組織制定的標準。
  • 流派二:ISO(International Standards Organization)的MPEG(Moving Picture Experts Group),這個是ISO旗下的MPEG,本來是做視頻存儲的。例如,編碼後保存在VCD和DVD中,當然後來也慢慢側重視頻傳輸了。名詞系列三,就是這個組織制定的標準。

後來,ITU-T(國際電信聯盟電信標準化部門,ITU Telecommunication Standardization Sector)與MPEG聯合制定了H.264/MPEG-4 AVC,這纔是我們這一節要重點關注的。

經過編碼之後,生動活潑的一幀一幀的圖像,就變成了一串串讓人看不懂的二進制,這個二進制可以放在一個文件裏面,按照一定的格式保存起來,這就是名詞系列一。

其實這些就是視頻保存成文件的格式。例如,前幾個字節是什麼意義,後幾個字節是什麼意義,然後是數據,數據中保存的就是編碼好的結果。

如何在直播裏看到帥哥美女?

當然,這個二進制也可以通過某種網絡協議進行封裝,放在互聯網上傳輸,這個時候就可以進行網絡直播了。

網絡協議將編碼好的視頻流,從主播端推送到服務器,在服務器上有個運行了同樣協議的服務端來接收這些網絡包,從而得到裏面的視頻流,這個過程稱爲接流

服務端接到視頻流之後,可以對視頻流進行一定的處理,例如轉碼,也即從一個編碼格式,轉成另一種格式。因爲觀衆使用的客戶端千差萬別,要保證他們都能看到直播。

流處理完畢之後,就可以等待觀衆的客戶端來請求這些視頻流。觀衆的客戶端請求的過程稱爲拉流

如果有非常多的觀衆,同時看一個視頻直播,那都從一個服務器上拉流,壓力太大了,因而需要一個視頻的分發網絡,將視頻預先加載到就近的邊緣節點,這樣大部分觀衆看的視頻,是從邊緣節點拉取的,就能降低服務器的壓力。

當觀衆的客戶端將視頻流拉下來之後,就需要進行解碼,也即通過上述過程的逆過程,將一串串看不懂的二進制,再轉變成一幀幀生動的圖片,在客戶端播放出來,這樣你就能看到美女帥哥啦。

點擊這裏查看更多內容

整個直播過程,可以用這個的圖來描述。

接下來,我們依次來看一下每個過程。

編碼:如何將豐富多彩的圖片變成二進制流?

雖然我們說視頻是一張張圖片的序列,但是如果每張圖片都完整,就太大了,因而會將視頻序列分成三種幀。

  • I幀,也稱關鍵幀。裏面是完整的圖片,只需要本幀數據,就可以完成解碼。
  • P幀,前向預測編碼幀。P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面,疊加上和本幀定義的差別,生成最終畫面。
  • B幀,雙向預測內插編碼幀。B幀記錄的是本幀與前後幀的差別。要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之後的畫面,通過前後畫面的數據與本幀數據的疊加,取得最終的畫面。

可以看出,I幀最完整,B幀壓縮率最高,而壓縮後幀的序列,應該是在IBBP的間隔出現的。這就是通過時序進行編碼

在一幀中,分成多個片,每個片中分成多個宏塊,每個宏塊分成多個子塊,這樣將一張大的圖分解成一個個小塊,可以方便進行空間上的編碼

儘管時空非常立體的組成了一個序列,但是總歸還是要壓縮成一個二進制流。這個流是有結構的,是一個個的網絡提取層單元NALUNetwork Abstraction Layer Unit)。變成這種格式就是爲了傳輸,因爲網絡上的傳輸,默認的是一個個的包,因而這裏也就分成了一個個的單元。

每一個NALU首先是一個起始標識符,用於標識NALU之間的間隔;然後是NALU的頭,裏面主要配置了NALU的類型;最終Payload裏面是NALU承載的數據。

在NALU頭裏面,主要的內容是類型NAL Type

  • 0x07表示SPS,是序列參數集, 包括一個圖像序列的所有信息,如圖像尺寸、視頻格式等。
  • 0x08表示PPS,是圖像參數集,包括一個圖像的所有分片的所有相關信息,包括圖像類型、序列號等。

在傳輸視頻流之前,必須要傳輸這兩類參數,不然無法解碼。爲了保證容錯性,每一個I幀前面,都會傳一遍這兩個參數集合。

如果NALU Header裏面的表示類型是SPS或者PPS,則Payload中就是真正的參數集的內容。

如果類型是幀,則Payload中才是正的視頻數據,當然也是一幀一幀存放的,前面說了,一幀的內容還是挺多的,因而每一個NALU裏面保存的是一片。對於每一片,到底是I幀,還是P幀,還是B幀,在片結構裏面也有個Header,這裏面有個類型,然後是片的內容。

這樣,整個格式就出來了,一個視頻,可以拆分成一系列的幀,每一幀拆分成一系列的片,每一片都放在一個NALU裏面,NALU之間都是通過特殊的起始標識符分隔,在每一個I幀的第一片前面,要插入單獨保存SPS和PPS的NALU,最終形成一個長長的NALU序列。

點擊這裏查看更多內容

推流:如何把數據流打包傳輸到對端?

那這個格式是不是就能夠直接在網上傳輸到對端,開始直播了呢?其實還不是,還需要將這個二進制的流打包成網絡包進行發送,這裏我們使用RTMP協議。這就進入了第二個過程,推流

RTMP是基於TCP的,因而肯定需要雙方建立一個TCP的連接。在有TCP的連接的基礎上,還需要建立一個RTMP的連接,也即在程序裏面,你需要調用RTMP類庫的Connect函數,顯示創建一個連接。

RTMP爲什麼需要建立一個單獨的連接呢?

因爲它們需要商量一些事情,保證以後的傳輸能正常進行。主要就是兩個事情,一個是版本號,如果客戶端、服務器的版本號不一致,則不能工作。另一個就是時間戳,視頻播放中,時間是很重要的,後面的數據流互通的時候,經常要帶上時間戳的差值,因而一開始雙方就要知道對方的時間戳。

未來溝通這些事情,需要發送六條消息:客戶端發送C0、C1、 C2,服務器發送S0、 S1、 S2。

首先,客戶端發送C0表示自己的版本號,不必等對方的回覆,然後發送C1表示自己的時間戳。

服務器只有在收到C0的時候,才能返回S0,表明自己的版本號,如果版本不匹配,可以斷開連接。

服務器發送完S0後,也不用等什麼,就直接發送自己的時間戳S1。客戶端收到S1的時候,發一個知道了對方時間戳的ACK C2。同理服務器收到C1的時候,發一個知道了對方時間戳的ACK S2。

於是,握手完成。

握手之後,雙方需要互相傳遞一些控制信息,例如Chunk塊的大小、窗口大小等。

真正傳輸數據的時候,還是需要創建一個流Stream,然後通過這個Stream來推流publish。

推流的過程,就是將NALU放在Message裏面發送,這個也稱爲RTMP Packet包。Message的格式就像這樣。

發送的時候,去掉NALU的起始標識符。因爲這部分對於RTMP協議來講沒有用。接下來,將SPS和PPS參數集封裝成一個RTMP包發送,然後發送一個個片的NALU。

RTMP在收發數據的時候並不是以Message爲單位的,而是把Message拆分成Chunk發送,而且必須在一個Chunk發送完成之後,才能開始發送下一個Chunk。每個Chunk中都帶有Message ID,表示屬於哪個Message,接收端也會按照這個ID將Chunk組裝成Message。

前面連接的時候,設置的Chunk塊大小就是指這個Chunk。將大的消息變爲小的塊再發送,可以在低帶寬的情況下,減少網絡擁塞。

這有一個分塊的例子,你可以看一下。點擊這裏查看更多內容

假設一個視頻的消息長度爲307,但是Chunk大小約定爲128,於是會拆分爲三個Chunk。

第一個Chunk的Type=0,表示Chunk頭是完整的;頭裏面Timestamp爲1000,總長度Length 爲307,類型爲9,是個視頻,Stream ID爲12346,正文部分承擔128個字節的Data。

第二個Chunk也要發送128個字節,Chunk頭由於和第一個Chunk一樣,因此採用Chunk Type=3,表示頭一樣就不再發送了。

第三個Chunk要發送的Data的長度爲307-128-128=51個字節,還是採用Type=3。

就這樣數據就源源不斷到達流媒體服務器,整個過程就像這樣。

這個時候,大量觀看直播的觀衆就可以通過RTMP協議從流媒體服務器上拉取,但是這麼多的用戶量,都去同一個地方拉取,服務器壓力會很大,而且用戶分佈在全國甚至全球,如果都去統一的一個地方下載,也會時延比較長,需要有分發網絡。

分發網絡分爲中心邊緣兩層。邊緣層服務器部署在全國各地及橫跨各大運營商裏,和用戶距離很近。中心層是流媒體服務集羣,負責內容的轉發。智能負載均衡系統,根據用戶的地理位置信息,就近選擇邊緣服務器,爲用戶提供推/拉流服務。中心層也負責轉碼服務,例如,把RTMP協議的碼流轉換爲HLS碼流。

這套機制在後面的DNS、HTTPDNS、CDN的章節會更有詳細的描述。

拉流:觀衆的客戶端如何看到視頻?

接下來,我們再來看觀衆的客戶端通過RTMP拉流的過程。

先讀到的是H.264的解碼參數,例如SPS和PPS,然後對收到的NALU組成的一個個幀,進行解碼,交給播發器播放,一個絢麗多彩的視頻畫面就出來了。

小結

好了,今天的內容就到這裏了,我們來總結一下:

  • 視頻名詞比較多,編碼兩大流派達成了一致,都是通過時間、空間的各種算法來壓縮數據;
  • 壓縮好的數據,爲了傳輸組成一系列NALU,按照幀和片依次排列;
  • 排列好的NALU,在網絡傳輸的時候,要按照RTMP包的格式進行包裝,RTMP的包會拆分成Chunk進行傳輸;
  • 推送到流媒體集羣的視頻流經過轉碼和分發,可以被客戶端通過RTMP協議拉取,然後組合爲NALU,解碼成視頻格式進行播放。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章