WEBRTC 接收H264 RTP數據流小結

WEBRTC 接收H264 RTP數據流小結

這篇文章是對webrtc 中,接收H264 RTP包的一個總結,主要分爲兩個部分:
第一部分,介紹H264打包成RTP包的規範,以及WEBRTC中目前正在使用的幾種格式。
第二部分,介紹WEBRTC的數據流,從接收RTP包,到拼裝成H264 Frame,最終送入Decoder,獲取YUV數據。

第一部分:RTP Payload Format for H.264 Video閱讀筆記

參考鏈接:rfc6184

RTP Payload Format

具體RTP 的協議格式,可以參考RFC 3550

1.RTP Header

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

  Figure 1.  RTP header according to RFC 3550

2.Payload Structures

定義了三種不同的Playload結構類型

  1. Single NAL Unit Packet

    在一個RTP Playload中,只包含一個Nal Unit 。

  2. Single NAL Unit Packet

    在一個RTP Playload中,聚合了多個Nal Unit。大致包含以下幾種:

    • STAP-A:
    • STAP-B
    • MTAP-16
    • MTAP-24
  1. Fragmentation Unit

    把一個Nal Unit 進行拆分,打包到多個RTP 包中。

    • FU-A
    • FU-B
      Table 1.  Summary of NAL unit types and the corresponding packet
                types

      NAL Unit  Packet    Packet Type Name               Section
      Type      Type
      -------------------------------------------------------------
      0        reserved                                     -
      1-23     NAL unit  Single NAL unit packet             5.6
      24       STAP-A    Single-time aggregation packet     5.7.1
      25       STAP-B    Single-time aggregation packet     5.7.1
      26       MTAP16    Multi-time aggregation packet      5.7.2
      27       MTAP24    Multi-time aggregation packet      5.7.2
      28       FU-A      Fragmentation unit                 5.8
      29       FU-B      Fragmentation unit                 5.8
      30-31    reserved                                     -

2.1 NAL Unit Header

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

  • F:0表示payload 內容沒有錯誤,1表示payload中的內容可能有錯誤內容或語法錯誤。
  • NRI:00表示沒有參考幀。
  • Type:1-23

2.1.1 Packetization Modes

  • Single Nal unit mode:
  • Non-interleaved mode:
  • Interleaved mode:

--

      Table 3.  Summary of allowed NAL unit types for each packetization
            mode (yes = allowed, no = disallowed, ig = ignore)

  Payload Packet    Single NAL    Non-Interleaved    Interleaved
  Type    Type      Unit Mode           Mode             Mode
  -------------------------------------------------------------
  0      reserved      ig               ig               ig
  1-23   NAL unit     yes              yes               no
  24     STAP-A        no              yes               no
  25     STAP-B        no               no              yes
  26     MTAP16        no               no              yes
  27     MTAP24        no               no              yes
  28     FU-A          no              yes              yes
  29     FU-B          no               no              yes
  30-31  reserved      ig               ig               ig

2.2 Single NAL Unit Packet

在一個rtp'包中,只包含有一個完整的Nal Unit(視頻幀)。

例: 如有一個 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 包將如下:

[ F|NRI| Type ] [ 67 42 A0 1E 23 56 0E 2F ]

a single NAL unit :[ 67 42 A0 1E 23 56 0E 2F ], 即只要去掉 4 個字節的開始碼就可以了.

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

Figure 2.  RTP payload format for single NAL unit packet

2.3 Aggregation Packets

在一個rtp包中,會有多個Nul Unit(一個rtp包帶多個視頻幀)。這種情況會在視頻幀比較小的時候採用。

  1. Single-time aggregation packet (STAP):
    • STAP-A: without DON

例:

如有一個 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 包將如下:

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

          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        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            
        Figure 7.  An example of an RTP packet including an STAP-A
                   containing two single-time aggregation units
               
               
        <!---->
       
* STAP-B: including DON

    <!---->


         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-B NAL HDR | DON                           | NALU 1 Size   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        | NALU 1 Size   | NALU 1 HDR    | NALU 1 Data                   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
        :                                                               :
        +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |               | NALU 2 Size                   | NALU 2 HDR    |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                       NALU 2 Data                             |
        :                                                               :
        |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                               :...OPTIONAL RTP padding        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            
        Figure 8.  An example of an RTP packet including an STAP-B
                   containing two single-time aggregation units


<!---->
  1. Multi-time aggregation packet (MTAP):

    這兩種MAPS的區別在於 timestamp offset 的長度不同。

    • MTAP16:
        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                           |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |MTAP16 NAL HDR |  decoding order number base   | NALU 1 Size   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |  NALU 1 Size  |  NALU 1 DOND  |       NALU 1 TS offset        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |  NALU 1 HDR   |  NALU 1 DATA                                  |
        +-+-+-+-+-+-+-+-+                                               +
        :                                                               :
        +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |               | NALU 2 SIZE                   |  NALU 2 DOND  |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |       NALU 2 TS offset        |  NALU 2 HDR   |  NALU 2 DATA  |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               |
        :                                                               :
        |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                               :...OPTIONAL RTP padding        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
        Figure 12.  An RTP packet including a multi-time aggregation
                        packet of type MTAP16 containing two multi-time
                        aggregation units

* MTAP24:



        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                           |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |MTAP24 NAL HDR |  decoding order number base   | NALU 1 Size   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |  NALU 1 Size  |  NALU 1 DOND  |       NALU 1 TS offs          |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |NALU 1 TS offs |  NALU 1 HDR   |  NALU 1 DATA                  |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
        :                                                               :
        +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |               | NALU 2 SIZE                   |  NALU 2 DOND  |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |       NALU 2 TS offset                        |  NALU 2 HDR   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |  NALU 2 DATA                                                  |
        :                                                               :
        |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                               :...OPTIONAL RTP padding        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        
        Figure 13.  An RTP packet including a multi-time aggregation
                    packet of type MTAP24 containing two multi-time
                    aggregation units

--

2.4 Fragmentation Units

一個Nal Unit會被分割成,通過多個rtp包進行發送,這樣便於傳輸和以後做fec處理。

  • FU-A:
 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
  • FU-B:

 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

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:

  • S:1表示第一包
  • E:1表示是最後一個包
  • R:1表示中間
  • Type:類型


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

目前webrtc中使用的打包代碼如下:

    void RtpPacketizerH264::GeneratePackets() {
      LOG(LS_VERBOSE) << "RtpPacketizerH264::GeneratePackets packetization_mode "
                      << (int)packetization_mode_
                      << " max_payload_len "
                      << max_payload_len_
                      ;
    
      for (size_t i = 0; i < input_fragments_.size();) {
        switch (packetization_mode_) {
          case H264PacketizationMode::SingleNalUnit:
            PacketizeSingleNalu(i);
            ++i;
            break;
          case H264PacketizationMode::NonInterleaved:
            size_t fragment_len = input_fragments_[i].length;
            if (i + 1 == input_fragments_.size()) {
              // Pretend that last fragment is larger instead of making last packet
              // smaller.
              fragment_len += last_packet_reduction_len_;
            }
            if (fragment_len > max_payload_len_) {
              PacketizeFuA(i);
              ++i;
            } else {
              i = PacketizeStapA(i);
            }
            break;
        }
      }
    }

第二部分:接收端的數據流處理

先看一下整理的類圖

video_receive_stream.jpg

處理流程如下

  1. 首先在cricket::WebRtcVideoChannel中的OnPacketReceived函數中,我們會收到RTP包。這個是通過ICE 建立的UDP鏈接傳來的數據。
  2. RTP數據包一直走到webrtc::RtpVideoStreamReceiver的OnPacketReceived函數中,調用webrtc::RtpReceiverImpl的IncomingRtpPacket進行rtp 包解析。
  3. 解析完之後的數據,會通過OnReceivedPayloadData回調上來,webrtc::RtpVideoStreamReceiver會將接收到的rtp包數據,打包成VCMPacket的形式,插入到PacketBuffer中。
  4. PacketBuffer的主要工作就是收集rtp包,並且判斷這些rtp包能否組裝成一個完整的H264的Frame。主要的實現邏輯就是每次在InsertPacket的最後,都調用FindFrames函數去查是否有合適的幀組成。
  5. 如果發現一個完整的幀,PacketBuffer會通過OnReceivedFrame把frame數據回調給webrtc::RtpVideoStreamReceiver。然後再通過video_coding::RtpFrameReferenceFinder的ManageFrame來查找,是否有合適的幀可以送給Decoder解碼。這裏的合適主要分一下幾點:
    • 判斷幀是否連續
    • 判斷參考幀是有沒有丟失
    • 是否是IFRAME
  6. 找到decodeble的幀後,video_coding::RtpFrameReferenceFinder通過OnCompleteFrame把frame交給internal::VideoReceiveStream,它會把frame插入到FrameBuffer中。
  7. 這裏的FrameBuffer,就是以前版本的jitter buffer。在新的webrtc中已經更名。
  8. internal::VideoReceiveStream內部有一個decode 線程,這個線程會定期問是否有合適的Frame可以送給decode解碼。如果有,則把它送到vcm::VideoReceiver去解碼。
  9. vcm::VideoReceiver中持有decode的外部類,VCMGenericDecoder。我們把數據送給他,如果有decode解碼完的YUV數據,他會把數據通過FrameToRender 回調webrtc::VideoStreamDecoder。
  10. 最終,webrtc::VideoStreamDecoder把YUV數據通過OnFrame回調給internal::VideoReceiveStream。在這裏,webrtc就會把YUV數據傳給之前註冊的Render。

總結

整體的數據流程在上面的已經做了一個簡單的描述,其中比較主要的是還標黃色的幾個類。由於時間有限,還是會有很多具體的細節沒有擴展,比如packet buffer的拼frame的邏輯,FrameBuffer找decodable frame的邏輯。這些可以在下次的文章中再和大家分享。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章