RTC 场景下的屏幕共享优化实践 原创 精选
背景介绍
需求背景
屏幕共享是视频会议场景使用最广泛的功能之一,在共享一个 PPT 或者文档的情况下,人们对画面清晰度有着极高的要求,“看不清” 是最容易被用户吐槽的事情;而在共享一个视频素材的情况下,大家又对流畅度有着极高的要求,“卡顿” 也是最容易被用户吐槽的点。
为了更好地同时满足用户对清晰度和流畅度的要求,视频会议软件通常会设计两种模式:
- 清晰模式:主打清晰度,尽量保持高分辨率(如:最高 4K 原画质),带宽或性能不足的时候,只降低帧率(如:从 30fps -> 5fps),不降低分辨率。
- 流畅模式:主打流畅度,尽量提升帧率(如:最高 30fps),带宽或性能不足的时候,优先降低分辨率(如:从 4K -> 720p),最后才考虑降帧率。通常情况下,默认选择“清晰模式”,当用户要共享视频的时候,需要自己 “手动” 点击勾选上 “流畅度优先”按钮。
一般的做法是,让用户在共享屏幕时手动来勾选“清晰模式”还是“流畅模式”。但在实际的产品场景中,用户对这两种模式的感知并不是很强烈,不太可能要求用户在共享屏幕的过程中手动来回切换当前的共享模式,对用户体验影响比较大。
一种简单的方案是根据用户共享内容的文件后缀名来决定是“清晰度优先”还是“流畅度优先”,比如共享 PPT 时自动切换为“清晰模式”,共享视频时自动切换为“流畅模式”,但是这样设计会遇到一些问题:比如用户的 PPT 里嵌入了一段视频,在播放这段视频时理应追求“流畅度优先”;而如果用户视频其实是一段 PPT 的教学录屏,里面有大量的时间在播放静止的文字和画面,这时候“流畅模式”则会导致这些关键内容显得模糊。
RTC 要如何帮助用户及时调整最佳的共享模式呢?
需求分析
需求功能分析
痛点:
用户分享视频内容需要高帧率,而文字/ppt 需要高清晰度,这两种场景的需求是互相矛盾的,如果需要用户手动勾选相应的共享模式,不仅操作繁琐,也容易漏选、错选。
如何解决:
需要研发一个算法自动识别共享内容,进而确定当前是需要高帧率还是需要高清晰度。这样,在用户想要清晰画面的时候,产品就提供清晰的画面,用户想要流畅的视频体验时,产品就尽可能地保障屏幕画面的流畅性,用户在无感知的情况下就能获得当前场景的最佳体验。
屏幕共享场景定义
清晰度优先的场景
以文字为主,用户更需要看清楚画面的边缘特征,而较少关注其运动特征。
流畅度优先的场景
以视频内容为主,用户更需要流畅连贯的动态画面,而较少关注于单帧的清晰度。
技术实现
算法原理
学界相关成果概述
目前我们参考了以下两篇参考文献。第一篇是 Jing, Wang & Xuetao, Guan & Yang, Zhang. (2013). An Adaptive Encoding Application Sharing System Based on Remote Display. 266-269. 10.1109/ISDEA.2012.66.
该论文主要假定视频区域的均会以 24-30FPS 的频率发生变化,用 N*N 的 patch 的形式进行检测,从而发现视频区域。
第二篇参考文献是,侯文慧, 王俊峰. 面向云桌面协议的视频区域侦测算法[J]. 计算机应用, 2018, 038(005):1463-1469,1487.
这篇论文主要通过高变化区域侦测,并利用传统 sobel 算子+膨胀算法的边缘检测发现可能的矩形区域,通过颜色直方图的颜色数量判定文本区域从而确定视频内容区域。
相关算法的介绍
1、光流
光流(Optical flow or optic flow)是空间运动物体在成像平面上的像素运动的瞬时速度,是分析像素运动的一种方法。光流法在模式识别、计算机视觉以及其他图像处理领域中用处广泛,可用于运动检测、图像分割、运动补偿编码和立体视差测量等领域。
光流法实际是通过检测图像像素点随时间的变化进而推断出物体移动速度及方向的方法。假设该移动很小,那么可以根据泰勒级数得出:
因此可以推出
最终可得出光流方程:
这个方程有两个未知数,不能直接进行求解,这被称为光流算法的孔径问题。为了求解光流方程,还需要另一组方程,这个方程由附加的约束给出。(以上内容引用自 wikipedia)
孔径问题
(孔径问题示意,引用自:https://zhuanlan.zhihu.com/p/74460341)
假设:
- 相邻帧之间的亮度恒定;
- 相邻视频帧的取帧时间连续,或者,相邻帧之间物体的运动比较“微小”;
2、决策树
决策树是一种逻辑简单的机器学习算法,它是一种树形结构,所以叫决策树。这是一种基于 if-then-else 规则的有监督学习算法,决策树的这些规则通过训练得到,而不是人工制定的。
- 决策树易于理解和解释,可以可视化分析,容易提取出规则;
- 可以同时处理标称型和数值型数据;
- 比较适合处理有缺失属性的样本;
- 能够处理不相关的特征;
- 测试数据集时,运行速度比较快;
- 在相对短的时间内能够对大型数据源做出可行且效果良好的结果。(引用自 wikipedia)
3、颜色直方图
颜色直方图是许多图像检索系统中被广泛采用的颜色特征。它所描述的是不同色彩在整幅图像中所占的比例,而并不关心每种色彩所处的空间位置,即无法描述图像中的对象或物体。(引用自 wikipedia)
4、方向统计(Directional Statistics)
Directional statistics (also circular statistics or spherical statistics) is the subdiscipline of statistics that deals with directions (unit vectors in R(n)), axes (lines through the origin in R(n)) or rotations in R(n). More generally, directional statistics deals with observations on compact Riemannian manifolds including the Stiefel manifold. The fact that 0 degrees and 360 degrees are identical angles, so that for example 180 degrees is not a sensible mean of 2 degrees and 358 degrees, provides one illustration that special statistical methods are required for the analysis of some types of data (in this case, angular data). Other examples of data that may be regarded as directional include statistics involving temporal periods (e.g. time of day, week, month, year, etc.), compass directions, dihedral angles in molecules, orientations, rotations and so on. (引用自 wikipedia)
利用方向统计方法,能够准确地统计出向量样本的方向均值,以及方向的离散程度,也避免了传统统计方法在角度值统计计算上的误差。
举个简单的例子,如下图所示,7/4π 和 1/4π 统计均值,以传统方法计算为 π,而利用方向统计就可以得到出均值为 0 的结果。
算法总流程设计
视频的定义就是运动的画面,但在屏幕共享当中,并不能够将运动的画面都当作视频内容来处理。实际使用中,需要将部分运动的画面识别为需要高清优先、流畅度其次的屏幕内容,保证用户在此时获得清晰的观看体验。
1、探索性数据分析(EDA)
在正式进行算法开发之前,先进行了探索性数据分析,分析发现屏幕的运动特征具有较高的区分度,从而大致判定利用光流法来完成该任务的特征提取是可行的。
2、算法流程图
该检测算法分成三个模块,五个步骤。
三个模块分别是:
- 运动幅度分析:主要进行运动幅度相关特征的提取,能够统计运动画面比例,去除一些噪音。
- 运动角度分析:主要进行运动角度相关特征的提取,能够统计画面运动的方向,以及运动方向的分散程度等
- 纹理特征分析:主要提取一些纹理相关的特征,判定当前区域是否为文字区域。
具体分为五个步骤:
- 采样:光流算法需要前后两帧数据进行计算,需要对视频流进行采样,得到两帧数据
- 光流计算:计算出全图的稠密光流
- 特征提取:提取运动和纹理特征
- 状态转移:通过一系列模式和规则进行状态转移
- 输出结果:根据内部状态信息输出检测结果
算法参数优化与评价
数据采集和标注
由于数据集非常匮乏,需要我们自己高效地获取一批人工标注数据,进行参数的优化和算法的测试。我们自己录了一些数据,并开发了一个小型的标注软件,进行了数据标注工作。
算法评价指标
(图片来源:https://en.wikipedia.org/wiki/Sensitivity_and_specificity)
1、准确率 (precision)
精确率是针对预测结果而言的,它表示的是预测为正的样本中有多少是真正的正样本。那么预测为正就有两种可能,一种就是把正类预测为正类(TP),另一种就是把负类预测为正类(FP)
2、召回率(recall)
召回率是针对原来的样本而言的,它表示的是样本中的正例有多少被预测正确了。那也有两种可能,一种是把原来的正类预测成正类(TP),另一种就是把原来的正类预测为负类(FN)。
内容识别算法需要在准确率和召回率之间进行权衡,根据业务场景调整检测结果偏好。
算法实现与优化
算法实现
光流计算
稠密光流的计算目前有两种常见算法,HS 光流,DIS 光流 在实现上,选用了 DIS 光流估计的方法,两种方法在相同机器上运行时间如下表所示。
算法 | 分辨率 | 计算时间 |
DIS 光流 | 320x180 | 7ms |
HS 光流 | 320x180 | 13ms |
更为具体的计算开销和算法准确程度的数据可以参考下图
(DIS 光流法计算准确度与运算时长相较其他算法比较,引用自 Kroeger, Till & Timofte, Radu & Dai, Dengxin & Van Gool, Luc. (2016). Fast Optical Flow Using Dense Inverse Search. LNCS. 9908. 471-488. 10.1007/978-3-319-46493-0_29. )
特征提取
在计算光流之后,我们需要提取运动幅度,运动角度以及纹理相关的特征。
在计算光流之后,提取运动幅度、运动角度以及纹理相关的特征。
1、坐标系转化:笛卡尔系->极坐标系
光流估计得到的结果是每一个像素的(x,y)偏移,所以需要将这个笛卡尔坐标系的值转化为极坐标系,从而得到光流的运动幅度和方向信息,即(x,y) ->(ρ,θ)
2、纹理计算
参考了前文提到的两篇文献的相关工作,在 4x4 的 patch 内统计 Y 通道上的直方图特征,将 bin 的大小设为 1,统计 bin 的数量作为一个强特征。(这样实质就变成了统计有多少个 unique 值的问题),然后利用一个 hash 表进行映射与统计。随后与运动信息进行加权求和,可以获得一个全局的与运动相关的纹理特征值。
3、角度特征的提取
角度特征的提取使用了方向统计的方法,计算得到当前内容运动角度的均值、加权均值、离散程度、加权离散程度等特征,这些特征可以描述当前画面内容的运动信息。
状态转移
利用决策树,经过一些剪枝处理后,获得了一些强特征的阈值,比如运动的角度均值,运动的角度离散度等,这些阈值都具有非常显著的可解释性。在状态转移模块中,使用内置的一个概率值记录状态,然后根据上述基于机器学习的规则对概率值进行调整,再结合业务融合一些人工特征,最终根据概率值的变化转移模块的状态。
计算开销优化
虽然该算法能够以较快的速度对视频帧进行处理,但实际的屏幕共享中,对计算机资源的消耗也有更加严格的要求。那么就需要对检测的的策略进行细致的优化,够进一步降低 CPU 占用和耗电量。
1、计算量与运算速度
算法的运算量热点都在光流计算上,而光流的计算开销与选用的算法、图像大小以及算法具体参数有关。
算法 | 分辨率 | 运行时间 |
DIS(MEDIUM) | 320x180 | 7ms |
DIS(FAST) | 320x180 | 4ms |
DIS(ULTRA FAST) | 320x180 | 1 ms |
在算法应用了 Ultra fast 模式后,检测的 precision 和 recall 均出现了比较显著的下滑,而 Fast 和 Medium 差别不大。所以最终选择了 Fast 模式,在测试数据集上得到的结果也令人满意。
Accuracy | Recall | Precision |
0.9524 | 0.9608 | 0.9756 |
2、计算频率优化与静默模式
在计算量优化之后,算法能够以 150fps-200fps 的速度进行检测。在实际的屏幕共享场景,输入的帧率可以达到 30fps,如果检测频率为 30fps 仍然会带来显著的 CPU 占用,还需要进一步降低检测频率。
在权衡响应时间和 CPU 占用后,直接大幅度降低检测频率,比如每隔 5 帧检测一次,在这种策略下,响应时间和 CPU 占用都处于一种比较好的状态。
但是,这种较低的检测速度依旧会带来可察觉的 CPU 增量,能不能再极致一点呢?
考虑到常见的办公场景,用户在屏幕共享时,其内容类型在较长的时间内是保持不变的,所以检测的结果也应该是长时间保持不变。假如是我们人类在这种情况下,在做这样的分类结果一直不变的任务时,可不可以稍稍偷偷懒呢?答案是肯定的,那么计算机应该也可以在这种情况下“偷一下懒”。这样就可以在算法中引入了静默的概念,当检测的结果基本不变时,检测算法模块开始进入静默状态,此时检测降低到更低的频率,这样 CPU 占用增长基本就察觉不到了。
如何确定何时需要进入静默呢?算法利用时域上的积分求得一个分数,当该分数达到一定阈值的时候,并且满足一些其它的限制条件的时候,就可以认为检测到的为同一种类型了,就可以开始降低检测频率。这样就保证了大多数情况下 CPU 的极低开销,并且也尽可能保留了算法快速响应的特性。
功能实现
决策逻辑
在共享模式的决策逻辑的设计上,需要明确两点:
- 尽可能保持稳定的分辨率与编码策略,减少编解码器重启带来的开销
- 适当的切换速度
1. 帧率决策与分辨率决策
由于视频流传输的过程中,在有限的带宽下,往往需要将帧率和分辨率相匹配以获得合适的带宽消耗。
所以自动模式预设了若干个帧率和分辨率相匹配的档位,在每次获得检测算法的检测结果后对帧率进行增减,再根据帧率的大小匹配相应的分辨率。在帧率下降的时候,就可以根据内外部条件的限制升高传输分辨率;相反,在帧率上升的时候,就可以用适当的逻辑对分辨率进行降级操作。
2. 编码方式决策?
在共享文字场景为主的屏幕内容时,编码策略也会与流畅度优先的视频编码方式不同,这时会使用专门的针对屏幕内容的编码器,并开启重复帧检测等策略,同时也会对码控策略进行场景化的调整,从而使画面更符合用户需求。
3. 抗抖动?
策略的切换一般是需要需要响应时间的,比如分辨率的切换和编码策略的切换都会有一定的响应时间,如果频繁的切换就会造成卡顿。
为了在发生抖动的情况下,依旧能够保证良好的共享体验,需要引入一些抗抖动的机制。
抖动主要来自于两个方面
- 误检测造成抖动
- ?真实的共享内容频繁切换导致抖动??
对于第一点,通过两种机制来减少抖动影响。
- 在整个 pipeline 的设计上,设计一种负反馈的调节机制。如前文所述,在帧率越高时,光流估计越准确,而帧率低时,不准确的光流估计容易将一般的文档场景误检测成视频播放的场景。当检测出一次内容变化时,如果是因为输入帧率低导致误检,这个时候及时提高帧率又能够降低误检概率,这样就可以避免由于误检导致的共享模式的切换,促成检测速度和准确度的稳态。
- 通过控制决策频率来抑制抖动的现象。
对于第二点所提到的抖动,最影响体验的场景是在内容变化或者其他原因,帧率反复在决策点附近上下波动,导致分辨率反复切换。因此,在控制决策频率的基础上增加了 dead zone 机制,在该机制下,分辨率切换在提升和下降两个变化方向的决策点并不一样,留有一定的间隔,避免了内容频繁切换或者其他原因造成的分辨率的抖动现象。
在这种机制下,分辨率就不会随着帧率进行频繁地切换,能够更好地保证用户体验。
功能特色
业务实践
在飞书屏幕共享的流畅度优先模式中率先启用了该功能,在业务上称为智能流畅模式,这样在用户就能够在播放视频时达到 30fps 的流畅度,在共享文档/ppt 内容时,又能保持较高的清晰度。这个功能基本解决了用户错选流畅度优先造成的清晰度不符合需求的问题,同时又保证了在用户在真正需要流畅度体验的时候,得到高帧率的体验。
落地效果
经过大范围的线上测试之后,通过统计数据可以发现,采用“屏幕共享自动模式”后,一些原本采用“流畅模式”的共享场景被算法模块纠正为了“清晰模式”,同时通过下图可以发现,用户的屏幕分享分辨率有了极大地提升,得到了显著的清晰度提升。在线上算法的判定的准确程度上,通过对用户反馈的统计,该功能也有着比较好的评价。
同时通过统计数据可以发现,得益于采集和编码帧率的下降,CPU 占用不仅没有上升反而得到了一定的优化,如下图所示,开启自动模式的功能之后,最高可以得到 CPU 占用降低 20%的收益。
与其他候选方案的比较
在研发之初,我们也调研了一些候选方案,一种技术方案是使用像素差异与变化的占比作为切换依据,这样最大的问题是,在部分教学视频或说明类内容中,在视频内容中展示 ppt 场景时,算法会出现误判,将肉眼感知到的静态场景检测为视频场景,画面清晰度下降,不符合用户使用的直觉;此外还有一种方案是针对应用类型进行适配,比如根据进程名称和窗口大小进行策略调整,这样虽然能够解决用户场景化的需求差异,但是对于算法与策略的通用性会有较大的挑战。本文使用的这套算法就能够避开了上述的问题,体验更加友好。
未来的演进与规划
算法演进
虽然由于数据集的相对缺乏,在设计之初排除了深度学习模型的应用。在研发过程中,对算法流程与模块进行拆分,其中独立出的纹理分析等模块,这样就可以通过人工数据集的方式,在部分算法模块尝试应用深度学习模型,以期能够获得更好的算法表现。同时,考虑到当前的算法还是针对全局画面的分类,未来会推出视频区域的 ROI 检测,这样能够让下游应用具有更强的灵活性和对业务的适应能力。
业务演进
当前屏幕内容检测算法支持了共享模式的切换,此外,利用屏幕内容检测算法,还可以对发送端和接收端的网络策略进行更智能的调优,以期在文档、ppt 场景下,进一步减少屏幕共享的延时与卡顿,让投屏与屏幕共享响应更高清、更流畅、延时更低,给用户提供更好的沉浸式体验,带来更显著的生产力的飞跃。