實時視頻系統中的媒體傳輸,絕大多數都會採用RTP(實時傳輸協議)標準。H.264視頻做爲當前應用最普遍的視頻編碼標準,其傳輸協議也會首選RTP標準。在設計實現H.264的實時傳輸時,H.264協議基於RTP的打包和解包定義於IETF標準-RFC6184,RTC系統須要遵循這個標準來設計打包和解包處理模塊。在通訊理論中,這個過程能夠被認爲是基於傳輸的信道編碼。本篇技術文章帶你瞭解H.264在RTP中的基本格式和技術實踐。markdown
#01 基本格式ide
使用RTP對H.264打包和解包須要遵循IETF標準RFC6184, 咱們先來了解一下H.264在RTP中的封包協議。 01 H.264的RTP報頭編碼
圖1 RTP報頭spa
對於H.264的RTP負載格式而言,RTP報頭的格式和RFC 3550裏面的定義是一致的,不過有一些字段須要特別說明一下。 標記位 (M):1位 對RTP時間戳所對應訪問單元的最後一個數據包來設置標記位,符合視頻中M位的正常使用格式,以容許有效的播放緩衝處理。解碼器可使用這個位做爲訪問單元最後一個數據包的早期指示,可是不能徹底依賴這個屬性。 負載類型 (PT):7位 沒有特別指定的負載類型,須要經過協商來肯定。 序列號(SN):16位 根據RFC 3550設置和使用。對於單NAL單元和非交錯打包模式,序列號用於肯定NAL單元的解碼順序。 時間戳:32位 RTP時間戳設置爲視頻內容的採樣時間戳。必須使用90 kHz時鐘頻率。 02 H.264的RTP負載類型設計
H.264的RTP負載可分爲三大類,類型以下:code
單個NAL單元數據包: 此類RTP負載中僅包含單個NAL單元。負載報頭類型編號等於原始NAL單元類型,即從 1 到 23 的範圍值,詳見H.264規範。orm
聚合數據包: 此類型用於聚合多個NAL單元成爲單個 RTP 負載。這類數據包有四個細分版本:單時間聚合包A (STAP-A)、單時間聚合包B (STAP-B)、16位偏移多時間聚合包 (MTAP16) 和24位偏移多時間聚合包 (MTAP24)。負載類型編號分配給 STAP-A、STAP-B、MTAP16 和 MTAP24 的值分別爲 2四、2五、26 和27。視頻
分片單元: 用於將單個NAL單元分片到多個RTP 數據包。存在兩個版本:FU-A 和 FU-B,負載類型編號分別爲 28 和 29。排序
表1 H.264負載類型 03 H.264的RTP打包模式圖片
H.264的RTP打包模式有三種: 單NAL單元模式
全部的接收端都必須支持這種模式,主要應用於兼容低時延應用中的硬件設備。只有單NAL單元數據包能夠在這種模式下使用。
非交錯模式
建議接收端去支持這種模式,主要應用於低時延應用。只有單NAL單元、STAP-A和FU-A數據包能夠在這種模式下使用。
交錯模式
有需求的接收端能夠去支持這種模式,主要應用於非低延時應用。STAP-B、兩種MTAP、FU-A和FU-B數據包能夠在這種模式下使用。
表2 H.264打包模式容許的負載類型 單NAL單元和非交錯模式中,NAL單元必須以NAL單元解碼順序傳輸,這兩種模式更適合低延時需求的交互系統。
交錯模式中NAL單元的傳輸順序和解碼順序能夠是不一致的,致使接收端的解包過程當中須要按照解碼順序從新排序,引入更多的時延,所以並不適合須要低時延的交互系統。
04 H.264的RTP負載報頭
圖2 H.264的RTP負載報頭 H.264的RTP負載報頭位於負載的第1個字節,分紅三個字段:
F:1位 forbidden_zero_bit。值爲 0 表示NAL單元類型字節和負載不該包含位錯誤或其餘語法違規。值爲 1 表示NAL單元類型字節和負載可能包含位錯誤或其餘語法違規。 NRI:2位 nal_ref_idc。00值和非零值的語義與H.264規範保持不變。值00表示NAL單元的內容不是用於重建圖片間預測的參考圖片,這樣的NAL單元能夠被丟棄並不會致使參考圖片的不完整。值大於00表示須要對NAL單元進行解碼以保持參考圖片的完整性。 類型:5位 負載類型,包括表1裏面列舉的全部類型。 05 H.264的RTP負載格式
由於只有單NAL單元模式和非交錯模式打包模式更適合應用於低時延交互系統中,而這兩種打包模式所涉及的只有單NAL數據包、單時間聚合包A(STAP-A)和分片單元A(FU-A)三種RTP負載,因此在這裏只對這三種負載格式作個簡單的介紹。
單NAL數據包
圖3 單NAL數據包負載格式 單NAL數據包就是將原始的NAL單元直接放置到RTP的負載中,NAL單元頭就是做爲單NAL數據包的負載類型。
單時間聚合包A(STAP-A)
圖4 聚合數據包負載格式 聚合數據包的負載中包含一個或者多個聚合單元。一個聚合包能夠攜帶儘量多的聚合單元;不過聚合數據包中的總數據量應該選擇合適大小,以便生成的IP數據包小於MTU大小。聚合數據包負載報頭中的NRI字段的值必須是全部聚合NAL單元中最大值。
圖5 單時間聚合單元格式 STAP-A數據包中,每一個聚合單元的NAL都應該是共享相同的NALU時間。負載的首字節是STAP-A負載報頭,每一個聚合單元是由兩字節的NAL單元尺寸字段和原始NAL單元組成。若是STAP-A數據包中包含兩個聚合單元,負載格式以下圖:
圖6 包含兩個聚合單元的STAP-A數據包示例 分片單元A(FU-A)
圖7 FU-A數據包負載格式 FU-A數據包的負載包含1字節的分片單元標識(負載報頭)、1字節的分片單元報頭和分片單元負載。分片單元負載報頭中的NRI字段的值等同於被分片NAL單元的值。 分片單元報頭的格式以下:
圖8 分片單元報頭 S: 1 位 起始位。當設置爲 1 時,指示一個分片NAL 單元的開始。當 FU 負載不是分片NAL單元的開始片斷,設置起始位爲 0。 E: 1 位 結束位。當設置爲 1 時,指示一個分片NAL單元的結束。當 FU負載不是分片NAL單元的最後一個片斷,設置結束位爲 0 。 R: 1 位 保留位。必須等於 0,而且必須被接收者忽略。
類型:5位 被分片的原始NAL單元類型(1 - 23)。
#02 實踐分享
RTC系統中的視頻處理的結構大體以下圖,RTP打包解包是視頻編解碼和傳輸之間的橋樑。
圖9 視頻流工做流程
01 H.264打包
H.264的打包的基本流程大體以下:
輸入H.264 NAL,判決當前的H.264 NAL的打包格式,能夠選擇單NAL單元包格式、STAP-A包格式,或者是FU-A格式。MTAP格式通常不在實時系統中使用,考量的重點在於兼顧打包效率和傳輸效率。 Single-NAL-Unit 打包比較簡單,一個NAL封裝爲一個RTP包。 STAP-A在NAL包比較小的時候採用,多個相同時間戳的NAL包被打到一個RTP包。 FU在NAL包比較大的時候採用,限制RTP包的大小小於MTU。一個NAL包被拆成多個碎片(Fragment), 碎片被打成RTP包。
02 H.264解包
在此只對三種打包模式下的解包過程作一個大體的介紹。
單NAL單元和非交錯模式 接收端包括一個接收緩衝器來補償傳輸延遲和抖動。接收端將傳入的數據包按照接收順序存儲到接收緩衝器中。數據包按RTP序列號的順序被解包。若是解包的數據包是單個NAL單元包,包中包含的NAL單元直接傳遞給解碼器。若是解包的數據包是 STAP-A,則包含在數據包中的NAL單元按照它們封裝在數據包中的順序被傳遞給解碼器。對於全部 FU-A包含單個NAL單元片斷的數據包,解包的片斷按其發送順序恢復出NAL單元,而後傳遞給解碼器。 交錯模式 交錯模式的解包規則通常是從傳輸順序到解碼順序來從新排序NAL單元。在實時系統中應用比較少見,具體過程在此就不展開了。
參考文獻
一、RFC 3550 – RTP: A Transport Protocol for Real-time Application
二、RFC 6184 – RTP Payload Format for H.264 Video