保护因子的作用

image.png
保护因子的作用:是决定对一组媒体包产生多少个FEC包。

NumFecPackets

image.png
protection_factor 保护因子。
向右移8位,也就是除以256的原因,是因为webrtc的对包计算,是以256为单位计算的,也就是在256个包中,有多少个包丢失了。

保护因子从哪里来?

image.png
这类发现保护因子是从函数CurrentParams()函数得来的。

CurrentParams

image.png
后面查看是pendingparams是从SetProtectionParameters函数得来的。

SetProtectionParameters

image.png

更新FEC码调用栈

image.png
PostUpdates 更新目标码率,会周期调用。

UpdateFecRate

image.png
UpdateFecRate(评估码率, 真实帧率,丢包率,丢包的掩码数组,rtt时间)

ProtectionFactor计算保护因子

image.png
_maxPayloadSize : rtp包的最大字节,1460个。
effRateFecTable 有效码率
codeRateDelta 非关键帧的保护因子。关键帧的保护因子的计算方式跟这个差不多。
kFecRateTable 看《12-29 -FEC基础知识和原理

  1. bool VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters) {
  2. // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
  3. // No protection if (filtered) packetLoss is 0
  4. uint8_t packetLoss = rtc::saturated_cast<uint8_t>(255 * parameters->lossPr);
  5. if (packetLoss == 0) {
  6. _protectionFactorK = 0;
  7. _protectionFactorD = 0;
  8. return true;
  9. }
  10. // Parameters for FEC setting:
  11. // first partition size, thresholds, table pars, spatial resoln fac.
  12. // First partition protection: ~ 20%
  13. uint8_t firstPartitionProt = rtc::saturated_cast<uint8_t>(255 * 0.20);
  14. // Minimum protection level needed to generate one FEC packet for one
  15. // source packet/frame (in RTP sender)
  16. uint8_t minProtLevelFec = 85;
  17. // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
  18. // above which we allocate protection to cover at least first partition.
  19. uint8_t lossThr = 0;
  20. uint8_t packetNumThr = 1;
  21. // Parameters for range of rate index of table.
  22. const uint8_t ratePar1 = 5;
  23. const uint8_t ratePar2 = 49;
  24. // Spatial resolution size, relative to a reference size.
  25. float spatialSizeToRef = rtc::saturated_cast<float>(parameters->codecWidth *
  26. parameters->codecHeight) /
  27. (rtc::saturated_cast<float>(704 * 576));
  28. // resolnFac: This parameter will generally increase/decrease the FEC rate
  29. // (for fixed bitRate and packetLoss) based on system size.
  30. // Use a smaller exponent (< 1) to control/soften system size effect.
  31. const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
  32. const int bitRatePerFrame = BitsPerFrame(parameters);
  33. // Average number of packets per frame (source and fec):
  34. const uint8_t avgTotPackets = rtc::saturated_cast<uint8_t>(
  35. 1.5f + rtc::saturated_cast<float>(bitRatePerFrame) * 1000.0f /
  36. rtc::saturated_cast<float>(8.0 * _maxPayloadSize));
  37. // FEC rate parameters: for P and I frame
  38. uint8_t codeRateDelta = 0;
  39. uint8_t codeRateKey = 0;
  40. // Get index for table: the FEC protection depends on an effective rate.
  41. // The range on the rate index corresponds to rates (bps)
  42. // from ~200k to ~8000k, for 30fps
  43. const uint16_t effRateFecTable =
  44. rtc::saturated_cast<uint16_t>(resolnFac * bitRatePerFrame);
  45. uint8_t rateIndexTable = rtc::saturated_cast<uint8_t>(
  46. VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) / ratePar1, ratePar2), 0));
  47. // Restrict packet loss range to 50:
  48. // current tables defined only up to 50%
  49. if (packetLoss >= kPacketLossMax) {
  50. packetLoss = kPacketLossMax - 1;
  51. }
  52. uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss;
  53. // Check on table index
  54. RTC_DCHECK_LT(indexTable, kFecRateTableSize);
  55. // Protection factor for P frame
  56. codeRateDelta = kFecRateTable[indexTable];
  57. if (packetLoss > lossThr && avgTotPackets > packetNumThr) {
  58. // Set a minimum based on first partition size.
  59. if (codeRateDelta < firstPartitionProt) {
  60. codeRateDelta = firstPartitionProt;
  61. }
  62. }
  63. // Check limit on amount of protection for P frame; 50% is max.
  64. if (codeRateDelta >= kPacketLossMax) {
  65. codeRateDelta = kPacketLossMax - 1;
  66. }
  67. // For Key frame:
  68. // Effectively at a higher rate, so we scale/boost the rate
  69. // The boost factor may depend on several factors: ratio of packet
  70. // number of I to P frames, how much protection placed on P frames, etc.
  71. const uint8_t packetFrameDelta =
  72. rtc::saturated_cast<uint8_t>(0.5 + parameters->packetsPerFrame);
  73. const uint8_t packetFrameKey =
  74. rtc::saturated_cast<uint8_t>(0.5 + parameters->packetsPerFrameKey);
  75. const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta, packetFrameKey);
  76. rateIndexTable = rtc::saturated_cast<uint8_t>(VCM_MAX(
  77. VCM_MIN(1 + (boostKey * effRateFecTable - ratePar1) / ratePar1, ratePar2),
  78. 0));
  79. uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
  80. indexTableKey = VCM_MIN(indexTableKey, kFecRateTableSize);
  81. // Check on table index
  82. assert(indexTableKey < kFecRateTableSize);
  83. // Protection factor for I frame
  84. codeRateKey = kFecRateTable[indexTableKey];
  85. // Boosting for Key frame.
  86. int boostKeyProt = _scaleProtKey * codeRateDelta;
  87. if (boostKeyProt >= kPacketLossMax) {
  88. boostKeyProt = kPacketLossMax - 1;
  89. }
  90. // Make sure I frame protection is at least larger than P frame protection,
  91. // and at least as high as filtered packet loss.
  92. codeRateKey = rtc::saturated_cast<uint8_t>(
  93. VCM_MAX(packetLoss, VCM_MAX(boostKeyProt, codeRateKey)));
  94. // Check limit on amount of protection for I frame: 50% is max.
  95. if (codeRateKey >= kPacketLossMax) {
  96. codeRateKey = kPacketLossMax - 1;
  97. }
  98. _protectionFactorK = codeRateKey;
  99. _protectionFactorD = codeRateDelta;
  100. // Generally there is a rate mis-match between the FEC cost estimated
  101. // in mediaOpt and the actual FEC cost sent out in RTP module.
  102. // This is more significant at low rates (small # of source packets), where
  103. // the granularity of the FEC decreases. In this case, non-zero protection
  104. // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
  105. // is based on rounding off protectionFactor on actual source packet number).
  106. // The correction factor (_corrFecCost) attempts to corrects this, at least
  107. // for cases of low rates (small #packets) and low protection levels.
  108. float numPacketsFl =
  109. 1.0f + (rtc::saturated_cast<float>(bitRatePerFrame) * 1000.0 /
  110. rtc::saturated_cast<float>(8.0 * _maxPayloadSize) +
  111. 0.5);
  112. const float estNumFecGen =
  113. 0.5f +
  114. rtc::saturated_cast<float>(_protectionFactorD * numPacketsFl / 255.0f);
  115. // We reduce cost factor (which will reduce overhead for FEC and
  116. // hybrid method) and not the protectionFactor.
  117. _corrFecCost = 1.0f;
  118. if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec) {
  119. _corrFecCost = 0.5f;
  120. }
  121. if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec) {
  122. _corrFecCost = 0.0f;
  123. }
  124. // DONE WITH FEC PROTECTION SETTINGS
  125. return true;
  126. }