本文为「Dev for Dev 专栏」系列内容,作者为声网网络体验团队王瑞。
在实时音视频通话中,音视频质量受网络丢包影响较大,特别是对于视频。
为什么视频对丢包更敏感呢?通常来说,音频的原始码率相对视频来说比较小,因此音频编码器的压缩率比视频编码器要小很多。音频帧通常都是独立编码和解码的,因此任何一帧数据的丢失,都不会影响其他帧的解码。
而对于视频来说,为了达到较高的压缩率,通常会采用残差编码的方法来去除大量的空间和时间冗余信息,这就导致了在解码时,需要依赖参考帧才能正确解码,任何一帧数据的丢失,都会导致后续互相关联的一些帧无法解码。由于视频帧之间的这种相关性就导致了视频对传输丢包更加敏感。
常见的丢包包括 IP 传输网络的拥塞丢包,以及靠近用户侧的无线丢包。拥塞丢包一般是由于网络中处理能力比较小的瓶颈节点导致的,可能表现为随机或连续丢包,无线丢包一般是由于信道干扰导致的,经常表现为连续丢包。当然,在实际网络的丢包原因很多,表现也都不一样。
通过拥塞控制算法可以一定程度避免拥塞丢包的产生,但无法解决所有场景的丢包问题。
丢包发生后,通常会采用以下两种补救方法:
(1)重传(Automatic Repeat-reQuest, ARQ)
重传是一种高效的补救手段,但它依赖反馈信道,同时重传效率对网络RTT非常敏感。在高丢包下可能需要多次重传。
(2)纠错编码(Forward Error Correction, FEC)
纠错编码无需反馈信道,同时网络RTT的大小也不会影响它的效率。
在一对一的互联场景中,如果网络RTT较低,重传是一种合适的选择。但在RTT较大的时候,重传的效率会明显降低。另外在大规模的多播和广播应用中,过多的重传请求可能会加剧网络拥塞和丢包。
在这些情况下,采用FEC技术是更合适的选择。FEC在编码端进行冗余编码,在接收端通过冗余数据自动恢复出丢失的数据包,其优势在于不依赖反馈信道,且纠错效率不受RTT影响。因此,在高RTT环境中,可以有效避免重传导致的高延迟。本文主要对实时视频传输中的FEC技术做简要介绍,并介绍声网的最佳实践。
如果发送端发送的一组数据,经过特定信道传输,其丢失数据的位置对接收端是已知的,那么这种信道模型就称之为删除信道。基于互联网的包交换网络是一种典型的删除信道,在这种信道模型下,所有已接收到的数据都被认为是正确的。
在信道编码中,差错控制编码根据编码用途不同,可以分为检错码、纠错码和纠删码三种。
检错码是为了校验数据经过信道传输后是否出现了错误,常用的检错码包括简单奇偶校验码、循环冗余校验码等。纠错码不仅可以识别到信道传输是否出现了错误,还能纠正传输错误。在纠错码看来,经过差错信道传输后,接收端收到的数据都是不可靠的,需要通过解码来发现和纠正错误。常见的纠错码包括汉明码、BCH码等(见参考资料5)。
纠删码可以认为是一种特殊的纠错码,对于纠删码来说,其差错信道是一种删除信道,对接收者来说错误的位置是已知的,并且收到的数据都认为是正确的,因此其编译码会比纠错码更容易一些。
传统纠错码技术的发展已经非常成熟,通常用在网络协议的物理层和数据链路层,用于保障可靠的链路级信道。而纠删码大部分是基于纠错码的理论发展而来,常用于应用层的FEC编码。
在视频传输的应用层FEC编码算法中,RS码是一种常见的算法。RS码是一类重要的线性分组码,也是一种性能优异的短码,工作在有限域上。线性分组码通常用(n,k)码来表示,对于位编码来说,k和n表示比特数,其中k为信息位个数,n为码长;而在应用层FEC领域,FEC编码采用包编码方式,在包编码中,k和n都表示包数。对于码长为n的RS纠删码来说,只要收到任意k个信息位,就可以解码出所有n个数据。
对于一个(n,k)线性纠删码,可以表示为如下的矩阵运算: Y = x * G
其中,x是信息位向量,y是码字向量,G是生成矩阵。
在RS码中,常见的生成矩阵有范德蒙矩阵和柯西矩阵,分别如下图所示,这两种矩阵的特点是任意子矩阵均可逆,因此总能利用任意k个接收码字来解码出剩余n-k个码字。
■范德蒙矩阵
■柯西矩阵
域是一个可以在其上进行加、减、乘、除运算而结果不会超出域的集合,如果域中的元素个数是有限的,就称为有限域,或伽罗华域。有限域在密码学、编码理论中有着广泛的应用。
RS码是一种工作在有限域GF(2q)上的多进制纠删码,RS码的全部码元取自有限域GF(2q)上。通常,我们可以用以下两种方法来构造有限域:
定理一:对于集合Zp={0,1,…,p-1},如果p为素数,那么在Zp上进行模p的加法和乘法运算就构成一个有限域。
即Z2,Z3,Z5都是有限域,但是Z8不是,因为8不是素数。为了能够在非素数上构造有限域,就需要借助于本原多项式。
定理二:如果p为素数,m为正整数,那么在GF(p^m)上模一个m阶本原多项式也构成有限域。
本源多项式就是首项系数为1的不可约多项式,在实际算法实现中,考虑到性能与算法复杂性,RS算法常实现在GF(2^8)域上,本原多项式可以有多个,如下就是一个8阶本源多项式的例子:
所谓分组码是指编码器需要预先把输入数据分组,达到分组长度才能编码。而卷积码的输入是连续的,输出也是连续的,不需要进行预分组。
分组码的输出只与当前编码的分组数据有关,例如(n,k)分组码以k个输入为一组,编码出n个输出,输出仅与k个输入有关。而(n,k,L)卷积码的编码输出不仅与k个输入有关,还与历史的L个输入有关。L为约束长度,或记忆深度。
为了增强对抗连续丢包的能力,通常会增加分组码的分组长度(即k),但是由于分组码的解码延迟是线性的,k值的增加会导致解码延迟的增加。这就带来了分组长度的选择问题,较长的分组长度能提供更好的纠错能力,但同时增大了系统延迟。而卷积码不需要考虑分组长度问题,可以实现on-the-fly coding,更适合实时流传输场景使用。
对实时视频流来说,常见有以下几种编码方案,帧级编码、GOP级编码、扩窗编码、滑窗编码。其中前两种是分组码,后两种是卷积码的应用。
帧级FEC编码以单帧为分组单位(如下图),在这种编码方案中,FEC可以实现最小解码延迟,但在低码率下由于分组太小,导致在连续丢包时很容易出现无法解码的情况。GOP级编码以GOP为分组单位,这种编码方案的好处是大幅提高了连续丢包下的解码稳定性,但是也带来了较大的解码延迟,在实时场景中难以应用。
扩窗和滑窗编码是卷积码的具体应用,由于不存在分组问题,所以理论上可以在视频流的任意位置进行编码。两者的区别是,对帧X进行编码时,扩窗编码会编码所在GOP范围内的第1至第X帧,而滑窗编码只会编码第X-T到X帧,其中T为最大窗口长度。这两种编码方式都能很好的提高连续丢包场景下的解码概率,同时不会额外增加解码延迟。但由于扩窗编码在大GOP下存在性能问题,因此滑窗编码是一个更为实际的方案。下图是一个T=3的滑窗FEC编码的例子。
在声网的实践中,我们不仅大规模应用了卷积码方案,验证了卷积码在实时视频流传输中的优势,同时,我们将信源编码与信道编码结合,创造了一种新的编码方案,并命名为DMEC(Dense Matrix Erasure Coding),DMEC真正发挥了卷积码的最大性能优势,能够实现在不同场景下的最优视频QoE。
在信息论中,对信息的编码分为信源编码和信道编码,信源编码是为了去除冗余信息,提高通信效率,例如常用的视频编码器H.264就是一种信源编码器。而信道编码是为了对抗信道中的噪声和衰减,通过增加冗余,来提高抗干扰和纠错能力,例如上面讲到的RS码就是一种信道编码算法。
对于视频信源编码器来说,以H264为例,通常视频帧是逐帧参考的,即后一帧总是参考同GOP内的前一帧。但在分层编码的情况下则不然,在分层编码时,视频帧会分为基础层和一个或多个增强层。在多下行的场景中,分层编码可以为不同设备和不同网络情况的终端提供不同等级的自适应视频流。但与此同时,分层编码使得视频帧的依赖关系变得复杂,如果仍然套用简单的滑窗FEC编码,视频质量将无法达到最优。
相比于传统的滑窗方案,DMEC将信源编码器输出的视频帧参考关系作为卷积编码器的编码约束,排除了非参考帧对于解码概率的影响,使得视频可播放帧率(Playable Frame Rate, PFR)达到最优(该方案的理论依据见参考文献1)。
在DMEC编码时,当前帧的编码窗口仅包含当前帧以及其参考帧,越重要的帧被参考的概率就越大,那么在FEC编码时被编码次数就越多,在解码侧被恢复的概率就越高,通过这种机制,DMEC自动实现了非对等保护(UEP),而不需要为高优先级的帧分配更多的FEC码率。
仅以下图所示的两层时域、两层空域SVC为例说明,当T=6时,帧P31的编码窗口中包含了I00 , I01 , P20 , P21 , P30 ,和 P31 。
下图是不同FEC方案在实验室采用标准序列的PFR测试结果,PFR即可播放帧率,是评估FEC算法对最终视频体验的直观指标。其中红色是帧内FEC,蓝色是滑窗FEC,紫色是声网的DMEC。可以看出DMEC相较于另外两种方案的明显优势。
除了实验室数据,我们还通过对线上进行大规模的A/B Test,并通过数据挖掘获取了大量的对比数据(下表为部分客户的A/B Test对比数据),同样验证了声网自研的DMEC相比传统FEC方案对于降低视频卡顿率的效果。
场景 | 灰度分钟数 | 卡顿率降幅 | |
---|---|---|---|
客户A | 1v1 | 1.3 百万 | 22.22% |
客户B | 会议 | 5.6百万 | 10.94% |
客户C | 直播 | 0.4 百万 | 12.73% |
参考文献
1,R. Wang, L. Si and B. He, “Sliding-Window Forward Error Correction Based on Reference Order for Real-Time Video Streaming,” in IEEE Access, vol. 10, pp. 34288-34295, 2022, doi: 10.1109/ACCESS.2022.3162217.
< https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9741773 >
2, [RFC8680] Roca, V. and A. Begen, “Forward Error Correction (FEC) Framework Extension to Sliding Window Codes”, RFC 8680, DOI 10.17487/RFC8680, January 2020,
< https://www.rfc-editor.org/info/rfc8680 >
3, Vincent Roca, Belkacem Teibi, Christophe Burdinat, Tuan Tran-Thai, Cédric Thienot. Block or Convolutional AL-FEC Codes? A Performance Comparison for Robust Low-Latency Communications. 2017. ffhal-01395937v2
< https://hal.inria.fr/hal-01395937v2/document >
4, Sliding Window Selective Linear Code (SLC) Forward Error Correction(FEC) Scheme for FECFRAME draft-wang-tsvwg-sw-slc-fec-scheme-03
< https://datatracker.ietf.org/doc/html/draft-wang-tsvwg-sw-slc-fec-scheme-03 >
5,Department of Electrical and Computer Engineering - University of New Brunswick, Fredericton, NB, Canada
关于 Dev for Dev
Dev for Dev 专栏全称为 Developer for Developer,该专栏是声网与 RTC 开发者社区共同发起的开发者互动创新实践活动。
透过工程师视角的技术分享、交流碰撞、项目共建等多种形式,汇聚开发者的力量,挖掘和传递最具价值的技术内容和项目,全面释放技术的创造力。