一、核心功能
RateStatistics 类用于计算滑动时间窗口内的平均速率(如比特率、包率等)。核心功能包括:
-
动态更新:接收时间戳和计数更新(如字节数)
-
滑动窗口:维护固定时间窗口内的数据(默认1秒)
-
速率计算:实时计算窗口内的平均速率
-
动态调整:运行时修改窗口大小
-
溢出处理:自动检测计数溢出
-
边界处理:处理数据不足等边界情况
二、核心算法原理
-
时间桶机制:
-
将时间划分为1ms精度的桶
-
相同时间戳的计数合并到同一个桶
-
仅存储有数据的桶,节省内存
-
-
滑动窗口维护:
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) { // 删除过期桶并更新统计 } } -
速率计算:
rate = (总计数 × scale) / 实际窗口时间
-
实际窗口时间 = min(设定窗口, 数据存在时间)
-
缩放因子
scale实现单位转换(如8000将字节/ms转为比特/秒)
-
三、关键数据结构
struct Bucket {
int64_t sum; // 本桶计数总和
int num_samples; // 本桶样本数
const int64_t timestamp; // 桶对应的时间戳(ms)
};
std::deque<Bucket> buckets_; // 核心存储结构
-
双端队列(deque):
-
队头存储最旧数据,队尾存储最新数据
-
O(1)时间复杂度的头尾插入/删除操作
-
自动管理内存,无需预分配空间
-
-
统计变量:
int64_t accumulated_count_; // 窗口内计数总和 int64_t first_timestamp_; // 首个数据点时间戳 bool overflow_; // 计数溢出标志 int num_samples_; // 窗口内总样本数
四、核心方法详解
-
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; // 更新当前桶 // 更新统计值(处理溢出) } -
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); } -
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); // 立即应用新窗口 }
五、设计亮点
-
懒删除机制:
-
只在Update/Rate时清理过期数据,减少无效操作
-
避免定时器开销,按需处理
-
-
动态窗口适应:
active_window_size = (数据存在时间 < 设定窗口) ? 实际存在时间 : 设定窗口;-
避免启动初期窗口未满时的计算偏差
-
更精确反映真实速率
-
-
安全防护:
-
时间戳单调性检查:
if (now_ms < last_timestamp) -
计数溢出检测:
if (accumulated_count_ > INT64_MAX - count) -
速率越界检查:
result > INT64_MAX
-
-
精度保持:
-
四舍五入处理:
+0.5f保证整数转换精度 -
1ms时间桶:避免时间量化误差
-
六、典型工作流程

-
初始化:
RateStatistics rate_stat(1000, 8000) -
数据更新:
rate_stat.Update(1500, t1); // 收到1500字节 rate_stat.Update(2000, t2); // 2000字节
-
速率查询:
auto rate = rate_stat.Rate(now); // 返回比特率
-
窗口调整:
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 自适应视频流传输的核心组件之一。
1035

被折叠的 条评论
为什么被折叠?



