实时视频系统中的媒体传输,绝大多数都会采用RTP(实时传输协议)标准。H.264视频做为当前应用最普遍的视频编码标准,其传输协议也会首选RTP标准。在设计实现H.264的实时传输时,H.264协议基于RTP的打包和解包定义于IETF标准-RFC6184,RTC系统须要遵循这个标准来设计打包和解包处理模块。在通讯理论中,这个过程能够被认为是基于传输的信道编码。本篇技术文章带你了解H.264在RTP中的基本格式和技术实践。markdown
#01 基本格式ide
使用RTP对H.264打包和解包须要遵循IETF标准RFC6184, 咱们先来了解一下H.264在RTP中的封包协议。 01 H.264的RTP报头编码
图1 RTP报头spa
对于H.264的RTP负载格式而言,RTP报头的格式和RFC 3550里面的定义是一致的,不过有一些字段须要特别说明一下。 标记位 (M):1位 对RTP时间戳所对应访问单元的最后一个数据包来设置标记位,符合视频中M位的正常使用格式,以容许有效的播放缓冲处理。解码器可使用这个位做为访问单元最后一个数据包的早期指示,可是不能彻底依赖这个属性。 负载类型 (PT):7位 没有特别指定的负载类型,须要经过协商来肯定。 序列号(SN):16位 根据RFC 3550设置和使用。对于单NAL单元和非交错打包模式,序列号用于肯定NAL单元的解码顺序。 时间戳:32位 RTP时间戳设置为视频内容的采样时间戳。必须使用90 kHz时钟频率。 02 H.264的RTP负载类型设计
H.264的RTP负载可分为三大类,类型以下:code
单个NAL单元数据包: 此类RTP负载中仅包含单个NAL单元。负载报头类型编号等于原始NAL单元类型,即从 1 到 23 的范围值,详见H.264规范。orm
聚合数据包: 此类型用于聚合多个NAL单元成为单个 RTP 负载。这类数据包有四个细分版本:单时间聚合包A (STAP-A)、单时间聚合包B (STAP-B)、16位偏移多时间聚合包 (MTAP16) 和24位偏移多时间聚合包 (MTAP24)。负载类型编号分配给 STAP-A、STAP-B、MTAP16 和 MTAP24 的值分别为 2四、2五、26 和27。视频
分片单元: 用于将单个NAL单元分片到多个RTP 数据包。存在两个版本:FU-A 和 FU-B,负载类型编号分别为 28 和 29。排序
表1 H.264负载类型 03 H.264的RTP打包模式图片
H.264的RTP打包模式有三种: 单NAL单元模式
全部的接收端都必须支持这种模式,主要应用于兼容低时延应用中的硬件设备。只有单NAL单元数据包能够在这种模式下使用。
非交错模式
建议接收端去支持这种模式,主要应用于低时延应用。只有单NAL单元、STAP-A和FU-A数据包能够在这种模式下使用。
交错模式
有需求的接收端能够去支持这种模式,主要应用于非低延时应用。STAP-B、两种MTAP、FU-A和FU-B数据包能够在这种模式下使用。
表2 H.264打包模式容许的负载类型 单NAL单元和非交错模式中,NAL单元必须以NAL单元解码顺序传输,这两种模式更适合低延时需求的交互系统。
交错模式中NAL单元的传输顺序和解码顺序能够是不一致的,致使接收端的解包过程当中须要按照解码顺序从新排序,引入更多的时延,所以并不适合须要低时延的交互系统。
04 H.264的RTP负载报头
图2 H.264的RTP负载报头 H.264的RTP负载报头位于负载的第1个字节,分红三个字段:
F:1位 forbidden_zero_bit。值为 0 表示NAL单元类型字节和负载不该包含位错误或其余语法违规。值为 1 表示NAL单元类型字节和负载可能包含位错误或其余语法违规。 NRI:2位 nal_ref_idc。00值和非零值的语义与H.264规范保持不变。值00表示NAL单元的内容不是用于重建图片间预测的参考图片,这样的NAL单元能够被丢弃并不会致使参考图片的不完整。值大于00表示须要对NAL单元进行解码以保持参考图片的完整性。 类型:5位 负载类型,包括表1里面列举的全部类型。 05 H.264的RTP负载格式
由于只有单NAL单元模式和非交错模式打包模式更适合应用于低时延交互系统中,而这两种打包模式所涉及的只有单NAL数据包、单时间聚合包A(STAP-A)和分片单元A(FU-A)三种RTP负载,因此在这里只对这三种负载格式作个简单的介绍。
单NAL数据包
图3 单NAL数据包负载格式 单NAL数据包就是将原始的NAL单元直接放置到RTP的负载中,NAL单元头就是做为单NAL数据包的负载类型。
单时间聚合包A(STAP-A)
图4 聚合数据包负载格式 聚合数据包的负载中包含一个或者多个聚合单元。一个聚合包能够携带尽量多的聚合单元;不过聚合数据包中的总数据量应该选择合适大小,以便生成的IP数据包小于MTU大小。聚合数据包负载报头中的NRI字段的值必须是全部聚合NAL单元中最大值。
图5 单时间聚合单元格式 STAP-A数据包中,每一个聚合单元的NAL都应该是共享相同的NALU时间。负载的首字节是STAP-A负载报头,每一个聚合单元是由两字节的NAL单元尺寸字段和原始NAL单元组成。若是STAP-A数据包中包含两个聚合单元,负载格式以下图:
图6 包含两个聚合单元的STAP-A数据包示例 分片单元A(FU-A)
图7 FU-A数据包负载格式 FU-A数据包的负载包含1字节的分片单元标识(负载报头)、1字节的分片单元报头和分片单元负载。分片单元负载报头中的NRI字段的值等同于被分片NAL单元的值。 分片单元报头的格式以下:
图8 分片单元报头 S: 1 位 起始位。当设置为 1 时,指示一个分片NAL 单元的开始。当 FU 负载不是分片NAL单元的开始片断,设置起始位为 0。 E: 1 位 结束位。当设置为 1 时,指示一个分片NAL单元的结束。当 FU负载不是分片NAL单元的最后一个片断,设置结束位为 0 。 R: 1 位 保留位。必须等于 0,而且必须被接收者忽略。
类型:5位 被分片的原始NAL单元类型(1 - 23)。
#02 实践分享
RTC系统中的视频处理的结构大体以下图,RTP打包解包是视频编解码和传输之间的桥梁。
图9 视频流工做流程
01 H.264打包
H.264的打包的基本流程大体以下:
输入H.264 NAL,判决当前的H.264 NAL的打包格式,能够选择单NAL单元包格式、STAP-A包格式,或者是FU-A格式。MTAP格式通常不在实时系统中使用,考量的重点在于兼顾打包效率和传输效率。 Single-NAL-Unit 打包比较简单,一个NAL封装为一个RTP包。 STAP-A在NAL包比较小的时候采用,多个相同时间戳的NAL包被打到一个RTP包。 FU在NAL包比较大的时候采用,限制RTP包的大小小于MTU。一个NAL包被拆成多个碎片(Fragment), 碎片被打成RTP包。
02 H.264解包
在此只对三种打包模式下的解包过程作一个大体的介绍。
单NAL单元和非交错模式 接收端包括一个接收缓冲器来补偿传输延迟和抖动。接收端将传入的数据包按照接收顺序存储到接收缓冲器中。数据包按RTP序列号的顺序被解包。若是解包的数据包是单个NAL单元包,包中包含的NAL单元直接传递给解码器。若是解包的数据包是 STAP-A,则包含在数据包中的NAL单元按照它们封装在数据包中的顺序被传递给解码器。对于全部 FU-A包含单个NAL单元片断的数据包,解包的片断按其发送顺序恢复出NAL单元,而后传递给解码器。 交错模式 交错模式的解包规则通常是从传输顺序到解码顺序来从新排序NAL单元。在实时系统中应用比较少见,具体过程在此就不展开了。
参考文献
一、RFC 3550 – RTP: A Transport Protocol for Real-time Application
二、RFC 6184 – RTP Payload Format for H.264 Video