剑痴乎

  • 首页
  • 文章分类
    • 音视频
    • WebRTC
    • 编程之美
    • Linux
    • Windows
    • 生活点滴
    • 校园生活
  • 参考
    • API参考
    • 实用工具
    • 测试音视频
    • 文档
  • 留言板
  • 关于
剑痴乎
代码为剑,如痴如醉
  1. 首页
  2. WebRTC
  3. 正文

WebRTC研究:Simulcast层数变化

2020年12月27日 70点热度 2人点赞 0条评论

当我们上行推Simulcast流的时候,会发现Simulcast层数会时不时变化,本来是大小流(大小两个分辨率)两层,但是变为只有一层小流了,后面又恢复为两层了,如果我们服务端支持Simulcast的话,这就成为一个棘手问题。

例如我们团队的WebRTC产品,客户端默认会启用Simulcast,上行推送两个不同分辨率的流到服务端,服务端下行会依据带宽估计值,自动选择某个分辨率的流给订阅客户端。假设此时下行带宽足够,服务端会推送大流。但是对于上行客户端来说,因为某种原因,Simulcast层数减少为一层,只剩一路小流了,如果没有相应处理,此时订阅客户端就接收不到视频流了。

Simulcast层数为何变化

WebRTC中如果送到编码器的采集视频帧分辨率发生变化,会触发ReconfigureEncoder也就是重置编码器操作,然后Simulcast层数也会重新计算。在WebRTC中,Simulcast层数与采集视频帧分辨率的关系由一张表决定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
constexpr const SimulcastFormat kSimulcastFormats[] = {
    {1920, 1080, 3, webrtc::DataRate::KilobitsPerSec(5000),
     webrtc::DataRate::KilobitsPerSec(4000),
     webrtc::DataRate::KilobitsPerSec(800)},
    {1280, 720, 3, webrtc::DataRate::KilobitsPerSec(2500),
     webrtc::DataRate::KilobitsPerSec(2500),
     webrtc::DataRate::KilobitsPerSec(600)},
    {960, 540, 3, webrtc::DataRate::KilobitsPerSec(1200),
     webrtc::DataRate::KilobitsPerSec(1200),
     webrtc::DataRate::KilobitsPerSec(350)},
    {640, 360, 2, webrtc::DataRate::KilobitsPerSec(700),
     webrtc::DataRate::KilobitsPerSec(500),
     webrtc::DataRate::KilobitsPerSec(150)},
    {480, 270, 2, webrtc::DataRate::KilobitsPerSec(450),
     webrtc::DataRate::KilobitsPerSec(350),
     webrtc::DataRate::KilobitsPerSec(150)},
    {320, 180, 1, webrtc::DataRate::KilobitsPerSec(200),
     webrtc::DataRate::KilobitsPerSec(150),
     webrtc::DataRate::KilobitsPerSec(30)},
    {0, 0, 1, webrtc::DataRate::KilobitsPerSec(200),
     webrtc::DataRate::KilobitsPerSec(150),
     webrtc::DataRate::KilobitsPerSec(30)}};

对于1920x1080的采集分辨率,允许的最大Simulcast层数为3层,对于640x360的采集分辨率,允许的最大层数为2层。所以当采集视频分辨率从1920x1080变为640x360时,Simulcast层数就会发生变化。

下面简单说下几种造成采集视频帧分辨率变化的几种情况:
1)带宽估计值不够;
2)编码视频的QP值在设定的阈值范围外;
3)通过编码延时计算得到的CPU负载发生变化。

发生如上情况时,WebRTC会调整采集的原始视频帧分辨率或者帧率,至于是调整采集分辨率还是帧率,依据我们采取的策略,WebRTC中目前存在四种策略:
1)BALANCED,平衡模式;
2)MAINTAIN_FRAMERATE,保分辨率模式,也就是清晰模式;
3)MAINTAIN_RESOLUTION,保帧率模式,也就是流畅模式;
4)DISABLED,禁用模式。

例如对于摄像头视频流,默认是流畅模式,我们举两个例子说明下。
1)如果分配的带宽估计值满足不了当前编码器分辨率的码率设置时,就会触发降低采集视频帧分辨率的操作;
2)如果检测到CPU负载较高,也会触发降低采集视频帧分辨率的操作。这种现象在移动端设备较为明显,会看到视频刚开始很清晰,后面就模糊了(假设带宽足够情况下)。

当然了,对于屏幕共享流,默认是清晰模式,只会触发降低帧率的操作,看起来视频会变卡。

如何防止Simulcast层数变化

这里我们先看下启用Simulcast时,采集分辨率改变后,重置编码器的相关代码流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
VideoStreamEncoder::OnFrame
           ↓
VideoStreamEncoder::MaybeEncodeVideoFrame
           ↓
VideoStreamEncoder::ReconfigureEncoder
           ↓
EncoderStreamFactory::CreateEncoderStreams
           ↓
EncoderStreamFactory::CreateSimulcastOrConfereceModeScreenshareStreams
           ↓
GetSimulcastConfig
           ↓
LimitSimulcastLayerCount

在LimitSimulcastLayerCount中会根据前面提到的表内容,改变Simulcast层数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int LimitSimulcastLayerCount(int width, int height, int layer_count) {
  if (!webrtc::field_trial::IsDisabled(
          kUseLegacySimulcastLayerLimitFieldTrial)) {
    // 根据table,得到当前分辨率允许的simulcast最大层数
    int adaptive_layer_count =
        kSimulcastFormats[FindSimulcastFormatIndex(width, height)].max_layers;
    if (layer_count > adaptive_layer_count) {
      RTC_LOG(LS_WARNING) << "Reducing simulcast layer count from "
                          << layer_count << " to " << adaptive_layer_count;
      layer_count = adaptive_layer_count;
    }
  }
  return layer_count;
}

可知,通过在webrtc::field_trial设置禁用kUseLegacySimulcastLayerLimitFieldTrial即可保持当前Simulcast层数,避免了大流消失的麻烦。

总结

本文分析了Simulcast层数变化的原因,以及如何防止变化。其中介绍了WebRTC的清晰模式,流畅模式等概念,后续文章会对这些进行详细分析。

如何觉得好,请点赞、打赏、收藏三连哦,这样我才有更大动力写出更多底层分析文章。

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
标签: WebRTC
最后更新:2020年12月27日

Jeff Young

代码为剑,如痴如醉

打赏 点赞
< 上一篇

文章评论

取消回复

我的其它小窝

公众号:码上Play(基本不更新,回答问题用)

近期评论
  • Jeff on WebRTC研究:BBR拥塞控制被移除了研究过了,等后面有时间简单说明下
  • xhcx on WebRTC研究:BBR拥塞控制被移除了楼主,BBR移除的原因最近有研究吗,分享一下
  • Jeff on Windows平台WebRTC编译(持续更新)M79是2019年发布的版本,不适用这篇文章。编译…
  • haige on Windows平台WebRTC编译(持续更新)我编译的m79版本,用VS2019打开会报错, F…
  • 菜菜 on libcef编译使用--使用VS2015是真的鸟
版权声明

为支持原创,创作更好的文章,未经许可,禁止任何形式的转载与抄袭,如需转载请邮件私信!本人保留所有法定权利。违者必究!

目录
  • 1 Simulcast层数为何变化
  • 2 如何防止Simulcast层数变化
  • 3 总结
相关文章推荐
  • WebRTC研究:RTP头部扩展
  • WebRTC研究:音频带内FEC
  • WebRTC研究:BBR拥塞控制被移除了
  • WebRTC安卓编译
  • 音视频开发入门:视频基础

COPYRIGHT © 2021 剑痴乎. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS