webrtc弱网-RateStatistics源码分析与算法原理

一、核心功能

RateStatistics 类用于计算滑动时间窗口内的平均速率(如比特率、包率等)。核心功能包括:

  1. 动态更新:接收时间戳和计数更新(如字节数)

  2. 滑动窗口:维护固定时间窗口内的数据(默认1秒)

  3. 速率计算:实时计算窗口内的平均速率

  4. 动态调整:运行时修改窗口大小

  5. 溢出处理:自动检测计数溢出

  6. 边界处理:处理数据不足等边界情况

二、核心算法原理

  1. 时间桶机制

    • 将时间划分为1ms精度的桶

    • 相同时间戳的计数合并到同一个桶

    • 仅存储有数据的桶,节省内存

  2. 滑动窗口维护

    void EraseOld(int64_t now_ms) {
      const int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1;
      while (!buckets_.empty() && buckets_.front().timestamp < new_oldest_time) {
        // 删除过期桶并更新统计
      }
    }
  3. 速率计算

    rate = (总计数 × scale) / 实际窗口时间
    • 实际窗口时间 = min(设定窗口, 数据存在时间)

    • 缩放因子scale实现单位转换(如8000将字节/ms转为比特/秒)

三、关键数据结构

struct Bucket {
  int64_t sum;         // 本桶计数总和
  int num_samples;     // 本桶样本数
  const int64_t timestamp; // 桶对应的时间戳(ms)
};

std::deque<Bucket> buckets_; // 核心存储结构
  1. 双端队列(deque)

    • 队头存储最旧数据,队尾存储最新数据

    • O(1)时间复杂度的头尾插入/删除操作

    • 自动管理内存,无需预分配空间

  2. 统计变量

    int64_t accumulated_count_; // 窗口内计数总和
    int64_t first_timestamp_;   // 首个数据点时间戳
    bool overflow_;             // 计数溢出标志
    int num_samples_;           // 窗口内总样本数

四、核心方法详解

  1. Update() - 数据更新:

    void Update(int64_t count, int64_t now_ms) {
      EraseOld(now_ms);                    // 清理过期数据
      if (buckets_.empty() || now_ms != buckets_.back().timestamp) {
        buckets_.emplace_back(now_ms);     // 创建新时间桶
      }
      buckets_.back().sum += count;        // 更新当前桶
      // 更新统计值(处理溢出)
    }
  2. Rate() - 速率计算:

    absl::optional<int64_t> Rate(int64_t now_ms) {
      EraseOld(now_ms);
      // 计算有效窗口时间
      if (数据不足 || 溢出) return absl::nullopt; 
      // 核心计算公式:
      float result = accumulated_count_ * (scale_ / active_window_size) + 0.5f;
      return static_cast<int64_t>(result);
    }
  3. SetWindowSize() - 动态调窗:

    bool SetWindowSize(int64_t window_size_ms, int64_t now_ms) {
      // 边界检查
      first_timestamp_ = std::max(first_timestamp_, now_ms - window_size_ms + 1);
      current_window_size_ms_ = window_size_ms;
      EraseOld(now_ms); // 立即应用新窗口
    }

五、设计亮点

  1. 懒删除机制

    • 只在Update/Rate时清理过期数据,减少无效操作

    • 避免定时器开销,按需处理

  2. 动态窗口适应

    active_window_size = (数据存在时间 < 设定窗口) ? 
                         实际存在时间 : 设定窗口;
    • 避免启动初期窗口未满时的计算偏差

    • 更精确反映真实速率

  3. 安全防护

    • 时间戳单调性检查:if (now_ms < last_timestamp)

    • 计数溢出检测:if (accumulated_count_ > INT64_MAX - count)

    • 速率越界检查:result > INT64_MAX

  4. 精度保持

    • 四舍五入处理:+0.5f保证整数转换精度

    • 1ms时间桶:避免时间量化误差

六、典型工作流程

  1. 初始化RateStatistics rate_stat(1000, 8000)

  2. 数据更新

    rate_stat.Update(1500, t1); // 收到1500字节
    rate_stat.Update(2000, t2); // 2000字节
  3. 速率查询

    auto rate = rate_stat.Rate(now); // 返回比特率
  4. 窗口调整

    rate_stat.SetWindowSize(500, now); // 改为500ms窗口

七、注释精要

// 桶结构:存储1ms时间单元内的统计数据
struct Bucket {
  int64_t sum;         // 本时间单元计数总和
  int num_samples;     // 本时间单元更新次数
  const int64_t timestamp; // 时间戳(ms), 不可修改
};

class RateStatistics {
  // 滑动窗口核心:按时间排序的桶队列
  std::deque<Bucket> buckets_;
  
  int64_t accumulated_count_; // 窗口内有效计数总和
  int64_t first_timestamp_;   // 窗口内最早数据时间戳(-1表示空)
  bool overflow_ = false;     // 计数溢出标志(防止回绕)
  int num_samples_;           // 窗口内总样本数
  
  const float scale_;         // 单位转换因子 
  const int64_t max_window_size_ms_; // 最大允许窗口
  int64_t current_window_size_ms_;   // 当前有效窗口

  // 核心方法:删除过期桶(O(n)但均摊O(1))
  void EraseOld(int64_t now_ms) {
    const int64_t new_oldest = now_ms - current_window_size_ms_ + 1;
    while (!buckets_.empty() && 
           buckets_.front().timestamp < new_oldest) {
      // 更新统计值并删除队头
    }
  }
};

该模块通过BandwidthQualityScaler类实时统计码率,用于计算滑动时间窗口内的平均速率,为保证视频质量动态升降码率及分辨率提供了有力支撑,是 WebRTC 自适应视频流传输的核心组件之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值