音视频 RED 与 FEC 的 RTP 格式封装[通俗易懂]

音视频 RED 与 FEC 的 RTP 格式封装[通俗易懂]音视频冗余数据的RTP格式封装背景RTP格式(RFC3550)RED数据(RFC2198)背景知识REDRTP格式REDSDP协商一般FEC的RTP载荷格式(RFC2733)基本原理GenericFEC方案GenericFECRTP格式FEC生成与恢复FEC生成示例FEC作为冗余编码使用FECSDP协商FEC作为独立流传输FEC作为冗余编码传输ULPFE…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

背景

对于语音通信来说,语音的码率较低,添加适当的冗余是对抗网络丢包常见的方式。冗余方式分为多种,包括数据冗余,或者编码冗余等,RED,FEC等都是冗余的一种。如果冗余分数较多,可以采取交织的方式实现。RFC 2198 是冗余数据 RTP 封装的标准协议,RFC 3550 为RTP的基础标准协议,RFC 5109 为FEC数据的 RTP 封装标准协议。webrtc中有RED和FEC相关的实现与处理,这也是在看代码时才决定重新整理协议并记录下来。

RTP格式 (RFC 3550)

RTP(Real- time Transport Protocol,实时传输协议)是在互联网上常见的一种处理媒体数据流的网络协议,包括单播或者多播等多种场景下的网络环境中媒体数据的传输。RTP是一种应用层协议,一般使用 UDP作为底层协议实现数据传输,但并不强制底层协议的选择,比如利用 RTSP进行流媒体传输时使用 TCP也非常常见。

RTP本身没有提供任何的机制来确保实时的传输或其他的服务质量保证,而是由低层的服务来完成。它不保证传输或防止乱序传输,它不假定下层网络是否可靠,是否按顺序传送数据包。

RTP 一般与 RTCP 同时出现,端口号相邻。RTCP 主要用来提供数据传输质量的反馈,通过发送接收信息估算当前网络状态,调整数据流。RTCP 为每个RTP源传输一个固定的识别符,CNAME。当 SSRC 因重启或者冲突发生改变时,可以根据 CNAME 跟踪参与者,或者用CNAME来关联一系列相关RTP会话中来自同一个成员的多个数据流,例如同步语音和图像。当会议时,参与方过多时,需要控制 RTCP流的快速增长,一般以不超过总占用带宽的 5%。

本文主要是 RTP 的封装,所以仅仅讨论 RTP,协议格式如下:

    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             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中,主要的协议字段说明如下:

  1. V:version,2 bits, RTP协议版本号,缺省版本号为2, 值 0,1 已经被使用,如 1 用于第一个草案版本,。
  2. P:padding,1 bit, 填充标志。如果 P=1,则在该报文的尾部填充一个或多个额外的填充数据,它们不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充比特。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个RTP包。
  3. X:extension,1 bit,扩展标志。如果 X=1,则在 RTP 报头后将有且仅有一个扩展报头。
  4. CC:CSRC count,4 bits,CSRC 计数器,标识 CSRC 标识符的数量。
  5. M:marker,1 bit,由具体协议解释其意义。它用来允许在比特流中标记重要的事件,如音视频帧边界。
  6. PT:payload type,7 bits,载荷格式,可以用来区分多路音视频流。接收方必须忽略不理解的 PT 值的数据包。
  7. sequence number:16 bits,序列号,每发送一个 RTP 数据包,序列号加 1,接收端可以据此检测丢包和重建包序列。
  8. timestamp:32 bits,时间戳。反映了 RTP 数据包中第一个字节的采样时间。时间戳的初始值应当是随机的,类似序号。时钟频率依赖于负载数据格式,所以时间戳增量依据当前数据格式与策略。如果RTP包是周期性产生的,那么将使用由采样时钟决定的名义上的采样时刻,而不是读取系统时间。
  9. SSRC:Synchronization source,32 bits,同步源。RTP 包流的源,使其不依赖于网络地址。一个同步源的所有包构成了相同计时和序列号空间的一部分,这样接收方就可以把一个同步源的包放在一起,来进行重放。SSRC 标识符是一个随机值,它在特定的RTP会话中是全局唯一。一个同步源可能随着时间变化而改变其数据格式,如音频编码。
  10. CSRC:Contributing source,0~15 项,每个 32 bits,作用源。若一个 RTP 流的源,对由 RTP 混频器生成的组合流起了作用,则它就是一个作用源。对特定包的生成起作用的源,其SSRC标识符组成的列表,被混频器插入到包的RTP报头中,这个列表叫做CSRC表。相关应用的例子如,在音频会议中,混频器向所有的说话人(talker)指出,谁的话语(speech)将被组合到即将发出的包中,即便所有的包都包含在同一个(混频器的)SSRC标识符中,也可让听者(接收者)可以清楚谁是当前说话人。

RED数据(RFC 2198)

背景知识

RTP 本身并不提供任何质量保证措施,所以面对网络扰动时,常常表现的不如人意。所以考虑在通信过程中添加冗余数据,即使存在丢包,也可以在一定程度上进行恢复。RFC 2198 主要针对音频数据,在常见的实现中,如 webrtc 中,也是对于音频数据采用该标准协议。

对协议产生需求来说,主要存在以下几个方面:

  1. 每个包必须携带一个主编码数据,以及一个或多个冗余编码数据。
  2. 冗余信息可以存在多种方式,但是每一个冗余块必须有一个编码类型标识。
  3. 可能存在变长编码,所以每个编码块都存在长度标识。
  4. 每个编码块都有自己的时间戳,对于冗余块,可以参考与主编码块的时间戳差值。

RED RTP 格式

处理方式有增加 RTP header 扩展或者采用新的一个或多个负载类型,即 PT来标识。鉴于使用扩展头会带来更多的限制,所以建议采取新增负载类型的方式,静态分配或动态分配都可以。在RTP 中,冗余头格式如下:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |F|   block PT  |  timestamp offset         |   block length    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

相关字段说明如下:

  1. F:1 bit,标识后面是否还存在其他的头块。设置为 1 标识存在,0 标识不存在,此为最后一个头块。
  2. block PT:7 bits,此数据块的 RTP payload type。
  3. timestamp offset:14 bits,相对于 RTP header中时间戳的偏移量。使用 unsigned 表示主数据以发送。
  4. block length:10 bits,对应数据块的有效负载长度,不包含头长度。

主编码块头位于整个包头的最后,PT 与 timestamp 参考RTP头中的值,所以格式如下:

                      0 1 2 3 4 5 6 7
                     +-+-+-+-+-+-+-+-+
                     |0|   Block PT  |
                     +-+-+-+-+-+-+-+-+

               The primary encoding block header

最后一个头之后就是数据块,存储顺序和头的排列顺序相同。数据块之间不需要填充或者使用其它分隔,一般不需要32位对齐。如此选择仍是为了在损失一定额外解码时间的情况下降低带宽负担。举例如下,一个音频数据包包含 DVI4 (8KHz) 主编码,和一个 8KHz LPC (both 20ms) 的冗余编码包:

    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=0  |M|      PT     |   sequence number of primary  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              timestamp  of primary encoding                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1| block PT=7  |  timestamp offset         |   block length    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0| block PT=5  |                                               |
   +-+-+-+-+-+-+-+-+                                               +
   |                                                               |
   +                LPC encoded redundant data (PT=7)              +
   |                (14 bytes)                                     |
   +                                               +---------------+
   |                                               |               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               +
   |                                                               |
   +                                                               +
   |                                                               |
   +                                                               +
   |                                                               |
   +                                                               +
   |                DVI4 encoded primary data (PT=5)               |
   +                (84 bytes,not to scale)                       +
   /                                                               /
   +                                                               +
   |                                                               |
   +                                                               +
   |                                                               |
   +                                               +---------------+
   |                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

RED SDP 协商

在收发双方进行通信协商时,需要通知双方的 SDP 协商完成信息交互,协议中建议的SDP 形式如下:

       m=audio 12345 RTP/AVP 121 0 5
       a=rtpmap:121 red/8000/1
       a=fmtp:121 0/5

其中,121 为冗余编码的 PT值,0 为PCM,主编码,5 为 DVI4,第二编码。a=fmtp 行只有在指定编码有效时才可使用,否则,不出现这一行。一般情况下,可以与主编码保持一致。

一般FEC的RTP载荷格式 (RFC 2733)

在 Internet 中,语音质量表现不佳的主要原因在于高丢包率,在广域网中尤其突出。更不幸的是,实时多媒体通信过程中对时延的严格要求导致通过重传来解决这个问题难以实现。也正是基于此,FEC 才被考虑解决丢包的问题,特别时传统纠错码如校验码、RS码、汉明码等的使用引起了很多人的注意。为了能够更好地应用这些纠错码,必须有相关的协议来支持。

RFC 2733 定义了一种传输实时媒体数据的一般性的 RTP 的载荷格式。一般性意味着,

  1. FEC 协议独立于它保护的媒体数据,可以是音频,视频或者其他;
  2. 具有足够的灵活性以支持不同的 FEC 机制;
  3. 自适应的设计,使得 FEC 技术修改但不影响带外传输的信令;
  4. 支持许多不同的传输FEC 包的机制.

基本原理

RFC 2733 载荷格式支持基于异或校验算法的 FEC 机制。发送端在媒体流中取出一些包,并对其负荷,以及 RTP 头中的组件进行异或操作,得到包含 FEC 信息的 RTP 包。产生的FEC 包可以在接收端恢复关联到这个 FEC 包的任何一个包。实际中使用时,其实是overhead,时延以及恢复能力之间的一种平衡。

为了能正常恢复,发送方还需要在载荷格式中携带信息,包括哪些媒体包用来生成 FEC 包。每个 FEC 中包含一个24 位的掩码 mask,如果第 i 位被设置为 1,表示序号 N + 1 的媒体包被用来生成这个FEC 包,其中,N 为 base SN,也将被包含在 FEC 载荷格式中。接收端也可以在不了解具体就纠错码的细节使用 FEC,允许发送端具有较大的灵活性,可以根据网络环境进行自适应的编码,而接收端仍能正常恢复。

媒体流从发送端发送到接收端,不管是否存在FEC 包,FEC 包在生成后也立即发出,接收端即使不支持 FEC,也不影响媒体流的正常接收。但是也存在一些FEC 纠错码,不传输原始媒体流,只使用 FEC 流就可以恢复,缺点是要求所有接收者必须支持 FEC。

FEC 包不与媒体包在同一个RTP 流中发送,以一个单独的流进行发送,或者作为作为一种冗余编码中次编码发送(参见RFC 2198)。当作为单独流发送时,FEC 包具有独立的序列号空间,但时间戳从对应媒体包得来,单调递增。FEC 包流支持任何固定差值的包头压缩机制。对接收端来说,如果没有丢包,则忽略FEC 包,如果丢包出现,则FEC 将联合接收到的关联生成的媒体包组,完全恢复丢失的媒体包。

Generic FEC 方案

定义函数 f(x,y,…) 为对包x,y,…等的异或操作,被叫做奇偶校验包,也被称作监督包。为简单起见,假设监督包就是输入的各个包的按位异或得到。而使用校验包对数据包进行恢复是通过产生这些校验包的这一组数据包完成,这一组数据包必须是线性无关的。这个特定的组合就被称为一个奇偶校验码。一组 k 个数据包,生成 n-k 个校验包。对于给定的 n 和 k,可能存在大量可能的校验包,荷载格式并未要求使用某个特定的校验包。

举例来说,比如两个数据包,产生一个校验包,原始数据包 a,b,c,d,发送端产生包如下所示,时间从左到右。如果 b 丢失,可以通过a 和 f(a,b) 恢复。

   a        b        c        d               <-- media stream
              f(a,b)            f(c,d)        <-- FEC stream

其他的校验码产生方式如下所示:

方案1:

  a        b        c        d        e        <-- media stream
    f(a,b)   f(b,c)   f(c,d)   f(d,e)          <-- FEC stream

方案 1 可以恢复连续两个丢包。

方案2:

 f(a,b)  f(a,c)  f(a,b,c)  f(c,d)  f(c,e)  f(c,d,e)  <-- FEC stream

方案2不发送媒体流,直接发送 FEC 流,通过 FEC 流就可以恢复所有的数据包。好处是占用带宽小一些,能对付单个丢包和部分连续丢包。

方案3:

 a         b          c                    d     <-- 媒体流
             f(a,b,c)    f(a,c,d) f(a,b,d)       <-- FEC流

方案 3 恢复包时需要等待4个发包时间间隔。好处是可以恢复单个丢包和连续丢包。

Generic FEC RTP 格式

如果FEC 作为独立流发送,媒体数据包格式与传输不受影响,如果作为冗余编码发送,则参考RFC 2198中主编码传输媒体数据包,次编码传输FEC 包。

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         RTP Header                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         FEC Header                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         FEC Payload                           |
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                       FEC Packet Structure

FEC 的 RTP 头中,padding bit、extension bit、CC、marker bit 通过计算得到,SSRC的值一般情况下应当与它所保护的
媒体数据包的SSRC值相同,除非 FEC 流通过 SSRC 值来进行解复用操作。CSRC list 不存在,extension 不存在,这两个值不受 CC 与 X 影响。序号 sequence number 单调递增,timestamp 须与当时发送的媒体包时间戳一致,单调递增,与 FEC 方案无关。FEC 包的 PT 值动态确定,通过带外协商完成。不认识的 PT 值包需要抛弃,即提供灵活的处理机制。

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      SN base                  |        length recovery        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |E| PT recovery |                 mask                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          TS recovery                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                      Parity Header Format

FEC 头 12 个字节,如上所示,包含字段 SN base,length recovery,E,PT recovery,mask and TS recovery。

字段 length recovery 将被用来恢复任意关联数据包,通过多个数据包长度按位异或计算得到,为一个网络字节序的无符号的16位整数。数据包长度包含媒体负载,CSRC list,extension 和 padding。如果每个数据包长度不等,仍可以进行异或操作。如两个媒体包长度分别为 3 (0b011) 和 5 (0b101),则 length recovery 计算方式: 0b011 xor 0b101 = 0b110。

字段 mask 长度 24 bit,如果第 i 位设置为 1,表示序号 N + i 的媒体包被关联到这个 FEC 包,其中 N 为 SN base,表示这一组媒体包中最小的 RTP 序号。所以,一个 FEC 包最多可以通过一组 24 个包计算得到,最低为 i = 0,最高为 i = 23。

FEC 生成与恢复

保护操作,或者说计算,实际上就是将媒体包中 RTP 头中对应字段级联计算,以及负荷中。对于每一个要保护的媒体包,按照下面的次序将各个字段级联起来生成一个比特序列:

  • Padding Bit (1 bit) 最重要比特位
  • Extension Bit (1 bit)
  • CC bits (4 bits)
  • Marker bit (1 bit)
  • Payload Type (7 bits)
  • Timestamp (32 bits)
  • Unsigned network-ordered 16 bit representation of the sum ofthe lengths (in bytes) of the CSRC List length of the padding,length of the extension,and length of the media payload (16 bits)
  • if CC is nonzero,the CSRC List (variable length)
  • if X is 1,the Header Extension (variable length)
  • the payload (variable length)

如果比特字符串的长度不等,那些短的比特串需要填充到最长的串等长。填充值可以任意,但必须在比特串末尾。然后对这些bit 串进行异或操作,结果便适用于构造 FEC 包的比特串,成为 FEC 比特串。构造包时,按照上述顺序逐一按照比特大小填入。

使用FEC 包恢复丢包过程包含两步,第一步确定丢包所在的媒体包组,包括媒体包和 FEC 包,第二步进行恢复。设 T 为用来恢复一些媒体包 xi 的包组,包括接收到的媒体包和 FEC 包,RTP 头以及整个负荷的恢复方法如下:

  1. 对于 T 中的媒体包,如上节所述保护操作计算比特串;
  2. 对于 T 中的 FEC 包,以相同的方式计算比特串,除了使用 PT Recovery 代替 PT,使用 TS Recovery 代替 Timestamp,设置 CSRC list Extension,Padding 为空;
  3. 如果某个媒体包生成的比特串小于 FEC 包的比特串长度,则在后面填充到一样长,填充值随意;
  4. 对这些字符串执行异或操作,得到一个恢复比特串;
  5. 创建一个空的12字节的 RTP 头,负载为空;
  6. 设置新的 RTP 包版本号为 2;
  7. 设置新包 Padding 字段为恢复比特串的第 1 bit;
  8. 设置新包 Extension 字段为恢复比特串的第 2 bit;
  9. 设置新包 CC 字段为恢复比特串的接下来的 4 bits;
  10. 设置新包 marker 字段为恢复比特串的接下来的 1 bit;
  11. 设置新包 PT 字段为恢复比特串的接下来的 7 bits;
  12. 设置新包 SN 字段为 xi;
  13. 设置新包 TS 字段为恢复比特串的接下来的 32 bits;
  14. 从恢复出的比特序列中取出接下来的16 bits,将其作为一个网络序的无符号整数,然后从恢复出的比特序列中取出这个整数那么多的字节,添加在新包之后,表示新包的CSRC列表、扩展、荷载和填充;
  15. 设置新包 SSRC 字段为所保护媒体包的 SSRC。

FEC 生成示例

示例如下。两个媒体包 X, Y,其 RTP header 如下所示,根据这两个媒体包生成一个 FEC 包。负载长度分别为 10,11。

   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        Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|0|0 0 0 1 0 1 1|0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    0
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1|      PTI:       11
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        8
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        3
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

                  RTP Header for Media Packet X

   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        Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|1|0 0 1 0 0 1 0|0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1|      PTI:       18
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        9
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        5
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

                  RTP Header for Media Packet Y

FEC 包的 PT 值设置为 127, 对于 RTP Header 来说,Version 固定设置为 2,PTI 设置为 127,TS 与 Y 保持一致,设置为 5, SSRC 保持相同。对于 FEC Header,SN base 设置为组中最小序号,length recovery,PTI recovery,TS recovery 设置为异或计算结果。mask 表示连续的第 0,1 两个包。长度为最长值。

   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        Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|1|1 1 1 1 1 1 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1|      PTI:       127
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        5
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

                  RTP Header of FEC for Packets X and Y

 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN base:   8    [min(8,9)]
   |0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|      len. rec.: 1    [8 xor 9]
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      E:         0
   |0|0 0 1 1 0 0 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1|      PTI rec.:  25   [11 xor 18]
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      mask:      3
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0|      TS rec.:   6    [3 xor 5]
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      The payload length is 11 bytes.

                  FEC Header of Result

FEC 作为冗余编码使用

如果将 FEC 作为 RFC 2198 中的冗余编码发送,被保护的媒体流被封装到标准 RTP 媒体包中,产生的 FEC 包流需要稍有改变:如果媒体包包含 RTP extension,padding,或者 a CSRC list,必须先从包中移除,然后设置the CC field,Padding Bit,and Extension 被设置为 0,然后再对这些包应用 FEC 保护操作。原始媒体包作为主编码数据,仅仅在生成 FEC 包时才去掉上述字段。

一旦 FEC 包生成,将媒体包中的负荷提取出来,作为主编码数据。FEC header 和 FEC 包中的 payload 提取出来,作为冗余编码。FEC 包外其他包也可以增加在冗余编码发送,但是不受 FEC 保护。 主编码的冗余编码头按照 RFC 2198 中的定义进行设置。

FEC 数据的冗余编码头的设置:

  • 块荷载类型域(block PT)设置为与 FEC 相关联的动态 PT 值;
  • 块长度(block length)设置为 FEC 头和 FEC 荷载的长度之和;
  • 时间戳偏移(timestamp offset)应当设置为 0;
  • 次编码(secondary codec)的荷载包括 FEC 头和 FEC 荷载。

在接收端,主编码与所有次编码作为独立的 RTP 包提取出来,复制冗余编码包的 RTP 头中的 sequence number,SSRC,marker bit,CC field,RTP version,和 extension bit 到每一个提取出来包的 RTP 头。如果次编码包含 FEC,那么FEC 包的 RTP 头中 CC,Extension Bit,和 Padding Bit 必须设置为 0, 提取出的包的 PT 从冗余编码头中 block PT 复制过来, 提取出的包的时间戳是 RTP 头中 timestamp 与 block header 中的 offset 之差。

为了使用 FEC 和媒体包进行恢复,CSRC list,extension,和 padding 如果存在则需要先去掉,并把 CC,Extension Bit,和 Padding Bit 设置为 0,修改后的媒体包与 FEC 包一起进行恢复丢失包。恢复出的包将总是没有 extension,padding,或者 CSRC list。在具体实现中,如果其它包中存在这些部分,可以从其它包中将这些部分拷贝过来。

使用冗余编码的荷载格式,有可能不能正确恢复出 marker bit。在使用 RFC 2198 来进行 FEC 封装的应用程序中,必须把恢复出的媒体数据包的 marker bit 设置为零。相对于发送完整的FEC包,这种方法的优点在于它能够减少 overhead。

FEC SDP 协商

SDP 协商将必要信息带外传输给对端,包括 RTP PT,多播组或端口,是否使用冗余编码载荷格式等。本节主要分为 FEC 流独立流传输,和使用冗余编码中传输两种方式。

FEC 作为独立流传输

FEC包是作为一个独立的流来进行传输的。这可能意味着它们被发往与媒体包不同的端口或不同的多播组。必须携带信息:

  • FEC包被发往的地址和端口
  • FEC包的 PT 值
  • 所保护的流标识

FEC 的 rtpmap 行表明 FEC 的 PT 值,以及名称 “parityfec”, FEC 的 fmtp 行传递端口和地址信息,格式如下所示:

a=fmtp:<荷载类型号> <端口> <网络类型> <地址类型> <连接地址>

SDP 示例如下,媒体格式为 0 的 PCM 编码的音频,它被 PT 值为 78 的 FEC 流保护,视频流被 PT 值为 79 的 FEC 流保护,这个FEC流的端口号是一样的,但是多播地址不一样:

   v=0
   o=hamming 2890844526 2890842807 IN IP4 126.16.64.4
   s=FEC Seminar
   c=IN IP4 224.2.17.12/127
   t=0 0
   m=audio 49170 RTP/AVP 0 78
   a=rtpmap:78 parityfec/8000
   a=fmtp:78 49172 IN IP4 224.2.17.12/127
   m=video 51372 RTP/AVP 31 79
   a=rtpmap:79 parityfec/8000
   a=fmtp:79 51372 IN IP4 224.2.17.13/127

FEC 作为冗余编码传输

当 FEC 流以冗余编码格式作为次编码来发送的时候,必须使用 RFC2198中定义的步骤通过 SDP 通知对方。FEC的荷载类型就象其它任意一个次编码那样表示,用 rtpmap 属性行来指示出 FEC 包的动态 PT 值。FEC必须只保护主编码。这时,FEC 的 fmtp 属性必须不出现。

SDP 示例如下,有一个单一的音频流,由 PCM 格式(PT 值为 0)和 DVI 格式(PT 值为 5)组成,一个冗余编码(用 PT 值 121 表示,在 rtpmap 属性中绑定为 red),以及一个FEC(PT 值 100,在 rtpmap 属性中绑定为 parityfec)。尽管 FEC 格式是作为媒体流的一个可能编码来描述的,但它不能单独传送。它出现在 m 行中只是因为按照 RFC 2198,非主编码(non-primary codec)都必须在这里列出来。fmtp 属性指出冗余编码格式可以这样使用:DVI 作为一个次编码(secondary coding),而 FEC 作为第三编码(tertiary encoding)。

   m=audio 12345 RTP/AVP 121 0 5 100
   a=rtpmap:121 red/8000/1
   a=rtpmap:100 parityfec/8000
   a=fmtp:121 0/5/100

ULP FEC的RTP载荷格式(RFC 5109)

RTP 格式

ULP (uneven level protection) 为不均等保护,即对被保护的数据重要性进行分级保护,保证重要的数据拥有更大的可恢复性,同时也会占用更多的带宽。这一点,在音视频数据上表现较明显,携带多个 level 的 ULP FEC 包结构如下所示。RTP Header 格式遵循 RFC 3550。

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                RTP Header (12 octets or more)                 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    FEC Header (10 octets)                     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                      FEC Level 0 Header                       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                     FEC Level 0 Payload                       |
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                      FEC Level 1 Header                       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                     FEC Level 1 Payload                       |
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                            Cont.                              |
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  FEC Packet Structure

FEC 包的 RTP Header 仅仅针对数据流与 FEC 分离的方式。FEC Header 如下所示,与 RFC 2733 比较,需要注意区别。

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |E|L|P|X|  CC   |M| PT recovery |            SN base            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                          TS recovery                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        length recovery        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  FEC Header Format 

其中:

  1. E 为扩展位,被设置为0,接收方应当忽略此字段;
  2. L 标识长掩码是否被使用,缺省不设置,16 位,如果设置,则 48 位。
  3. FEC Header 中五个恢复相关字段 P,X,CC,M,PT recovery 的值都是通过被保护数据的 RTP 头中对应字段通过 FEC 算法计算而出。
  4. SN base 字段中填入被 FEC 保护的媒体包的最小 RTP 序号(注意序号环绕),标识起始序号。如果 L 字段被设置为 0,最多16个包,如果 L 字段被设置为 1,则可最多 48 个包。
  5. TS recovery 通过关联的媒体包的时间戳计算而来,可以对时间戳进行恢复。
  6. length recovery 根据长度字段计算得到,用于得到恢复包的长度。长度包括media payload,CSRC list,extension 和 padding,所以被保护的媒体包长度可以不相同。

FEC level header 长度与 L 字段有关,4 字节或 8 字节,Protection Length 占 16 位, mask 占 16 位或者48 位,结构格式如下所示。

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       Protection Length       |             mask              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              mask cont. (present only when L = 1)             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  ULP Level Header Format

其中,mask 字段标识哪些包在当前的保护层级(level)上被保护。如果 mask 第 i 位被设置为 1, 表示序号为 SN base + i 的媒体包被保护。对边界情形 i = 0 和 i = 15 的情况需要特别注意一些。mask 字段设置需要遵循的规则如下:

  • a. 一个媒体数据包在高于保护等级 0 的级别中只能被保护一次,但可能被多个包在等级 0 上保护,且在等级 0 上保护长度相等;
  • b. 如果一个包在等级 p 上被保护,它也必须在等级 p-1 上被一些 FEC 包保护。注意,对相同媒体包,在等级 p 上的 FEC 包和 p-1 上的 FEC 包可以不同;
  • c. 如果一个 ULP FEC 包在等级 p 上对媒体包提供保护,那么也将在 p-1 上提供。注意,在等级 p 上保护的包组可能不同于 p -1 上保护的包组。

数据包保护与等级示例

         Packet A          #####################
                                  :        :
         Packet B          ############### :
                                  :        :
         ULP FEC Packet #1 @@@@@@@@        :
                                  :        :
         Packet C          ###########     :
                                  :        :
         Packet D          ###################################
                                  :        :
         ULP FEC Packet #2 @@@@@@@@@@@@@@@@@
                           :      :        :
                           :<-L0->:<--L1-->:

         Payload packet #  |  ULP FEC packet that protects at level
                           |          L0             L1
      ---------------------+---------------------------------------
                A          |          #1             #2
                B          |          #1             #2
                C          |          #2             #2
                D          |          #2             #2

           An Example of Protection Combination

在上例中可以看出,ULP FEC packet #1 仅保护等级 0, ULP FEC packet #2 同时保护等级 0 和等级 1。数据包 A 在保护等级 0 被 ULP FEC packet #1 保护,在保护等级 1 被 ULP FEC packet #2 保护。ULP FEC packet #2 在 等级 0上保护数据包 C 和 D,在等级 1 上保护 A,B,C,D。

ULP FEC 保护操作

在ULP FEC 包的每一层负荷数据都是通过 FEC 保护算法(如 XOR) 对关联到这一保护层级的媒体数据包中的负荷以及填充数据进行计算而得到,ULP FEC 包的长度由所保护的长度决定。

FEC Header 占 80 bits,其中前 64 bits 是 RTP Header 中对应字段进行奇偶校验操作得到(XOR),剩余 16 bits 为网络字节序的无符号整数,表示计算得到的保护长度值。

将数据包看成由 bit 组成的 字符串,那么 FEC bit string 的生成实际上是需要被保护的 payload bit string 按位异或操作得到。如果有包的长度较短,需要先用 0 做补齐操作。

对于每个保护级别 n (n = 0,1,…),第 n 级 ULP Header 后跟随第 n 级保护数据。所以 Ln 数据开始于FEC 字符串的 第(Sn + 13)字节,其中 Sn = sum(Li : 0 <= i < n),前12个字节为 FEC Header。

ULP FEC 恢复操作

FEC 主要用来恢复丢失媒体包,恢复操作分为两部分,首先需要找到包括丢失包的这一组生成 FEC 包的媒体包,然后再重建,包括头部与负载。丢失的负荷包可能被完全或部分恢复,取决于丢包程度以及保护等级。

RTP Header 重建

设 T 表示 在等级 0 上,用于恢复一些媒体包 xi 的包组,包括 FEC 包和媒体包。过程如下:

  1. 对 T 中的每个媒体包,计算被保护的序列最前面的 80 位;
  2. 对 T 中的 FEC 包,FEC 比特序列是 80 位的 FEC 头;
  3. 计算恢复字串,通过对 T 中所有的媒体包和FEC 的比特序列按位异或;
  4. 创建一个无负荷的 RTP 包头;
  5. version 为 2, recovery bit string 后移 2 位;
  6. Padding 为 recovery bit string 下一位;
  7. Extension 为 recovery bit string 下一位;
  8. CC 为 recovery bit string 下 4 位;
  9. marker 为 recovery bit string 下一位;
  10. PT 为 recovery bit string 下 7 位;
  11. SN 为 xi,跳过 recovery bit string 16位;
  12. TS 为 recovery bit string 下 32 位;
  13. 在新包后添加 recovery bit string 下 16 位,表示 CSRC list,extension,payload,padding;
  14. SSRC 与关联媒体流中相同。

RTP payload 重建

T 与 xi 同上,重建过程如下:

  1. 假定我们需要重建的是等级 n 上的数据,首先需要从等级 n 的 ULP header 中获取保护长度 Ln;
  2. 对 T 中的 FEC 包,FEC 在 等级 n 上的负载为等级 n 上的 FEC 比特序列;
  3. 对 T 中的 媒体包,在等级 n 上被保护的比特序列为包从第 (Sn + 13) 个字节开始的 Ln 个字节;
  4. 如果从媒体包中产生的在等级 n 上被保护的比特序列长度小于当前等级的保护长度,则在后面补 0 到对应长度;
  5. 对 T 中所有媒体包在等级 n 产生的被保护的比特串,以及 T 中所有 FEC 包在等级 n 产生的比特串进行异或操作计算,得到恢复的比特序列;
  6. 联合其他等级生成的恢复字符串,生成恢复的媒体包;
  7. 被恢复媒体包的总长度从等级 0 的恢复操作中得到,也可以用这个长度来检查是否恢复完全。

示例

RFC 2733 相似示例

4 个媒体包,生成一个 FEC 包,如下所示:

                    +-------------------+             :
         Packet A   |                   |             :
                    +-------------+-----+             :
         Packet B   |             |                   :
                    +---------+---+                   :
         Packet C   |         |                       :
                    +---------+-----------------------+
         Packet D   |                                 |
                    +---------------------------------+
                                                      :
                    +---------------------------------+
         Packet FEC |                                 |
                    +---------------------------------+
                    :                                 :
                    :<------------- L0 -------------->:

            FEC Scheme with Single-Level Protection

假设 FEC 包 PT 值为 127,生成包中 RTP Header 如下所示:

    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       Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|0|1 1 1 1 1 1 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    0
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1|      PT:        127
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        9
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

                  RTP Header of FEC Packet

FEC 包 FEC header 如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0|0|0|0|0 0 0 0|0|0 0 0 0 0 0 0|0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 1 0 1 1 1 0 1 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      E:         0     [this specification]
      L:         0     [short 16-bit mask]
      P rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      X rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      CC rec.:   0     [0 XOR 0 XOR 0 XOR 0]
      M rec.:    0     [1 XOR 0 XOR 1 XOR 0]
      PT rec.:   0     [11 XOR 18 XOR 11 XOR 18]
      SN base:   8     [min(8,9,10,11)]
      TS rec.:   8     [3 XOR 5 XOR 7 XOR 9]
      len. rec.: 372   [200 XOR 140 XOR 100 XOR 340]

               FEC Header of FEC Packet

在等级 0 上的 FEC level header 如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 0|1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      L0:        340   [the longest of 200,140,100,and 340]
      mask:      61440 [with Bits 1,2,3,and 4 marked accordingly for
                        Packets 8,9,10,and 11]
      The payload length for level 0 is 340 bytes.

               FEC Level Header (Level 0)

两个保护等级的示例

两个保护等级将会更复杂,等级 0 的 FEC 将对包的前部分提供更重要的保护,因为一般情况下,前部分的数据最重要。等级 1 将对其余包提供额外的保护,如下所示,其中 L0 = 70 ,L1 = 90。

              +------:--------:---+
   Packet A   |      :        :   |
              +------:------+-:---+
   Packet B   |      :      | :
              +------:--+---+ :
                     :        :
              +------+        :
   ULP #1     |      |        :
              +------+        :
                     :        :
              +------:--+     :
   Packet C   |      :  |     :
              +------:--+-----:-----------------+
   Packet D   |      :        :                 |
              +------:--------:-----------------+
                     :        :
              +------:--------+
   ULP #2     |      :        |
              +------:--------+
              :      :        :
              :<-L0->:<--L1-->:

    ULP FEC Scheme with Protection Level 0 and Level 1

如上所示,将产生两个 FEC 包,#1 和 #2。ULP FEC packet #1 中的 RTP header 如下图所示:

    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       Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|1|1 1 1 1 1 1 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1|      PT:        127
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        5
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

               RTP Header of FEC Packet #1

ULP FEC packet #1 中的 level 0 ULP header 如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0|0|0|0|0 0 0 0|0|0 0 1 1 0 0 1|0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      E:         0     [this specification]
      L:         0     [short 16-bit mask]
      P rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      X rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      CC rec.:   0     [0 XOR 0 XOR 0 XOR 0]
      M rec.:    0     [1 XOR 0 XOR 1 XOR 0]
      PT rec.:   25    [11 XOR 18]
      SN base:   8     [min(8,9)]
      TS rec.:   6     [3 XOR 5]
      len. rec.: 68    [200 XOR 140]

               FEC Header of ULP FEC Packet #1

FEC Packet #1 的 FEC Level Header (Level 0)如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0|1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      L0:        70
      mask:      49152 [with Bits 1 and 2 marked accordingly for
                        Packets 8 and 9]

      The payload length for level 0 is 70 bytes.

      FEC Level Header (Level 0) for FEC Packet #1

FEC packet #2 的 RTP header 如下所示:

    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       Version:   2
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Padding:   0
   |1 0|0|0|0 0 0 0|1|1 1 1 1 1 1 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      Extension: 0
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      Marker:    1
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1|      PT:        127
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SN:        2
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|      TS:        9
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+      SSRC:      2

                RTP Header of FEC Packet #2

FEC packet #2 的 FEC header 如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0|0|0|0|0 0 0 0|0|0 0 1 1 0 0 1|0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      E:         0     [this specification]
      L:         0     [short 16-bit mask]
      P rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      X rec.:    0     [0 XOR 0 XOR 0 XOR 0]
      CC rec.:   0     [0 XOR 0 XOR 0 XOR 0]
      M rec.:    0     [1 XOR 0 XOR 1 XOR 0]
      PT rec.:   25    [11 XOR 18]
      SN base:   8     [min(8,9,10,11)]
      TS rec.:   14    [7 XOR 9]
      len. rec.: 304   [100 XOR 340]

               FEC Header of FEC Packet #2

FEC Packet #2 在等级 0 上的 ULP header 如下图所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0|0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      L0:        70
      mask:      12288 [with Bits 3 and 4 marked accordingly for
                        Packets 10 and 11]

      The payload length for level 0 is 70 bytes.

      FEC Level Header (Level 0) for FEC Packet #2

FEC Packet #2 在等级 1 上的 ULP header 如下图所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0|1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      L1:        90
      mask:      61440 [with Bits 1,2,3,and 4 marked accordingly for
                        Packets 8,9,10,and 11]

      The payload length for level 1 is 90 bytes.

       FEC Level Header (Level 1) for FEC Packet #2

FEC 作为冗余编码的示例

FEC 作为冗余编码在同一个流中传输,设定 5 个媒体包 A,B,C,D,and E,均来自 SSRC 2。序号分别为 8,9,10,11,和 12,时间戳分别是 3,5,7,9,和 11。所有媒体包作为主编码,FEC 作为次编码,媒体流 PT 设置为 11。负荷长度分别是 200 bytes,140 bytes,100 bytes,340 bytes,160 bytes。包 A 和 包 C 的 marker bit 被设置。FEC 结构如上所示,保护长度 L0 为 340 字节。

冗余编码打包时,PT 值被设置为 100,FEC PT 值设置为 127。开始是从 RED #1 到 RED #4 的四个 RED 包,均包含一个独立的媒体包A,B,C,D。然后开始生成对前四个媒体包的 FEC 包。接下来是第五个冗余包 RED #5,包含媒体包 E 和冗余编码的 FEC 数据。

   RED Packet #1:    Media Packet A
   RED Packet #2:    Media Packet B
   RED Packet #3:    Media Packet C
   RED Packet #4:    Media Packet D
   RED Packet #5:    FEC Packet,Media Packet E

RED packets #1 到 RED packets #4 结构如下所示:

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                 RTP Header (RED) - 6 octets                   |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |        Primary Encoding Block Header (RED) - 1 octet          |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                      Media Packet Data                        |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

         RED Packet Structure - Media Data Only

RED packet #1 的 RTP header 如下所示,其他 RED 包类似:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1 0|0|0|0 0 0 0|0|1 1 0 0 1 0 0|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      Version:   2
      Padding:   0
      Extension: 0
      Marker:    0     [Even though media packet A has marker set]
      PT:        100   [Payload type for RED]
      SN:        1
      TS:        5
      SSRC:      2

               RTP Header of RED Packet #1

主编码的 block header 如下所示:

    0 1 2 3 4 5 6 7
   +-+-+-+-+-+-+-+-+
   |0|0 0 0 1 0 1 1|
   +-+-+-+-+-+-+-+-+

      F bit:     0     [This is the primary coding data]
      Block PT:  11    [The payload type of media]

   Primary Encoding Block Header of the RED packets

FEC 数据并不直接从 RED 包中生成,二十通过包含媒体包的虚拟 RTP 包。从RED 包到虚拟 RTP 包的转化方式如下:

  1. 移除所有的 RED 包头和冗余编码数据;
  2. 用主编码的 PT 替换 RTP header 中的 PT 值。

注意:依据 RFC 2198,无论是否使用 FEC,一旦主编码数据通过 RED 包传输, marker bit 都将丢失,不可恢复。

包含 FEC 数据的 RED 包结构如下所示:

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                 RTP Header (RED) - 6 octets                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       Redundant Encoding Block Header (RED) - 4 octets        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        FEC Packet Data                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        Primary Encoding Block Header (RED) - 1 octet          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Media Packet Data                       |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

            RED Packet Structure - With FEC Data

RED packet #5 中携带 FEC 与媒体数据,FEC 包的冗余编码 block header 如下所示:

    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1|1 1 1 1 1 1 1|0 0 0 0 0 0 0 0 0 0 0 0 0 0|0 1 0 1 1 0 0 0 1 0|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      F bit:     1     [This is the redundant coding data]
      Block PT:  127   [The dynamic payload type for FEC]
      TS Offset: 0     [The instance at which the FEC data is
                        transmitted]
      Block Len: 354   [FEC header (10 octets) plus ULP level 0 header
                        (4 octets) and ULP level 0 data (340 octets)]

          Redundant Encoding Block Header

Redundant Encoding Block Header 后面数据如下:

  • FEC header (10 octets)
  • ULP level 0 header (4 octets)
  • ULP level 0 data (340 octets for level 0)
  • The primary encoding block (the data of media packet E)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/169602.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 什么是前端开发工程师?

    什么是前端开发工程师?前端工程师是web前端开发工程师的简称,它是随着web(WorldWideWeb)发展,细分出来的行业,可以说,它是时代的产物。Web前端开发技术(因为技术的更新,又称为H5开发工程师)主要包括

  • 安全帽识别软件使用中常见问题分析[通俗易懂]

    安全帽识别软件使用中常见问题分析[通俗易懂]一、安全帽识别软件的主要功能是什么?安全帽识别是通俗的说法,相对准确的名称应该是安全帽佩戴检测,是用深度学习的算法对视频流进行分析,通过人工智能来判断视频中的人是否未佩戴安全帽,如果未佩戴,则触发告警规则。二、安全帽识别软件的技术成熟吗?2012年人工智能领域的卷积神经网络迎来重大突破,深圳强美随即将此尖端技术应用于工业安全监控,因为掌握海量样本数据的先天优势,鹰眸安全帽(佩戴检测)识别系…

  • Java字符串转集合_java集合转数组

    Java字符串转集合_java集合转数组数组转集合方法使用Arrays.asList(数组)代码如下: //定义一个字符串 Stringzhuan=”1,2,3,4,5,6,7,8,9″; //分割字符串String[]split=zhuan.split(“,”);//把数组转成集合List<String>stringList=Arrays.asList(split);//输出结果S

  • 软件激活成功教程官网_激活成功教程软件资源

    软件激活成功教程官网_激活成功教程软件资源[转]国内软件激活成功教程下载网站列表!Postedon2005-04-2511:17Laser.NET阅读(872)评论(1)编辑收藏国内最有信誉的激活成功教程下载网站,总能让你有意外收获。18DD资源中心:http://www.18dd.com7年:http://www.7year.com/热战软件园:http://soft.rezhan.comwqsky:http…

    2022年10月11日
  • 服务降级设计

    服务降级设计实际系统运维中会出现某点的流量高峰,该时间有些可以预计,如双十一,有些不能预计,如某明星大爆料等等,那么对着此类情况加设备等不能满足要求或者不能立刻满足邀请的时候,就需要对服务进行降级操作。…

  • java中notify作用_notify的过去式

    java中notify作用_notify的过去式用Java通知vsnotifyAllnotify和notifyAll方法之间有什么区别是棘手的Java问题之一,这很容易回答但是一旦访问者提出后续问题,你要么感到困惑,要么无法提供明确的答案?notify和notifyAll之间的主要区别在于notify方法只通知一个Thread,notifyAll方法将通知在该监视器上等待的所有线程或锁定。顺便说一句,这是你在各地阅读的内容,坦率地说,这句话…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号