📄 rfc2508.txt
字号:
个RTP头及其负载)。不过,FULL_HEADER也可以携带IP封装的包,其中可能有两个IP头
及其相应的UDP和RTP。对于IPv6,该包还可能是IPv6和IPv4头的组合。通常每个后续头都
由前一个头的类型字段来指示。
FULL_HEADER包与IPv4或IPv6包的区别在于它必须携带压缩环境ID和4位的顺序号。为了
避免头变大,这些值被插入到IP和UDP头的长度字段中,因为实际的长度可以根据链路层提
供的长度推算出来。这里需要2个16位长的字段:它们来自包中的头两个可用头。对于
IPv4/UDP包,第一个长度字段是IP头总长度字段,第二个字段是UDP头长度字段。对于IPv4
封装包,第一个长度字段为第一个IP头的总长度字段,第二个字段是第二个IP头的总长度字
段。
如5.3.2节所规定,环境ID(CID)和4位顺序号的位置取决于是采用8位还是16位环境ID,
如下图所示(16位宽,左边为最高位):
对于8位环境ID:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1| Generation| CID | 第一长度字段
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0 | seq | 第二长度字段
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
对于16位环境ID:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1|1| Generation| 0 | seq | 第一长度字段
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CID | 第二长度字段
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
第一长度字段的起始位表示CID的长度。CID的长度要么对于所有环境均相同,要么必须
提供两个额外包类型来分别指示COMPRESSED_UDP和COMPRESSED_RTP包格式采用8位还是16位
CID。 对于IP/UDP/RTP压缩方案,第一长度字段的第二位为1表示当前为4位顺序号。
在IPv6的COMPRESSED_NON_TCP包中使用Generation字段方法如[3]所述。IPv4实现不使用
COMPRESSED_NON_TCP包,压缩器应该将generation字段设置为0。为了使IPv4和IPv6操作一
致,当解压器接收到Generation值后就将它存在环境中,并在CONTEXT_STATE包中返回最近
的值。
当接收到一个FULL_HEADER时,接收方将整个头存在由环境ID选择的环境中。4位顺序号
也存在环境中,从而可实现解压器和压缩器的同步。在使用COMPRESSED_NON_TCP包时,顺序
号插入到该包的“Data字段”中,并且D位设置参照[3]的第6节所述。在接收到
COMPRESSED_NON_TCP包后,接收方将Generation号和存在环境中的值进行比较。如果不同,
则环境已经过期,需要用该FULL_HEADER包来进行刷新。如果一致,则压缩的IP和UDP头信息,
顺序号,以及RTP头都存入已保存的环境中。
保存环境所需要的内存数量取决于FULL_HEADER中到底封装了多少个头。最大头的大小可
通过压缩/解压缩双方协商得到。
3.3.2. COMPRESSED_RTP包格式
如果包中RTP头的二次差分值为0,则解压器只需在前一个包的未压缩头上加上存储的一
次差分值就可以重建该包。双方之间只需传输会话环境标识符和顺序号就可以维持同步和检
测出丢失包。
如果包中RTP头某些字段的二次差分值不为0,则要在双方要传输这些字段的新的一次差
分结果的压缩编码。除了要把新的一次差分值加到解压器会话环境的未压缩头上,也要加到
那些二次差分为0的后续包的相应字段上并显式地存储到环境里。每当一次差分改变时,都
要对其进行传输和存储。在实际应用中,唯一需要用到一次差分的字段就是IPv4 ID字段和
RTP时间戳字段。
RTP顺序号字段的增量为1。如果顺序号变化不是1,则必须进行通信以报告该区别,但并
不因此为下一个包重新设置期望的变化值。期望的一次差分值仍然为1,这样如果下一个包
按顺序来到就不用再为变化进行通信。
对于RTP时间戳,当发送FULL_HEADER, COMPRESSED_NON_TCP和COMPRESSED_UDP包刷新RTP
状态时,存储的一次差分初始化为0。如果下一个包的时间戳一样(如相同的视频帧),则二
次差分值为0。否则必须将两个包时间戳的差别作为新的一次差分传输并存入环境中,该值
将被加到解压器环境存储的未压缩头时间戳上。每当后续包的一次差分改变时,都要用该变
化来更新环境。
类似地,由于IPv4 ID字段每次递增1,当用FULL_HEADER刷新状态或以非压缩形式发送携
带ID字段的COMPRESSED_NON_TCP包时,该字段的一次差分初始化为1。然后,每当一次差分
改变其变化都会重传并存到环境中。
这里还用了一个掩蔽码来表示哪个字段发生了非预期变化。除了小链路顺序号外,要在
压缩的IP/UDP/RTP头中进行传输的项列表如下:
I = IPv4包ID (非IPv4头为常数0)
U = UDP校验和
M = RTP标志位
S = RTP顺序号
T = RTP时间戳
L = RTP CSRC记数和列表
如果用4位作为链路顺序号来进行丢失检测,包头中就没有足够的位逐一分配给上面的几
项并填充到一个单字节中随环境ID发送。
因为发送源要么在会话中所有的包里包括UDP校验和,要么就根本不用校验和,所以没必
要显式地携带U位表示UDP校验和的存在。如果以未压缩包头初始化会话状态时其校验和非0,
就说明在所有的后续压缩包中都将插入16位的未编码校验和,直到发送了另一个未压缩包改
变该设置。对于剩余的几项,用于CSRC记数和列表的L位可能是使用频率最低的。与其专门
在掩蔽码中用一位来表示CSRC改变,还不如采用另外一种不常用的位组合。该位组合称为
MSTI。如果IP包ID,RTP标志位,RTP顺序号和RTP时间戳的位都已经被使用,这种特殊情况
表示其后可能有一种扩展形式的压缩RTP包头。该包头将包括一个额外字节,其中含有4位加
上CC记数的实际值。当CSRC列表(长度由CC记数表示)出现在未压缩RTP头中时也将被包含
其中。
假设RTP头中的其余字段(版本, P位, X位, 负载类型和SSRC标识符)都保持相对恒定。
特别地,对于给定的环境SSRC标识符定义为常量,因为SSRC标识符是选择环境的一个因素。
如果任何其它字段发生变化,都必须按照3.3.3节要求发送未压缩RTP包。
下图中,带点划线的压缩IP/UDP/RTP头表示可选字段。最高位为0。多字节字段按照网络
字节顺序发送(最高字节在先)。Delta字段通常如图所示为单字节,但根据具体delta值也可
能为2或3字节,如3.3.4节所解释。
0 1 2 3 4 5 6 7
+...............................+
: 会话环境 ID 的msb : (如果使用16位CID)
+-------------------------------+
| 会话环境 ID 的lsb |
+---+---+---+---+---+---+---+---+
| M | S | T | I | 链路顺序号 |
+---+---+---+---+---+---+---+---+
: :
+ UDP 校验和 + (如果环境中校验和为非0)
: :
+...............................+
: :
+ "RANDOM" fields + (如果被封装)
: :
+...............................+
: M'| S'| T'| I'| CC : (如果MSTI = 1111)
+...............................+
: delta IPv4 ID : (如果I或I' = 1)
+...............................+
: delta RTP 顺序号 : (如果S或S' = 1)
+...............................+
: delta RTP 时间戳 : (如果T或T' = 1)
+...............................+
: :
: CSRC list : (如果MSTI = 1111
: : 并且CC非0)
: :
+...............................+
: :
: RTP 头扩展 : (如果环境中设置了X位)
: :
: :
+-------------------------------+
| |
| RTP 数据 |
/ /
/ /
| |
+-------------------------------+
: 填充 : (如果环境中设置了P位)
+...............................+
如果FULL_HEADER初始化的环境中IPv4头数目多余1,则封装头的IP ID字段必须如[3]所
述按照绝对值形式发送。这些字段标识为"RANDOM"字段。它们按照与原始包中相同的顺序被
插入COMPRESSED_RTP包,如图所示,其后紧接着是UDP校验和或MSTI字节。除非IPv4包正好
在UDP头之前,该头的IP ID才会被区别发送,例如,如果二次差分为0,或者二次差分不为0
但该字段是作为delta IPv4 ID字段它就不占任何位。如果没有IPv4头正好位于UDP头之前,
则I位必须为0且不应存在delta IPv4 ID字段。
3.3.3. COMPRESSED_UDP包格式
如果RTP头中任何一般情况下应为常量的字段(如负载类型字段)发生了变化,则必须发
送一个非压缩RTP头。如果IP和UDP头不需要更新,则该RTP头可以用COMPRESSED_UDP包携带,
而不必用FULL_HEADER包。除了M,S和T为为常数0以及没有相应的delta字段以外,
COMPRESSED_UDP包同COMPRESSED_RTP格式相同:
0 1 2 3 4 5 6 7
+...............................+
: 会话环境ID的msb : (如果使用16位CID)
+-------------------------------+
| 会话环境ID的lsb |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | I | 链路顺序号 |
+---+---+---+---+---+---+---+---+
: :
+ UDP 校验和 + (如果环境中校验和非0)
: :
+...............................+
: :
+ "RANDOM" 字段 + (如果被封装)
: :
+...............................+
: delta IPv4 ID : (如果I = 1)
+-------------------------------+
| UDP 数据 |
: (非压缩RTP ) :
请注意,这里IP/UDP头的压缩形式和[3]中定义的COMPRESSED_NON_TCP包类型不同。其目
的是象IPv4所允许的那样,当禁用UDP校验和时使压缩目标达到2字节。[3]中定义的协议没
有使用UDP包的差分编码,所以在用于IPv4时,除了前面的两个压缩字节,还有两个字节的
IP ID和两个字节的非0 UDP校验和都要进行传输。对于IPv6,可使用COMPRESSED_NON_TCP包
类型来替代。
3.3.4.差分编码Encoding of differences
COMPRESSED_RTP和COMPRESSED_UDP包的delta字段为变长编码,可将压缩数据映射到更多
的通常使用值。下面规定了一种优化的哈夫曼编码作为缺省编码,推荐在实现表驱动delta
编/解码器来为会话进行面向表协商时使用。针对一定范围内数据的测试表明,在合理的表
规模下基于对位流进行顺序解释的编码执行速度比非表驱动的实现要快,这种缺省表和哈夫
曼编码就是例子。缺省delta编码规范见下表。该编码在IP ID和RTP顺序号变化很小的情况
下可高效编码,此时压缩器发出的包丢失,但仍能将大多数音视频deltas保持为2字节。左
边的列是要编码的10进制数,右边的列是16进制显示的编码后按发送顺序排列(网络字节顺
序)的字节序列。其中显示了相临范围的首尾值,其余均省略:
十进制 16进制
-16384 C0 00 00
: :
-129 C0 3F 7F
-128 80 00
: :
-1 80 7F
0 00
: :
127 7F
128 80 80
: :
16383 BF FF
16384 C0 40 00
: :
4194303 FF FF FF
对于正数,在一个字节内直接以0到127表示。如果该字节的最高两位是10或者11,则表示
分别表示要扩展到2或3个字节。低6位按照降序同后面紧跟的1到2个字节联合表示一个14或
22位值。
当包出现乱序或者在MPEG视频的RTP时间戳故意被打乱时可能会出现负数的delta值。这
种情况很少见,所以负数值编码范围更小,仅使用表中正数值剩余的部分。
RTP时间戳值中小于-16384或大于4194303的改变都会导致强制发送未压缩的
FULL_HEADER, COMPRESSED_NON_TCP或COMPRESSED_UDP类型RTP头。IP ID和RTP顺序号字段都
只有16位,所以这些字段的负数delta都掩蔽为16位再进行编码(作为16位正数)。
3.3.5.错误恢复
除了由FULL_HEADER和COMPRESSED_NON_TCP包设置外,当特定环境的4位顺序号增量不为1
时,解压器必须将环境置为无效并发送CONTEXT_STATE包回压缩器表示环境已经无效。无效
环境的所有当前包都必须丢弃,直到收到一个FULL_HEADER或COMPRESSED_NON_TCP重建稳定
状态为止(除非使用了本节后面将描述的"twice"算法。)。由于在这一过渡时期可能会有
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -