天天看點

rtp h264打包和解包

1、學習思路

         在了解rtp對h264資料的打包之前,需要對rtp、h264的一些基本概念有一個初步的了解,然後再使用rtp對h264的打包解包做解析

2、rtp認知

實時傳送協定(Real-time Transport Protocol或簡寫RTP,也可以寫成RTTP)是一個網絡傳輸協定,它是由IETF的多媒體傳輸工作小組1996年在RFC 1889中公布的。

RTP協定詳細說明了在網際網路上傳遞音頻和視訊的标準資料包格式。它一開始被設計為一個多點傳播協定,但後來被用在很多單點傳播應用中。RTP協定常用于流媒體系統(配合RTCP協定或者RTSP協定)。因為RTP自身具有Time stamp是以在ffmpeg 中被用做一種formate.

RTP協定格式:

0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |V=2|P|X|  CC      |M|     PT           |       sequence number         |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           timestamp                                                           |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |           synchronization source (SSRC) identifier                     |
    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    |            contributing source (CSRC) identifiers                        |
    |                             ....                                                                         |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      

上圖引自rfc3550,由上圖中可知道RTP封包由兩個部分構成--RTP報頭和RTP的負載:

RTP封包由兩部分組成:報頭和有效載荷。RTP報頭格式如圖6.7所示,其中:

1.V:RTP協定的版本号,占2位,目前協定版本号為2。

2. P:填充标志,占1位,如果P=1,則在該封包的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分。

3. X:擴充标志,占1位,如果X=1,則在RTP報頭後跟有一個擴充報頭。

4.  CC:CSRC計數器,占4位,訓示CSRC 辨別符的個數。

5. M: 标記,占1位,不同的有效載荷有不同的含義,對于視訊,标記一幀的結束;對于音頻,标記會話的開始。

6. PT: 有效載荷類型,占7位,用于說明RTP封包中有效載荷的類型,如GSM音頻、JPEM圖像等,在流媒體中大部分是用來區分音頻流和視訊流的,這樣便于用戶端進行解析。

7. 序列号:占16位,用于辨別發送者所發送的RTP封包的序列号,每發送一個封包,序列号增1。這個字段當下層的承載協定用UDP的時候,網絡狀況不好的時候可以用來檢查丢包。同時出現網絡抖動的情況可以用來對資料進行重新排序,在helix伺服器中這個字段是從0開始的,同時音頻包和視訊包的sequence是分别記數的。

8. 時戳(Timestamp):占32位,時戳反映了該RTP封包的第一個八位組的采樣時刻。接收者使用時戳來計算延遲和延遲抖動,并進行同步控制。

9. 同步信源(SSRC)辨別符:占32位,用于辨別同步信源。該辨別符是随機選擇的,參加同一視訊會議的兩個同步信源不能有相同的SSRC。

10. 特約信源(CSRC)辨別符:每個CSRC辨別符占32位,可以有0~15個。每個CSRC辨別了包含在該RTP封包有效載荷中的所有特約信源。

如果擴充标志被置位則說明緊跟在報頭後面是一個頭擴充,其格式如下:

0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |      defined by profile                  |           length                            |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                        header extension                                                   |
    |                             ....                                                                             |      

3、h264認知

H264資料2層結構:

一:視訊編碼層(VCL)

二:網絡适配層(NAL)

    在H.264/AVC視訊編碼标準中,整個系統架構被分為了兩個層面:視訊編碼層面(VCL)和網絡抽象層面(NAL)。其中,前者負責有效表示視訊資料的内容,而後者則負責格式化資料并提供頭資訊,以保證資料适合各種信道和存儲媒體上的傳輸。NAL占一個位元組。

    NAL單元(NALU):NAL的基本文法結構,它包含一個位元組的頭資訊和一系列來自VCL的稱為原始位元組序列載荷(RBSP)的位元組流。

資料流是儲存在媒體上時: 每個NALU 前添加起始碼:0x00000001(或者0x000001),用來訓示一個 NALU的起始和終止位置。

NALU頭由一個位元組組成, 它的文法如下:

+---------------+
       |0|1|2|3|4|5|6|7|
       +-+-+-+-+-+-+-+-+
       |F|NRI|  Type   |
       +---------------+      

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     一個非IDR圖像的編碼條帶 (bp幀)

slice_layer_without_partitioning_rbsp( )     

2     編碼條帶資料分割塊A

slice_data_partition_a_layer_rbsp( )     

3     編碼條帶資料分割塊B

slice_data_partition_b_layer_rbsp( )     

4     編碼條帶資料分割塊C

slice_data_partition_c_layer_rbsp( )     

5     IDR圖像的編碼條帶 (i幀)

slice_layer_without_partitioning_rbsp( )     

6     輔助增強資訊 (SEI)

sei_rbsp( )     

7     序列參數集 (sps幀)

seq_parameter_set_rbsp( )     

8     圖像參數集

pic_parameter_set_rbsp( pps幀)     

9     通路單元分隔符

access_unit_delimiter_rbsp( )     

10     序列結尾

end_of_seq_rbsp( )     

11     流結尾

end_of_stream_rbsp( )     

12     填充資料

filler_data_rbsp( )     

13     序列參數集擴充

seq_parameter_set_extension_rbsp( )     

14...18     保留     

19     未分割的輔助編碼圖像的編碼條帶

slice_layer_without_partitioning_rbsp( )     

20...23     保留     

24    STAP-A   單一時間的組合包

25    STAP-B   單一時間的組合包

26    MTAP16   多個時間的組合包

27    MTAP24   多個時間的組合包

28    FU-A     分片的單元

29    FU-B     分片的單元

30-31 沒有定義

4、rtp 對h264的打包和解包

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.通用采用FU-A 。

2.1 單一 NAL 單元模式

  對于 NALU 的長度小于 MTU 大小的包, 一般采用單一 NAL 單元模式.

  對于一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用于标示這是一個

NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個位元組, 其後都是 NALU 單元内容.

  打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他資料封包的 RTP 包即可.

0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |F|NRI|  type   |                                                                                 |
       +-+-+-+-+-+-+-+-+                                                                           |
       |                                                                                                         |
       |               Bytes 2..n of a Single NAL unit                                    |
       |                                                                                                          |
       |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                               :...OPTIONAL RTP padding                          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      

  如有一個 H.264 的 NALU 是這樣的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]      

  這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個位元組的開始碼, 67 是 NALU 頭, 42 開始的資料是 NALU 内容.

  封裝成 RTP 包将如下:

[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]      

  即隻要去掉 4 個位元組的開始碼就可以了.

2.2 組合封包模式

  其次, 當 NALU 的長度特别小時, 可以把幾個 NALU 單元封在一個 RTP 包中.

0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                          RTP Header                                                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         NALU 1 Data                                                          |
       :                                                               :
       +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |               | NALU 2 Size                   | NALU 2 HDR    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         NALU 2 Data                                                         |
       :                                                               :
       |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                               :...OPTIONAL RTP padding                          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      

2.3 分片打包(FU A).

  而當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包. 也稱為 Fragmentation Units (FUs).

0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       | FU indicator  |   FU header   |                                                      |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                              |
       |                                                                                                          |
       |                         FU payload                                                            |
       |                                                                                                          |
       |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                               :...OPTIONAL RTP padding                          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       Figure 14.  RTP payload format for FU-A
    The FU indicator octet has the following format:
       +---------------+
       |0|1|2|3|4|5|6|7|
       +-+-+-+-+-+-+-+-+
       |F|NRI|  Type   |
       +---------------+
       F     NALU頭中的F
       NRI     NALU頭中的NRI
       type    28 表示 FU-A打包 
    The FU header has the following format:
       +---------------+
       |0|1|2|3|4|5|6|7|
       +-+-+-+-+-+-+-+-+
       |S|E|R|  Type   |
       +---------------+      

      S     bit為1表示分片的NAL開始,當它為1時,E不能為1

      E     bit為1表示結束,當它為1,S不能為1

      R     bit保留位,必須是0

      Type    就是NALU頭中的Type,取1-23的那個值

分片打包解包執行個體:

80 60 01 0f 00 0e 1000 00 00 00 00 7c 85 8882
00 0a 7f  ca 94 053b 7f  3e 7f   fe14  2b 27 26 f8
89 88 dd85 62 e1 6dfc 33 01 38 1a 10 35 f214 
84 6e 21 24 8f  7262 f0 51 7e 10 5f 0d 42 71 12
17 65 62 a1 f1  44dc  df 4b 4a 38 aa 96 b7dd 24      

前12位元組為RTP頭