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

一、核心功能
  • CPU负载检测:监控视频帧的捕获、编码、发送全流程耗时,实时计算CPU使用率

  • 自适应决策:基于CPU使用率阈值触发视频质量调整(降级/升级)

  • 多策略支持:提供新旧两套CPU负载估计算法,支持实验性参数配置

  • 指标上报:通过CpuOveruseMetricsObserver接口反馈性能数据

二、核心算法原理
  1. 负载估算算法

    • 旧算法(SendProcessingUsage1)

      复制代码
      // 基于指数滤波的帧处理时间/帧间隔时间比率
      usage_percent = 100 * filtered_processing_ms / filtered_frame_diff_ms
    • 新算法(SendProcessingUsage2)

      复制代码
      // 基于时间常数的指数平滑:load <-- x/d * (1-exp(-d/T)) + exp(-d/T)*load
      double tau = options_.filter_time_ms * 0.001;
      double e = diff_time / tau;
      double c = (e < 0.0001) ? (1-e/2)/tau : -expm1(-e)/diff_time;
      load_estimate_ = c * encode_time + exp(-e) * load_estimate_;
  2. 过载决策逻辑

    复制代码
    // 过载条件:连续高阈值检测
    bool OveruseFrameDetector::IsOverusing(int usage_percent) {
      return (usage_percent >= options_.high_threshold) && 
             (++checks_above_threshold_ >= options_.high_threshold_consecutive_count);
    }
    
    // 低载条件:低于阈值 + 冷却时间
    bool IsUnderusing(int usage_percent, int64_t time_now) {
      return (usage_percent < options_.low_threshold) && 
             (time_now > last_rampup_time_ms_ + current_rampup_delay_ms_);
    }
三、关键数据结构
复制代码
struct CpuOveruseOptions { // 核心配置参数
  int high_encode_usage_threshold_percent = 85; // 过载阈值(85%)
  int low_encode_usage_threshold_percent = 42;  // 低载阈值(高阈值的1/2)
  int frame_timeout_interval_ms = 1500;         // 帧超时判定时间
  int min_frame_samples = 120;                  // 最小采样帧数
};

struct FrameTiming { // 帧时序追踪(旧算法)
  int64_t capture_time_us;  // 原始捕获时间
  uint32_t timestamp;       // 帧时间戳
  int64_t capture_us;       // 首次进入系统时间
  int64_t last_send_us;     // 发送完成时间
};

// 状态机标识(测试注入器)
enum class State { kNormal, kOveruse, kUnderuse };
四、核心方法详解
  1. 帧生命周期管理

    复制代码
    void FrameCaptured(bool is_preprocess, uint32_t timestamp, 
                       const VideoFrame& frame, int64_t time_when_first_seen_us) {
      // 重置条件:分辨率变化(1280x720->640x480)或帧超时(>1500ms)
      if (FrameSizeChanged(...) || FrameTimeoutDetected(...)) 
         ResetAll(...);
      
      // 记录帧进入系统的时间点
      usage_->FrameCaptured(..., time_when_first_seen_us, last_capture_time_us_);
      last_capture_time_us_ = time_when_first_seen_us;
    }
    
    void FrameSent(..., absl::optional<int> encode_duration_us) {
      // 计算实际编码耗时(支持外部传入或内部计算)
      duration_us = usage_->FrameSent(..., capture_time_us, encode_duration_us);
      
      // 上报编码耗时指标
      if (duration_us) EncodedFrameTimeMeasured(*duration_us / 1000);
    }
  2. 动态调整机制

    复制代码
    void CheckForOveruse(OveruseFrameDetectorObserverInterface* observer) {
      // 过载处理:指数退避延迟算法
      if (IsOverusing(*usage_percent_)) {
        current_rampup_delay_ms_ *= kRampUpBackoffFactor; // 延迟翻倍(最大240s)
        observer->AdaptDown(); // 触发降级决策
      } 
      // 低载处理:快速恢复机制
      else if (IsUnderusing(*usage_percent_, now_ms)) {
        in_quick_rampup_ = true;
        observer->AdaptUp(); // 触发升级决策
      }
    }
五、设计亮点
  1. 双算法热切换

    复制代码
    // 根据filter_time_ms配置自动选择算法
    std::unique_ptr<ProcessingUsage> CreateProcessingUsage(...) {
      return (options.filter_time_ms > 0) ? 
             std::make_unique<SendProcessingUsage2>(options) :
             std::make_unique<SendProcessingUsage1>(options);
    }
  2. 测试注入器模式

    复制代码
    // 通过字段试验模拟过载场景(WebRTC-ForceSimulatedOveruseIntervalMs)
    OverdoseInjector::Value() {
      switch(state_) {
        case State::kOveruse: return 250; // 强制返回250%使用率
        case State::kUnderuse: return 5;  // 强制返回5%使用率
        default: return usage_->Value();
      }
    }
  3. 抗抖动设计

    • 帧间隔时间上限约束:max_sample_diff_ms_ = (1000/fps)*1.35

    • 最小采样帧数限制:min_frame_samples=120

    • 连续阈值检测机制:high_threshold_consecutive_count=2

六、典型工作流程

注释精要

复制代码
// 帧捕获处理(核心逻辑)
void OveruseFrameDetector::FrameCaptured(...) {
  // 重置条件检查:分辨率变化或帧超时
  if (FrameSizeChanged(frame.width() * frame.height()) || 
      FrameTimeoutDetected(time_when_first_seen_us)) {
    ResetAll(frame.width() * frame.height()); // 重置统计状态
  }
  
  // 区分预处理器/编码器场景
  if(is_preprocess) {
    frame_timing_.push_back(FrameTiming(frame.timestamp_us(), timestamp, ...));
  } else {  
    frame_timing_.push_back(FrameTiming(frame.timestamp_us(), frame.timestamp(), ...));
  }
}

// 过载检测算法(策略核心)
void OveruseFrameDetector::CheckForOveruse(...) {
  // 过载处理:指数退避延迟
  if (IsOverusing(*usage_percent_)) {
    if (now_ms - last_rampup_time_ms_ < kStandardRampUpDelayMs) {
      current_rampup_delay_ms_ *= kRampUpBackoffFactor; // 延迟翻倍
      if (current_rampup_delay_ms_ > kMaxRampUpDelayMs) // 上限240s
        current_rampup_delay_ms_ = kMaxRampUpDelayMs;
    }
    observer->AdaptDown(); // 触发降级
  } 
  // 低载处理:快速恢复
  else if (IsUnderusing(*usage_percent_, now_ms)) {
    last_rampup_time_ms_ = now_ms;
    in_quick_rampup_ = true; // 启用快速恢复模式
    observer->AdaptUp(); // 触发升级
  }
}

该设计通过多算法支持、动态阈值调整和状态机管理,实现了高效的CPU负载感知和视频质量自适应控制,在WebRTC中为实时视频通信提供了关键QoS保障能力。