media_opt_util.h 是WebRTC 能够在复杂网络环境下保持视频流畅性的关键组件之一,它在带宽开销(FEC/NACK 占用额外带宽)和视频质量(抗丢包能力)之间寻找最佳平衡点。
media_opt_util.h 定义了 WebRTC 视频编码模块中用于**媒体优化(Media Optimization)的核心逻辑,特别是针对丢包保护策略(Loss Protection)**的选择和参数计算。
它的主要目标是根据当前的网络状况(RTT、丢包率)和视频流特性(码率、帧率、分辨率),动态决定使用哪种纠错机制:NACK(重传)、FEC(前向纠错)还是 NACK+FEC 混合模式,并计算出具体的 FEC 冗余比例。
一,常量与枚举 (Constants & Enums)
1.1 丢包统计窗口:
• kLossPrHistorySize = 10: 历史丢包样本的数量。
• kLossPrShortFilterWinMs = 1000: 每个样本代表的时间窗口(1秒)。总观察窗口为 10 秒。
1.2 FilterPacketLossMode: 丢包率的过滤模式。
• kNoFilter: 不使用过滤。
• kAvgFilter: 递归平均滤波(平滑瞬时波动)。
• kMaxFilter: 取窗口内的最大值(保守策略,应对突发丢包)。
1.3 阈值:
• kLowRttNackMs = 20: NACK 有效的低 RTT 阈值。如果 RTT 低于此值,NACK 非常高效。
• kMaxRttDelayThreshold = 500: 最大 RTT 阈值,超过此值抖动缓冲区不再额外增加延迟。
1.4 VCMProtectionMethodEnum: 保护方法类型。
• kNack: 仅重传。
• kFec: 仅前向纠错。
• kNackFec: 混合模式。
• kNone: 无保护。
二、数据结构 (Structs)
2.1 VCMProtectionParameters:
这是一个输入参数结构体,汇集了当前会话的所有关键指标,用于决策算法:
• rtt: 往返时延。
• lossPr: 丢包概率。
• bitRate: 目标码率。
• packetsPerFrame / packetsPerFrameKey: 每帧(P帧/I帧)包含的 RTP 包数量。
• frameRate: 帧率。
• keyFrameSize: 关键帧大小。
• fecRateDelta / fecRateKey: 期望覆盖的丢包率(用于 Delta 帧和 Key 帧)。
• codecWidth/Height, numLayers: 视频分辨率和时空层数。
2.2 VCMLossProbabilitySample:
• 用于存储历史丢包样本:
1,lossPr255 (0-255 范围的丢包率) 丢包概率,范围是 0-255。使用 uint8_t 而不是浮点数是为了节省内存和计算开销,其中 255 代表 100% 丢包,0 代表无丢包。
2, timeMs (时间戳)。该样本采集时的时间戳(毫秒)。
三、核心类层次结构 (Class Hierarchy)
这部分采用了策略模式(Strategy Pattern),定义了一个基类和三个具体实现类。
3.1 . 基类: VCMProtectionMethod
1, 职责: 定义所有保护方法的通用接口。
2 , 关键方法:
• UpdateParameters(...): 核心函数。根据传入的网络参数,计算当前策略是否有效,并内部更新保护因子(如 FEC 冗余度)。返回 true 表示推荐使用该策略。
• RequiredProtectionFactorK/D(): 获取关键帧(Key)和差值帧(Delta)所需的 FEC 保护因子(冗余比例)。
• RequiredUepProtectionK/D(): 是否启用不等保护(UEP,即对重要数据给予更强保护)。
• MaxFramesFec(): FEC 编码跨越的最大帧数。
3.2 具体策略类
3.2.1 VCMNackMethod:
1, 逻辑: 评估纯 NACK 策略。
2, 判断依据: 主要依赖 rtt。如果 RTT 太大,NACK 会导致播放延迟过高或来不及重传,此时该方法可能返回 false(不推荐)。
3.2.2 VCMFecMethod:
1, 逻辑: 评估纯 FEC 策略。
2, 判断依据:
• 计算在给定丢包率下,需要多少冗余包才能恢复数据。
• 检查码率和帧大小。如果每帧字节数太少(如 kMaxBytesPerFrameForFecLow = 400),FEC 的头部开销占比过大,效率极低,此时可能禁用 FEC。
• AvgRecoveryFEC: 估算 FEC 的平均恢复能力。
3.2.3 VCMNackFecMethod (继承自 VCMFecMethod):
1, 逻辑: 评估混合策略。这是 WebRTC 最常用的模式。
2, 判断依据:
• 结合 RTT 和丢包率。
• 通常在低 RTT 时优先依赖 NACK(因为带宽效率高),在高丢包或高 RTT 时引入 FEC 作为补充,以填补 NACK 无法及时恢复的空窗期。
• BitRateTooLowForFec: 如果码率太低,关闭 FEC 以节省带宽。
四、控制器类: VCMLossProtectionLogic
这是上层调用的主要入口类,它维护状态并协调上述策略类。
4.1 状态管理:
• 持有当前的 _selectedMethod(指向 VCMProtectionMethod 子类的指针)。
• 维护各种滤波器:_lossPr255 (丢包率指数滤波), _packetsPerFrame (每帧包数滤波) 等,以平滑输入数据的抖动。
• 维护历史丢包记录 _lossPrHistory。
4.2 更新接口 (Update APIs):
• UpdateRtt, UpdateFilteredLossPr, UpdateBitRate, UpdateFrameRate 等:接收来自编码器、发送端和接收端反馈的最新网络和视频统计信息。
• UpdatePacketsPerFrame: 动态估算每帧产生的 RTP 包数量,这对计算 FEC 开销至关重要。
4.3 决策执行:
• UpdateMethod(): 核心驱动函数。
-
收集当前所有参数到 VCMProtectionParameters。
-
调用当前选中策略的 UpdateParameters。
-
如果当前策略不再适用(返回 false),或者有更好的策略,它会切换 _selectedMethod。
• SelectedMethod(): 返回当前最优的策略对象,供编码器查询具体的 FEC 冗余度(Protection Factor)。
4.4 辅助功能:
• FilteredLoss(): 根据指定模式(平均或最大)计算过滤后的丢包率。
• Reset(): 重置状态,通常在会话开始或网络剧烈变化时调用。
五,工作流程
-
数据采集: WebRTC 运行时不断监测网络 RTT、丢包率,以及视频编码产生的帧大小、包数量。
-
输入更新: 调用 VCMLossProtectionLogic 的 Update... 系列函数。
-
策略评估: 定期调用 UpdateMethod()。
• 逻辑类将数据打包成 VCMProtectionParameters。
• 当前的 VCMProtectionMethod(例如 VCMNackFecMethod)分析这些数据。
• 它计算出:"在当前 200ms RTT 和 5% 丢包率下,我们应该为 P 帧添加 10% 的 FEC 冗余,并为 I 帧添加 20% 的冗余。"
- 应用配置: 视频发送端(VideoSender)查询 SelectedMethod()->RequiredProtectionFactorD(),并将该值传递给 FEC 生成模块,从而在发出的 RTP 流中插入相应的冗余包。