本文根据网易云信资深引擎工程师戚继跃在《MCtalk Live#4:视频 QoE 的平衡之道》线上直播分享整理,文末有直播视频回顾以及 QA 整理。
导读
互联网发展迅猛,实时通信(Real Time Communication,简称 RTC)需求与日俱增。如何在各种复杂网络服务质量 (Quality of Serverice,简称 QoS)下,以及参差不齐的硬件终端上取得最佳的视频体验质量 (Quality of Experience,简称 QoE) ,是 RTC 技术的重要一环。
本文从视频质量控制系统 (Video Quality Controller,简称 VQC)模块出发,介绍网易云信 NERTC 在提升视频 QoE 方面做的一些工作。
VQC 在视频 QoE 中的作用
视频的 QoE 主要包含视频的清晰度、视频流畅度、视频延时三个方面的指标,整体上由网络 QoS、视频处理算法、VQC 共同决定:
- 网络 QoS:提供尽可能充分的可使用带宽
- 视频处理算法:在一定的码率下,输出尽可能好的视频质量
VQC:
- 对 QoS 负责,控制码率,保证流畅度和延时
- 对视频算法负责,保证性能,平衡清晰度和流畅度
VQC 通过对视频 QoS 状态、视频算法状态的监控,输出控制信号,达到场景化的最佳 QoE 表现,包括平衡清晰度、流畅度、延时这几个指标。今天,我们主要分享网易云信 NERTC 上的 VQC 实现以及 QoE 调优的相关工作。
网易云信 VQC 实现
网易云信的 VQC 模块部分参考了 WebRTC 的模块设计,整体结构如图中所示,主要包含四个监控模块和一个策略模块。输入的参数通过监控模块后得到当前的各种状态结果,然后由 VQC 策略模块决定最终输出的控制信号,控制视频 pipeline 的工作。下面,我们具体介绍每个模块。
QualityScaller
QualityScaller 模块的作用是监测当前的编码质量,主要对清晰度和编码器稳定性负责。
该模块输入根据编码器类型和编码算法类型而确定的 QP 阈值、当前输出编码帧的 QP 值、当前丢帧的统计数据,输出视频质量好坏的结果。
其中 QpSmoother 模块使用指数加权累加的方式来确定 QP 的统计值,如下:
我们详细看一下这个公式的组成,公式中:
- sample 为当前帧的 QP
- 输出 y 为 QP 统计值
- alpha 是根据编码器 QP 变化特性总结的一组系数值,根据上限和下限使用不同的系数值。比如我们测试下来针对 OpenH264 编码器,QP 上限系数值可以使用 0.9995, QP 下限系数值可以使用 0.9999。通过这种差异性的上下限系数,达到视频质量变差时(QP 增加)反应迅速,视频质量变好时(QP 减小)反应稍微迟钝的效果。
最终统计的上下限 QP 统计值,与输入的 QP 阈值比较判断,决定当前画质的好坏。输入的 QP 阈值也是根据编码器不同而不同的,比如在 OpenH264 上我们测试下来使用阈值下限为 24,上限为 37;硬件 iOS 设备上硬件编码则使用其他值,Android 上硬件编码则又不同,这都需要根据设备的大量验证来获取。
MovingAverage 为一个滑动窗口函数,取这个窗口内的丢帧比例,超过一定阈值认为是质量变差。
最终内部周期性查询模块会收集 QpSmoother 和 MovingAverage 的统计结果,输出两个结果(不输出不计入结果):
视频质量好
- QpSmoother 的 QP 统计值下限小于等于 QP 下限阈值
- MovingAverage 统计的丢包率超过阈值
视频质量差
- QpSmoother 的 QP 统计值上限大于 QP 上限阈值
OveruseFrameDetector
OveruseFrameDetector 模块主要作用是监测当前的性能能否支撑当下帧率的运行,对视频的流畅度负责。
该模块输入当前的目标帧率、分辨率、CPU Usage 阈值,采集和发送视频帧时间,输出当前性能好或者坏的结果。
ProcessingUsage 模块通过输入的视频帧采集和发送的时间,统计整个视频发送链路即视频采集到发送的时长,用这个时长做一些平滑运算后得到一个统计值,用这个统计值和当前帧率下帧间隔的理论时长做比较,统计时长是否超过理论值,并记录次数。然后周期性的收集次数,超过一定次数则输出性能差 CPU bad 的结果,低于一定次数则输出性能好 CPU good 的结果。
在该模块中,需要防止一些假的 CPU good 或者 bad 结果,比如:
- 样本数量少时(比如帧率低),周期性收集数据的时间没有变,这就容易导致结果误差
- 新的帧率分辨率刚开始工作时,各个环节的处理时间还没有问题,也需要特殊处理
RateAllocator
RateAllocator 模块负责决定当前码率的使用,在大小流场景下充当大小流使用的策略模块。
该模块有几个关键性作用:
- 远端有多个用户,其中有用户订阅了小流也有用户订阅了大流,该模块会决定有限的码率按照什么比例分配比较合适
- 同样的场景,在码率十分不足的情况下,该模块会决策大小流合并成一条流使用,提升画质
- 在下行的带宽受限情况下,该模块会决策发送端有没有必要降低带宽发送
MediaOptimization
MediaOptimization 模块主要负责监测和修正实时的码率和帧率,防止码率超发导致网络拥堵,因为拥堵后网络会进一步恶化,导致画质、流畅度、延时全面的降低。
该模块控制实时码率主要通过内部的 FrameDropper 模块,其使用漏斗算法决策当前是否码率超发,是否需要丢帧来稳定码率。
在每一帧编码之前,将该帧的目标码率作为输入放入漏斗中,编码之后将当前帧的实际码率作为漏斗的输出,然后去查看漏斗是否满了,如果满了就丢弃下一个编码帧来控制码率。漏斗的容量大小和可以容忍的延时相关,需要进行场景化定义。
丢帧与否的结果也会输出给 QpScaller 模块,作为评价编码质量的依据的一方面。
VQC 决策模块
VQC 决策模块根据 VQC 内部前述所有模块的结果,结合用户的场景设置,决策当下的视频策略。
其内部包含两个状态机以及一个决策模块。
两个状态机相互独立,互不影响:
- 视频质量状态机
- 性能情况状态机
一个决策模块,我们具体说明其中的一些重要功能:
- 根据用户设置的场景以及期望视频参数,设置各种内部调整的阈值
- 根据状态机的结果,决策提高或者降低视频的参数 (分辨率、帧率),以及提高或者降低的策略
- 根据其他信息,决策当前帧编码的其他参数,比如 simulcast 双流场景下大流或者小流是否编码
- 根据其他信息,决定算法是否需要调整,比如编码算法,后处理算法等
通过 VQC 进行视频 QoE 调优
VQC 通过对视频质量的全链路监控和调节来保证良好的视频 QoE ,下面介绍下云信 RTC 这边在通过 VQC 调优 QoE 方面的一些工作。
正确判断编码质量
表征编码质量的参数有很多:PSNR、SSIM、QP、VMAF 等,因为硬件编码器的特殊性以及参数获取计算成本的考虑,选用了 QP 作为评判标准。
如果选择使用 QP 作为正确反应编码质量的指标,需要考虑如下几点:
- 常规的 Slice QP 在 H264/265 编码中,一般编码器中只能反应前面几个编码宏块的质量。在软件编码上可以使用更优的 average QP 来作为视频帧的 QP,这样判断软件编码质量效果更优。
- 不同编码算法的 QP 阈值是不同的,比如我们在 OpenH264 上可以使用 (24,37)作为 QP 好坏判断的上下限,但是在不同的编码器和不同的编码算法上就需要调整,比如我们的 NE264、NE265、NEVC 编码算法都需要做对应的适配调整。
- 不同硬件加速平台上编码器的 QP 的阈值是不同的,比如 iOS 系统、Android 系统,甚至 Android 不同的芯片平台也需要做对应的适配。
- 不同编码算法,不同硬件平台,QP 质量变化的曲线不同,为了提取特征,需要调节统计方法的统计系数。
正确判断性能问题
为了防止性能问题导致的视频 QoE 降低,我们需要能准确的甄别出性能问题并作出正确有效的调整。当前我们的 VQC 中,使用视频帧处理时间来表征性能状态,想要正确甄别性能状态,需要考虑以下几个方面:
- 能判断编码和前处理的整个流程的性能
- 一些硬件有 pipeline 延时需要考虑
- 如果帧间隔不均匀,会导致误判定性能问题,需要识别出这种特征
为了进行有效的调整,我们主要需要考虑以下几个方面内容:
- 根据测试中性能消耗的优先级来调整,比如我们测试下来部分模块的优先级是:前处理 > 编码算法 > 帧率调整 > 分辨率调整
- 如果做了相应的调整,统计的性能状态还是没有变化,我们需要有相应的处理手段,反馈调整内容和结果给状态机,让状态机报告给决策模块进行下一步决策
- 如果性能状态变化过大,需要拉大调整步长
最优化调整
有效的调整就是是调整后视频 QoE 提升明显,我们主要可以通过以下几个方面进行调整:
- 分辨率调整
- 帧率调整
- Simulcast 流的调整
- 前处理的一些算法开关
- Codec 调整
VQC 是如何进行最优化调整的呢,如下:
支持用户可配置多种场景和策略
- 通信模式,直播模式
- 用户高可定制化:特殊场景模式,分辨率不变模式,帧率不变模式,最小帧率最小码率等设置
- 内部自适应调整,根据大量测试试验确定某个具体场景下的参数组合,调整步长以及最佳路径,比如如下视频分辨率和帧率调整步长和路径
结语
本文主要介绍了网易云信 RTC 中视频质量控制系统 VQC 的设计,以及在 QoE 调优方面的一些工作。没有一种策略是完美无缺的,鱼和熊掌不可兼得。我们在 QoE 调优中做的工作就是在一定的条件下,通过一些列手段平衡清晰度、流畅度、延时这些指标,趋利避害。通过互相配合的策略以及大量的数据测试验证,寻找出最优的策略。
QA 整理
以下内容,根据线上直播群内 QA 记录整理:
- @一苇以航 提问:
Q: 请问 ratecontroller 的时候,一般都是 SFU 转发模式,这个时候的 simulcast 是从服务端考虑所有订阅端反馈给发送者去调整大小流的码率吗?
A:我们服务端做了各种场景下的策略,默认是走可配置的 TopN 策略,部分头部观众尽量使用高清高流畅的大流,少量网络质量不好的用户使用小流,服务端会根据下行所有观众的网络情况,算出一个合适的反馈码率
Q: 恩,我的问题不是问服务端的 SFU 转发策略,而是发送端在大小流的码率调整策略,你们谈 ratecontrol 这个模块的时候说到了一点,发送端收到一个 cc 的带宽反馈,同时发送端提供了 simulcast,你们好像还能够考虑到不同的接收端的网络状态,进行大小流的码率调整 , 是有这个能力吗?
A: 我们有下行的 cc,服务器会根据下行 cc 输出的估计带宽,然后综合出一个合适的带宽反馈给发送端。Simulcast 是端上根据总的码率,在我们模块里面做决策,是发大流还是小流,还是双流。服务端也会根据每个端的情况,决定给下行发送大流还是小流。
Q:美颜跟超分会带来多大的延迟?
A: 关于美颜跟超分会带来多大的延迟的问题:小于帧间隔,不会 delay 我们 pipeline,我们做了动态适配,如果大于帧间隔,会动态关闭掉,对整个流水线的延时小于一个帧间隔,如果 30 fps 就是小于 33ms。
Q: 一般做这一块的都是基于 WebRTC 去做的,好像中途要切换 codec 的话,要么就重新创建 peerconnection 重新协商,你们支持是因为自研添加的吗,还是 WebRTC 本身支持呀?
A: 我们有部分参考了 WebRTC,codec 切换这块不需要重新协商,我们做了频道内的能力协商,是私有协议,不需要像 WebRTC 那样做 sdp 交换,我们有自己的能力协商协议,然后音视频引擎内部做切换。
Q:还有一个问题,你们在 RTC 会议房间里如何处理关键帧请求,每一个新加入的用户如果都发关键帧请求,会导致房间的流量很大,但是不发的话等到下一个 GOP 会很久,你们采用了什么样的策略去均衡?
A: 1. 一般逻辑是每个新加入的用户都会有 intra request 发出来,然后接收端有一个 key frame 发送间隔的控制。这样不会有太多 key frame,也不会导致出图很慢。
- 当然我们为快速出图做了些优化,提前服务器 intrarequest, 保存近期的 key frame 等操作。
这些都是我们实际调整的一些细节,需要根据自己的场景去适配,我们也是分场景的。直播和通信策略就不一样。 @galen 提问:
Q: 请教下怎么检测卡顿呢, 一般检测卡顿帧间隔时间有讲究吗?
A:卡顿我们会统计 200ms 卡顿和 500ms 卡顿,检测实际渲染的帧率间隔,超过 200ms 或者 500ms,统计小卡顿或者大卡顿。作者介绍
戚继跃,网易云信资深引擎工程师,长期从事音视频相关开发工作,对 WebRTC 引擎,音视频会议系统,视频编解码等有深入研究。目前主要负责网易云信 NERTC 引擎的视频体验。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。