总括: 一帧视频数据可以编码成多个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]
...

[转] rtp h264注意点(FU-A分包方式说明)的更多相关文章

  1. 多媒体开发之rtp打包---打包中的FU-A分包方式说明

    继上篇rtp中的时间戳和负载类型之后,升入到了nalu的分片打包问题,这里做下笔记 (1)fu-a的打包格式 1.基于RTP协议的打包及解包 (1)单个NAL打包 H.264NALU单元常由[star ...

  2. FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法。。

    [原创] RFC3984是H.264的baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法. 1.单个NAL包单元 12字节 ...

  3. H265(HEVC) nal 单元头介绍及rtp发送中的fu分组发送详解

    首先来介绍下h265(HEVC)nal单元头,与h264的nal层相比,h265的nal unit header有两个字节构成,如下图所示: 从图中可以看出hHEVC的nal包结构与h264有明显的不 ...

  4. Eclipse版本android 65535解决方案(原理等同android studio现在的分包方式)

    由于工作的需要看了下Eclipse下android65535的解决方案,查了好多文档,真心的发自内心的说一句请不要再拷贝别人的博客了,害人,真害人. 接下来我说下我的实现方式,首先说下65535的最可 ...

  5. Android开源项目分包方式学习(eoe、oschina、github)

    总感觉Android中关于分包的文章很少,或者几乎可以说没有.但是合理地分包,又可以使整个项目模块化,减少包与包之间的依赖,让整个项目的框架更加清晰,更利于后续功能的拓展. 因为没有相关的文章,所以这 ...

  6. rtp h264注意点(FU-A分包方式说明)

    前写过一篇文章,分析了h264使用rtp进行封包的格式介绍:RTP封装h264.但里面好像没有把拆分以及一些需要注意的情况说清楚,因此这里做补充,也作为自己的备忘(自己记性好像不太好). 关于时间戳, ...

  7. SpringBoot 分包方式多数据源

    1.引入依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spri ...

  8. springboot 配置多数据源实例代码(分包方式)

    目录 1.数据库 2.pom与yml 2.1.pom中的依赖部分 2.2.yml数据库配置部分 3.数据源配置类 DataSourceConfig 3.1.DataSourceConfig1.java ...

  9. RTP协议全解析(H264码流和PS流)

    转自:http://blog.csdn.net/chen495810242/article/details/39207305 写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个 ...

随机推荐

  1. You have new mail in /var/spool/mail/root 烦不烦你(转)

    转自(http://blog.csdn.net/yx_l128125/article/details/7425182) 有时在进入系统的时候经常提示You have new mail in /var/ ...

  2. BJDP结对编程活动

    7月21日参与了 BJDP北京的活动 在北京首次参与能够参与动手编程活动,感觉挺不错的. 本次活动共有三项内容 1.      金锐分享单元测试的Mocking技术,20 mins 2.      伍 ...

  3. css3怎么隐藏dom:4种方法

    1.display:none; 2.position:absolute; left:-99999px; 3.visibility:hidden; 4.opacity:0;

  4. 精通 Oracle+Python,第 1 部分:查询最佳应践

    原文链接:http://www.oracle.com/technetwork/cn/articles/dsl/mastering-oracle-python-1391323-zhs.html 在 Py ...

  5. Makefile与shell脚本的区别

    引用博客:Makefile与shell脚本区别 在Makefile可以调用shell脚本,但是Makefile和shell脚本是不同的.本文试着归纳一下Makefile和shell脚本的不同. 1.s ...

  6. 定位 -CLGeocoder - 编码

    #import "ViewController.h" #import <CoreLocation/CoreLocation.h> @interface ViewCont ...

  7. IOS7,做为开发者,你需要知道的变更

    IOS7即将发布,那么我们需要做些什么呢? 升级你的程序Icon至 120*120 更新一张包含状态栏大小的闪屏图片 还有些什么东西呢? IOS7中需要使用更加扁平化的设计,所以BUTTON的图片,边 ...

  8. HIVE编程指南之HiveQL的学习笔记1

    // HiveQLa) 数据定义语言1 数据库表的一个目录或命名空间,如果用户没有指定数据库的话,那么将会使用默认的数据库default-----创建数据库CREATE DATABASE guoyon ...

  9. XE5 安装破解

    以下转载自:  盒子 不可以将本破解补丁分享到国外网站.论坛中!低调啊! 本破解补丁只适合中国大陆地区的Delphi.C++Builder爱好者和开发者! 本破解补丁只可用于个人研究交流使用,不得做商 ...

  10. Java文件备份类

    import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import ...