WebRTC 如何应用 FEC 以提升游戏流质量

WebRTC 最常见的用途就是视频会议。通常是传输分辨率为 720p,帧率为 30 fps 的视频流,带宽要求不过几兆而已。当网络状况不太好时,会发生丢包,于是视频就会出现卡顿。你可以通过重传来解决丢包的问题,这样视频流就不会卡顿。但这种情况严重时,会导致视频画面卡顿持续到几秒的量级。当然这样的事情我们每天都会遇到,在视频会议场景中这是可以忍受的。

但是对游戏场景来说,视频传输的要求就大大高于视频会议场景。游戏画面要求很高的分辨率(QHD),码率平均高达 30 Mbit/s,远远高于视频会议视频流的码率。Nvidia 在 chromebook 上支持 120 fps 的高帧率游戏画面传输,这就要求 WebRTC 能够以超低延迟传送高帧率的视频流。而在游戏场景中,卡顿是难以忍受的,想象你在玩一个射击游戏,游戏画面无法实时响应你的外设操作,那你射击的时候会打不中你的目标甚至被敌方玩家射死。

图片
图 1
图片
图 2

让我们来分析通常情况下什么原因会导致卡顿。图 2 是一个传统的收发包时间线,这个图展示了等待重传来恢复包是特别缓慢的。当右边的收端丢失一个包的时候,它必须得发送一个 NACK 反馈给发端,在能完整复原一帧之前需要等待一个完整的 RTT 时间,于是帧延迟就增大了。而在左边的发端,Frame Duration 是可变的,取决于你设置的视频帧率。当你设置的帧率为 120 fps 时,发端每隔 8.3 ms 就需要发送一个新的帧。如果仅使用重传来恢复包,那么要在收端保持和发端一样的帧率 (120 fps),你就需要确保你的网络 RTT 要比 Frame Duration (8.3 ms)(图 2 中的黄色线条)小很多。也许你并不清楚你的网络 RTT 有多差,那让我们来看几个例子。

图片
图 3 RTT 测试

图 3 是集成在 nvidia Gforce 上的网络测试工具,左侧是从我的本机 ping 到本机的服务器,可以看到在带宽大于 50 Mbps 的时候,延迟是 13 ms,在视频会议场景中,30 fps 的视频流的 Frame duration 有 33 ms,但是仍旧比游戏场景中 120 fps 的 Frame duration 8.3 ms 高。情况更坏的是,如果你尝试连接距离较远的服务器,如图 3 右图所示,在带宽大于 50 Mbps 的情况下延迟有 32 ms,远高于 8.3 ms。不是每个用户都能很靠近服务器,所以仅靠重传是无法解决传输高码率高帧率的游戏视频流的。

让我们来了解一下 FEC 是怎么解决这个问题的。FEC 全称为 forward error correction。FEC 通过发送冗余数据或者冗余包以在收端恢复丢失的包。可以认为 FEC 是一个主动的包恢复机制,他主动防止包丢失,而不是出现了丢包再去解决。如图 4 所示,FEC 包与视频数据包一起发送到对端起到保护作用。如此,即使丢失了视频数据包,只要你收到了足够多的视频包和 FEC 包,你就可以恢复出丢失的包而不需要重传。相比重传情况,收端节省了一个 RTT 时间,从而大大减少了视频帧的组装时间,从而降低了帧延迟。

图片
图 4 FEC传输示意图

图5展示了单个 FEC 包如何恢复出单个丢失的视频包。发端将一个完整的视频帧分成 4 个 RTP 包发送到收端,这 4 个包均通过 FEC 编码器,四个包的数据通过异或机制生成一个 FEC 包。然后这 4 个包和 FEC 包一起通过网络发送到收端。而收端仅收到 4 个包时,就会检查出丢失了第 3 个 RTP 包,这时将收到的视频数据包和 FEC 包通过 FEC 解码器,通过异或机制就可以恢复出第 3 个丢失的视频数据包。FEC 率通常设置为 FEC 占视频数据包的百分之多少。在这个例子中,4 个数据包对应一个 FEC 包,所以 FEC 率为 25%。

图片
图 5 FEC 工作流程

但是总体带宽是有限制的。使用 FEC 必定会使传输视频数据包的带宽减小,过度使用 FEC 会导致视频质量下降,但是如果 FEC 率过低则只能恢复有限的丢包。所以就带来了下一个问题,我们应该使用多大的 FEC 率呢?

图片
图 6 FEC 率的选择

仅仅是使用一个固定的 FEC 率是不行的。可能会被短期网络状况误导,以致于生成一个不符合实际网络状况的 FEC 率。最安全的方法就是根据丢包报告来实时调整 FEC 率。即通过收端周期性地反馈丢包情况,发端周期性地调整 FEC 率。图 7 展示了一个如何动态选择 FEC 的流程框图。当然你可以给动态 FEC 控制器的输入多样化,不仅包括丢包情况,还可以有 RTT 时间,可用带宽以及丢包图案(突发丢失,恒定丢包率,随机丢包等)。但是在浏览器中想要做到这么多反馈输入很困难,因为缺乏合适的 API。

图片
图 7 如何选择一个 FEC

FEC 在 WebRTC 中叫做 FlexFEC。Flex 源自于其灵活的  bitmask。这个 bit mask 可以指出这个 FEC 包可以恢复的包序列 x, y, z… 所以当收端收到视频包和 FEC 包时,他能够知道哪些视频包对应哪些特定的 FEC 包。这种方式给发端提供了很大的灵活性,发端可以灵活调整 FEC 率而不需要打破任何现有的协议进行编码,所以命名为 FlexFEC。

图片
图 8 FlexFEC 包头格式

早期的 RFC 草案已经在 libWebrtc 中实现了,但是默认设置是不使用 FEC 的。所以早期的 WebRTC 默认的恢复机制只有重传机制。Nvidia 完善了 libWebRTC 中的 FEC 功能并默认使用 FEC。同时 libWebRTC 可以自定义你自己的 Dynamic FEC Controller 而不是使用其默认的 FEC 编码。当然你也可以选择不同实现的 WebRTC 来部署 FEC 策略。

最后看一眼我们在浏览器上应用 FlexFEC 的一些结果。实验采用 120 fps 的视频流,在 Chrome 109 上进行实验。视频的卡顿显著减少,因为帧的组装时间大幅减少如图 9 所示。NACK 和 PLI 的数量变少。而视频质量的降低在可接受范围内。

图片
图 9 FlexFEC 的实验结果

总结起来,FEC 是重传恢复包机制的一种补充机制,在用户需求低延迟零卡顿的场景下使用十分理想。但是它会占据一部分可用带宽,可能会导致视频质量下降。但是总体来说,服务质量是提高的。

来自Kranky Geek WebRTC 2022 秋季大会演讲。

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

发表回复

登录后才能评论