剑痴乎

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

WebRTC研究:Simulcast层数变化

2020年12月27日 306点热度 6人点赞 7条评论

当我们上行推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_RESOLUTION,保分辨率模式,也就是清晰模式;
3)MAINTAIN_FRAMERATE,保帧率模式,也就是流畅模式;
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
最后更新:2021年4月6日

Jeff

管理员——代码为剑,如痴如醉

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • 头像
    悠哉嗑瓜子

    博主好,感谢分享! :smile:
    2)MAINTAIN_FRAMERATE,保分辨率模式,也就是清晰模式;
    3)MAINTAIN_RESOLUTION,保帧率模式,也就是流畅模式;
    这两个从字面意思看,貌似是写反了?

    2021年3月17日
    回复
    • 头像
      Jeff

      @悠哉嗑瓜子 感谢纠正,已修改

      2021年3月17日
      回复
  • 头像
    Jason

    博主您好,请问WebRTC启用simulcast后,
    VideoStreamEncoder::OnEncodedImage(video_stream_encoder.cc)是不是应该收到多个编码流呀?我应该成功配置了两个Simulcast流,但是只收到了1280*720的编码流,博主您知道可能是什么原因导致的吗?
    以下是我的配置信息:
    video_stream_encoder.cc: (line 685): ReconfigureEncoder:
    Simulcast streams:
    0: 640x360 fps: 60 min_kbps: 150 target_kbps: 500 max_kbps: 700 max_fps: 60 max_qp: 56 num_tl: 3 active: true
    1: 1280x720 fps: 60 min_kbps: 600 target_kbps: 2500 max_kbps: 2500 max_fps: 60 max_qp: 56 num_tl: 3 active: true
    最后感谢博主的分享!

    2021年3月29日
    回复
    • 头像
      Jeff

      @Jason 只编码出一路流,你把日志都打开,应该能看出问题

      2021年3月29日
      回复
  • 头像
    Jason

    @Jeff,感谢博主的回复。我看了一下日志,应该是硬编码器不支持。
    【video_stream_encoder.cc: (line 1278): Encoder settings 】
    这里的EncoderInfo::supports_simulcast = 0.
    博主您觉得是这个原因吗?

    2)另外,请问目前WebRTC如果要支持H264的Simulcast功能,是不是必须得使用OpenH264进行软编?
    博主之前也是使用软编实现的吗?(我现在在安卓平台测试,发现WebRTC目前不支持H264软编)

    2021年3月30日
    回复
    • 头像
      Jeff

      @Jason 恩,你要相信WebRTC日志。安卓上,WebRTC支持H264软编,你照着VP8/VP9的调用接口,自己实现jni接口调用,调用openH264库进行软编:
      src\sdk\android\api\org\webrtc\LibvpxVp8Encoder.java
      src\sdk\android\src\jni\vp8_codec.cc

      你模仿这个VP8接口调用实现openH264编码器调用即可

      2021年3月30日
      回复
  • 头像
    Jason

    @Jeff,我用VP8软编试了一下,simulcast是正常的。之前的H264、VP8都是使用的硬编。后面的工作就是实现以及选择支持的硬/软编码器了。感谢!

    2021年3月31日
    回复
  • 取消回复

    我的其它小窝

    公众号:码上Play(基本不更新,回答问题用。如果没回复就多发几次,忙的时候可能会看不到。)

    近期评论
    • 头像lingjzhang on WebRTC研究:Trendline滤波器-TrendlineEstimator我个人一直很好奇threshold_gain_参数…
    • 头像lingjzhang on WebRTC研究:Trendline滤波器-TrendlineEstimator你好,我这边看modified_trend的计算公…
    • 头像Jeff on 大话WebRTC是的
    • 头像tube on 大话WebRTC这个人抄袭你的吧:https://develope…
    • 头像vivi on WebRTC 安卓Native code编译问题sudo update-alternatives…
    版权声明

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

    目录
    • 1 Simulcast层数为何变化
    • 2 如何防止Simulcast层数变化
    • 3 总结
    相关文章推荐
    • WebRTC研究:Encoded Transform
    • WebRTC研究:统计参数之往返时延
    • WebRTC研究:统计参数之抖动
    • WebRTC研究:WebRTC M89关键更新
    • Linux平台WebRTC编译

    COPYRIGHT © 2021 剑痴乎. ALL RIGHTS RESERVED.

    THEME KRATOS MADE BY VTROIS