zoukankan      html  css  js  c++  java
  • [转] rtp h264注意点(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]
    ...

     

  • 相关阅读:
    64位内核开发第十二讲,进程监视,ring3跟ring0事件同步.
    64位内核开发第十讲,IRQL中断级别了解
    64位内核开发第九讲,注册表编程.
    64位内核开发第8讲,文件操作.以及删除文件.
    64位内核第七讲.内核中字符串编程注意事项
    【Unity】7.5 移动设备输入
    【Unity】7.4 游戏外设输入
    【Unity】7.3 键盘输入
    【Unity】7.2 鼠标输入
    【Unity】7.1 Input类的方法和变量
  • 原文地址:https://www.cnblogs.com/welhzh/p/4785545.html
Copyright © 2011-2022 走看看