Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/video_coding/main/source/media_opt_util.h"
     12 
     13 #include <algorithm>
     14 #include <float.h>
     15 #include <limits.h>
     16 #include <math.h>
     17 
     18 #include "webrtc/modules/interface/module_common_types.h"
     19 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
     20 #include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
     21 #include "webrtc/modules/video_coding/main/source/er_tables_xor.h"
     22 #include "webrtc/modules/video_coding/main/source/fec_tables_xor.h"
     23 #include "webrtc/modules/video_coding/main/source/nack_fec_tables.h"
     24 
     25 namespace webrtc {
     26 namespace media_optimization {
     27 
     28 VCMProtectionMethod::VCMProtectionMethod():
     29 _effectivePacketLoss(0),
     30 _protectionFactorK(0),
     31 _protectionFactorD(0),
     32 _residualPacketLossFec(0.0f),
     33 _scaleProtKey(2.0f),
     34 _maxPayloadSize(1460),
     35 _qmRobustness(new VCMQmRobustness()),
     36 _useUepProtectionK(false),
     37 _useUepProtectionD(true),
     38 _corrFecCost(1.0),
     39 _type(kNone),
     40 _efficiency(0)
     41 {
     42     //
     43 }
     44 
     45 VCMProtectionMethod::~VCMProtectionMethod()
     46 {
     47     delete _qmRobustness;
     48 }
     49 void
     50 VCMProtectionMethod::UpdateContentMetrics(const
     51                                           VideoContentMetrics* contentMetrics)
     52 {
     53     _qmRobustness->UpdateContent(contentMetrics);
     54 }
     55 
     56 VCMNackFecMethod::VCMNackFecMethod(int lowRttNackThresholdMs,
     57                                    int highRttNackThresholdMs)
     58     : VCMFecMethod(),
     59       _lowRttNackMs(lowRttNackThresholdMs),
     60       _highRttNackMs(highRttNackThresholdMs),
     61       _maxFramesFec(1) {
     62   assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
     63   assert(highRttNackThresholdMs == -1 ||
     64          lowRttNackThresholdMs <= highRttNackThresholdMs);
     65   assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
     66   _type = kNackFec;
     67 }
     68 
     69 VCMNackFecMethod::~VCMNackFecMethod()
     70 {
     71     //
     72 }
     73 bool
     74 VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
     75 {
     76     // Hybrid Nack FEC has three operational modes:
     77     // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
     78     //    (_protectionFactorD) to zero. -1 means no FEC.
     79     // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
     80     //    -1 means always allow NACK.
     81     // 3. Medium RTT values - Hybrid mode: We will only nack the
     82     //    residual following the decoding of the FEC (refer to JB logic). FEC
     83     //    delta protection factor will be adjusted based on the RTT.
     84 
     85     // Otherwise: we count on FEC; if the RTT is below a threshold, then we
     86     // nack the residual, based on a decision made in the JB.
     87 
     88     // Compute the protection factors
     89     VCMFecMethod::ProtectionFactor(parameters);
     90     if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs)
     91     {
     92         _protectionFactorD = 0;
     93         VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
     94     }
     95 
     96     // When in Hybrid mode (RTT range), adjust FEC rates based on the
     97     // RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
     98     else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
     99     {
    100         // TODO(mikhal): Disabling adjustment temporarily.
    101         // uint16_t rttIndex = (uint16_t) parameters->rtt;
    102         float adjustRtt = 1.0f;// (float)VCMNackFecTable[rttIndex] / 100.0f;
    103 
    104         // Adjust FEC with NACK on (for delta frame only)
    105         // table depends on RTT relative to rttMax (NACK Threshold)
    106         _protectionFactorD = static_cast<uint8_t>
    107                             (adjustRtt *
    108                              static_cast<float>(_protectionFactorD));
    109         // update FEC rates after applying adjustment
    110         VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
    111     }
    112 
    113     return true;
    114 }
    115 
    116 int VCMNackFecMethod::ComputeMaxFramesFec(
    117     const VCMProtectionParameters* parameters) {
    118   if (parameters->numLayers > 2) {
    119     // For more than 2 temporal layers we will only have FEC on the base layer,
    120     // and the base layers will be pretty far apart. Therefore we force one
    121     // frame FEC.
    122     return 1;
    123   }
    124   // We set the max number of frames to base the FEC on so that on average
    125   // we will have complete frames in one RTT. Note that this is an upper
    126   // bound, and that the actual number of frames used for FEC is decided by the
    127   // RTP module based on the actual number of packets and the protection factor.
    128   float base_layer_framerate = parameters->frameRate /
    129       static_cast<float>(1 << (parameters->numLayers - 1));
    130   int max_frames_fec = std::max(static_cast<int>(
    131       2.0f * base_layer_framerate * parameters->rtt /
    132       1000.0f + 0.5f), 1);
    133   // |kUpperLimitFramesFec| is the upper limit on how many frames we
    134   // allow any FEC to be based on.
    135   if (max_frames_fec > kUpperLimitFramesFec) {
    136     max_frames_fec = kUpperLimitFramesFec;
    137   }
    138   return max_frames_fec;
    139 }
    140 
    141 int VCMNackFecMethod::MaxFramesFec() const {
    142   return _maxFramesFec;
    143 }
    144 
    145 bool VCMNackFecMethod::BitRateTooLowForFec(
    146     const VCMProtectionParameters* parameters) {
    147   // Bitrate below which we turn off FEC, regardless of reported packet loss.
    148   // The condition should depend on resolution and content. For now, use
    149   // threshold on bytes per frame, with some effect for the frame size.
    150   // The condition for turning off FEC is also based on other factors,
    151   // such as |_numLayers|, |_maxFramesFec|, and |_rtt|.
    152   int estimate_bytes_per_frame = 1000 * BitsPerFrame(parameters) / 8;
    153   int max_bytes_per_frame = kMaxBytesPerFrameForFec;
    154   int num_pixels = parameters->codecWidth * parameters->codecHeight;
    155   if (num_pixels <= 352 * 288) {
    156     max_bytes_per_frame = kMaxBytesPerFrameForFecLow;
    157   } else if (num_pixels > 640 * 480) {
    158     max_bytes_per_frame = kMaxBytesPerFrameForFecHigh;
    159   }
    160   // TODO (marpan): add condition based on maximum frames used for FEC,
    161   // and expand condition based on frame size.
    162   if (estimate_bytes_per_frame < max_bytes_per_frame &&
    163       parameters->numLayers < 3 &&
    164       parameters->rtt < kMaxRttTurnOffFec) {
    165     return true;
    166   }
    167   return false;
    168 }
    169 
    170 bool
    171 VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
    172 {
    173     // Set the effective packet loss for encoder (based on FEC code).
    174     // Compute the effective packet loss and residual packet loss due to FEC.
    175     VCMFecMethod::EffectivePacketLoss(parameters);
    176     return true;
    177 }
    178 
    179 bool
    180 VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
    181 {
    182     ProtectionFactor(parameters);
    183     EffectivePacketLoss(parameters);
    184     _maxFramesFec = ComputeMaxFramesFec(parameters);
    185     if (BitRateTooLowForFec(parameters)) {
    186       _protectionFactorK = 0;
    187       _protectionFactorD = 0;
    188     }
    189 
    190     // Efficiency computation is based on FEC and NACK
    191 
    192     // Add FEC cost: ignore I frames for now
    193     float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
    194     _efficiency = parameters->bitRate * fecRate * _corrFecCost;
    195 
    196     // Add NACK cost, when applicable
    197     if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
    198     {
    199         // nackCost  = (bitRate - nackCost) * (lossPr)
    200         _efficiency += parameters->bitRate * _residualPacketLossFec /
    201                        (1.0f + _residualPacketLossFec);
    202     }
    203 
    204     // Protection/fec rates obtained above are defined relative to total number
    205     // of packets (total rate: source + fec) FEC in RTP module assumes
    206     // protection factor is defined relative to source number of packets so we
    207     // should convert the factor to reduce mismatch between mediaOpt's rate and
    208     // the actual one
    209     _protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK);
    210     _protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD);
    211 
    212     return true;
    213 }
    214 
    215 VCMNackMethod::VCMNackMethod():
    216 VCMProtectionMethod()
    217 {
    218     _type = kNack;
    219 }
    220 
    221 VCMNackMethod::~VCMNackMethod()
    222 {
    223     //
    224 }
    225 
    226 bool
    227 VCMNackMethod::EffectivePacketLoss(const VCMProtectionParameters* parameter)
    228 {
    229     // Effective Packet Loss, NA in current version.
    230     _effectivePacketLoss = 0;
    231     return true;
    232 }
    233 
    234 bool
    235 VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
    236 {
    237     // Compute the effective packet loss
    238     EffectivePacketLoss(parameters);
    239 
    240     // nackCost  = (bitRate - nackCost) * (lossPr)
    241     _efficiency = parameters->bitRate * parameters->lossPr /
    242                   (1.0f + parameters->lossPr);
    243     return true;
    244 }
    245 
    246 VCMFecMethod::VCMFecMethod():
    247 VCMProtectionMethod()
    248 {
    249     _type = kFec;
    250 }
    251 VCMFecMethod::~VCMFecMethod()
    252 {
    253     //
    254 }
    255 
    256 uint8_t
    257 VCMFecMethod::BoostCodeRateKey(uint8_t packetFrameDelta,
    258                                uint8_t packetFrameKey) const
    259 {
    260     uint8_t boostRateKey = 2;
    261     // Default: ratio scales the FEC protection up for I frames
    262     uint8_t ratio = 1;
    263 
    264     if (packetFrameDelta > 0)
    265     {
    266         ratio = (int8_t) (packetFrameKey / packetFrameDelta);
    267     }
    268     ratio = VCM_MAX(boostRateKey, ratio);
    269 
    270     return ratio;
    271 }
    272 
    273 uint8_t
    274 VCMFecMethod::ConvertFECRate(uint8_t codeRateRTP) const
    275 {
    276     return static_cast<uint8_t> (VCM_MIN(255,(0.5 + 255.0 * codeRateRTP /
    277                                       (float)(255 - codeRateRTP))));
    278 }
    279 
    280 // Update FEC with protectionFactorD
    281 void
    282 VCMFecMethod::UpdateProtectionFactorD(uint8_t protectionFactorD)
    283 {
    284     _protectionFactorD = protectionFactorD;
    285 }
    286 
    287 // Update FEC with protectionFactorK
    288 void
    289 VCMFecMethod::UpdateProtectionFactorK(uint8_t protectionFactorK)
    290 {
    291     _protectionFactorK = protectionFactorK;
    292 }
    293 
    294 // AvgRecoveryFEC: computes the residual packet loss (RPL) function.
    295 // This is the average recovery from the FEC, assuming random packet loss model.
    296 // Computed off-line for a range of FEC code parameters and loss rates.
    297 float
    298 VCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
    299 {
    300     // Total (avg) bits available per frame: total rate over actual/sent frame
    301     // rate units are kbits/frame
    302     const uint16_t bitRatePerFrame = static_cast<uint16_t>
    303                         (parameters->bitRate / (parameters->frameRate));
    304 
    305     // Total (average) number of packets per frame (source and fec):
    306     const uint8_t avgTotPackets = 1 + static_cast<uint8_t>
    307                         (static_cast<float> (bitRatePerFrame * 1000.0) /
    308                          static_cast<float> (8.0 * _maxPayloadSize) + 0.5);
    309 
    310     const float protectionFactor = static_cast<float>(_protectionFactorD) /
    311                                                       255.0;
    312 
    313     // Round down for estimated #FEC packets/frame, to keep
    314     // |fecPacketsPerFrame| <= |sourcePacketsPerFrame|.
    315     uint8_t fecPacketsPerFrame = static_cast<uint8_t>
    316                                       (protectionFactor * avgTotPackets);
    317 
    318     uint8_t sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
    319 
    320     if ( (fecPacketsPerFrame == 0) || (sourcePacketsPerFrame == 0) )
    321     {
    322         // No protection, or rate too low: so average recovery from FEC == 0.
    323         return 0.0;
    324     }
    325 
    326     // Table defined up to kMaxNumPackets
    327     if (sourcePacketsPerFrame > kMaxNumPackets)
    328     {
    329         sourcePacketsPerFrame = kMaxNumPackets;
    330     }
    331 
    332     // Table defined up to kMaxNumPackets
    333     if (fecPacketsPerFrame > kMaxNumPackets)
    334     {
    335         fecPacketsPerFrame = kMaxNumPackets;
    336     }
    337 
    338     // Code index for tables: up to (kMaxNumPackets * kMaxNumPackets)
    339     uint16_t codeIndexTable[kMaxNumPackets * kMaxNumPackets];
    340     uint16_t k = 0;
    341     for (uint8_t i = 1; i <= kMaxNumPackets; i++)
    342     {
    343         for (uint8_t j = 1; j <= i; j++)
    344         {
    345             codeIndexTable[(j - 1) * kMaxNumPackets + i - 1] = k;
    346             k += 1;
    347         }
    348     }
    349 
    350     uint8_t lossRate = static_cast<uint8_t> (255.0 *
    351                              parameters->lossPr + 0.5f);
    352 
    353     // Constrain lossRate to 50%: tables defined up to 50%
    354     if (lossRate >= kPacketLossMax)
    355     {
    356         lossRate = kPacketLossMax - 1;
    357     }
    358 
    359     const uint16_t codeIndex = (fecPacketsPerFrame - 1) * kMaxNumPackets +
    360                                      (sourcePacketsPerFrame - 1);
    361 
    362     const uint16_t indexTable = codeIndexTable[codeIndex] * kPacketLossMax +
    363                                       lossRate;
    364 
    365     // Check on table index
    366     assert(indexTable < kSizeAvgFECRecoveryXOR);
    367     float avgFecRecov = static_cast<float>(kAvgFECRecoveryXOR[indexTable]);
    368 
    369     return avgFecRecov;
    370 }
    371 
    372 bool
    373 VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
    374 {
    375     // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
    376 
    377     // No protection if (filtered) packetLoss is 0
    378     uint8_t packetLoss = (uint8_t) (255 * parameters->lossPr);
    379     if (packetLoss == 0)
    380     {
    381         _protectionFactorK = 0;
    382         _protectionFactorD = 0;
    383          return true;
    384     }
    385 
    386     // Parameters for FEC setting:
    387     // first partition size, thresholds, table pars, spatial resoln fac.
    388 
    389     // First partition protection: ~ 20%
    390     uint8_t firstPartitionProt = (uint8_t) (255 * 0.20);
    391 
    392     // Minimum protection level needed to generate one FEC packet for one
    393     // source packet/frame (in RTP sender)
    394     uint8_t minProtLevelFec = 85;
    395 
    396     // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
    397     // above which we allocate protection to cover at least first partition.
    398     uint8_t lossThr = 0;
    399     uint8_t packetNumThr = 1;
    400 
    401     // Parameters for range of rate index of table.
    402     const uint8_t ratePar1 = 5;
    403     const uint8_t ratePar2 = 49;
    404 
    405     // Spatial resolution size, relative to a reference size.
    406     float spatialSizeToRef = static_cast<float>
    407                            (parameters->codecWidth * parameters->codecHeight) /
    408                            (static_cast<float>(704 * 576));
    409     // resolnFac: This parameter will generally increase/decrease the FEC rate
    410     // (for fixed bitRate and packetLoss) based on system size.
    411     // Use a smaller exponent (< 1) to control/soften system size effect.
    412     const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
    413 
    414     const int bitRatePerFrame = BitsPerFrame(parameters);
    415 
    416 
    417     // Average number of packets per frame (source and fec):
    418     const uint8_t avgTotPackets = 1 + (uint8_t)
    419                                         ((float) bitRatePerFrame * 1000.0
    420                                        / (float) (8.0 * _maxPayloadSize) + 0.5);
    421 
    422     // FEC rate parameters: for P and I frame
    423     uint8_t codeRateDelta = 0;
    424     uint8_t codeRateKey = 0;
    425 
    426     // Get index for table: the FEC protection depends on an effective rate.
    427     // The range on the rate index corresponds to rates (bps)
    428     // from ~200k to ~8000k, for 30fps
    429     const uint16_t effRateFecTable = static_cast<uint16_t>
    430                                            (resolnFac * bitRatePerFrame);
    431     uint8_t rateIndexTable =
    432         (uint8_t) VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) /
    433                                          ratePar1, ratePar2), 0);
    434 
    435     // Restrict packet loss range to 50:
    436     // current tables defined only up to 50%
    437     if (packetLoss >= kPacketLossMax)
    438     {
    439         packetLoss = kPacketLossMax - 1;
    440     }
    441     uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss;
    442 
    443     // Check on table index
    444     assert(indexTable < kSizeCodeRateXORTable);
    445 
    446     // Protection factor for P frame
    447     codeRateDelta = kCodeRateXORTable[indexTable];
    448 
    449     if (packetLoss > lossThr && avgTotPackets > packetNumThr)
    450     {
    451         // Set a minimum based on first partition size.
    452         if (codeRateDelta < firstPartitionProt)
    453         {
    454             codeRateDelta = firstPartitionProt;
    455         }
    456     }
    457 
    458     // Check limit on amount of protection for P frame; 50% is max.
    459     if (codeRateDelta >= kPacketLossMax)
    460     {
    461         codeRateDelta = kPacketLossMax - 1;
    462     }
    463 
    464     float adjustFec = 1.0f;
    465     // Avoid additional adjustments when layers are active.
    466     // TODO(mikhal/marco): Update adjusmtent based on layer info.
    467     if (parameters->numLayers == 1)
    468     {
    469         adjustFec = _qmRobustness->AdjustFecFactor(codeRateDelta,
    470                                                    parameters->bitRate,
    471                                                    parameters->frameRate,
    472                                                    parameters->rtt,
    473                                                    packetLoss);
    474     }
    475 
    476     codeRateDelta = static_cast<uint8_t>(codeRateDelta * adjustFec);
    477 
    478     // For Key frame:
    479     // Effectively at a higher rate, so we scale/boost the rate
    480     // The boost factor may depend on several factors: ratio of packet
    481     // number of I to P frames, how much protection placed on P frames, etc.
    482     const uint8_t packetFrameDelta = (uint8_t)
    483                                            (0.5 + parameters->packetsPerFrame);
    484     const uint8_t packetFrameKey = (uint8_t)
    485                                          (0.5 + parameters->packetsPerFrameKey);
    486     const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta,
    487                                                     packetFrameKey);
    488 
    489     rateIndexTable = (uint8_t) VCM_MAX(VCM_MIN(
    490                       1 + (boostKey * effRateFecTable - ratePar1) /
    491                       ratePar1,ratePar2),0);
    492     uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
    493 
    494     indexTableKey = VCM_MIN(indexTableKey, kSizeCodeRateXORTable);
    495 
    496     // Check on table index
    497     assert(indexTableKey < kSizeCodeRateXORTable);
    498 
    499     // Protection factor for I frame
    500     codeRateKey = kCodeRateXORTable[indexTableKey];
    501 
    502     // Boosting for Key frame.
    503     int boostKeyProt = _scaleProtKey * codeRateDelta;
    504     if (boostKeyProt >= kPacketLossMax)
    505     {
    506         boostKeyProt = kPacketLossMax - 1;
    507     }
    508 
    509     // Make sure I frame protection is at least larger than P frame protection,
    510     // and at least as high as filtered packet loss.
    511     codeRateKey = static_cast<uint8_t> (VCM_MAX(packetLoss,
    512             VCM_MAX(boostKeyProt, codeRateKey)));
    513 
    514     // Check limit on amount of protection for I frame: 50% is max.
    515     if (codeRateKey >= kPacketLossMax)
    516     {
    517         codeRateKey = kPacketLossMax - 1;
    518     }
    519 
    520     _protectionFactorK = codeRateKey;
    521     _protectionFactorD = codeRateDelta;
    522 
    523     // Generally there is a rate mis-match between the FEC cost estimated
    524     // in mediaOpt and the actual FEC cost sent out in RTP module.
    525     // This is more significant at low rates (small # of source packets), where
    526     // the granularity of the FEC decreases. In this case, non-zero protection
    527     // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
    528     // is based on rounding off protectionFactor on actual source packet number).
    529     // The correction factor (_corrFecCost) attempts to corrects this, at least
    530     // for cases of low rates (small #packets) and low protection levels.
    531 
    532     float numPacketsFl = 1.0f + ((float) bitRatePerFrame * 1000.0
    533                                 / (float) (8.0 * _maxPayloadSize) + 0.5);
    534 
    535     const float estNumFecGen = 0.5f + static_cast<float> (_protectionFactorD *
    536                                                          numPacketsFl / 255.0f);
    537 
    538 
    539     // We reduce cost factor (which will reduce overhead for FEC and
    540     // hybrid method) and not the protectionFactor.
    541     _corrFecCost = 1.0f;
    542     if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec)
    543     {
    544         _corrFecCost = 0.5f;
    545     }
    546     if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec)
    547     {
    548         _corrFecCost = 0.0f;
    549     }
    550 
    551      // TODO (marpan): Set the UEP protection on/off for Key and Delta frames
    552     _useUepProtectionK = _qmRobustness->SetUepProtection(codeRateKey,
    553                                                          parameters->bitRate,
    554                                                          packetLoss,
    555                                                          0);
    556 
    557     _useUepProtectionD = _qmRobustness->SetUepProtection(codeRateDelta,
    558                                                          parameters->bitRate,
    559                                                          packetLoss,
    560                                                          1);
    561 
    562     // DONE WITH FEC PROTECTION SETTINGS
    563     return true;
    564 }
    565 
    566 int VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) {
    567   // When temporal layers are available FEC will only be applied on the base
    568   // layer.
    569   const float bitRateRatio =
    570     kVp8LayerRateAlloction[parameters->numLayers - 1][0];
    571   float frameRateRatio = powf(1 / 2.0, parameters->numLayers - 1);
    572   float bitRate = parameters->bitRate * bitRateRatio;
    573   float frameRate = parameters->frameRate * frameRateRatio;
    574 
    575   // TODO(mikhal): Update factor following testing.
    576   float adjustmentFactor = 1;
    577 
    578   // Average bits per frame (units of kbits)
    579   return static_cast<int>(adjustmentFactor * bitRate / frameRate);
    580 }
    581 
    582 bool
    583 VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
    584 {
    585     // Effective packet loss to encoder is based on RPL (residual packet loss)
    586     // this is a soft setting based on degree of FEC protection
    587     // RPL = received/input packet loss - average_FEC_recovery
    588     // note: received/input packet loss may be filtered based on FilteredLoss
    589 
    590     // The packet loss:
    591     uint8_t packetLoss = (uint8_t) (255 * parameters->lossPr);
    592 
    593     float avgFecRecov = AvgRecoveryFEC(parameters);
    594 
    595     // Residual Packet Loss:
    596     _residualPacketLossFec = (float) (packetLoss - avgFecRecov) / 255.0f;
    597 
    598     // Effective Packet Loss, NA in current version.
    599     _effectivePacketLoss = 0;
    600 
    601     return true;
    602 }
    603 
    604 bool
    605 VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
    606 {
    607     // Compute the protection factor
    608     ProtectionFactor(parameters);
    609 
    610     // Compute the effective packet loss
    611     EffectivePacketLoss(parameters);
    612 
    613     // Compute the bit cost
    614     // Ignore key frames for now.
    615     float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
    616     if (fecRate >= 0.0f)
    617     {
    618         // use this formula if the fecRate (protection factor) is defined
    619         // relative to number of source packets
    620         // this is the case for the previous tables:
    621         // _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
    622 
    623         // in the new tables, the fecRate is defined relative to total number of
    624         // packets (total rate), so overhead cost is:
    625         _efficiency = parameters->bitRate * fecRate * _corrFecCost;
    626     }
    627     else
    628     {
    629         _efficiency = 0.0f;
    630     }
    631 
    632     // Protection/fec rates obtained above is defined relative to total number
    633     // of packets (total rate: source+fec) FEC in RTP module assumes protection
    634     // factor is defined relative to source number of packets so we should
    635     // convert the factor to reduce mismatch between mediaOpt suggested rate and
    636     // the actual rate
    637     _protectionFactorK = ConvertFECRate(_protectionFactorK);
    638     _protectionFactorD = ConvertFECRate(_protectionFactorD);
    639 
    640     return true;
    641 }
    642 VCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs):
    643 _selectedMethod(NULL),
    644 _currentParameters(),
    645 _rtt(0),
    646 _lossPr(0.0f),
    647 _bitRate(0.0f),
    648 _frameRate(0.0f),
    649 _keyFrameSize(0.0f),
    650 _fecRateKey(0),
    651 _fecRateDelta(0),
    652 _lastPrUpdateT(0),
    653 _lossPr255(0.9999f),
    654 _lossPrHistory(),
    655 _shortMaxLossPr255(0),
    656 _packetsPerFrame(0.9999f),
    657 _packetsPerFrameKey(0.9999f),
    658 _residualPacketLossFec(0),
    659 _codecWidth(0),
    660 _codecHeight(0),
    661 _numLayers(1)
    662 {
    663     Reset(nowMs);
    664 }
    665 
    666 VCMLossProtectionLogic::~VCMLossProtectionLogic()
    667 {
    668     Release();
    669 }
    670 
    671 bool
    672 VCMLossProtectionLogic::SetMethod(enum VCMProtectionMethodEnum newMethodType)
    673 {
    674     if (_selectedMethod != NULL)
    675     {
    676         if (_selectedMethod->Type() == newMethodType)
    677         {
    678             // Nothing to update
    679             return false;
    680         }
    681         // New method - delete existing one
    682         delete _selectedMethod;
    683     }
    684     VCMProtectionMethod *newMethod = NULL;
    685     switch (newMethodType)
    686     {
    687         case kNack:
    688         {
    689             newMethod = new VCMNackMethod();
    690             break;
    691         }
    692         case kFec:
    693         {
    694             newMethod  = new VCMFecMethod();
    695             break;
    696         }
    697         case kNackFec:
    698         {
    699             // Default to always having NACK enabled for the hybrid mode.
    700             newMethod =  new VCMNackFecMethod(kLowRttNackMs, -1);
    701             break;
    702         }
    703         default:
    704         {
    705           return false;
    706           break;
    707         }
    708 
    709     }
    710     _selectedMethod = newMethod;
    711     return true;
    712 }
    713 bool
    714 VCMLossProtectionLogic::RemoveMethod(enum VCMProtectionMethodEnum method)
    715 {
    716     if (_selectedMethod == NULL)
    717     {
    718         return false;
    719     }
    720     else if (_selectedMethod->Type() == method)
    721     {
    722         delete _selectedMethod;
    723         _selectedMethod = NULL;
    724     }
    725     return true;
    726 }
    727 
    728 float
    729 VCMLossProtectionLogic::RequiredBitRate() const
    730 {
    731     float RequiredBitRate = 0.0f;
    732     if (_selectedMethod != NULL)
    733     {
    734         RequiredBitRate = _selectedMethod->RequiredBitRate();
    735     }
    736     return RequiredBitRate;
    737 }
    738 
    739 void
    740 VCMLossProtectionLogic::UpdateRtt(uint32_t rtt)
    741 {
    742     _rtt = rtt;
    743 }
    744 
    745 void
    746 VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
    747 {
    748     _residualPacketLossFec = residualPacketLoss;
    749 }
    750 
    751 void
    752 VCMLossProtectionLogic::UpdateMaxLossHistory(uint8_t lossPr255,
    753                                              int64_t now)
    754 {
    755     if (_lossPrHistory[0].timeMs >= 0 &&
    756         now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
    757     {
    758         if (lossPr255 > _shortMaxLossPr255)
    759         {
    760             _shortMaxLossPr255 = lossPr255;
    761         }
    762     }
    763     else
    764     {
    765         // Only add a new value to the history once a second
    766         if (_lossPrHistory[0].timeMs == -1)
    767         {
    768             // First, no shift
    769             _shortMaxLossPr255 = lossPr255;
    770         }
    771         else
    772         {
    773             // Shift
    774             for (int32_t i = (kLossPrHistorySize - 2); i >= 0; i--)
    775             {
    776                 _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
    777                 _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
    778             }
    779         }
    780         if (_shortMaxLossPr255 == 0)
    781         {
    782             _shortMaxLossPr255 = lossPr255;
    783         }
    784 
    785         _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
    786         _lossPrHistory[0].timeMs = now;
    787         _shortMaxLossPr255 = 0;
    788     }
    789 }
    790 
    791 uint8_t
    792 VCMLossProtectionLogic::MaxFilteredLossPr(int64_t nowMs) const
    793 {
    794     uint8_t maxFound = _shortMaxLossPr255;
    795     if (_lossPrHistory[0].timeMs == -1)
    796     {
    797         return maxFound;
    798     }
    799     for (int32_t i = 0; i < kLossPrHistorySize; i++)
    800     {
    801         if (_lossPrHistory[i].timeMs == -1)
    802         {
    803             break;
    804         }
    805         if (nowMs - _lossPrHistory[i].timeMs >
    806             kLossPrHistorySize * kLossPrShortFilterWinMs)
    807         {
    808             // This sample (and all samples after this) is too old
    809             break;
    810         }
    811         if (_lossPrHistory[i].lossPr255 > maxFound)
    812         {
    813             // This sample is the largest one this far into the history
    814             maxFound = _lossPrHistory[i].lossPr255;
    815         }
    816     }
    817     return maxFound;
    818 }
    819 
    820 uint8_t VCMLossProtectionLogic::FilteredLoss(
    821     int64_t nowMs,
    822     FilterPacketLossMode filter_mode,
    823     uint8_t lossPr255) {
    824 
    825   // Update the max window filter.
    826   UpdateMaxLossHistory(lossPr255, nowMs);
    827 
    828   // Update the recursive average filter.
    829   _lossPr255.Apply(static_cast<float> (nowMs - _lastPrUpdateT),
    830                    static_cast<float> (lossPr255));
    831   _lastPrUpdateT = nowMs;
    832 
    833   // Filtered loss: default is received loss (no filtering).
    834   uint8_t filtered_loss = lossPr255;
    835 
    836   switch (filter_mode) {
    837     case kNoFilter:
    838       break;
    839     case kAvgFilter:
    840       filtered_loss = static_cast<uint8_t> (_lossPr255.Value() + 0.5);
    841       break;
    842     case kMaxFilter:
    843       filtered_loss = MaxFilteredLossPr(nowMs);
    844       break;
    845   }
    846 
    847   return filtered_loss;
    848 }
    849 
    850 void
    851 VCMLossProtectionLogic::UpdateFilteredLossPr(uint8_t packetLossEnc)
    852 {
    853     _lossPr = (float) packetLossEnc / (float) 255.0;
    854 }
    855 
    856 void
    857 VCMLossProtectionLogic::UpdateBitRate(float bitRate)
    858 {
    859     _bitRate = bitRate;
    860 }
    861 
    862 void
    863 VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets, int64_t nowMs)
    864 {
    865     _packetsPerFrame.Apply(static_cast<float>(nowMs - _lastPacketPerFrameUpdateT),
    866                            nPackets);
    867     _lastPacketPerFrameUpdateT = nowMs;
    868 }
    869 
    870 void
    871 VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets, int64_t nowMs)
    872 {
    873     _packetsPerFrameKey.Apply(static_cast<float>(nowMs -
    874                               _lastPacketPerFrameUpdateTKey), nPackets);
    875     _lastPacketPerFrameUpdateTKey = nowMs;
    876 }
    877 
    878 void
    879 VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
    880 {
    881     _keyFrameSize = keyFrameSize;
    882 }
    883 
    884 void
    885 VCMLossProtectionLogic::UpdateFrameSize(uint16_t width,
    886                                         uint16_t height)
    887 {
    888     _codecWidth = width;
    889     _codecHeight = height;
    890 }
    891 
    892 void VCMLossProtectionLogic::UpdateNumLayers(int numLayers) {
    893   _numLayers = (numLayers == 0) ? 1 : numLayers;
    894 }
    895 
    896 bool
    897 VCMLossProtectionLogic::UpdateMethod()
    898 {
    899     if (_selectedMethod == NULL)
    900     {
    901         return false;
    902     }
    903     _currentParameters.rtt = _rtt;
    904     _currentParameters.lossPr = _lossPr;
    905     _currentParameters.bitRate = _bitRate;
    906     _currentParameters.frameRate = _frameRate; // rename actual frame rate?
    907     _currentParameters.keyFrameSize = _keyFrameSize;
    908     _currentParameters.fecRateDelta = _fecRateDelta;
    909     _currentParameters.fecRateKey = _fecRateKey;
    910     _currentParameters.packetsPerFrame = _packetsPerFrame.Value();
    911     _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
    912     _currentParameters.residualPacketLossFec = _residualPacketLossFec;
    913     _currentParameters.codecWidth = _codecWidth;
    914     _currentParameters.codecHeight = _codecHeight;
    915     _currentParameters.numLayers = _numLayers;
    916     return _selectedMethod->UpdateParameters(&_currentParameters);
    917 }
    918 
    919 VCMProtectionMethod*
    920 VCMLossProtectionLogic::SelectedMethod() const
    921 {
    922     return _selectedMethod;
    923 }
    924 
    925 VCMProtectionMethodEnum
    926 VCMLossProtectionLogic::SelectedType() const
    927 {
    928     return _selectedMethod->Type();
    929 }
    930 
    931 void
    932 VCMLossProtectionLogic::Reset(int64_t nowMs)
    933 {
    934     _lastPrUpdateT = nowMs;
    935     _lastPacketPerFrameUpdateT = nowMs;
    936     _lastPacketPerFrameUpdateTKey = nowMs;
    937     _lossPr255.Reset(0.9999f);
    938     _packetsPerFrame.Reset(0.9999f);
    939     _fecRateDelta = _fecRateKey = 0;
    940     for (int32_t i = 0; i < kLossPrHistorySize; i++)
    941     {
    942         _lossPrHistory[i].lossPr255 = 0;
    943         _lossPrHistory[i].timeMs = -1;
    944     }
    945     _shortMaxLossPr255 = 0;
    946     Release();
    947 }
    948 
    949 void
    950 VCMLossProtectionLogic::Release()
    951 {
    952     delete _selectedMethod;
    953     _selectedMethod = NULL;
    954 }
    955 
    956 }  // namespace media_optimization
    957 }  // namespace webrtc
    958