webrtc QOS方法二.3(flexfec rfc8627简介)

  • Post author:
  • Post category:其他


一、背景介绍

WebRTC实现的冗余方式有三种:UlpFEC(rfc5109)、FlexFEC(rfc8627)、inbandFEC(opus音频使用)。

UlpFEC和FlexFEC实现的原理都是,将一组M个报文进行异或,生成N(N就是FEC的冗余度)个FEC报文,打包出去。这组报文任意丢其中的N个,都可以通过这组(M-N)个报文+FEC冗余包恢复回来,增大FEC冗余报文的保护范围。例如下面示意图:D为媒体包,R为冗余包,该图所示的冗余度为2。

1、发送端打包示意图

2、网络丢包示意图

3、报文恢复示意图

二、FlexFec VS UlpFEC

媒体包打包格式 FEC SSRC FEC Sequence
UlpFEC rfc2198+rfc5109 同媒体报文SSRC 与媒体报文共享Sequence
FlexFEC rfc8627 单独SSRC 使用独立的Sequence

1、WebRTC H264在封装上只有一层Sequence,依靠Sequence连续来完判断是否是完整视频帧,没有更多信息的封装,导致如果FEC报文数据在一帧的包中间,这样的判断逻辑就会有问题。而VPX,除了Sequence,还有PictureId等比较多的边界信息和类型信息,可以很好的解码FEC包。所以WebRTC默认只有在VPX时才启用UlpFEC。

MaybeCreateFecGenerator
->ShouldDisableRedAndUlpfec
->PayloadTypeSupportsSkippingFecPackets

默认只有VPX支持UlpFEC冗余编码。

bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name,
                                           const WebRtcKeyValueConfig& trials) {
  const VideoCodecType codecType = PayloadStringToCodecType(payload_name);
  if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) {
    return true;
  }
  if (codecType == kVideoCodecGeneric &&
      absl::StartsWith(trials.Lookup("WebRTC-GenericPictureId"), "Enabled")) {
    return true;
  }
  return false;
}

2、实际上UlpFEC的SSRC同媒体报文的SSRC,且Sequence和媒体报文是共享的,这样会导致在开启UlpFEC时,无法区分媒体报文还是FEC报文,在开启NACK时使FEC冗余包也会NACK重传,会导致一定程度上的带宽浪费。

所以目前大家都比较优选FlexFEC冗余编码,比较少使用UlpFEC冗余编码。

三、FlexFEC原理

1、冗余模式

按照rfc8627协议建议,FlexFEC可以在1D行、列、2D数组异或,三种编码模式。

1)1D行异或模式

2)1D列异或模式

3)2D数组异或模式

但是Webrtc源码仅实现了MaskRandom、MaskBursty或1D列异或冗余模式。

具体细节可参考PacketMaskTable::LookUp函数实现

2、RTP包协议

1)完整RTP报文格式

2)FEC Header定义

webrtc并没有完全遵循RFC协议,而是自己自定义一套协议。该格式在flexfec_header_reader_writer.h头文件定义。

mask掩码长度说明

// Size (in bytes) of packet masks, given number of K bits set.
constexpr size_t kFlexfecPacketMaskSizes[] = {2, 6, 14};

掩码用来标识改FEC冗余报文保护报文的列表。保护序列号列表的计算公式为:

SN base_i + mask对应为1的bit位置序号。 参见ForwardErrorCorrection::InsertFecPacket函数计算FEC冗余报文的保护队列序列号:

3、SDP协商

上面的示例可以看到,媒体视频rtp报文的pt值是100,flexfec冗余报文的PT值时110,媒体视频RTP报文的ssrc是1234,flexfec冗余报文的ssrc是2345。

对应webrtc的实现代码如下:

1、PT值确定GetPayloadTypesAndDefaultCodecs

2、ssrc的确认 AddFecFrSsrc

四、代码实现

1、FlexFEC编码实现

1)FlexFEC生成和push pacer队列调用栈

2)FlexFEC报文生成流程

UlpfecGenerator::AddPacketAndGenerateFec函数走读说明:

目前webrtc限制,仅支持48bit的掩码(因为Kbit需要占位,48个报文打冗余的话,maskhead就是14字节),代码里面有一处不足,就是单帧视频报文数大于48的话,后续报文不会push到media_packets_队列,也就不会参与冗余。

WebRTC这样设计是考虑到UlpFEC不允许在一帧的包中间发送FEC报文,否则会影响接收端对帧的完整性判断。但是目前FlexFEC使用单独的SSRC和Sequence参数,这个问题可以天然解决。但是WebRTC源码没有同步更新设计。导致会出现概率情况下一帧报文中的部分报文不能进行FEC保护。

2、FlexFEC解码实现



版权声明:本文为CrystalShaw原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。