繼續上一篇博客,在使用x264對視頻進行編碼以後,咱們須要將編碼好的視頻進行網絡傳輸,發送給其餘的客戶端,以後再進行解碼。那麼,這篇博客我將介紹下如何使用jrtplib這個庫對編碼後的文件傳輸。網絡
RTP協議基礎知識:函數
首先,咱們依然要先了解一些關於協議的基礎知識,否則對於其中的傳輸參數與發送的數據包順序什麼的咱們也就無從下手。在這裏,咱們僅對一些傳輸須要瞭解的關鍵知識進行介紹,若想了解更全面的關於RTP協議的知識,請直接參看RTP協議的rfc文檔,另外,這裏有一份翻譯的中文版。或者你能夠參考這篇博客:按照RFC3984協議實現H264視頻流媒體(附源代碼),其中有不少有用的資料。編碼
RTP(Real-time Transport Protocol)協議,詳細說明了在互聯網上傳遞音頻和視頻的標準數據包格式。它一開始被設計爲一個多播協議,但後來被用在不少單播應用中,因此這個協議既支持單播又支持多播。RTP協議和RTP控制協議RTCP一塊兒使用,並且它是建立在UDP協議上的。可是網上也有人說若是不使用RTSP協議(不瞭解的話,點這裏)的話,RTCP協議就等於形同虛設,我對此觀點不太贊同,我以爲不使用RTSP協議也是能夠用RTCP配合RTP協議是用的。我在下面的介紹中將會有應用。spa
既然RTP協議定義的是一個數據包格式,那麼下面咱們來具體研究下對於傳輸H264來講,其數據包時如何定義的。.net
首先,咱們來看RTP數據包的結構,RTP數據包由RTPheader和RTPpayload組成,下圖爲RTP數據頭部格式:翻譯
圖1,RTP數據包格式設計
各個字段表明含義以下:orm
V:版本號,通常爲2;視頻
P:填充字段標識;ip
X:擴展頭標識;
M:標誌 1bit,在傳輸h264時表示h264 nalu的最後一包
PT: 負載類型 7 bits, H264類型爲96
SN:序列號16 bits
Timestamp: 時間戳32bits,若是爲視頻的話,應該設置爲1/9000,音頻爲1/8000
SSRC: 3bits,用以識別同步源。
CSRC:做用我也未搞清楚,我並未使用該字段。
下面咱們來探討RTP的負載包(payload),在此以前,咱們必須先了解H264的NALU的負載,對於H264編碼後的數據,通過網絡層(NAL)編碼後產生NALU,其格式已在上篇博客中說明,下面咱們介紹naluheader結構,nalu的頭部只有一個字節,以下圖所示:
其中各個部分定義以下:
F: 1 個比特.
forbidden_zero_bit. 在 H.264 規範中規定了這一位必須爲 0.
NRI: 2 個比特.
nal_ref_idc. 取 00 ~ 11, 彷佛指示這個 NALU的重要性, 如 00 的 NALU 解碼器能夠丟棄它而不影響圖像的回放. 不過通常狀況下不太關心這個屬性.
Type: 5 個比特.
nal_unit_type. 這個 NALU 單元的類型. 簡述以下:
0 沒有定義
1-23 NAL單元 單個 NAL 單元包.
24 STAP-A 單一時間的組合包
24 STAP-B 單一時間的組合包
26 MTAP16 多個時間的組合包
27 MTAP24 多個時間的組合包
28 FU-A 分片的單元
29 FU-B 分片的單元
30-31 沒有定義
H.264Payload 格式定義了三種不一樣的基本的負載(Payload)結構. 接收端可能經過RTP Payload的第一個字節來識別它們. 這一個字節相似NALU 頭的格式, 而這個頭結構的NAL 單元類型字段,則指出了表明的是哪種結構,這個字節的結構以下, 能夠看出它和H.264 的NALU 頭結構是同樣的.
字段Type:這個RTPpayload 中 NAL 單元的類型. 這個字段和 H.264 中類型字段的區別是, 當 type的值爲 24 ~ 31 表示這是一個特別格式的 NAL 單元, 而 H.264 中, 只取 1~23 是有效的值.
關於NALU使用RTP包進行發送可能的類型有:
1. 單一 NAL 單元模式
即一個 RTP 包僅由一個完整的 NALU 組成. 這種狀況下 RTP NAL 頭類型字段和原始的H.264的NALU 頭類型字段是同樣的.
2. 組合封包模式
便可能是由多個 NAL 單元組成一個 RTP 包. 分別有4種組合方式:STAP-A, STAP-B, MTAP16, MTAP24。那麼這裏的類型值分別是 24,25, 26 以及 27.
3. 分片封包模式
用於把一個 NALU單元封裝成多個 RTP 包. 存在兩種類型 FU-A 和 FU-B. 類型值分別是 28 和 29.
在個人使用中只遇到第1種和第3中狀況,所以我就對這兩種進行下詳細介紹:
1. 單一NAL單元發送:
對於 NALU的長度小於 MTU 大小的包, 通常採用單一 NAL 單元模式.
對於一個原始的H.264 NALU 單元常由 [StartCode] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用於標示這是一個NALU 單元的開始, 必須是"00 00 00 01" 或"00 00 01", NALU 頭僅一個字節, 其後都是 NALU 單元內容.打包時去除 "00 00 01" 或"00 00 00 01" 的開始碼, 把其餘數據封包的 RTP 包便可.有以下例子:
有一個H.264 的 NALU 是這樣的:
[00 0000 01 67 42 A0 1E 23 56 0E 2F ... ]
這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個字節的開始碼, 67 是 NALU 頭, 42 開始的數據是 NALU 內容.
封裝成 RTP 包將以下:
[ RTPHeader ] [ 67 42 A0 1E 23 56 0E 2F ]
(在這裏要說明的是,若是客戶端是通用的播放器,好比VLC或者JM的話須要將前導碼去掉,可是若是使用的是ffmpeg在客戶端解碼的話,發送前不須要去掉前導碼,去掉以後可能會致使ffmpeg解碼錯誤)。
2. 分片封包模式
而當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包. 也稱爲Fragmentation Units(FUs).將NALU拆分紅小於MTU的數據包進行發送,若是使用的是VLC等網絡播放器的話,須要設置FU header,以下圖所示:
可是,仍然注意一點,若是使用的是ffmpeg自行進行數據包接收與解碼,則徹底沒必要寫FU header。
下面稍微介紹下RTCP協議:
RTCP的主要功能是:服務質量的監視與反饋,媒體間的同步,以及多播組中成員的標識。因爲RTCP分組很短,所以把多個RTCP分組封裝在一個UDP用戶數據報中。RTCP分組週期性的在網上傳送,它帶有發送端和接收端對服務質量的統計信息報告(如已發送的分組數和字節數,分組丟失率,分組到達時間間隔的抖動等)。
RTCP能夠說是控制交通的協議,它提供了:
1)SR發送者報告分組:用來使發送端週期的向全部接收端用多播方式進行報告。內容包括:該RTP流的SSRC;該RTP流中最新產生的RTP分組的時間戳和絕對時鐘時間(或稱牆上時間:wallclock time);該RTP流包含的分組數;該RTP流包含的字節數。
絕對時鐘時間是必要的。由於RTP要求每一種媒體使用一個流。有了絕對時鐘時間就能夠進行圖形和聲音的同步。
2)RR接收者報告分組:用來使接收端週期性的向全部的點用多播方式進行報告。內容包括:所接收到的RTP流的SSRC;該RTP流的分組丟失率;在該RTP流中的最後一個RTP分組的序號;分組到達時間間隔的抖動等。
發送RR分組有兩個目的:
第一,可使全部的接收端和發送端了解當前網絡的狀態。
第二,可使全部發送RTCP分組的站點自適應的調整本身發送RTCP分組的速率,RTCP分組的通訊量不超過網絡中的數據分組的通訊量的5%,而接收端分組報告分組的通訊量又應小於全部RTCP分組的通訊量的75%。
3)SDES源描述分組:給出會話中參加者的描述,包括參加者的規範名(CNAME)
4)BYE分組:關閉一個數據流。
5)APP分組:應用程序可以定義新的分組類型。
在這其中我用到4,5分組,其他的能夠用來作QoS,暫時我尚未用到。另外,關於顯示網絡當前情況的RTCP包是由jrtplib自動發送的,不須要本身寫代碼生成,可是若是你要使用這些包作QoS的話,是須要本身添加消息響應函數來處理的,jrtplib自己並無提供這樣的機制。
關於怎樣使用jrtplib進行傳輸我在下一篇博客中進行介紹。