美文网首页多媒体开发程序员
WEBRTC 接收H264 RTP数据流小结

WEBRTC 接收H264 RTP数据流小结

作者: 木韦杂货店 | 来源:发表于2018-08-05 09:42 被阅读3次

    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的逻辑。这些可以在下次的文章中再和大家分享。


    相关文章

      网友评论

        本文标题:WEBRTC 接收H264 RTP数据流小结

        本文链接:https://www.haomeiwen.com/subject/fcavvftx.html