h264 rtp FU-A

總括: 一幀視頻數據可以編碼成多個H264的NALU, 每個NALU的開頭爲00 00 00 01; 一個RTP包可以傳送 部分、一個或多個 NALU,看NALU的大小而定。

 

之前寫過一篇文章,分析了h264使用rtp進行封包的格式介紹:RTP封裝h264 (見下面)。但裏面好像沒有把拆分以及一些需要注意的情況說清楚,因此這裏做補充,也作爲自己的備忘(自己記性好像不太好)。

 
        關於時間戳,需要注意的是h264的採樣率爲90000HZ(被標準固定死的,爲了方便轉換成npt時間,見維基百科:https://en.wikipedia.org/wiki/RTP_audio_video_profile),因此時間戳的單位爲1(秒)/90000,因此如果當前視頻幀率爲25fps,那時間戳間隔或者說增量應該爲3600,如果幀率爲30fps,則增量爲3000,以此類推。
        關於h264拆包,按照FU-A方式說明:
        1)第一個FU-A包的FU indicator:F應該爲當前NALU頭的F,而NRI應該爲當前NALU頭的NRI,Type則等於28,表明它是FU-A包。FU header生成方法:S = 1,E = 0,R = 0,Type則等於NALU頭中的Type。
        2)後續的N個FU-A包的FU indicator和第一個是完全一樣的,如果不是最後一個包,則FU header應該爲:S = 0,E = 0,R = 0,Type等於NALU頭中的Type。
        3)最後一個FU-A包FU header應該爲:S = 0,E = 1,R = 0,Type等於NALU頭中的Type。

        因此總結就是:同一個NALU分包厚的FU indicator頭是完全一致的,FU header只有S以及E位有區別,分別標記開始和結束,它們的RTP分包的序列號應該是依次遞增的,並且它們的時間戳必須一致,而負載數據爲NALU包去掉1個字節的NALU頭後對剩餘數據的拆分,這點很關鍵,你可以認爲NALU頭被拆分成了FU indicator和FU header,所以不再需要1字節的NALU頭了。
        關於SPS以及PPS,配置幀的傳輸我採用了先發SPS,再發送PPS,並使用同樣的時間戳,或者按照正常時間戳增量再或者組包發送的形式處理貌似都可以,看播放器怎麼解碼了,另外提一下,如果我們使用vlc進行播放的話,可以在sdp文件中設置SPS以及PPS,這樣就可以不用發送它們了。
        使用VLC播放時,sdp文件中的分包模式選項:packetization-mode=1,否則有問題。另外sdp裏面設置的編碼type必須和rtp包中的一致。


轉自 http://blog.csdn.net/jwybobo2007/article/details/7235942

 
項目中的總結
  (1) FU-A 還原的時候,也是0x00 00 00 01 開始,不需要自己額外添加0x00 00 00 01
  (2) FU-A 的的解析,start end等數據要解析好
  (3) single nal unit 也是以0x00 00 00 01開始,也不需要自己添加分隔符


---------------------------------------------------------------------------------------------------------------------------------------------

h264 NALU格式

網絡抽象層單元類型 (NALU): 一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成,形如 00 00 00 01 67 42 A0 1E 23, 則67是nalu header, 42之後的是payload(有效的原始視頻數據). 有些代碼中的 nal_octet 變量指的就是 nalu header 字節。

NALU頭(NALU Header)由一個字節組成,它的語法如下:

      +---------------+
      |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-23  NAL單元  單個 NAL 單元包
  24    STAP-A   單一時間的組合包
  25    STAP-B   單一時間的組合包
  26    MTAP16   多個時間的組合包
  27    MTAP24   多個時間的組合包
  28    FU-A     分片的單元
  29    FU-B     分片的單元
  30-31 沒有定義

h264僅用1-23, 24以後的用在RTP H264負載類型頭中(即24以後在rtp中使用)

---------------------------------------------------------------------------------------------------------------------------------------------


---------------------------------------------------------------------------------------------------------------------------------------------

RTP格式:

總括:[RTP Packet] = [RTP Header] + [RTP PayLoad]

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             |
      |                             ....                              |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      負載類型 Payload type(PT): 7bits      (請和H264 NALU的payload區別開來,H264的payload指的是純視頻編碼數據,這裏的payload type指的是rtp的載荷類型)
rfc裏面對一些早期的格式定義了這個payload type。但是後來的,如h264並沒有分配,那就用96來代替。因此現在96以上都不表示特定的格式,具體表示什麼要用sdp或者其他協議來協商。

      序列號 Sequence number(SN): 16bits
      時間戳 Timestamp: 32bits     (rtp打包時使用的時間戳都是pts,因爲dts是解碼器根據I、P、B幀的順序自己設定的解碼順序,而pts是編碼時按照顯示順序輸出的幀序列,幾乎每個編碼器都會按照顯示順序輸出幀序 列:如 I B1 B2 B3 P4 B5 B6 B7 B8 B9 P10;而dts是解碼器重新排列幀順序後的解碼順序,前面的解碼順序[dts]爲: I P4 B1 B2 B3 P10 B5 B6 B7 B8 B9)

 

RTP 格式Payload的結構,下面介紹的全部都是RTP PayLoad的部分,即RTP PayLoad 封包介紹:

 

單一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 包即可. 以下即是一個被打包進rtp的NALU單元(不包含rtp頭),第一個字節是NALU頭:

       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 個字節的開始碼就可以了.

 

 

組合封包模式

  其次, 當 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        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

這裏只介紹STAP-A模式,如果是STAP-B的話會多加入一個DON域,另外還有MTAP16、MTAP24,具體不介紹,可以看rfc文檔,文章尾貼一個鏈接可以去看。

轉載的話註明一下作者:jwybobo2007 出處:http://blog.csdn.net/jwybobo2007/article/details/7054140

例:

 

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

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

  [00 00 00 01 68 42 B0 12 58 6A D4 FF ... ]

  封裝成 RTP 包將如下:

  [ RTP Header ] [78 (STAP-A頭,佔用1個字節)] [第一個NALU長度 (佔用兩個字節)] [ 67 42 A0 1E 23 56 0E 2F ] [第二個NALU長度 (佔用兩個字節)] [68 42 B0 12 58 6A D4 FF ... ]


分片的單元:

 

  當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   |
      +---------------+

   別被名字嚇到這個格式就是上面提到的RTP h264負載類型,Type爲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保留位

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

 

 

 

 

 

 

 

 

 

 

 

 

H.264 RTP Streaming

 

根據RFC3984以RTP 封裝H.264 raw data來作video streaming.

1.H.264 raw data
以00 00 01 或 00 00 00 01作為開頭(Start Code),接著是8 bit NALU 
NALU的format
      +---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+

F : forbidden zero bit, 一定為0
NRI : nal_ref_idc, 表示資料的重要性, 00為最不重要.
Type :nal_unit_type, H.264只定義1~23的範圍

一個H.264 raw data看起來像這樣
00 00 00 01 09 30 ......

2.RTP header
因為一個H.264 video frame資料的大小往往會在數k bytes到數十K bytes,
在傳送封包時就會將資料切割分別封裝,也因此需要加入一些額外的參數讓
接收端可以正確組合被分割的video frame.這也是RFC3984最主要的目的.

RTP header 中有三個參數要注意
timestamp : 以90KHz作為基準,以30 fps為例,timestamp遞增 90000 / 30.
實務上是以payload實際間隔時間作計算.同一個video frame的
            分割資料timestamp是相同的
sequence : 每個RTP封包sequence number都遞增.
mark bit : RTP封包封裝的是最後一個分割的video frame時mark bit 為 1.

2.Payload format
1~23 : Single NAL unit packet.

RFC3984使用了H.264 NALU中未定義的type 24~29 (相當於增加H.264 nal_unit_type定義)

24 : STAP-A 單一時間組合
25 : STAP-B 單一時間組合
26 : MTAP16 多個時間組合
27 : MTAP32 多個時間組合
28 : FU-A 分割資料
29 : FU-B 分割資料

比較常見的是28,29.

3.Single NAL unit packet
當資料少於MTU的大小就用此方式封裝.
H.264 raw data foramt 為 [Start code][NALU][Raw Data]
封裝時去掉Start Code即可.Format 如下
[RTP Header][NALU][Raw Date]

4.FU-A (Fragmentation unit)
當資料大於MTU以此方式分割
H.264 raw data foramt 為 [Start code][NALU][Raw Data]
去掉[Start code],[NALU],以不超過MTU大小分割[Raw Data]
以NALU產生FU indicator, FU Header.

RFC 3984

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 |
+---------------+

The FU header has the following format:

+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+

[FU indicator] = (NALU & 0x60) | 28;
[FU Header] = (start << 7) | (end << 6) | (NALU & 0x1f);

format如下

[RTP Header][FU indicator][FU header][Raw Data Part 0]
[RTP Header][FU indicator][FU header][Raw Data Part 1]
[RTP Header][FU indicator][FU header][Raw Data Part 2]
...

5.FU-B (Fragmentation unit)

RFC 3984

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 | DON |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 15. RTP payload format for FU-B

format如下
[RTP Header][FU indicator][FU header][DON][Raw Data Part 0]
[RTP Header][FU indicator][FU header][DON][Raw Data Part 1]
[RTP Header][FU indicator][FU header][DON][Raw Data Part 2]
發佈了49 篇原創文章 · 獲贊 21 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章