在webrtc弱网整个链路中,存在这么一个模块,当网络发送不及时或拥塞时,会采取丢帧策略。来满足当前的带宽。这个模块就是FrameDropper类。
一、核心功能
FrameDropper 是 WebRTC 视频编码模块中的帧丢弃控制器,通过漏桶算法变体实现动态帧丢弃策略,防止在带宽不足时视频数据堆积。主要功能包括:
-
根据目标比特率和实际帧大小动态计算丢帧比例
-
平滑处理关键帧和大帧的突发流量
-
避免长时间连续丢帧影响观看体验
二、核心算法原理
1. 漏桶模型 (Leaky Bucket)
float accumulator_; // 当前桶内数据量(kbits) float accumulator_max_; // 桶容量 = target_bitrate_ * kLeakyBucketSizeSeconds float target_bitrate_; // 当前目标比特率(kbps)
-
填充(Fill):当编码器输出帧时,按帧大小填充桶
-
泄漏(Leak):按帧率持续漏出数据:
accumulator_ -= target_bitrate_ / framerate
2. 关键帧/大帧特殊处理
int large_frame_accumulation_count_; // 大帧分块计数 float large_frame_accumulation_chunk_size_;// 每块大小
-
关键帧:强制分块处理,块数 =
max(0.5*fps, 5)
-
超大Delta帧(>3倍平均帧大小):分块处理
3. 丢帧决策算法
bool DropFrame(absl::optional<int64_t> last_drop_frame_ms);
-
丢帧比例计算:通过指数平滑滤波更新
rtc::ExpFilter drop_ratio_; // 基值0.9,初始值0.96
-
两种丢帧模式:
-
高丢帧率(≥0.5):连续丢帧直到满足
drop_count_ ≥ 1/(1-ratio)
-
低丢帧率(<0.5):丢帧间隔
1/ratio
帧
-
4. 动态参数调整
void SetRates(float bitrate, float incoming_frame_rate);
-
比特率变化时等比缩放桶内数据:
accumulator_ *= new_bitrate / old_bitrate
-
更新帧率相关参数:
large_frame_accumulation_spread_ = max(0.5*fps, 5)
三、关键数据结构
1. 指数滤波器 (ExpFilter)
rtc::ExpFilter key_frame_ratio_; // 关键帧比例滤波(α=0.99) rtc::ExpFilter delta_frame_size_avg_kbits_;// 帧大小滤波(α=0.9) rtc::ExpFilter drop_ratio_; // 丢帧比例滤波(α=0.9)
滤波公式:new_val = α * old_val + (1-α) * sample
2. 大帧处理参数
float large_frame_accumulation_spread_; // 分块数 = max(0.5*fps, 5) const int kLargeDeltaFactor = 3; // 大帧阈值系数
四、核心方法详解
1. Fill() - 帧数据填充
void Fill(size_t framesize_bytes, bool delta_frame)
处理流程:
-
关键帧:强制分块处理,更新关键帧比例
-
超大Delta帧:满足
size > 3*avg_size
时分块 -
普通帧:直接更新桶和帧大小平均值
-
分块处理时:当前帧大小记为0,后续通过
Leak()
分次添加
2. Leak() - 漏桶泄漏
void Leak(uint32_t input_framerate)
处理流程:
-
计算每帧理论比特值:
target_bitrate_ / fps
-
大帧分块处理:每次泄漏扣除分块大小
-
更新丢帧比例:
UpdateRatio()
3. UpdateRatio() - 动态调整丢帧率
void UpdateRatio()
决策逻辑:
-
桶溢出时(
accumulator_ > max
):-
设置
drop_next_ = true
-
提升丢帧率:
drop_ratio_.Apply(1.0f, 1.0f)
-
-
桶未溢出:降低丢帧率:
drop_ratio_.Apply(1.0f, 0.0f)
4. DropFrame() - 丢帧决策
bool DropFrame(...)
决策矩阵:
丢帧率 | 策略 |
---|---|
≥0.5 | 连续丢帧直到满足 N=1/(1-ratio) |
(0, 0.5) | 每 1/ratio 帧丢1帧 |
0 | 不丢帧 |
五、设计亮点
-
大帧分块处理
避免单一大帧导致桶溢出引发连续丢帧:if (framesize_kbits > kLargeDeltaFactor * avg_size) large_frame_accumulation_count_ = spread;
-
桶容量动态缩放
比特率降低时等比缩小桶内数据:accumulator_ = bitrate / target_bitrate_ * accumulator_;
-
丢帧平滑控制
通过指数滤波避免丢帧率剧烈波动:drop_ratio_.UpdateBase(0.9f); // 平滑因子
-
最大连续丢帧限制
防止长时间黑屏:const float kDefaultMaxDropDurationSecs = 4.0f; int max_limit = fps * max_drop_duration_secs_;
六、典型工作流程
该模块通过动态平衡帧率、帧大小和带宽关系,在拥塞时智能丢弃非关键帧,保障视频流畅传输。