WebRTC Pacing之IntervalBudget分析

WebRTC中Pacing等模块需要按照指定的码率发送报文,保证码率稳定,会用到IntervalBudget这个类,这个类是控制码率平稳的核心。本篇将介绍IntervalBudget这个类。

1. ✨IntervalBudget原理

IntervalBudget顾名思义,就是一段时间内的发送码率预算。 IntervalBudget根据时间流逝增加budget,报文发送后减少budget,每次发送报文前判断剩余budget是否足够,如果不足则取消本次发送。

举个例子 :

  • 当前目标码率设置为1000kbps,剩余预算100bytes。
  • 距离上次更新相隔50ms,那么budget就多了1000kbps*50/8=600bytes, 剩余100+600=700bytes
  • 如果当前发送一个1000bytes的报文,先判断是否有剩余budget,当前700bytes肯定有剩余,因此可以发送,并减少budget,剩余700-1000=-300bytes


IntervalBudget这个类比较小,因此这里直接贴上其声明:

class IntervalBudget {
 public:
  explicit IntervalBudget(int initial_target_rate_kbps);
  IntervalBudget(int initial_target_rate_kbps, bool can_build_up_underuse);
  // 设置目标发送码率
  void set_target_rate_kbps(int target_rate_kbps);

  // 时间流逝后增加budget
  void IncreaseBudget(int64_t delta_time_ms);
  // 发送数据后减少budget
  void UseBudget(size_t bytes);

  // 剩余budget
  size_t bytes_remaining() const;
  // 剩余budget占当前窗口数据量比例
  double budget_ratio() const;
  // 目标发送码率
  int target_rate_kbps() const;

 private:
  // 设置的目标码率,按照这个码率控制数据发送
  int target_rate_kbps_;
  // 窗口内(500ms)对应的最大字节数=窗口大小*target_rate_kbps_/8
  int64_t max_bytes_in_budget_;
  // 剩余可发送字节数,限制范围:[-max_bytes_in_budget_, max_bytes_in_budget_]
  int64_t bytes_remaining_;
  // 上个周期underuse,本周期是否可以借用上个周期的剩余量
  bool can_build_up_underuse_;
};

2. ✨budget增加

如果距离上次更新时间相隔delta_time_ms,那么随着时间流逝,那么这段时间增长的budget为delta_time_ms* target_rate_kbps_

void IntervalBudget::IncreaseBudget(int64_t delta_time_ms) {
  int64_t bytes = target_rate_kbps_ * delta_time_ms / 8;
  // 一般来说,can_build_up_underuse_都会关闭,关于这个开关的介绍见最后一部分介绍
  if (bytes_remaining_ < 0 || can_build_up_underuse_) {
    // We overused last interval, compensate this interval.
    // 如果上次发送的过多(bytes_remaining_ < 0),那么本次发送的数据量会变少
    // 如果开启can_build_up_underuse_,则表明可以累积之前没有用完的预算
    bytes_remaining_ = std::min(bytes_remaining_ + bytes, max_bytes_in_budget_);
  } else {
    // If we underused last interval we can't use it this interval.
    // 1) 如果上次的budget没有用完(bytes_remaining_ > 0),如果没有设置can_build_up_underuse_
    // 不会对上次的补偿,直接清空所有预算,开始新的一轮

    // 2) 如果设置了can_build_up_underuse_标志,那意味着要考虑上次的underuse,
    // 如果上次没有发送完,则本次需要补偿,见上面if逻辑
    bytes_remaining_ = std::min(bytes, max_bytes_in_budget_);
  }
}

3. ✨减少budget

发送了数据后需要减少budget,直接减去发送字节数即可:

void IntervalBudget::UseBudget(size_t bytes) {
  bytes_remaining_ = std::max(bytes_remaining_ - static_cast<int>(bytes),
                              -max_bytes_in_budget_);
}

4. ✨谈谈IntervalBudget窗口大小

这里的窗口目前主要是用来控制can_build_up_underuse_开关打开下,build_up的上限。 考虑到存在这样的情况,随着时间流逝,我们每5ms都有5ms的budget可供使用,但是并不是每一个5ms我们都能够完全使用掉这5ms的budget,这里称作underuse。因此,can_build_up_underuse_开关允许我们将这些没有用完的预算累计起来,以供后续使用。kWindowMs = 500ms意味着我们可以累积500ms这么多没有用完的预算。

打开这个开关好处在于某些时刻,我们短时间内可供发送的预算更多,在码率抖动较大的时候,我们可以更快地将数据发送出去。带来的缺陷是,短时间内的码率控制不够平滑,在一些低带宽场景影响更大。

原文 WebRTC Pacing之IntervalBudget分析 - 知乎

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

猜你喜欢

转载自blog.csdn.net/yinshipin007/article/details/133281084