转自:http://www.cnblogs.com/webrtc/p/7402570.htmlhtml
[TOC]web
Tags: WebRTC FEC算法
- WebRTC对FEC进行恢复处理的动做对RTCP的统计是透明的.
- WebRTC对FEC的冗余度计算是动态的, 会根据丢包状况和网络带宽估计(BWE)的结果动态调整冗余度,
内部会维护一个静态的冗余度表. 冗余度范围: 0-255.(255至关于100%冗余度)
ULPFEC: Uneven Level Protection FEC.数组
将须要保护的媒体流按照重要性分红若干区域(section),
不一样的区域使用不一样的保护级别(levels),每一个ulpfec能够携带多个级别的保护区域。网络
Packet A ##################### : : Packet B ############### : : : ULP FEC Packet #1 @@@@@ : : : Packet C ########### : : : Packet D ################################### : : ULP FEC Packet #2 @@@@@@@@@@@@@@ : : : :<-L0->:<--L1-->: Figure 1: Unequal Level Protection Payload packet # | ULP FEC packet that protects at level | L0 L1 ---------------------+--------------------------------------- A | #1 #2 B | #1 #2 C | #2 #2 D | #2 #2
FEC Packet Structureapp
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RTP Header (12 octets or more) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | FEC Header (10 octets) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | FEC Level 0 Header | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | FEC Level 0 Payload | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | FEC Level 1 Header | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | FEC Level 1 Payload | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Cont. | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 2: FEC Packet Structure
FEC Headertcp
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |E|L|P|X| CC |M| PT recovery | SN base | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TS recovery | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length recovery | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
E(Extension):0ide
L(Long Mask):使用使用long mask,0:16 bits mask、1:48 bits maskflex
P、X、CC、M、PT (Recovery field):对主流的RTP header使用保护算法计算后获得ui
SN base:被保护的主流的RTP包中最小的序号,经过结合 level header中的mask来表示该fec保护的主流的包的序号
TS recovery:对主流的RTP header中的 TS使用保护算法计算后获得
Length recovery:用于验证恢复的包的payload长度,由被保护的rtp包的长度使用保护算法计算后获得
ULP Level Header:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Protection Length | mask | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | mask cont. (present only when L = 1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
fec level header长度为 4字节(L=0)或8字节(L=1)
Proctection Length:fec level 负载的长度
Mask:bit i = 1 则该fec保护的包的序号包括 SN base + i,mask决定了该levle 保护了主流的哪些包。
设置原则:
- 一个媒体包只能被大于0的level 保护一次,能够被level 0保护屡次。(多重保护的开销太大)
- 一个媒体包被 level p 保护,那么确定的也会被 level p-1 保护,且 levle p 与 p-1 可能不是同一个fec包。(含有不一样levle 的fec包)
- 一个fec包若是有 levle p 保护区,那么也确定有 levle =p-1 且 level p 与 p-1 可能保护着不一样的packet(变长媒体包)
FEC的两种传输方式:
(1) 以分开的一路流传输
使用另一路 M 行来表示 fec, 并使用 mid 和 group 来绑定 FEC 流和被保护的流
v=0 o=adam 289083124 289083124 IN IP4 host.example.com s=ULP FEC Seminar t=0 0 c=IN IP4 224.2.17.12/127 a=group:FEC 1 2 a=group:FEC 3 4 m=audio 30000 RTP/AVP 0 a=mid:1 m=application 30002 RTP/AVP 100 a=rtpmap:100 ulpfec/8000 a=mid:2 m=video 30004 RTP/AVP 31 a=mid:3 m=application 30004 RTP/AVP 101 c=IN IP4 224.2.17.13/127 a=rtpmap:101 ulpfec/8000 a=mid:4
(2) FEC 做为冗余编码传输(Chrome)
使用RED封装 被保护的主流和 FEC 流.
m=audio 12345 RTP/AVP 121 0 5 100 a=rtpmap:121 red/8000/1 a=rtpmap:100 ulpfec/8000 a=fmtp:121 0/5/100
平时的主流使用 RED+RTP封装, 当产生FEC时可以使用 RED + FEC封装格式传输FEC流. FEC 流跟在Marker后面, 使用跟Marker同样的TS.
flexible 主要体如今能够自由选择对行仍是列(RTP包组成的数组)来生成fec包, 也能够选择直接重传某个包.
也体如今保护的源RTP包个数没有ulpfec中的 Long Mask = 1 (48bit)的限制, flexfec可使用 f bit来表示使用变长的mask bit,仍是固定长度mask
(即便是固定长度mask bit, 也是可自定义 M(column), N(raw))
1-D Parity FEC protection
非交错 1-D 失败的状况(连续丢包): +---+ +---+ +===+ | 1 | X X | 4 | |R_1| +---+ +---+ +===+ +---+ +---+ +---+ +---+ +===+ | 5 | | 6 | | 7 | | 8 | |R_2| +---+ +---+ +---+ +---+ +===+ +---+ +---+ +---+ +---+ +===+ | 9 | | 10| | 11| | 12| |R_3| +---+ +---+ +---+ +---+ +===+ 交错 1-D 失败的状况(定时丢包): +---+ +---+ +---+ | 1 | X | 3 | | 4 | +---+ +---+ +---+ +---+ +---+ +---+ | 5 | X | 7 | | 8 | +---+ +---+ +---+ +---+ +---+ +---+ +---+ | 9 | | 10| | 11| | 12| +---+ +---+ +---+ +---+ +===+ +===+ +===+ +===+ |C_1| |C_2| |C_3| |C_4| +===+ +===+ +===+ +===+
2-D Parity FEC protection:
+---+ +---+ +===+ X X | 3 | | 4 | |R_1| +---+ +---+ +===+ +---+ +---+ +---+ +---+ +===+ | 5 | | 6 | | 7 | | 8 | |R_2| +---+ +---+ +---+ +---+ +===+ +---+ +---+ +===+ | 9 | X X | 12| |R_3| +---+ +---+ +===+ +===+ +===+ +===+ +===+ |C_1| |C_2| |C_3| |C_4| +===+ +===+ +===+ +===+ 2-D 失败的状况(特定定时连续丢包) +---+ +---+ +===+ | 1 | X X | 4 | |R_1| +---+ +---+ +===+ +---+ +---+ +---+ +---+ +===+ | 5 | | 6 | | 7 | | 8 | |R_2| +---+ +---+ +---+ +---+ +===+ +---+ +---+ +===+ | 9 | X X | 12| |R_3| +---+ +---+ +===+ +===+ +===+ +===+ +===+ |C_1| |C_2| |C_3| |C_4| +===+ +===+ +===+ +===+
FlexFEC Header
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|R|F| P|X| CC |M| PT recovery | length recovery |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TS recovery |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRCCount | reserved |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC_i |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SN base_i |k| Mask [0-14] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |k| Mask [15-45] (optional) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |k| | +-+ Mask [46-108] (optional) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ... next in SSRC_i ... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
R:0:repair packet、1:retransmision
F:0:flexible mask、1:offset M and N
P、X、CC、M、PT (Recovery field):对主流的RTP header使用保护算法计算后获得
Length recovery:用于验证恢复的包的payload长度,由被保护的rtp包的长度使用保护算法计算后获得、TS recovery:对主流的RTP header中的 TS使用保护算法计算后获得
SSRCCount:被fec保护的SSRC 个数,0:非法
Reserved: 0
SSRC_i、SN base_i: 分别描述fec 所保护的包的 SSRC、SN base
若是 F = 1 则使用固定长度描述被保护的包信息
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|0| P|X| CC |M| PT recovery | length recovery | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TS recovery | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRCCount | reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC_i | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SN base_i | M (columns) | N (rows) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ... next in SSRC_i ... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
M > 0 and N = 0 Row Fec
M > 0 and N = 1 Row Fec + colum FEC follow
M > 0 and N > 1 Column FEC
若是 R=1 、F=1 则表示使用 Retransmision
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|1| P|X| CC |M| PT recovery | sequence number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Retransmission | : payload : | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FlexFEC in Offer、Answer
multiplexed on different SSRCs
Required
rate: RTP timestamp clock rate
repair-window: 主流与fec包的时间跨度
Optional:
L: columns
D:rows
ToP: 0:1-D interleaved FEC 1:1-D non-interleaved FEC 2:2-D parity FEC 3:reserved
v=0
o=ali 1122334455 1122334466 IN IP4 fec.example.com
s=2-D Parity FEC with no in band signalling Example
t=0 0
m=video 30000 RTP/AVP 100 110
c=IN IP4 233.252.0.1/127
a=rtpmap:100 MP2T/90000
a=rtpmap:110 flexfec/90000
a=fmtp:110 L:5; D:10; ToP:2; repair-window:200000 a=ssrc:1234 a=ssrc:2345 a=ssrc-group:FEC-FR 1234 2345
ssrc-group:FEC-FR
定义在 RFC 5956 (FEC grouping semantics in the SDP)
用于描述 source 和 repair 的对应关系.
modules/rtp_rtcp/source/ulpfec_genrator.h
class UlpfecGenerator
中定义了ulpfec的编码实现
设置 fec相关参数:
WebRTC 中对视频帧类型为 KeyFrame 和 DeltaFrame 分开设置 FEC 相关参数, 均使用 FecProtectionParams 结构
// Struct containing forward error correction settings. struct FecProtectionParams { int fec_rate;//fec的冗余度, The range is between 0 and 255, //where 255 corresponds to 100% overhead int max_fec_frames;//fec保护的码流的最大帧数 //(好比视频时max_fec_frames = 30表示在30帧时必须生成fec包) FecMaskType fec_mask_type;//fec的mask bitflag 使用模式, 分为随机和突发模式. };
编码FEC包
使用 AddRtpPacketAndGenerateFec
传入须要保护的packet.
而后使用emphasized text
获取生成的 fec包数量
而后使用 GetUlpfecPacketsAsRed
可获取 RED封装的FEC包
内部细节:
传入的 RTP 的包数量最多为ulpfec的最大bitflag长度(48), 内部会检测RTP的Marker位用于检测保护的流的帧数 生成fec的条件: 1) marker = 1 2) 保护的帧数达到了 params中的max_fec_frames 或者 fec的开销和最小媒体包数量达到要求 生成的 fec 存放在 generated_fec_packets_ , 使用 NumAvailableFecPackets 可获取其数量
PS:
ulpfecGenerator
内部使用的是ForwarErrorCorrection
对象 fec_ 来实现 ulpfecmodules\rtp_rtcp\source\forward_error_correction.h 这里是fec更底层的实现,
fec_.EnbcodeFec 能够指定更多的编码参数。
fec_factor, 也就是建立Generator时指定的 fec_rate(0-255), 255表示100%冗余度, 即多少个包就用多少个fec
num_important_packets, 用于指定这一帧中重要的包的个数(前面多少个包较重要),
当使用UEP(Unequal Protection)时使用, 这些包会使用level比较高的保护
use_unequal_protection, 是否使用 UEP(Generator中就默认不使用UEP)
fec_mask_type, (这里同Generato中的 mask type)
class UlpfecReceiver 定义了 ulpfec 接收和恢复相关接口, 具体实如今子类 calss UlpfecReceiverImpl 中.
modules\rtp_rtcp\include\ulpfec_receiver.h
modules\rtp_rtcp\source\ulpfec_receiver_impl.h
基本步骤
UlpfecReceiver::Create()
RtpData
(defined in rtp_rtcp_defines.h)的对象, 内部定义了回调接口OnRecoveredPacket
当媒体包获得恢复时会回调上来.UlpfecReceiver::AddReceivedRedPacket
UlpfecReceiver::ProcessReceivedFec()
进行恢复处理, 而后使用 UlpfecReceiver::GetPacketCounter
可获取 receiver 中的媒体包/fec/恢复的包 的个数.恢复的包会使用建立 Receiver 时指定的 RtpData的回调到上层详见 VideoCoding::protection_bitrate_calculator 用于动态计算 FEC / NACK 可以使用的发送 bitrate
WebRTC 中将 NACK 和 FEC 的动态发送bitrate 处理逻辑放在一块儿实现, 相关类包括: ProtectionBitrateCalculator
为了动态获得FEC/NACK的发送bitrate, 跟其相关的参数一共包括以下. 这些参数有些是直接从对端信令获得, 好比丢包率, RTT等信息,有些是本身根据本端实际发送数据获得, 好比实际发送 framerate, BitRatePerFrame, PacektNumPerFrame 等等.
1.struct VCMProtectionParameters { 2. int64_t rtt; 3. float lossPr; 4. float bitRate; 5. float packetsPerFrame; 6. float packetsPerFrameKey; 7. float frameRate; 8. float keyFrameSize; 9. uint8_t fecRateDelta; 10. uint8_t fecRateKey; 11. uint16_t codecWidth; 12. uint16_t codecHeight; 13. int numLayers; 14.};
当使用 Nack 和 Fec 混合模式时有以下逻辑:
1.// Thresholds for hybrid NACK/FEC
2.// common to media optimization and the jitter buffer.
3.const int64_t kLowRttNackMs = 20;
当前 RTT < kLowRttNackMs = 20ms, 使用 NACK, 此时FEC仅用于保护 关键帧.
当前 RTT > kHightRttNackMs 时仅使用 FEC, 关闭 NACK ( WebRTC 暂时未启用 )
当前 RTT > kLowRttNackMs =20ms, 混合使用 NACK 和 FEC.
当前每帧画面平均发送的BitRate 过低则会关闭 FEC, 此时不关心当前丢包率. 相关的几个阈值以下:
1. enum { kUpperLimitFramesFec = 6 }; 2. // Thresholds values for the bytes/frame and round trip time, below which we 3. // may turn off FEC, depending on |_numLayers| and |_maxFramesFec|. 4. // Max bytes/frame for VGA, corresponds to ~140k at 25fps. 5. enum { kMaxBytesPerFrameForFec = 700 }; 6. // Max bytes/frame for CIF and lower: corresponds to ~80k at 25fps. 7. enum { kMaxBytesPerFrameForFecLow = 400 }; 8. // Max bytes/frame for frame size larger than VGA, ~200k at 25fps. 9. enum { kMaxBytesPerFrameForFecHigh = 1000 }; 单位为 kb/s, 而且这个 每帧平均bitrate 有本身的计算方法.
关键帧和非关键帧使用分开的 FEC 冗余度, 而且根据 effective rate(bits/frame) 每帧平均bitrate 和 丢包率 一块儿决定查表索引,静态表定义以下:
1.// Table for Protection factor (code rate) of delta frames, for the XOR FEC. 2.// Input is the packet loss and an effective rate (bits/frame). 3.// Output is array kFecRateTable[k], where k = rate_i*129 + loss_j; 4.// loss_j = 0,1,..128, and rate_i varies over some range. 5. 6.static const int kFecRateTableSize = 6450; 7.static const unsigned char kFecRateTable[kFecRateTableSize]
表中最大冗余度为 127, 至关于 WebRTC 最大FEC冗余为 50%, 255至关于100%冗余度.
关键帧的 FEC 冗余度还与 关键帧的每帧平均包数 跟 非关键帧的每帧平均包数的比值相关,
会从新计算查表索引获得本身的冗余度
因为每一个参数都会通过一些数学算法计算, 可是本人没法看出这么处理的意义, 就不详细讲其处理算法了.
上述逻辑源码位置:
modules\video_coding\protection_bitrate_calculator.cc
modules\video_coding\media_opt_util.cc
FlexFEC 跟 UlpFEC实现有较大区别.
ulpfec 是在
VideoReceiveStream
中解析RED后判断 PT 再 将 RTP 包添加到UlpfecReceiver 中,
处理完再回调回来(分别使用AddReceivedPacket
OnRecoveredPackt
).FlexFEC 是新建一个相似VideoReceiveStream的流: FlexfecReceiveStream. 处理完成后将恢复的包再经过VideoReceiveStream::OnRtpPacket进行处理.
建立 FlexfecReceiveStream
FlexfecReceiveStream* Call::CreateFlexfecReceiveStream(const FlexfecReceiveStream::Config& config) receive_stream = new FlexfecReceiveStreamImpl( &video_receiver_controller_, config, recovered_packet_receiver, call_stats_->rtcp_rtt_stats(), module_process_thread_.get()); RecoveredPacketReceiver* recovered_packet_receiver = this;
在 webrtcvideoengine.cc 中判断flexfec是否开启后再建立并启动 FlexfecReceiveStream
recovered_packet_receiver
用于传入 FlexfecReceiveStreamImpl 中, 某个包恢复以后用于回调到 Call 这层.
建立 FlexfecReceiver
在 FlexfecReceiveStream 中会建立 FlexfecReceiver(属于RtpRtcp模块), 也会建立本身的 RtpRtcp 实例.
FlexfecReceiver 用于处理处理收到的 flexfec 包.
增长 Sink 到 RtpStreamReceiverController
会使用 RtpStreamReceiverController
建立 Receiver, 同时将 this( FlexfecReceiveStream::OnPacket)做为
Sink 传入 controller, 在sink中收到 RTP 包后传入 FlexfecReceiver 中处理.
controller 增长sink时也会传入 SSRC, 能够收取指定ssrc的 rtp 包.
在FlexfecReceiver 中处理 flexfec 包
经过 Sink::OnPacket 传入到 FlexfecReceiver::OnPacket后在
在 FlexfecReceiver::AddReceivedPacket 中判断包的负载长度要求以及ssrc
flexfec负载要求最小长度为 20byte.
最后使用 FlexfecReceiver::ProcessReceivedPackets进行flexfec 解码获取恢复出来的包
而后使用 recovered_packet_receiver::OnRecoveredPacket 回调到上层(Call).