實時視訊系統中的媒體傳輸,絕大多數都會采用RTP(實時傳輸協定)标準。H.264視訊作為目前應用最廣泛的視訊編碼标準,其傳輸協定也會首選RTP标準。在設計實作H.264的實時傳輸時,H.264協定基于RTP的打包和解包定義于IETF标準-RFC6184,RTC系統需要遵循這個标準來設計打包和解包處理子產品。在通信理論中,這個過程可以被認為是基于傳輸的信道編碼。本篇技術文章帶你了解H.264在RTP中的基本格式和技術實踐。
#01
基本格式
使用RTP對H.264打包和解包需要遵循IETF标準RFC6184, 我們先來了解一下H.264在RTP中的封包協定。
01
H.264的RTP報頭
圖1 RTP報頭
對于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負載可分為三大類,類型如下:
單個NAL單中繼資料包:
此類RTP負載中僅包含單個NAL單元。負載報頭類型編号等于原始NAL單元類型,即從 1 到 23 的範圍值,詳見H.264規範。
聚合資料包:
此類型用于聚合多個NAL單元成為單個 RTP 負載。這類資料包有四個細分版本:單時間聚合包A (STAP-A)、單時間聚合包B (STAP-B)、16位偏移多時間聚合包 (MTAP16) 和24位偏移多時間聚合包 (MTAP24)。負載類型編号配置設定給 STAP-A、STAP-B、MTAP16 和 MTAP24 的值分别為 24、25、26 和27。
分片單元:
用于将單個NAL單元分片到多個RTP 資料包。存在兩個版本:FU-A 和 FU-B,負載類型編号分别為 28 和 29。
負載類型 | 資料包類型 | 資料包類型名 |
1-23 | NAL單元 | 單個NAL單元包 |
24 | STAP-A | 單個時間聚合包 |
25 | STAP-B | 單個時間聚合包 |
26 | MTAP16 | 多個時間聚合包 |
27 | MTAP24 | 多個時間聚合包 |
28 | FU-A | 分片單元 |
29 | FU-B | 分片單元 |
表1 H.264負載類型
03
H.264的RTP打包模式
H.264的RTP打包模式有三種:
單NAL單元模式
所有的接收端都必須支援這種模式,主要應用于相容低延遲時間應用中的硬體裝置。隻有單NAL單中繼資料包可以在這種模式下使用。
非交錯模式
建議接收端去支援這種模式,主要應用于低延遲時間應用。隻有單NAL單元、STAP-A和FU-A資料包可以在這種模式下使用。
交錯模式
有需求的接收端可以去支援這種模式,主要應用于非低延時應用。STAP-B、兩種MTAP、FU-A和FU-B資料包可以在這種模式下使用。
負載類型 | 資料包類型 | 單NAL單元模式 | 非交錯模式 | 交錯模式 |
1-23 | NAL單元 | 允許 | 允許 | 不允許 |
24 | STAP-A | 不允許 | 允許 | 不允許 |
25 | STAP-B | 不允許 | 不允許 | 允許 |
26 | MTAP16 | 不允許 | 不允許 | 允許 |
27 | MTAP24 | 不允許 | 不允許 | 允許 |
28 | FU-A | 不允許 | 允許 | 允許 |
29 | 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單元。在實時系統中應用比較少見,具體過程在此就不展開了。
參考文獻
1、RFC 3550 – RTP: A Transport Protocol for Real-time Application
2、RFC 6184 – RTP Payload Format for H.264 Video