近年来,伴随着采集渲染设备终端发展,人们对视频质量的需求也在日益“膨胀”,更高的分辨率:4k/8k,更宽泛的亮度,色度动态范围HDR/Dolby视界,更沉浸式感受:VR /AR 360全景体验等;这也给网络带宽/设备计算能力等带来了新的挑战,怎么在有限的容量下传输最有价值的视频信息始终是我们需要解决的核心问题;面向未来,七牛云作为领先的云服务厂商,全线产品支持更好的视频编解码成为必然选择。本次LiveVideoStack 2021 北京站邀请到七牛云视频编解码负责人—朱玲,重点分享七牛云将H.265落地运用到QRTC场景的一些创新经验和教训。
文 | 朱玲
整理 | LiveVideoStack
我是朱玲,在视频编解码领域有10多年的工作经验,目前就职于七牛云,负责视频编解码方面工作。
本次主要和大家分享七牛云RTC场景中落地H.265的实践经验。
本次分享从以下三方面展开:首先是为什么在QRTC支持H.265?其次是如何更好支持H.265?最后探讨QRTC在视频质量优化方面的规划。
1.为什么支持H.265
很多同学可能会疑惑,2013年H.265就结题了,七牛云为什么在过了将近十年后的今天才来谈在rtc场景落地H.265,似乎很不fashion。我也观察到,国内音视频行业对H.265的讨论在2017年达到高峰,内容主要集中在点播、转码、窄带高清领域,少部分关于RTC领域的讨论也主要是桌面共享优化中提到的H.265 SCC Tools,甚至于,近两年关于AV1的讨论却逐渐多起来,这次大会就有几场分享主题是AV1的,其实这都很好理解,AV1作为Google家VPx的下一代,就像10年前的VP8 vs H264之争一样,不同的是,Google这次联合了许多商家研发AV1,也可见AV1的复杂程度,难搞啊。
在选择H.265之前七牛云进行了完备的市场调研,结果显示经过八年的发展,H.265生态已经非常完善,基本所有OTT设备包括摄像头、smartphone都能够支持H.265,这是AV1所远不能及的。当然,RTC领域的从业者更多关注Web端,我们也对Web端进行了调研,Safari和Edge均支持H.265,个人看来Chrome支持H.265可能只是时间问题。
而且,伴随着HDR/4K、8K高清视频的出现,H.264已无法满足不断提升的视频质量需求了,即使带宽充足了,H.264的压缩成本也非常高,亟需更高压缩率的编码器来解决当下的痛点。
左图中黄线代表H.265,预测从2020年开始一直处于稳步上升的态势,到2029年完全超过H.264。我个人是非常认可这张图,从我们的后台监控流量观察,2019年H.265的量并不大,大概占据10%,但从2020年开始,流量就一直在不断增加了。
业内同学经常讨论H.265的好处和优点,在WebRTC中的应用效果还是那么好吗?目前没有足够的文献、数据支持定论,但我相信已经有许多厂商尝试甚至已经开始支持H.265,七牛云也不例外。
在测试H.265时,我们找了一大批数据集(Class B-E,标准组织的开放源码)。我们没有测试2K,是因为RTC场景主要是720p、1080p。Qiniu是我们自己的用户数据测试集,大概有六十多个,包括游戏、直播等场景。在所有的测试系列上对比了X265(不是very fast或ultra fast,是七牛云自己定的档次,这一档次的速度类似于ultra fast,但性能更好)、X264及OpenH264(WebRTC默认集成)。数据显示,相对于X264,X265压缩率提升了36.3%,相对于Open H264更是提升了64.1%。简而言之就是节省了许多带宽成本。但问题在于编码速度降低了2-5倍,表中列举的是相对速度,在四核机器上跑1080p时,X265编码的绝对速度大概~20fps。
左视频由OpenH264编码,右视频由X265编码。大家可以观察两个视频中“数字19”及地面上绿色的线,可以明显看到左边比较模糊。
总之,由于AV1的生态不完善,而H.265落地就能为用户带来价值,所以七牛云优先选择H.265。
2.如何支持H.265
图中是X265的框架,做编码器的同学应该非常熟悉。X264和X265在框架图中的区别仅在于SAO和Split into CTUs,既然框架大致相同,那么为何前者相对后者能够提升较大性能呢?
主要原因是X265的分块更大更灵活,编码单元最大是64x64,64x64可以继续以四叉树形式划分为32x32, 16x16,到8x8的分割,块划分方式一共有85种可能性,比H.264更丰富。
X265的帧内、帧间预测模式也更丰富,这里截取的是Inter模式下的PU划分方式,左侧的对称性分割两者都有,但H.265还能进行4x16或12x16的非对称性分割。
X265的TU也更大,从之前的4x4,8x8到现在的16x16,32x32,TU越大,去冗余也就越多,(当然计算量也会越大,下文会详细讨论)。
除此以外,X265也增加了新的coding tools,如SAO、AMVP,AMVP相较于H.264中的MVP加了时域MV预测,还有Merge模式等等。
以上是X265性能提升的主要原因。
既然H.265 这么好,那是否有现成的编码器实现可以直接应用到我们的产品中呢?带着这个疑问,我们重点测试了硬件实现的代表:Video TooLBox,学术界实现:HM,以及开源实现X265,从测试数据看来,VideoTooLBox并不乐观,两个指标甚至都不如X.264,所以大家在直接使用Apple硬件支持H.265时也许会发现,怎么性能可能还不如X264啊;而HM 的速度真的太慢了,完全不能产品化,但压缩率确实好。至于X265,前面也介绍了在特定环境下绝对速度只有20fps,达不到实时高清要求,而且相对于HM,X265的压缩也有很大提升空间。
我们的目标是产品化的H265的速度能达到或接近H264的水平,压缩率达到HM水平。
七牛云对265编码器的优化包括码率控制优化、编码工具优化、汇编优化。
2.1 码率控制分析&优化
WEBRTC传输层为了能够实时检测带宽,耗费了很大精力在带宽估计上,比如推出了GCC、TCC等,光带宽估计准确是不够的,编码器的码率控制(尤其在WebRTC场景下)同样重要。
码率控制的主要内容是预估当前帧/宏块的相对复杂度,结合可分配码率,计算当前帧/宏块的编码QP,可以简化为Bit->QP, 码率控制要注意以下问题:
1、控制粒度,控制到帧级还是宏块级,如果控制到宏块级,那么一帧里的每个宏块的QP都是不同的。
2、帧/宏块复杂度估计,如何计算复杂度。
3、如何建立Bit-QP之间的关系模型,使用R-Q还是R-λ模型。
4、实时反馈调整机制,估计不准确要尽快进行调整。
优秀的码率控制首先要能控住,但这并不是最重要的,比如500k的带宽控制到200k,视频质量会非常差,这样的控住没有意义,所以应该是控制且最大化发挥带宽能力。其次还需要平稳的视频质量和最优的压缩性能。
下面让我们带着这四个问题,分析下X265的码控实现。
图为one-pass的ABR算法下X265帧级码控流程图
X265在计算当前帧的复杂度时,不仅使用了当前帧的SATD,还使用了之前的SATD。所以X265码控特征是波动小,新的一帧对整个系统影响和冲击比较小,延续了X264作者说到的希望QP波动不大。虽然这个想法很好,但当某一个场景下的R-Q关系发生大的变化后,这时如果QP波动还很小,无法对系统造成冲击,势必不能较好地控制码率。X265也打了一些补丁,当出现新的一帧或新场景的时候,就会重置整个系统的码控。
针对RTC场景,我们对X265帧级码控了个有趣的测试。
横坐标是时间维度的帧数(25帧/s),在250帧(10s)这一点改变目标码率,从1000k改为500k(码率实时波动是RTC场景的一个显著特征),可以看到,如果在ABR码控中只修改Bit值,不进行其他操作,图示蓝线(代表实际码率)和目标码率的跟随很不紧密,一直到350帧也就是14s左右才能接近目标码率,而且码率很快又降低很多,和目标码率差距较大。如果在改变目标码率的同时刷新码控模型,就会像红线(代表重置后的实际码率)的表现一样,紧紧跟随目标码控并且很快达到目标码率水平。
测试说明如果在RTC场景使用X265的ABR,设置新的目标码率同时需要刷新码控模型,否则会像蓝线一样表现非常差。
宏块级码率控制不是X265默认选项,需要先设置VBV才会启动宏块级调控,更准确地说是编码一行之后再调整QP。VBV对QP的调整区间为[-6,+6],当超过+6时,系统判断为此时码率明显不够,将使用新的QP重新编码这一行。
我们将码率控制在500kbps,对RTC场景下使用VBV算法的X265宏块级码控系统做了大量测验,数据显示如果不打开VBV,码率是能控住的,打开之后,PSNR表现差不多。
图示QP-Limit的意思是,我们限制了码控输出的QP范围:WebRTC的代码中经常会将量化范围设置为24~37,认为这个区间的视频质量是人眼能够接受的,低于24会浪费bit,人眼也不太能主观看出差别,大于37人眼则不能接受。所以我们也设置了24~37的码控限制,试图造一个“不打开宏快级别码控,码率控不住,打开之后就能控住的case”,结果显示, 打不打开VBV都控制不住,宏块级别码控没什么作用。我个人怀疑是复杂度计算出了问题,但没有深究。至少在大量测试数据的佐证下,VBV在RTC场景发挥的空间较小。另外,QP限制是有一定作用的,PSNR提升很多,视频质量也会更好。
在保证单帧质量的情况下,X265控不住码率,那么如何解决这个问题呢?既然X265不是针对RTC场景优化的编码器,那我们就找到了为RTC场景诞生的OpenH264来进行测试。
图为OpenH264的码率控制模型,和X265的码控系统相同,它也有复杂度、不断更新的模型、上溢下溢。它的特别之处在于skip,当码率控不住的情况下,会选择跳帧来控制码率,否则对带宽应用影响很大。当然,跳帧也需要聪明的逻辑加持:如果10帧给了300k冗余,结果3帧就用完了后面7帧的冗余,其它全部跳帧,会导致画面不连续。
对OpenH264进行的测验中,QP限制是必须的,因为需要保证单帧质量,否则出现马赛克会严重影响用户体验。在已经进行QP限制的情况下,控不住码率时就要打开skip,对比最后两行数据,打开skip控住后的码率是496.8,未打开skip控不住时码率达到653.3,当然帧数也是从本来的1000帧到694帧,跳了300多帧。
分析了这么多算法后,七牛云也提出了自己的码控算法QNRC。目前只做了帧级的码率控制。
QNRC采用的是R-λ模型。右上图是我们拟合的一条bpp(bits per pixel)和qs cale的关系,这样就可以跳过帧复杂度的计算,因为在实时场景下复杂度计算也不准确。QNRC允许skip,同时设置QP调节范围。
右下图是测试结果,横坐标每2s为一个点,可以看到500k时QN265表现非常平稳(1s为一点时会有一些波动),而蓝线X265-ABR波动比较大。从码控来看,QN265基本接近目标码控500k,码率大概浪费了0.04,PSNR高了0.5,质量高很多,这就是七牛云目前所做的码控系统,还有一定的优化空间。
2.2 编码工具分析&优化
编码工具优化我们主要介绍广义B帧、AMP、Adaptive QP、SAO、帧间模式选择(整个编码器中最耗时的部分)的优化。
2.2.1.广义B帧
H.264或H.265的传统B帧用到后向参考帧,实时系统中实现传统B帧势必会增加延时。广义B帧的出现就解决了这个问题,它的预测编码模式选择都和B帧一样,但只用了前向参考帧,这就是广义B帧(Generalized P and B picture)。
目前苹果硬件码流支持GPB, HM也是支持的,X265不支持,所以我们在HM上测试了广义B帧的功能,观察GPB是否能在RTC场景中产生效益。
为HM配的参数适用于zero lantency场景,从数据来看,GPB是有效果的,1080p能带来超过10%的压缩率,这是非常可观的数据。
我们也尝试了在X265上集成支持并做了些测试,将X265的P帧全部改为了GPB帧,压缩速率并没有达到预期效果。分析码流发现,左上图是HM中第一个GPB帧中的第一个采用双向预测的宏块,L0和L1不同。按理说,参考帧相同 L0应该等于L1(第一个宏块,后面的可能被AMVP影响就不列举),这是因为B帧的双向预测会固定L0的mv,再重新降低范围,增大精度进行精确搜索,而X265尚不支持双向预测运动估计。
于是,在支持GPB的同时QN265也只吃了了Bi- prediction motion search,右图数据显示支持BI search和GPB后能够带来8.36%的压缩率。
所以大家如果想要实现RTC场景下的编码器,最好能够支持BI search和GPB。
2.2.2.AMP
上文也提到了X264都是对称性分割,X265增加了不对称性分割,结合视频块运动的复杂多样性,增加不对称PU划分分时,往往能找到更精确的mv。
测试显示:X265也支持AMP +RECT,整体带来了9.5%的性能提升,速度也降低的比较多了,怎么降低复杂度呢?
我们做了些测试,设置一个QP值37,码率不太高的平滑运动场景,发现打开和关闭AMP其实影响不大,选中AMP的没有多少,可见,针对码率比较低低,比较平缓运动的视频序列,可以自适应关闭AMP。
另外,我们对打开AMP的码流进行了仔细的分析,如图所示左边是前一帧,右边是后一帧。红色箭头所指的帧选中了非对称性的划分方式,它的前一帧不是skip。总结得出一个结论:如果当前帧用AMP的划分方式,它的前一帧中相应块大概率不是skip的,我们将这个逻辑运用到快速算法 中,结果显示:可以看到压缩性能提升了7.7%,速度略有一点降低。
2.2.3.Adaptive QP
Adaptive QP是X264作者的拿手之作, 它的实际思想是人眼对视频中平坦区的失真是非常敏感的,而对于快速变化的失真没有那么敏感,所以应该把码率主要用在平坦的地方。它会检测帧的复杂度,如果是平坦的就降低QP,提升整体主观质量。
我们也集成了Adaptive QP算法,进行了大量测试,但设计了很多case都没有看到明显的主观质量提升,虽然压缩率降低是符合预期,但是画质没有增强就有点意外了,QN265暂时没有打开此功能选项。
2.2.4.SAO
SAO(Sample Adaptive Offset ,样本自适应偏移),它的出发点是:在编码端既有重建解码图像也有原始图像,对二者像素进行比较,如果将这个像素值偏移offset写到码流里传到解码端,解码端解码重建时候加上这个offset,那么就更接近原始帧了。这个工具主要是用来提升编码的PSNR,使解码帧接近于原始帧。想法自然是很好的,但每个pixel都计算残差写入码流是是非常浪费bits,无法达到视频压缩目的的。因此,SAO的研发者提出了对图像进行分类传输,只对特定类别的像素offset进行传递,这样即能节省码流也能降低视频压缩失真。
SAO在X265的实现可以说是直接从HM拿来的,站在巨人的肩膀上,避免重复造轮子一点问题也没有,同时也说明了这部分的优化空间非常大,因为HM的实现侧重点不在产品化上。
X265里面又个SAO加速工具 “SAO-imited”挺好使的,建议大家支持SAO,毕竟能带来可观的视频质量提升,同时也要研发更多的快速算法实现宏块级别自适应SAO功能,整体提升效率和压缩率。
2.2.5.帧间模式选择
图示是X265的帧间模式流程图简化版,相较于HM的流程有很大变化。前面也提到,X265和HM比较有30%的压缩率差异,这一块就占了较大比重。QN265的帧间模式选择流程充分接近HM实现,同时集成了自己的快速算法(主要是early skip),从现阶段的测试数据来看,QN265帧间预测部分相较于X265压缩率提升了5%。建议大家在实现或优化自己的265编码器的时候,尝试打破X265的思路,也许会有意想不到的效果。
2.3 代码分析&汇编优化
最后是代码的汇编优化部分,我们首先使分析工具对代码进行复杂度/cpu耗时分析,如图所示,对耗时比较多的函数进行逐个分析优化来降低函数执行时间。
举个例子:X265的“ ComlexityCheckCU”函数,实现的功能是:先求像素平均值,再用每个像素值减去平均值得出差值。编译器自动解析需要12条机器指令外加两个大循环来实现,复杂耗时。
对这个函数进行指令集优化,所谓指令集优化或汇编优化,它的底层逻辑即使是一条指令并行处理多个数据,增加指令处理的吞吐量。如图所示,使用 AVX2的汇编指令集,用四条指令,每条指令并行处理八个像素,整体耗时是原先的1/5。
经过以上几方面的优化,QN265编码器速度和X265的ultra fast相当,在720p上能达到实时编码,1080p大概在20多帧。压缩率提升~20%。
当然了,光有好的算法还不够,在RTC场景中还需要实现一整套的质量控制系统,将具体应用的场景特性,设备特性,利用大数据的手段整合起来作为我们编码器使用的指导。QN265在保证实时性的前提下提供了三个档次可供选用,大概的性能指标如图所示。可编码速度越快,压缩率会随之下降。一般而言,好的设备最好用最慢的档次,压缩率会节省更多,毕竟带宽占据视频应用的大部分成本。
3.未来规划
未来,我们会持续优化H.265,虽然速度已超过ultra fast,但我们不满足于此。其次会集成一些抗弱网工具,RTC场景最大的问题就是弱网。最后,我们拥抱所有的好技术,新标准。