FlexfecReceiver 和FlexfecSender 是webrtc用于处理视频FEC的接收和发送模块:
FlexfecReceiver 是 WebRTC 中用于处理 FlexFEC (Flexible Forward Error Correction) 接收逻辑的类。它的主要职责是接收包含媒体数据或 FlexFEC 冗余数据的 RTP 包,利用纠删码(Erasure Code)算法从冗余包中恢复丢失的媒体包,并将恢复后的包传递给上层模块进行解码和播放。
FlexfecSender 是 WebRTC 中用于生成 FlexFEC (Flexible Forward Error Correction) 冗余包的发送端类。它实现了 VideoFecGenerator 接口,负责接收原始的媒体 RTP 包,根据配置的保护参数(如 FEC 率、保护帧数),计算并生成对应的 FlexFEC 包,以增强视频流在网络丢包环境下的鲁棒性。
一、主要职责
1.1 接收端- FlexfecReceiver
1, FlexFEC 接收端:它是 RFC 8627 (FlexFEC) 标准在 WebRTC 中的实现部分。与传统的 ULPFEC 不同,FlexFEC 更灵活,支持保护多个媒体流、不同的保护等级以及更高效的编码方案。
2, 包恢复引擎:它内部维护一个缓冲区,收集到达的媒体包和 FEC 包。当收集到足够的数据时,它会尝试解码以恢复丢失的媒体包。
1.2 发送端- FlexfecSender
1, FEC 生成:作为视频发送流的一部分,它拦截发出的媒体包,缓冲它们,并在满足条件时生成纠错码(FEC)包。
2, FlexFEC 特定逻辑:与旧的 ULPFEC 不同,FlexFEC 支持更灵活的拓扑结构(例如一个 FEC 流保护多个媒体流,尽管当前实现主要关注单流保护),并使用不同的 RTP 头部扩展和 payload 格式。
3, 状态管理:维护 FlexFEC 流的 SSRC、序列号、时间戳偏移等状态,确保生成的 FEC 包符合 RTP 规范。
二、关键成员
2.1 接收端- FlexfecReceiver
cpp
private:
// Config.
const uint32_t ssrc_;
const uint32_t protected_media_ssrc_;
// Erasure code interfacing and callback.
std::unique_ptr<ForwardErrorCorrection> erasure_code_
RTC_GUARDED_BY(sequence_checker_);
ForwardErrorCorrection::RecoveredPacketList recovered_packets_
RTC_GUARDED_BY(sequence_checker_);
RecoveredPacketReceiver* const recovered_packet_receiver_;
// Logging and stats.
Clock* const clock_;
int64_t last_recovered_packet_ms_ RTC_GUARDED_BY(sequence_checker_);
FecPacketCounter packet_counter_ RTC_GUARDED_BY(sequence_checker_);
SequenceChecker sequence_checker_;
2.1.1 ssrc:
FlexFEC 流自身的 SSRC。用于识别哪些 RTP 包属于这个 FEC 流。
2.1.2 protected_media_ssrc_:
被保护的媒体流的 SSRC。FlexFEC 包是为了保护这个特定的媒体流而生成的。
2.1.3 erasure_code_ (std::unique_ptr<ForwardErrorCorrection>):
核心的纠删码算法实现对象。它负责执行具体的数学运算(如异或操作、矩阵运算等)来从冗余数据中重建原始数据。
2.1.4 recovered_packets_:
一个列表,用于暂存成功恢复出来的媒体包。
2.1.5 recovered_packet_receiver_:
回调接口指针。当有包被成功恢复后,FlexfecReceiver 会通过这个接口将包"发送"给上层(通常是 RtpVideoStreamReceiver 或类似的模块),以便将其插入抖动缓冲区或直接解码。
2.1.6 packet_counter_:
统计计数器,记录接收到的包数量、恢复的包数量等,用于生成 RTCP 报告或内部监控。
2.1.7 sequence_checker_:
线程安全检查器,确保该类的所有方法都在同一个线程序列上被调用,防止竞态条件。
2.1.8 统计信息 (GetPacketCounter)
返回 FecPacketCounter 结构体,包含:
- 接收到的媒体包数。
2 . 接收到的 FEC 包数。
- 恢复的媒体包数。
4 . 丢弃的包数(无法恢复或重复的)。
2.2 发送端- FlexfecSender
cpp
private:
// Utility.
Clock* const clock_;
Random random_;
int64_t last_generated_packet_ms_;
// Config.
const int payload_type_;
const uint32_t timestamp_offset_;
const uint32_t ssrc_;
const uint32_t protected_media_ssrc_;
// MID value to send in the MID header extension.
const std::string mid_;
// Sequence number of next packet to generate.
uint16_t seq_num_;
// Implementation.
UlpfecGenerator ulpfec_generator_;
const RtpHeaderExtensionMap rtp_header_extension_map_;
const size_t header_extensions_size_;
rtc::CriticalSection crit_;
RateStatistics fec_bitrate_ RTC_GUARDED_BY(crit_);
2.2.1 配置与标识
• payload_type: FlexFEC 包使用的 RTP Payload Type。
• ssrc: FlexFEC 流自身的 SSRC。注意,FEC 流通常有独立的 SSRC,与被保护的媒体流不同。
• protected_media_ssrc_: 被保护的媒体流的 SSRC。在 FlexFEC 头中会引用这个 SSRC,告诉接收端这些冗余数据是给哪个流用的。
• mid: Media ID。用于 BUNDLE 策略下区分不同的媒体流。FlexFEC 包需要携带与媒体包相同的 MID 扩展。
• seq_num: FlexFEC 包的序列号计数器,独立于媒体流递增。
2.2.2 内部实现
• ulpfec_generator_ (UlpfecGenerator):
• 关键点:尽管类名是 FlexfecSender,但它内部复用了 UlpfecGenerator 的核心算法逻辑。
• FlexFEC 和 ULPFEC 在底层的纠删码数学运算(XOR 等)上是相似的。FlexfecSender 主要负责构建符合 FlexFEC 标准(RFC 8627)的 RTP 头部和 Payload 结构,而具体的"哪些包参与计算"、"如何生成冗余块"的逻辑委托给了 ulpfec_generator_。
• rtp_header_extension_map_ & header_extensions_size_:
• 用于正确构建 FlexFEC 包的 RTP 头部扩展。FlexFEC 包必须包含与媒体包一致的扩展(如 MID, Transmission Time Offset 等),以便接收端能正确关联和处理。
2.2.3 统计与工具
• fec_bitrate_ (RateStatistics): 统计当前 FEC 生成的比特率,用于监控带宽开销。
• random: 用于生成初始序列号或时间戳偏移的随机数,避免冲突。
• clock: 用于获取当前时间,计算比特率统计。
三,工作流程
3.1 接收端- FlexfecReceiver
3.1.1. 接收包 (OnRtpPacket)
这是入口函数,每当网络层收到一个 RTP 包(无论是媒体包还是 FlexFEC 包)时都会调用。
-
分类:判断包是属于媒体流还是 FlexFEC 流。
-
缓冲:调用 AddReceivedPacket 将包转换为内部格式并存储起来。
-
处理:调用 ProcessReceivedPacket。
• 如果是媒体包:检查是否之前因为丢失而被"占位",如果现在恢复了,则标记。
• 如果是 FEC 包:检查是否已经收集了足够的包(媒体+冗余)来进行一次解码操作。
3.1.2. 恢复逻辑 (ProcessReceivedPacket -> erasure_code_)
-
ForwardErrorCorrection 模块会检查当前的包集合。
-
如果满足解码条件(例如,收到了 N 个包,其中包含 K 个媒体包和 M 个 FEC 包,且 K+M >= 原始媒体包总数),它就会执行恢复算法。
-
恢复出的新包会被放入 recovered_packets_ 列表。
3.1.3. 回调上层
-
一旦有包被恢复,FlexfecReceiver 会遍历 recovered_packets_。
-
对于每个恢复的包,调用 recovered_packet_receiver_->OnRecoveredPacket(...)。
-
上层模块拿到恢复的包后,会像处理正常接收到的包一样处理它(排序、去重、解码)。
3.2 发送端- FlexfecSender
3.2.1. 初始化:
-
构造函数中设置 FlexFEC 流的 SSRC、Payload Type、MID 等。
-
初始化内部的 ulpfec_generator_。
3.2.2. 设置保护参数 (SetProtectionParameters):
-
接收来自带宽估计模块或配置的策略。
-
delta_params: 针对 P 帧/B 帧(差值帧)的保护参数(如 FEC 率 0.2 表示增加 20% 冗余)。
-
key_params: 针对 I 帧(关键帧)的保护参数(通常关键帧更重要,保护率更高)。
-
这些参数会被传递给内部的 ulpfec_generator_。
3.2.3. 添加媒体包并生成 FEC (AddPacketAndGenerateFec):
-
当视频编码器产生一个 RTP 包时,调用此方法。
-
缓冲:将媒体包的信息(序列号、时间戳、大小等)添加到内部的 FEC 缓冲区。
-
触发判断:检查是否达到了生成 FEC 的条件(例如,累积了 N 个媒体包,或者时间窗口到期)。
-
生成:如果条件满足,调用内部生成器计算冗余数据。
-
存储:生成的 FlexFEC 包被存储在内部队列中,等待被取出发送。
3.2.4. 获取 FEC 包 (GetFecPackets):
-
发送线程调用此方法,获取所有已生成但尚未发送的 FlexFEC 包。
-
返回的包是完整的 RtpPacketToSend 对象,包含正确的 RTP 头、FlexFEC 头和冗余 Payload。
这些包随后会被送入网络发送队列。
3.2.5. 开销计算 (MaxPacketOverhead):
返回每个 FlexFEC 包的额外头部开销(字节数)。这有助于带宽控制器精确计算可用带宽,因为 FEC 包占用带宽但不携带新视频内容。
四,与ULPFEC 的区别的关系
4.1 接收端- FlexfecReceiver
webrc也实现了ULPFEC,UlpfecReceiver, 两者的区别为:
-
UlpfecReceiver 处理旧的 ULPFEC (RFC 5109),通常只保护单个媒体流,且 FEC 头结构简单。
-
FlexfecReceiver 处理新的 FlexFEC,支持更复杂的拓扑结构(如一个 FEC 流保护多个媒体流),效率更高,但实现也更复杂。
4.2 发送端- FlexfecSender
主要使用 UlpfecGenerator实现发生,当前模块复用了 UlpfecGenerator,但 FlexfecSender 在以下方面不同:
-
RTP 头部: FlexFEC 使用特定的 Payload Type 和可能的头部扩展。
-
SSRC: FlexFEC 有独立的 SSRC,而 ULPFEC 通常与媒体流共享 SSRC(通过 Marker Bit 或 Payload Type 区分,但在 WebRTC 旧实现中 ULPFEC 也有独立 SSRC,不过 FlexFEC 标准化了这一行为并增强了多流保护能力)。
-
Payload 格式: FlexFEC 的冗余载荷格式遵循 RFC 8627,比 RFC 5109 (ULPFEC) 更灵活,支持更长的掩码和更复杂的保护结构。
五,与 ForwardErrorCorrection 的关系
主要是FlexfecReceiver接收端与 ForwardErrorCorrection的差别
-
FlexfecReceiver 是管理层,负责包的收集、状态维护和回调。
-
ForwardErrorCorrection 是算法层,只负责纯粹的数学恢复计算。