-
H264流結構
H264的ES流的結構分爲兩層,包括視頻編碼層(VCL)和網絡適配層(NAL)。視頻編碼層負責視頻內容表示,而網絡適配層負責對數據進行打包和傳送。NAL和VCL分離主要有以下兩方面的好處:
1、信號處理和網絡傳輸分層,VCL和NAL可以在不同的處理平臺上實現;
2、VCL和NAL分離設計,可以在不同的網絡環境內,網關不需要因爲網絡環境不同而對VCL比特流進行重構和重編碼。
H264的ES流由一系列的NALU(Network Abstraction Layer Unit)組成,不同的NALU數據量各不相同。每個NALU前添加起始碼:0x000001或0x00000001,用來指示一個NALU的起始和終止位置。在這樣的機制下,解碼器在碼流中檢測起始碼,作爲一個NALU的起始標識,當檢測到下一個起始碼時,當前NALU結束。每個NALU單元由一個字節的NALU頭(NALU Header)和若干字節的載荷數據(RBSP)組成。其中NALU頭的格式如圖2所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
F | NRI | TYPE |
F:forbidden_zero_bit 佔1位,如果有語法衝突,則爲1。當網絡識別此單元存在比特錯誤時,可將其設爲1,以便接收方丟掉該 單 元。
NRI:nal_ref_idc. 佔2位,用來指示該NALU的重要性等級。值越大,表示當前NALU越重要。具體大於0時取何值,沒有具體規定。
Type:佔5位,指出NALU的類型,具體類型如下所示:
nal_unit_type | NALU內容 | C |
0 | 未指定 | |
1 | 非IDR圖像的編碼slice | 2,3,4 |
2 | 編碼slice數據劃分A | 2 |
3 | 編碼slice數據劃分B | 3 |
4 | 編碼slice數據劃分C | 4 |
5 | IDR圖像中的編碼slice | 2,3 |
6 | SEI(補充增強信息) | 5 |
7 | SPS(序列參數集) | 0 |
8 | PPS(圖像參數集) | 1 |
9 | 接入單元定界符 | 6 |
10 | 序列結束 | 7 |
11 | 碼流結束 | 8 |
12 | 填充數據 | 9 |
13~23 | 保留 | |
24~31 | 未指定 |
需要特別指出的是,NRI值爲7和8的NALU分別爲序列參數集(SPS)和圖像參數集(PPS).
-
RTP簡介
RTP全名是Real-time Transport Protocol(實時傳輸協議),配套的相關協議RTCP(Real-time Transport Control Protocol,即實時傳輸控制協議),實時流傳輸協議RTP詳細說明了在互聯網上傳遞音頻和視頻的標準數據包格式,它與RTCP協議配合使用,本篇只講視頻H264的rtp封包,RTP實現IP網絡端到端實時的傳輸多媒體數據,並提供時間信息和流同步,具有低延時的特點。
-
RTP封包
-
RTP包頭header
每一個RTP數據包都由固定的包頭(header)和載荷(payload)兩部分組成,其中包頭前12字節的含義是固定的,而載荷則可以是音頻或者視頻數據。RTP的12字節固定包頭格式如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
V | P | X | CC | M | 載荷類型(PT) | 序號(sequence number) | |||||||||||||||||||||||||
時間戳(timestamp) |
|||||||||||||||||||||||||||||||
同步信源標識符(SSRC identifier) | |||||||||||||||||||||||||||||||
特約信源標識符(CSRC identifiers) |
各字段含義:
V:RTP協議版本號,佔2位,一般協議版本號爲2
P:填充標誌,佔1位,如果P = 1,則在該報文的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分
X:擴展標誌,佔1位,如果X = 1, 則在RTP報頭後跟有一個擴展報頭
CC:CSC計數器,佔4位,指示CSRC標識符的個數
M:佔1位,標記解釋由設置定義,目的在於允許重要事件在包流中標記出來,如不同的有效載荷有不同的含義,對於視頻,標記 一 幀的結束;對於音頻,標記會話的開始。
載荷類型(PT):佔7位,用來指出RTP負載的具體格式。rfc裏面對一些早期的格式定義了這個payload type,但是後來的h264並沒 有分配,現在用96代替,因此現在96以上都不表示特定個的格式,具體表示什麼要用sdp或者其他協議來協商。
序列號(SN):佔16位,用於標識發送者所發送的RTP報文的序列號,每發送一個報文,序列號增1 ,序列號的初始值是隨機產生 的,可以用於檢查丟包以及進行數據包排序。
時間戳Timestamp:佔32位,必須使用90KHz時鐘頻率
同步信源(SSRC)標識符:佔32位,指RTP包流的來源。該標識符是隨機產生的,
參加同一視頻會議的兩個同步信源不能有相同的SSRC
特約信源(CSRC)標識符:佔32位,可以有0~15個。每個CSRC標識了包含在該RTP報文有效載荷中的所有特約信源。
-
RTP負載payload
RTP的負載payload的數據就是H264的NALU,對於每個NALU,根據其包含的數據量的不同,其大小也有差異。在IP網絡中,當要傳輸的IP報文大小超過最大傳輸單元MTU(Maximum Transmission Unit)時就會產生IP分片情況。在以太網環境中可傳輸的最大IP報文(MTU)的大小爲1500字節。如果發送的IP數據包大於MTU,數據包就會被拆開來傳送。
RTP負載的第一個字節的結構體如下,它和H264的NALU頭結構一致,可以把它認爲是RTP h264負載類型字節,完全是多增加的一個字節,不影響後面的NALU結構。
-
-
封包
單一NAL單元模式
對於NALU的長度小於MTU大小的包,一般採用單一NAL單元模式,對於一個原始的H264NALU單元常由“起始碼”+“Nalu Header” + "Nalu Payload"三部分組成,其中起始碼是一個Nalu的開始,必須是“00 00 00 01”或“00 00 01”,Nalu頭僅爲一個字節,其後都是Nalu單元內容,打包時把起始碼去除掉,其他數據打包成payload即可。
例: 如有一個 H.264 的 NALU 是這樣的:
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]
這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個字節的開始碼, 67 是 NALU 頭, 42 開始的數據是 載荷數據內容.
封裝成 RTP 包將如下:
[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]
即只要去掉 4 個字節的開始碼就可以了.
FU-A打包方式
當NALU的長度超過MTU時,就必須對NALU單元進行分片封包,這裏只講一下FU-A的分片封包方式。FU-A的頭部由兩個字節組成,分別是Fu Indicator和Fu-A Header,再後面是負載。Fu Indicator見上圖1,Fu Header如下
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
S | E | R | Type |
S:1位,Start位,當被設置爲1時,表示NAL單元的開始。當後面的Fu載荷不是被分片Nal單元載荷的開始時,此位置0。
E:1位,End位,意義和Start位相反,當置1時,表示Nal單元的結束,當FU載荷不是Nal單元的最後一個分片時,此位置0。
R:1位,Reserved位,必須等於0,且接收者必須忽略它。
Type:5位,Nal單元荷載類型,定義見表《NALU類型》