网易云信 NERTC 高清画质体验之 H.265的工程实践 | 体验共享技术专题

1,310 阅读14分钟

导读:H.265是 ITU-T VCEG 继 H.264之后制定的新一代视频编码标准,相比于 H.264,H.265能够进一步提高压缩效率,提升画质,在当前的很多音视频场景中,得到了越来越广泛的应用,我们在网易云信 NERTC 中对 H.265做了大量的工程实践,本文为体验共享系列第三篇—视频篇,文章将从四个方面做具体介绍。

能力协商

一个客户端能否发送指定的特征的码流,不仅由本端是否支持编码决定,也由房间里其他接收端能否解码决定。**即发送端和接收端共同决定了本端能发送什么样的码流。**对于 H.265,可能会出现下面的情况:

表1.png

那么他们之间将如何通信?客户端 B 如果发 H.265的流,客户端 A 和客户端 D 由于只支持 H.264解码,它们接收到客户端 B 发送的 H.265的码流,是无法解码的,所以我们需要设计一套能力协商机制,来保证支持不同编解码能力的客户端之间可以正常的通信。

下图为能力协商的整体设计图:

图1.png

下面详细介绍一下我们能力协商的设计方案。

能力集设计

能力集定义为 { uint32 key : [ uint8 value1, uint8 value2 ... ] },使用1位掩码

**sdk **的 key 范围是 [ 0, 2^8  ) 

video 的 key 范围是 [ 2^8, 2^16 )

audio 的 key 的范围是 [ 2^16, 2^24 )

字节示意如下:

图2.png

举例说明如下:

表2.png

能力协商流程(客户端)

  1. 客户端本地定义能力集

  2. 客户端本地实现能力集上报,能力集下发配置的机制

  3. 服务端提供频道内能力集的生成、综合以及下发功能

举例说明:

定义:能力字段** VideoCodec : 256 (2^8),能力值 H.264 : 0,H.265 : 1**

 客户端 A 和客户端 B 进入同一个频道时,客户端 A 上报能力集{ 256 : [0, 1]},客户端 B 上报能力{ 256 : [0]}

服务端收到客户端 A 和客户端 B 的能力集上报之后,知道 A 支持 H.264和 H.265,B 支持 H.264,综合 A 和 B 的能力集,得到频道内支持 H.264的结论,下发能力集 {256: [0]}

客户端 A 收到能力集后,主动关闭自己的 H.265能力;客户端 B 收到能力集后,和自己的能力集一致,不做改变。

能力协商流程(服务器)

  1. 房间创建时,生成默认能力集,默认能力集由引擎提供,服务器用作一个全局配置

  2. 第一个 edge_login 请求如果有能力集字段,则使用这个能力集覆盖默认能力集,作为房间的能力集;如果没有能力集字段,则使用默认能力集作为房间的能力集。由于是第一个,不需要广播。

  3. 后续每个用户进来,如果能力集大于房间的能力集,则返回房间的能力集给这个用户,房间的能力集不变。举例说明如下图:

表3.png

  1. 后续每个用户进来,如果能力集小于房间的能力集,则取交集,缩小房间的能力集,并把结果广播给所有的用户。举例说明如下图:

表4.png

H.265编解码器实践

各个平台有自己特有的硬件265编解码器,同时还有各种开源的软件265编解码器,那么我们将如何选择,才能实现最佳的使用效果?

下面我们将分 Android,iOS,Mac 和 Windows 四个平台分别介绍各平台265编解码器的实践情况。其中软件编码器选用 x265做测评,软解选用 ffmpeg,libhevc 做测评。

Android 端

首先我们看一下 android 端硬件编解码器的功耗和码率情况(测试机型 Mi 10 : Qualcomm Technologies, Inc SM8250,测试 Profile:720P 30fps 1.7M)

表5.png

再看一下 android 端各软件编解码器的性能情况(测试机型 Mi 10 : Qualcomm Technologies, Inc SM8250,测试 Profile:720P 30fps 1.7M)

表6.png

表7.png

最后看一下画质对比(测试机型 Mi 10 : Qualcomm Technologies, Inc SM8250,测试 Profile:720P 30fps 858k),左为 H.264,右为 H.265

图3.png

总结:

  1. android 硬编265在功耗方面基本跟硬编264持平,同时 android 硬编265码率比硬编264更稳一些
  2. android 端软编265的性能还是比较差的,不能满足需求
  3. android 端 ffmpeg 软解265在 arm64上面性能比较差,**CPU 占用达15%,同样条件下,使用 libhevc,CPU 占用只有4.5%,性能上有很大提升空间 4. android 硬编265的画质明显要比硬编264的画质更清晰,画质收益很明显

所以 android 端我们265编解码器的使用策略如下:

  1. 优先使用265硬解。一些设备存在265硬解兼容问题的,高端机型选择265软解码器,低端设备直接认为不支持265解码
  2. 优先使用265硬编。一些设备存在265硬编兼容问题的,则认为不支持265编码,降级到264编码
  3. 由于 libhevc 软解的性能明显优于 ffmpeg 软解265,所以265软解码器我们会优先选择 libhevc

iOS 端

首先我们看一下 iOS 端硬件编解码器的功耗情况(测试机型 iPhone11,测试 Profile:720P 30fps 1.7M)

表8.png

表9.png

另外我们发现在某些机型上或者某些场景下,iOS 硬编265会出现明显的码率不足的问题(测试机型 iPhoneXR,测试 Profile:720P 30fps 1.7M)

H.264:

图4.png

H.265:

图5.png

像这种出现码率严重不足的情况,我们基于 iOS 硬编码控,设计了一套码率监控方法,如果监控到码率出现严重不足,会从 H.265回退到 H.264

最后看一下在硬编码率稳定的情况下的画质对比(测试机型 iPhone11,测试 Profile:720P 30fps 858k)

左 H.264,右 H.265

图6.png

总结:

  1. 使用 iOS 硬编265功耗明显比硬编264要大,同样的使用 iOS 硬解265功耗也明显比硬解264要大一些
  2. iOS 硬编265偶现一些码率不足的情况,导致画质反而不如264
  3. iOS 硬编265的画质要比硬编264的画质更清晰一些,有一些画质收益

所以最后 iOS 端我们265编解码器的使用策略如下:

  • 优先使用硬编265,不支持软编265
  • 优先使用硬解265,只有在硬解265多次解码失败无法恢复后才会回退到 ffmpeg 265软解
  • 由于 iOS 265硬件编码功耗比硬件264要大,监测 iOS 设备整体电量,在低电量情况下(比如到20%临界点),我们把硬件265切回到了264硬件编码器
  • 使用 iOS 硬编码控模块,监测实际编码码率情况,若出现明显的码率不足或者码率超发,我们把硬编265切回到了硬编264

iOS 硬编码控

下图为硬编码控模块设计图:

图7.png

码控流程:

  • 首先硬编码器将目标码率 Target Bitrate 传递给码控模块 HWBitrateController

  • 每编码完成一帧,将编码后的帧大小更新给 HWBitrateController 估算出每秒的实际编码码率 Estimated Bitrate

  • 计算目标码率与实际码率直接的差值 Diff

  • 通过二分法,取0.5倍的 Diff 加 Target Bitrate,作为需要调整的码率 Adjusted Bitrate

  • 将需要调整的码率 Adjusted Bitrate 设置回硬编码器 HWEncoder,作为 HWEncoder 的目标码率 Target Bitrate

  • 再**回到第一步,**硬编码器将当前目标码率 Target Bitrate 传递给码控模块 HWBitrateController

  • 计算 Diff/Target Bitrate,如果持续大于30%,则认为码率出现明显不足,需要触发降级编码器

**Mac 端 **

首先我们看一下 Mac 端265软硬件编解码器的 CPU 和码率情况(测试机型 MacBook Pro (15-inch, 2016): Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz,测试 Profile:720P 30fps 1.7M)

表10.png

表11.png

硬编265码率情况:

图8.png

软编265码率情况:

图9.png

同时,我们通过 dump Mac 硬编265的码流,发现使用前向 B 帧取代了 P 帧

图10.png

最后,我们看一下画质对比(测试机型 MacBook Pro (15-inch, 2016): Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz,测试 Profile:720P 30fps 1M)

对比图1.png

对比图2.png

总结:

  1. Mac 上面硬件265相对于软件265,CPU 占用更低,性能收益比较明显
  2. 硬编265码率稳定性不如软编265,波动比较大,但都是围绕目标码率上下波动,经过长时间测试,发现整体码率平均下来没有明显的超发或者不足情况出现
  3. 硬编编码码流前向 B 帧取代了 P 帧,整体压缩率会更高,同等码率画质更优
  4. 硬编265画质明显优于264,而软编265与硬编265画质差异不大

所以 Mac 我们265编解码器的使用策略如下:

  1. 优先使用265硬解。一些设备存在265硬解兼容问题或者不支持265硬解的,在 CPU 性能比较强的设备上面使用软解265(ffmpeg),如果是 CPU 比较弱的设备,则认为不支持265解码
  2. 优先使用265硬编。一些设备存在265硬编兼容问题或者不支持265硬编的,在 CPU 性能比较强的设备上面使用软编265,如果是 CPU 比较弱的设备,则认为不支持265编码

Windows 端

windows 上面由于硬编硬解碎片化比较严重,我们暂时没有考虑使用硬编硬解,目前以使用软编软解为主。

下图为 win 上面软编软解265的情况(测试机型 Dell Latitude 5290: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz,测试 Profile:720P 30fps 1.7M)

表12.png

表13.png

可以看到:

1. 软编265和软解265在 x86上面的性能表现不如 x86_64

2. 软编265在 x86_64上面的 CPU 消耗也是远远高于软编264的

所以最后 Win 我们265编解码器的使用策略如下:

1. 在使用 win x86的情况下,直接不支持265软编软解

2. 在使用 win x86_64的情况下,CPU 性能比较强的设备上开启265软编软解;同时软编265对 CPU 性能要求比软解265更高,所以对设备的性能要求也会更加严格

工程策略

白名单策略 

前面有提到,我们在使用265硬编硬解的时候,需要考虑设备兼容性的问题;同时在使用265软编软解的时候,由于涉及大量的编解码运算,也要考虑设备的性能问题。

为了在整体工程层面提供最佳的用户体验,我们使用到了白名单策略。通过白名单配置下发,把是否支持265硬编硬解和软编软解的设备区分出来。

以下是我们的具体做法:

  • 通过大量的设备适配,把对265硬编硬解支持比较好的设备,配置到线上白名单里面
  • 通过设备跑分,区分出设备 CPU 性能的高低,配置高性能的设备支持265软编软解,低性能设备不支持265软编软解,然后将配置更新到线上白名单里面
  • 最后通过线上白名单配置下发,客户端获取到当前是否支持硬编硬解和是否支持软编软解的配置信息

H.265能力协商 

协商的是 H.265解码能力,协商结果最后作用于编码侧,是否使用 H.265编码

  • H.265解码的配置下发,用户设置以及当前设备支持能力,三者综合得出当前 H.265的解码能力
  • 能力协商模块,根据当前 H.265的解码能力,生成能力集,上报给能力协商服务器
  • 能力协商服务器综合频道内各客户端的能力集,生成新的房间能力集,下发给各客户端
  • 客户端收到来自于服务器下发的能力集,解析出当前频道内 H.265的能力集
  • 根据当前频道内 H.265的能力集,H.265编码的配置下发、用户设置以及当前设备支持能力,服务器对 H.265的支持能力,三部分综合得出当前是否支持 H.265编码,最后作用于编码侧是否编 H.265的流

CPU OverUse 策略 

通过跑分,区分出不同设备 CPU 性能的高低,可能不是完全的准确。在实际场景中,有可能存在跑分数据很高,但是编码性能不够的情况,这时候我们需要通过实时监测统计当前视频编码耗时,来判断当前是否 CPU 过载。

我们的做法是:

  • 硬编265考虑到可能存在 pipeline delay 的情况,目前我们暂不统计每帧编码的编码耗时
  • 在使用软编265的时候,统计每帧编码的编码耗时,如果出现持续编码耗时过长,那么就认为当前 CPU 过载,265软编将会立即回退到264

QP 阈值调整 

**我们的 QOE 模块,会根据 QP 阈值调整帧率和分辨率,以达到主观视频质量最优,**所以设定合理的编码器 QP 阈值就显得非常重要,那么在实际工程实践中,准对硬件265编码器,我们如何探索出合理的 QP 上下限阈值?

我们的做法是:

  • 确保 H.264和 H.265在主观画质基本对齐的情况下,打出 QP 值,生成 QP 曲线,基于 QP 曲线得出 QP 上下限阈值基本的范围

我们以这款机型为例:(测试机型 Mi 10 : Qualcomm Technologies, Inc SM8250,测试 Profile:720P 30fps)

表14.png

可以看到:

  1. 在720p 30fps 这个 Profile 档位,硬编265与硬编264在画质基本对齐的情况下,硬件265码率能够节省40%,QP 波动基本相似,上下阈值也基本接近。所以如果当前 android 硬编264的 QP 上下阈值是[A, B],那么建议 android 硬编265的 QP 上阈值范围为[A-1, A+1],QP 下阈值范围为[B-1,B+1]

  2. 基于步骤1得出的 QP 上下阈值范围,逐步网损逐步放开,观测 QOE 模块基于 QP 阈值的分辨率和帧率的调整情况,从 QP 阈值范围中摸出最合理的一个 QP 阈值,以下面的数据为例:

表15.png

我们发现在 QP 阈值为[A-1,B-1]的时候,整体 QOE 表现最好,所以选定[A-1,B-1]为最后的硬编265的 QP 阈值

收益

目前第一阶段的收益评测,我们是基于与 H.264分辨率码率对齐,看画质收益、端到端延迟、CPU 占用、流畅度这四个指标。这里先列举了与硬编264对比,Android 硬编265和 iOS 硬编265的画质收益情况,从我们评测下来的情况看,**端到端延迟、CPU 占用、流畅度这三个指标基本上差异不大,**而画质收益,可以参考以下图表数据:

图15.png

图16.png

总体来看:

  1. 相比于264,265在视频画质上是有明显收益的

  2. 在低码率、弱网或者画面变化比较剧烈的场景下,画质收益会更加明显

  3. android 硬编265的画质收益要明显优于 iOS 硬编265

总结

不管是硬编265,还是软编265,相比于264,视频画质都有明显的收益;后续网易云信将准对画质对齐,节省码率这个维度做进一步的探索。

作者介绍

施灵凯,网易云信音视频引擎开发工程师,负责 NERTC 视频引擎的开发与维护。