基础传输结构

rtp中对于h264数据的存储分为两层,分别是

  • VCL: video coding layer 视频编码层

    这是h264中block, macro block 以及 slice级别的定义,目的是为了独立网络传输,进行高效的编解码

  • NAL: network abstraction layer 网络提取层

    NAL层的不同是为了根据不同的网络把VCL数据进行打包成不同的格式,进行传输

NAL

H264中的数据分组有头部(譬如: pkt->data),解码器可以很方便的检测到NAL的分界,依次去除NAL进行解码,但为了节省码流,NAL没有在数据头部设立特定元素,如果编码数据存储在介质上,NAL依次紧密相连(这时就无法通过对象取读取一个nal数据了),就无法区分出不同的nal单元,为了解决该问题,存储的时候会在每一个nal前添加0x000001或0x000000。

但数据内部也可能出现0x000001或0x000000,为此nal中规定不能出现0x000001或0x000000,源数据需要进行如下变换:

原数据 替换数据
0X000000 0X00000300
0X000001 0X00000301
0X000002 0X00000302
0X000003 0X00000303

在网络传输过程中, NAL中的数据被分成NALU(nal unit)单元,然后由RTP进行封装传输

如上图所示,VCL的数据经过上图所示

  • 在SODB的后面添加了结尾若干比特"0",以用字节对齐成了RBSP
  • 在RBSP的基础上,对数据进行循环检测替换上述的0x000000 ~ 0x000002,避免nal单元边界被破坏,成了EBSP(扩展字节序列载荷,在 RBSP 基础上填加了仿校验字节(0x03),它的原因是:在 NALU 加到 Annexb 上时,需要添加每组 NALU 之前的开始码 StartCodePrefix,如果该 NALU 对应的 slice 为一帧的开始(即为 IDR 帧)则用 4 位字节表示:0x00000001,否则用 3 位字节表示:0x000001。为了使 NALU 主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为 0,就插入一个字节的 0x03。解码时将 0x03 去掉。也称为 "脱壳操作"。)
  • 在EBSP上添加一个字节的header后成了 NALU,

NALU

上述EBSP添加的一个字节的header的结构如下所示:

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

F:0表示payload 内容没有错误,1表示payload中的内容可能有错误内容或语法错误。

NRI:用来表示当前NALU单元的重要性(从00 ~11),00最低,表示这不是一个用于帧间预测的参考帧,可以丢弃。

Type:表示当前NALU的类型,这些类型如下表所示


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

再具体一点如下所示:

nal_unit_type	NAL类型
1 非IDR图像中不采用数据划分的片段
2 非IDR图像中A类数据划分片段
3 非IDR图像中B类数据划分片段
4 非IDR图像中C类数据划分片段
5 IDR图像的片
6 补充增强信息单元(SEI)
7 序列参数集
8 图像参数集
9 分界符
10 序列结束
11 码流结束
12 填充
13…23 保留
24…31 不保留(RTP打包时会用到)

比较重要的是

nal_unit_type = 7 RTP 负载的是序列参数集

nal_unit_type = 8 RTP 负载的是图像参数集

nal_unit_type = 5 IDR图像的片 (立即刷新图像,I帧给P帧和B帧作为参考)

23之前的都是signal-nalu单rtp就可以传输完毕,只是对其细分了说明nalu中的数据类型,而超过23的时候多RTP打包开始用到,此时NALU太大了,决定NALU如何拆分打包进 RTP。(因为NALU 大小有可能远远小于RTP payload,也有可能正好等于RTP payload,或者远大于RTP payload) ,那么NALU 就需要再次拆分包,即一帧拆开发送,拆开发送时,rtp的markbit就可以用上来判断当前这个单元是否为一帧的结束,nalu被拆分的时候,timestamp是不变的

 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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type | |
+-+-+-+-+-+-+-+-+ |
| |
| Bytes 2..n of a Single NAL unit |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

聚合包 nal_unit_type = 24~27

本类型用于聚合多个NAL单元到单个RTP荷载中。本包有四种版本,单时间聚合包类型A (STAP-A),单时间聚合包类型B (STAP-B),多时间聚合包类型(MTAP)16位位移(MTAP16), 多时间聚合包类型(MTAP)24位位移(MTAP24)。赋予STAP-A, STAP-B, MTAP16, MTAP24的NAL单元类型号分别是 24,25, 26, 27;

下图的单时间聚合包

     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

分片单元 nal_unit_type = 28 或者 29

将NALU 单元拆分到多个RTP包中发送 典型的就是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 | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 14. RTP payload format for FU-A

其中FU indicator的格式如下

   +---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+ S:1表示第一包
E:1表示是最后一个包
R:1表示中间
Type:类型

RTP负载PS



H264通常以NALU的方式进行传输,但是H264还有另一种数据组织和传输方式但是使用较少, 其在NALU的基础上又进行了封装,由于每个IDR NALU 前一般都会包含SPS、PPS 等NALU,因此将SPS、PPS、IDR 的NALU 封装为一个PS 包,包括ps 头,然后加上PS system header,PS system map,PES header+h264 raw data。所以一个IDR NALU PS 包由外到内顺序是:PSheader| PS system header | PS system Map | PES header | h264 raw data。对于其它非关键帧的PS 包,就简单多了,直接加上PS头和PES 头就可以了。顺序为:PS header | PES header | h264raw data。以上是对只有视频video 的情况,如果要把音频Audio也打包进PS 封装,也可以。当有音频数据时,将数据加上PES header 放到视频PES 后就可以了。顺序如下:PS 包=PS头|PES(video)|PES(audio),再用RTP 封装发送就可以了。如上图,其中:

  • ES流(Elementary Stream原始流),是音、视频信号经过编码器之后或数据信号的基本码流。只包含一种内容。每个ES都由若  干个存取单元(AU)组成,每个视频或音频AU都是由头部和编码数据两部分组成,1个AU相当于编码的1幅视频图像或1个  音频帧  也可以说,每个AU实际上是编码数据流的显示单元,即相当于解码的1幅视频图像或1个音频帧的取样。
  • PES(Paketized Elementary Stream)是ES经过打包后的码流,长度可变。视频一般一帧一个包,音频一般不超过64KB.
  • PTS--(presentation time stamp)显示时间戳,表示显示单元出现在系统目标解码器(H.264、MJPEG等)的时间。
  • DTS--(Decoding Time Stamp)解码时间戳,表示将存取单元全部字节从解码缓存器移走的时间。
  • PTS和DTS打在PES包头内,是解决音视频同步,防止解码器输入缓存上溢或下溢的关键。每一个pes header都包含pts和dts,是相对SCR(系统参考)的时间戳,以90000为单位,系统时钟频率(H264采样频率)



    最后由rtp将ps包传输出去,RFC2250中建议96 表示PS 封装,建议97 为MPEG-4,建议98 为H264

REF

[h264 基础](https://www.cnblogs.com/jimodetiantang/p/9110647.html)

H264 NALunit

RTP包 NALU FU-A等之间的关系

WEBRTC 接收H264 RTP数据流小结

RTP PS PES ES H264协议学习

RTP Payload Format for H.264 Video

最新文章

  1. win8环境安装.net3.5
  2. Centos6---Fail2ban
  3. poj 2240(floyd)
  4. C++处理一个动态规划的问题
  5. DevExpress后置代码中初始化SQL数据源的方法
  6. C#实现DNS解析服务
  7. 一个小例子讲讲jsonp
  8. iOS中数据库运用之前的准备-简单的数据库
  9. Web 端 js 导出csv文件(使用a标签)
  10. [Python] Codecombat 攻略 Sarven 沙漠 (1-43关)截止至30关
  11. ffempg支持文件解码
  12. Navicat Premium 12.1.16.0安装与激活
  13. 1003 Emergency Dijkstra
  14. OVS-----CentOS7上搭建基于Open vSwitch的VxLAN隧道实验
  15. hibernate validation内置注解及自定义注解
  16. 【SqlServer】Sqlserver中的DOS命令操作
  17. 利用jenkins+saltstack+sh 修改nginx配置文件并重新加载
  18. (转)Python函数式编程——map()、reduce()
  19. android studio build.gradle中 project.ANDROID_BUILD_SDK_VERSION
  20. 使用模拟对象(Mock Object)技术进行测试驱动开发

热门文章

  1. Python文章相关性分析---金庸武侠小说分析-2018.1.16
  2. Jmeter查看结果树之查看响应的13种方法[详解]
  3. JS内置对象Array之reduce()用法
  4. Web基础了解版02-JavaScript
  5. JS 判断移动端 ,跳转
  6. 9月最新184道阿里、百度、腾讯、头条Java面试题合集
  7. 在 ASP.NET Core 中使用 AutoMapper 使 Entity 和 Resource 之间进行映射
  8. java基础- 你真的了解运算符吗?
  9. Java String indexOf()方法
  10. Vue基础系列(五)——Vue中的指令(中)