RTSP系列:
RTSP系列一:RTSP协议介绍-CSDN博客
RTSP系列二:RTSP协议鉴权-CSDN博客
RTSP系列三:RTP协议介绍-CSDN博客
RTSP系列四:RTSP Server/Client实战项目-CSDN博客
目录
一、基本概念
二、RTP报文格式
三、RTP封装视频
3.1、RTP封装H264
3.1.1、单一封包模式
3.1.2、组合封包模式
3.1.3、分片封包模式
3.1.4、RTP抓包分析
3.2、RTP封装H265
四、RTP封装音频
4.1、RTP封装AAC
4.2、RTP打包PCMA
五、RTP扩展头部
一、基本概念
一种数据数据传输协议,RTP 协议实际上是由实时传输协议RTP(Real-time Transport Protocol)和实时传输控制协议RTCP(Real-time Transport Control Protocol)两部分组成。
RTP 协议基于多播或单播网络为用户提供连续媒体数据的实时传输服务;RTCP 协议是RTP 协议的控制部分,用于实时监控数据传输质量,为系统提供拥塞控制和流控制。 由于TCP 需要较多的开销,故不太适合传输实时数据。在流式传输的实现方案中,一般采用RTSP/TCP 来传输控制信息,而用RTP/UDP 来传输实时声音数据(也可以用RTP/TCP)。RTP也属于应用层协议,与RTSP的关系如下图所示:
RTP传输音视频过程如下:
二、RTP报文格式
RTP报文格式如下:
*版本号(V):2比特,用来标志使用的RTP版本。
*填充位(P):1比特,如果该位置位,则该RTP包的尾部就包含附加的填充字节。
*扩展位(X):1比特,如果该位置位的话,RTP固定头部后面就跟有一个扩展头部。
*CSRC计数器(CC):4比特,含有固定头部后面跟着的CSRC的数目。
*标记位(M):1比特,该位的解释由配置文档(Profile)来承担.
*载荷类型(PT):7比特,标识了RTP载荷的类型。
*序列号(SN):16比特,发送方在每发送完一个RTP包后就将该域的值增加1,接收方可以由该域检测包的丢失及恢复包序列。序列号的初始值是随机的。
*时间戳:32比特,记录了该包中数据的第一个字节的采样时刻。在一次会话开始时,时间戳初始化成一个初始值。即使在没有信号发送时,时间戳的数值也要随时间而不断地增加(时间在流逝嘛)。时间戳是去除抖动和实现同步不可缺少的。
*同步源标识符(SSRC):32比特,同步源就是指RTP包流的来源。在同一个RTP会话中不能有两个相同的SSRC值。该标识符是随机选取的 RFC1889推荐了MD5随机算法。
*贡献源列表(CSRC List):0~15项,每项32比特,用来标志对一个RTP混合器产生的新包有贡献的所有RTP包的源。由混合器将这些有贡献的SSRC标识符插入表中。SSRC标识符都被列出来,以便接收端能正确指出交谈双方的身份。
符号 | 位数 | 定义 | 数值 |
V | 2bit | 版本号 | 2 |
P | 1bit | 填充位 | 0 |
X | 1bit | 扩展位 | 0 |
CC | 4bit | CSRC数目 | 0 |
M | 1bit | 标志位 | 当RTP负载是一个完整的NALU时M 位置为 1;当前RTP 数据包为一个NALU 的最后的那个分片时(NALU 的分片在后面讲述),M位置 1。其余情况下M位保持为 0。 |
PT | 7bit | 载荷类型 | 负载类型(音视频负载,类型在SDP中描述) |
SeqNum | 16bit | 序列号 | 每发一个包加1 |
Timestamp | 32bit | 时间戳 | 单一封包 +采样率,h264为3600; 分片封包第一个加采样率,后续不变 |
SSRC | 32bit | 同步源标识 | 任意指定,标准是一个MD5算法值,未明 |
CSRC | 0bit | 贡献源列表 | CC为0,所以此项没有 |
一个RTP数据包定义如下:
三、RTP封装视频
3.1、RTP封装H264
首先看一下H264 NALU头部定义:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
F: 1 个比特. 一般为0 forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.
NRI: 2 个比特. nal_ref_idc. 取 00 ~ 11, 指示nalu单元的重要性,, 如 00 的 NALU 解码器可以丢弃而不影响图像的回放. 不过一般情况下不太关心这个属性.
Type: 5 个比特.nal_unit_type. 这个 NALU 单元的类型.
RTP打包原则
RTP的包长度必须要小于MTU(最大传输单元),IP协议中MTU的最大长度为1500字节。除去IP报头(20字节)、UDP报头(8字节)、RTP头(12字节),所有RTP有效载荷(即NALU内容)的长度不得超过1460字节。TCP(20字节)
RTP有三种封包模式:单一封包模式,组合封包模式,分片封包模式
3.1.1、单一封包模式
对于 NALU 的长度小于 MTU 大小的包, 一般采用单一 NAL 单元模式。对于一个原始的 H.264 NALU 单元打包时去除 "00 00 01" 或 "00 00 00 01" 的开始码, 把其他数据封包的 RTP 包即可.
如有一个 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 个字节的开始码就可以了。
3.1.2、组合封包模式
当 NALU 的长度特别小时, 可以把几个 NALU 单元封在一个 RTP 包中.这里只介绍STAP-A模式
如有一个 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 ... ]
3.1.3、分片封包模式
当NALU的长度超过MTU时,就必须对NALU单元进行分片封包.也称为Fragmentation Units(FUs).
高三位--F、NRI:与NALU第一个字节的高三位相同--F、NRI, Type:28
S:标记该分片打包的第一个RTP包 E:该分片打包的最后一个RTP包Type:NALU的Type
FU payload就是去掉起始码和头部的NALU。
3.1.4、RTP抓包分析
RTP封包常用的就是单一封包模式和分片模式,组合封包模式几乎不用。
RTP,序列号-每发送一个数据包就+1,时间戳--SPS/PPS时间戳不变、属于同一NALU的分片数据包时间戳不变,其余时间戳+90000/25
SDP(会话协议)文件描述和视频封包的关联:
m=video 49170 RTP/AVP 98
a=rtpmap:98 H264/90000
a=fmtp:98;profile-level-id=42A01E;packetization-mode=1;sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
packetization-mode: 表示支持的封包模式.
当 packetization-mode 的值为 0 时或不存在时, 必须使用单一 NALU 单元模式.
当 packetization-mode 的值为 1 时必须使用非交错(non-interleaved)封包模式.
当 packetization-mode 的值为 2 时必须使用交错(interleaved)封包模式.
回顾H264类型:
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负载类型头中
如下表所示,每个打包方式允许的NAL单元类型总结(yes = 允许, no = 不允许, ig = 忽略)
Type | Packet | Single NAL Unit Mode | Non-Interleaved Mode | Interleaved Mode |
0 | undefined | 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 | undefined | ig | ig | ig |
用wireshark抓取的RTP数据包如下所示:
3.2、RTP封装H265
首先看一下H265 NALU头部定义:
F: 1 bit. forbidden_zero_bit. 265要求是0,是1的话指示语法违规等.
Type: 6 bits. Nal类型. vps是32, sps是33, pps是34, 前缀sei是39. IDR是19和20.
LayerId: 6 bits. nuh_layer_id. 现在是0,将来可能扩展用.
TID: 3 bits. nuh_temporal_id_plus1. TemporalId 是TID-1.
H265和H264打包模式类似,都是单一封包或分片封包。单一封包和H264完全一样,分片封包略有不同,如下图所示,为H265分片封包格式。
PayloadHdr还是拷贝NAL单元头,但是要把Type换成49。FU header 就一个字节,格式如下:
S:为1表示第一个分片。 E:为1表示表示最后一个分片。FuType就是实际的Nal type类型。
四、RTP封装音频
4.1、RTP封装AAC
RTP封装AAC部分参考:RFC3640中对AAC进行RTP打包方式介绍-CSDN博客
AU概念:在audio stream中就是一个audio frame。
一个rtp包携带一个AU
对应音频数据,就是携带一个audio frame
一个rtp包中携带多个AU
一个编码后的audio frame通常是比较小的(通常是100~300的字节),一个rtp(通常是1000个字节以上)通常是可以携带多个audio frame
一个rtp包中可携带一个AU的片段
多个rtp包携带一个AU,类似RTP打包的H264/265 FU-A模式,这种情况是针对视频等大数据量的码流。对音频来说,是不会出现这种情况的。
RTP封装AAC格式如下:
这里要注意的是,这些字段并不是固定出现的字段(按需携带,可有可无),所以码流结构图描述只是字段的名字,并没有给出字段的位数(位数也是可变的)。这个跟常见的码流结构定义不一样,比如rtp for h264/h265 rfc中,对字段名和位数都进行详细的规定。一个RTP包中可能包含多个AU,多个AU的头信息都被集中放在AU Header Section中。AU Header Section中有几个头信息则有几个AU。
下面逐一对字段意思进行解释。
AU Header Section
下图是其结构图,其中包含的字段也是可变的(字段可有可无,长度可变)
AU Header Section = AU-Headers-lengths + AU-header + Padding Bit
AU-header 可以有0~n个,AU-Headers-lengths为0个时则整个AU Header Section都不会携带。一个AU-header对应一个AU,AU-header中包含对应AU解码所需的一些参数信息。
AU-Headers-Lengths 固定的两个字节的长度,表示AU-Headers的总长度(单位是位),所以AU-Headers所占的字节数=AU-Headers-Lengths/8
Padding Bits: 所有的Au-Header的总长度必须是整数个字节,如果不够则添加Padding Bit
AU-header定义如下:
如上图所示为AU-header的结构及字段意义,AU-Size,AU-Index,AU-Index-delta为固定字段,其余的几个字段都是码流的参数信息,这些字段都是按需出现的。如果MIME format parameter中携带了对应的属性说明(SDP中),则就存在对应的字段。
- AU-size:就是整个数据帧的长度
- AU-Index: Indicates the serial number of the associated Access Unit
- AU-Index-delta:就是AU-Index
关于AU-Index和AU-Index-delta,用在AU fragement(或interleaving模式)情况下,RTP payload携带的是AU的分片,那么AU-Index/AU-Index-delta就是标识分片的顺序(以加1递增)。那么除此之外,AU携带一个可解码的完整的audio frame时,AU-Index/AU-Index-delta填0即可)
SDP和AAC的关联
打包AAC
通过RTP打包AAC,需要结合一种协议携带Format Parameters。最常用的是sdp,rfc 3640定义了一些具体模式的约束。这里我们主要是关心携带AAC的情况。
在 section 3.3.5和3.3.6分别描述了 Low Bit-rate AAC 和 High Bit-rate AAC sdp所应携带的信息
- Low Bit-rate AAC
rfc中给出如下约束:
1.The maximum size of an AAC frame in this mode is 63 octets(AAC帧的最大长度是63个字节)
2.AAC frames MUST NOT be fragmented when using this mode(这种模式下不可携带AAC 帧片段)
sdp携带参数信息的例子:
m=audio 49230 RTP/AVP 96
a=rtpmap:96 mpeg4-generic/22050/1
a=fmtp:96 streamtype=5; profile-level-id=14; mode=AAC-lbr; config=
1388; sizeLength=6; indexLength=2; indexDeltaLength=2;
constantDuration=1024; maxDisplacement=5
- High Bit-rate AAC
这种模式下AAC frame的长度有约束,最大长度为8191个字节(音频数据不会有这么大)
sdp携带参数信息的例子
m=audio 49230 RTP/AVP 96
a=rtpmap:96 mpeg4-generic/48000/6
a=fmtp:96 streamtype=5; profile-level-id=16; mode=AAC-hbr;
config=11B0; sizeLength=13; indexLength=3;
indexDeltaLength=3; constantDuration=1024
这两种模式的区别就是AAC Frame的大小限制。是用Low Bit-rate模式还是High Bit-rate模式,取决于AAC的编码格式。sizeLength,indexLength,indexDeltaLength,这3个属性值分别描述的是AU-header中AU-size,AU-index,AU-index-delta字段所占的字节数。是一定会携带的,
其它属性则是跟码流的参数相关的,比如config等。对于AAC config是一定要带的,这是有音频的采样率、通道数、编码级别按照一定格式编码而成的。
4.2、RTP打包PCMA
RTP打包PCMA相对简单,RTP payload就是PCMA的一帧数据。
五、RTP扩展头部
RTP扩展头参考:RTP包头扩展_rtp 扩展字段-CSDN博客
如果RTP Header中X字段为1,说明后面跟着RTP Header Extension。RTP Header Extension结构如下:
- defined by profile:决定使用哪种Header Extension:one-byte或者two-byte header
- length:表示Header Extension的长度:length x 4字节
如果不关心扩展头部,解析出length就可以把扩展头部跳过,解析RTP payload获取音视频了。
One-Byte Header
对于One-Byte Header,"defined by profile"字段为固定的0xBEDE。接着后面的结构如下:
- ID:4-bit长度的ID表示本地标识符
- len:表示extension data长度,范围:0~15,为0表示长度为1字节,15表示16字节
RTP扩展头示例:
首先是0xBEDE固定字段开头,接着length长度为3,说明后面跟着3x4字节长度的header extension 。对于第一个header extension:L=0,表示data长度为1字节。对于第二个header extension:L=1,表示data长度为2字节。由于按4字节对齐,所以接着是值为0的填充数据。最后一个header extension:L=3,表示data长度为4字节。
Two-Byte Header
首先"defined by profile"字段为0x1000,length为3,后面跟着3x4字节长度扩展,对于第一个header extension:L=0,数据长度为0,对于第二个header extension:L=1,data长度为1,接着是填充数据,对于第三个header extension:L=4,后面跟着4字节长度数据。