RTSP系列三:RTP协议介绍

我的音视频/流媒体开源项目(github)

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字节长度数据。

        

猜你喜欢

转载自blog.csdn.net/weixin_43147845/article/details/140920183