LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/video_coding - media_opt_util.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 300 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 47 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/media_opt_util.h"
      12             : 
      13             : #include <float.h>
      14             : #include <limits.h>
      15             : #include <math.h>
      16             : 
      17             : #include <algorithm>
      18             : #include <limits>
      19             : 
      20             : #include "webrtc/modules/include/module_common_types.h"
      21             : #include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
      22             : #include "webrtc/modules/video_coding/include/video_coding_defines.h"
      23             : #include "webrtc/modules/video_coding/fec_rate_table.h"
      24             : #include "webrtc/modules/video_coding/nack_fec_tables.h"
      25             : 
      26             : namespace webrtc {
      27             : // Max value of loss rates in off-line model
      28             : static const int kPacketLossMax = 129;
      29             : 
      30             : namespace media_optimization {
      31             : 
      32           0 : VCMProtectionMethod::VCMProtectionMethod()
      33             :     : _effectivePacketLoss(0),
      34             :       _protectionFactorK(0),
      35             :       _protectionFactorD(0),
      36             :       _scaleProtKey(2.0f),
      37             :       _maxPayloadSize(1460),
      38             :       _corrFecCost(1.0),
      39           0 :       _type(kNone) {}
      40             : 
      41           0 : VCMProtectionMethod::~VCMProtectionMethod() {}
      42             : 
      43           0 : VCMNackFecMethod::VCMNackFecMethod(int64_t lowRttNackThresholdMs,
      44           0 :                                    int64_t highRttNackThresholdMs)
      45             :     : VCMFecMethod(),
      46             :       _lowRttNackMs(lowRttNackThresholdMs),
      47             :       _highRttNackMs(highRttNackThresholdMs),
      48           0 :       _maxFramesFec(1) {
      49           0 :   assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
      50           0 :   assert(highRttNackThresholdMs == -1 ||
      51             :          lowRttNackThresholdMs <= highRttNackThresholdMs);
      52           0 :   assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
      53           0 :   _type = kNackFec;
      54           0 : }
      55             : 
      56           0 : VCMNackFecMethod::~VCMNackFecMethod() {
      57             :   //
      58           0 : }
      59           0 : bool VCMNackFecMethod::ProtectionFactor(
      60             :     const VCMProtectionParameters* parameters) {
      61             :   // Hybrid Nack FEC has three operational modes:
      62             :   // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
      63             :   //    (_protectionFactorD) to zero. -1 means no FEC.
      64             :   // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
      65             :   //    -1 means always allow NACK.
      66             :   // 3. Medium RTT values - Hybrid mode: We will only nack the
      67             :   //    residual following the decoding of the FEC (refer to JB logic). FEC
      68             :   //    delta protection factor will be adjusted based on the RTT.
      69             : 
      70             :   // Otherwise: we count on FEC; if the RTT is below a threshold, then we
      71             :   // nack the residual, based on a decision made in the JB.
      72             : 
      73             :   // Compute the protection factors
      74           0 :   VCMFecMethod::ProtectionFactor(parameters);
      75           0 :   if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs) {
      76           0 :     _protectionFactorD = 0;
      77           0 :     VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
      78             : 
      79             :     // When in Hybrid mode (RTT range), adjust FEC rates based on the
      80             :     // RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
      81           0 :   } else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs) {
      82             :     // TODO(mikhal): Disabling adjustment temporarily.
      83             :     // uint16_t rttIndex = (uint16_t) parameters->rtt;
      84           0 :     float adjustRtt = 1.0f;  // (float)VCMNackFecTable[rttIndex] / 100.0f;
      85             : 
      86             :     // Adjust FEC with NACK on (for delta frame only)
      87             :     // table depends on RTT relative to rttMax (NACK Threshold)
      88           0 :     _protectionFactorD = static_cast<uint8_t>(
      89           0 :         adjustRtt * static_cast<float>(_protectionFactorD));
      90             :     // update FEC rates after applying adjustment
      91           0 :     VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
      92             :   }
      93             : 
      94           0 :   return true;
      95             : }
      96             : 
      97           0 : int VCMNackFecMethod::ComputeMaxFramesFec(
      98             :     const VCMProtectionParameters* parameters) {
      99           0 :   if (parameters->numLayers > 2) {
     100             :     // For more than 2 temporal layers we will only have FEC on the base layer,
     101             :     // and the base layers will be pretty far apart. Therefore we force one
     102             :     // frame FEC.
     103           0 :     return 1;
     104             :   }
     105             :   // We set the max number of frames to base the FEC on so that on average
     106             :   // we will have complete frames in one RTT. Note that this is an upper
     107             :   // bound, and that the actual number of frames used for FEC is decided by the
     108             :   // RTP module based on the actual number of packets and the protection factor.
     109             :   float base_layer_framerate =
     110           0 :       parameters->frameRate /
     111           0 :       static_cast<float>(1 << (parameters->numLayers - 1));
     112             :   int max_frames_fec = std::max(
     113           0 :       static_cast<int>(2.0f * base_layer_framerate * parameters->rtt / 1000.0f +
     114             :                        0.5f),
     115           0 :       1);
     116             :   // |kUpperLimitFramesFec| is the upper limit on how many frames we
     117             :   // allow any FEC to be based on.
     118           0 :   if (max_frames_fec > kUpperLimitFramesFec) {
     119           0 :     max_frames_fec = kUpperLimitFramesFec;
     120             :   }
     121           0 :   return max_frames_fec;
     122             : }
     123             : 
     124           0 : int VCMNackFecMethod::MaxFramesFec() const {
     125           0 :   return _maxFramesFec;
     126             : }
     127             : 
     128           0 : bool VCMNackFecMethod::BitRateTooLowForFec(
     129             :     const VCMProtectionParameters* parameters) {
     130             :   // Bitrate below which we turn off FEC, regardless of reported packet loss.
     131             :   // The condition should depend on resolution and content. For now, use
     132             :   // threshold on bytes per frame, with some effect for the frame size.
     133             :   // The condition for turning off FEC is also based on other factors,
     134             :   // such as |_numLayers|, |_maxFramesFec|, and |_rtt|.
     135           0 :   int estimate_bytes_per_frame = 1000 * BitsPerFrame(parameters) / 8;
     136           0 :   int max_bytes_per_frame = kMaxBytesPerFrameForFec;
     137           0 :   int num_pixels = parameters->codecWidth * parameters->codecHeight;
     138           0 :   if (num_pixels <= 352 * 288) {
     139           0 :     max_bytes_per_frame = kMaxBytesPerFrameForFecLow;
     140           0 :   } else if (num_pixels > 640 * 480) {
     141           0 :     max_bytes_per_frame = kMaxBytesPerFrameForFecHigh;
     142             :   }
     143             :   // TODO(marpan): add condition based on maximum frames used for FEC,
     144             :   // and expand condition based on frame size.
     145             :   // Max round trip time threshold in ms.
     146           0 :   const int64_t kMaxRttTurnOffFec = 200;
     147           0 :   if (estimate_bytes_per_frame < max_bytes_per_frame &&
     148           0 :       parameters->numLayers < 3 && parameters->rtt < kMaxRttTurnOffFec) {
     149           0 :     return true;
     150             :   }
     151           0 :   return false;
     152             : }
     153             : 
     154           0 : bool VCMNackFecMethod::EffectivePacketLoss(
     155             :     const VCMProtectionParameters* parameters) {
     156             :   // Set the effective packet loss for encoder (based on FEC code).
     157             :   // Compute the effective packet loss and residual packet loss due to FEC.
     158           0 :   VCMFecMethod::EffectivePacketLoss(parameters);
     159           0 :   return true;
     160             : }
     161             : 
     162           0 : bool VCMNackFecMethod::UpdateParameters(
     163             :     const VCMProtectionParameters* parameters) {
     164           0 :   ProtectionFactor(parameters);
     165           0 :   EffectivePacketLoss(parameters);
     166           0 :   _maxFramesFec = ComputeMaxFramesFec(parameters);
     167           0 :   if (BitRateTooLowForFec(parameters)) {
     168           0 :     _protectionFactorK = 0;
     169           0 :     _protectionFactorD = 0;
     170             :   }
     171             : 
     172             :   // Protection/fec rates obtained above are defined relative to total number
     173             :   // of packets (total rate: source + fec) FEC in RTP module assumes
     174             :   // protection factor is defined relative to source number of packets so we
     175             :   // should convert the factor to reduce mismatch between mediaOpt's rate and
     176             :   // the actual one
     177           0 :   _protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK);
     178           0 :   _protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD);
     179             : 
     180           0 :   return true;
     181             : }
     182             : 
     183           0 : VCMNackMethod::VCMNackMethod() : VCMProtectionMethod() {
     184           0 :   _type = kNack;
     185           0 : }
     186             : 
     187           0 : VCMNackMethod::~VCMNackMethod() {
     188             :   //
     189           0 : }
     190             : 
     191           0 : bool VCMNackMethod::EffectivePacketLoss(
     192             :     const VCMProtectionParameters* parameter) {
     193             :   // Effective Packet Loss, NA in current version.
     194           0 :   _effectivePacketLoss = 0;
     195           0 :   return true;
     196             : }
     197             : 
     198           0 : bool VCMNackMethod::UpdateParameters(
     199             :     const VCMProtectionParameters* parameters) {
     200             :   // Compute the effective packet loss
     201           0 :   EffectivePacketLoss(parameters);
     202             : 
     203             :   // nackCost  = (bitRate - nackCost) * (lossPr)
     204           0 :   return true;
     205             : }
     206             : 
     207           0 : VCMFecMethod::VCMFecMethod() : VCMProtectionMethod() {
     208           0 :   _type = kFec;
     209           0 : }
     210           0 : VCMFecMethod::~VCMFecMethod() {
     211             :   //
     212           0 : }
     213             : 
     214           0 : uint8_t VCMFecMethod::BoostCodeRateKey(uint8_t packetFrameDelta,
     215             :                                        uint8_t packetFrameKey) const {
     216           0 :   uint8_t boostRateKey = 2;
     217             :   // Default: ratio scales the FEC protection up for I frames
     218           0 :   uint8_t ratio = 1;
     219             : 
     220           0 :   if (packetFrameDelta > 0) {
     221           0 :     ratio = (int8_t)(packetFrameKey / packetFrameDelta);
     222             :   }
     223           0 :   ratio = VCM_MAX(boostRateKey, ratio);
     224             : 
     225           0 :   return ratio;
     226             : }
     227             : 
     228           0 : uint8_t VCMFecMethod::ConvertFECRate(uint8_t codeRateRTP) const {
     229           0 :   return static_cast<uint8_t>(VCM_MIN(
     230             :       255,
     231           0 :       (0.5 + 255.0 * codeRateRTP / static_cast<float>(255 - codeRateRTP))));
     232             : }
     233             : 
     234             : // Update FEC with protectionFactorD
     235           0 : void VCMFecMethod::UpdateProtectionFactorD(uint8_t protectionFactorD) {
     236           0 :   _protectionFactorD = protectionFactorD;
     237           0 : }
     238             : 
     239             : // Update FEC with protectionFactorK
     240           0 : void VCMFecMethod::UpdateProtectionFactorK(uint8_t protectionFactorK) {
     241           0 :   _protectionFactorK = protectionFactorK;
     242           0 : }
     243             : 
     244           0 : bool VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters) {
     245             :   // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
     246             : 
     247             :   // No protection if (filtered) packetLoss is 0
     248           0 :   uint8_t packetLoss = static_cast<uint8_t>(255 * parameters->lossPr);
     249           0 :   if (packetLoss == 0) {
     250           0 :     _protectionFactorK = 0;
     251           0 :     _protectionFactorD = 0;
     252           0 :     return true;
     253             :   }
     254             : 
     255             :   // Parameters for FEC setting:
     256             :   // first partition size, thresholds, table pars, spatial resoln fac.
     257             : 
     258             :   // First partition protection: ~ 20%
     259           0 :   uint8_t firstPartitionProt = static_cast<uint8_t>(255 * 0.20);
     260             : 
     261             :   // Minimum protection level needed to generate one FEC packet for one
     262             :   // source packet/frame (in RTP sender)
     263           0 :   uint8_t minProtLevelFec = 85;
     264             : 
     265             :   // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
     266             :   // above which we allocate protection to cover at least first partition.
     267           0 :   uint8_t lossThr = 0;
     268           0 :   uint8_t packetNumThr = 1;
     269             : 
     270             :   // Parameters for range of rate index of table.
     271           0 :   const uint8_t ratePar1 = 5;
     272           0 :   const uint8_t ratePar2 = 49;
     273             : 
     274             :   // Spatial resolution size, relative to a reference size.
     275             :   float spatialSizeToRef =
     276           0 :       static_cast<float>(parameters->codecWidth * parameters->codecHeight) /
     277           0 :       (static_cast<float>(704 * 576));
     278             :   // resolnFac: This parameter will generally increase/decrease the FEC rate
     279             :   // (for fixed bitRate and packetLoss) based on system size.
     280             :   // Use a smaller exponent (< 1) to control/soften system size effect.
     281           0 :   const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
     282             : 
     283           0 :   const int bitRatePerFrame = BitsPerFrame(parameters);
     284             : 
     285             :   // Average number of packets per frame (source and fec):
     286             :   const uint8_t avgTotPackets = static_cast<uint8_t>(
     287           0 :       std::min(static_cast<float>(std::numeric_limits<uint8_t>::max()),
     288           0 :                1.5f +
     289           0 :                    static_cast<float>(bitRatePerFrame) * 1000.0f /
     290           0 :                        static_cast<float>(8.0 * _maxPayloadSize)));
     291             : 
     292             :   // FEC rate parameters: for P and I frame
     293           0 :   uint8_t codeRateDelta = 0;
     294           0 :   uint8_t codeRateKey = 0;
     295             : 
     296             :   // Get index for table: the FEC protection depends on an effective rate.
     297             :   // The range on the rate index corresponds to rates (bps)
     298             :   // from ~200k to ~8000k, for 30fps
     299             :   const uint16_t effRateFecTable =
     300           0 :       static_cast<uint16_t>(resolnFac * bitRatePerFrame);
     301             :   uint8_t rateIndexTable = static_cast<uint8_t>(
     302           0 :       VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) / ratePar1, ratePar2), 0));
     303             : 
     304             :   // Restrict packet loss range to 50:
     305             :   // current tables defined only up to 50%
     306           0 :   if (packetLoss >= kPacketLossMax) {
     307           0 :     packetLoss = kPacketLossMax - 1;
     308             :   }
     309           0 :   uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss;
     310             : 
     311             :   // Check on table index
     312           0 :   RTC_DCHECK_LT(indexTable, kFecRateTableSize);
     313             : 
     314             :   // Protection factor for P frame
     315           0 :   codeRateDelta = kFecRateTable[indexTable];
     316             : 
     317           0 :   if (packetLoss > lossThr && avgTotPackets > packetNumThr) {
     318             :     // Set a minimum based on first partition size.
     319           0 :     if (codeRateDelta < firstPartitionProt) {
     320           0 :       codeRateDelta = firstPartitionProt;
     321             :     }
     322             :   }
     323             : 
     324             :   // Check limit on amount of protection for P frame; 50% is max.
     325           0 :   if (codeRateDelta >= kPacketLossMax) {
     326           0 :     codeRateDelta = kPacketLossMax - 1;
     327             :   }
     328             : 
     329             :   // For Key frame:
     330             :   // Effectively at a higher rate, so we scale/boost the rate
     331             :   // The boost factor may depend on several factors: ratio of packet
     332             :   // number of I to P frames, how much protection placed on P frames, etc.
     333             :   const uint8_t packetFrameDelta =
     334           0 :       static_cast<uint8_t>(0.5 + parameters->packetsPerFrame);
     335             :   const uint8_t packetFrameKey =
     336           0 :       static_cast<uint8_t>(0.5 + parameters->packetsPerFrameKey);
     337           0 :   const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta, packetFrameKey);
     338             : 
     339           0 :   rateIndexTable = static_cast<uint8_t>(VCM_MAX(
     340             :       VCM_MIN(1 + (boostKey * effRateFecTable - ratePar1) / ratePar1, ratePar2),
     341           0 :       0));
     342           0 :   uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
     343             : 
     344           0 :   indexTableKey = VCM_MIN(indexTableKey, kFecRateTableSize);
     345             : 
     346             :   // Check on table index
     347           0 :   assert(indexTableKey < kFecRateTableSize);
     348             : 
     349             :   // Protection factor for I frame
     350           0 :   codeRateKey = kFecRateTable[indexTableKey];
     351             : 
     352             :   // Boosting for Key frame.
     353           0 :   int boostKeyProt = _scaleProtKey * codeRateDelta;
     354           0 :   if (boostKeyProt >= kPacketLossMax) {
     355           0 :     boostKeyProt = kPacketLossMax - 1;
     356             :   }
     357             : 
     358             :   // Make sure I frame protection is at least larger than P frame protection,
     359             :   // and at least as high as filtered packet loss.
     360           0 :   codeRateKey = static_cast<uint8_t>(
     361           0 :       VCM_MAX(packetLoss, VCM_MAX(boostKeyProt, codeRateKey)));
     362             : 
     363             :   // Check limit on amount of protection for I frame: 50% is max.
     364           0 :   if (codeRateKey >= kPacketLossMax) {
     365           0 :     codeRateKey = kPacketLossMax - 1;
     366             :   }
     367             : 
     368           0 :   _protectionFactorK = codeRateKey;
     369           0 :   _protectionFactorD = codeRateDelta;
     370             : 
     371             :   // Generally there is a rate mis-match between the FEC cost estimated
     372             :   // in mediaOpt and the actual FEC cost sent out in RTP module.
     373             :   // This is more significant at low rates (small # of source packets), where
     374             :   // the granularity of the FEC decreases. In this case, non-zero protection
     375             :   // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
     376             :   // is based on rounding off protectionFactor on actual source packet number).
     377             :   // The correction factor (_corrFecCost) attempts to corrects this, at least
     378             :   // for cases of low rates (small #packets) and low protection levels.
     379             : 
     380           0 :   float numPacketsFl = 1.0f + (static_cast<float>(bitRatePerFrame) * 1000.0 /
     381           0 :                                    static_cast<float>(8.0 * _maxPayloadSize) +
     382           0 :                                0.5);
     383             : 
     384             :   const float estNumFecGen =
     385           0 :       0.5f + static_cast<float>(_protectionFactorD * numPacketsFl / 255.0f);
     386             : 
     387             :   // We reduce cost factor (which will reduce overhead for FEC and
     388             :   // hybrid method) and not the protectionFactor.
     389           0 :   _corrFecCost = 1.0f;
     390           0 :   if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec) {
     391           0 :     _corrFecCost = 0.5f;
     392             :   }
     393           0 :   if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec) {
     394           0 :     _corrFecCost = 0.0f;
     395             :   }
     396             : 
     397             :   // DONE WITH FEC PROTECTION SETTINGS
     398           0 :   return true;
     399             : }
     400             : 
     401           0 : int VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) {
     402             :   // When temporal layers are available FEC will only be applied on the base
     403             :   // layer.
     404             :   const float bitRateRatio =
     405           0 :       kVp8LayerRateAlloction[parameters->numLayers - 1][0];
     406           0 :   float frameRateRatio = powf(1 / 2.0, parameters->numLayers - 1);
     407           0 :   float bitRate = parameters->bitRate * bitRateRatio;
     408           0 :   float frameRate = parameters->frameRate * frameRateRatio;
     409             : 
     410             :   // TODO(mikhal): Update factor following testing.
     411           0 :   float adjustmentFactor = 1;
     412             : 
     413           0 :   if (frameRate < 1.0f)
     414           0 :     frameRate = 1.0f;
     415             :   // Average bits per frame (units of kbits)
     416           0 :   return static_cast<int>(adjustmentFactor * bitRate / frameRate);
     417             : }
     418             : 
     419           0 : bool VCMFecMethod::EffectivePacketLoss(
     420             :     const VCMProtectionParameters* parameters) {
     421             :   // Effective packet loss to encoder is based on RPL (residual packet loss)
     422             :   // this is a soft setting based on degree of FEC protection
     423             :   // RPL = received/input packet loss - average_FEC_recovery
     424             :   // note: received/input packet loss may be filtered based on FilteredLoss
     425             : 
     426             :   // Effective Packet Loss, NA in current version.
     427           0 :   _effectivePacketLoss = 0;
     428             : 
     429           0 :   return true;
     430             : }
     431             : 
     432           0 : bool VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters) {
     433             :   // Compute the protection factor
     434           0 :   ProtectionFactor(parameters);
     435             : 
     436             :   // Compute the effective packet loss
     437           0 :   EffectivePacketLoss(parameters);
     438             : 
     439             :   // Protection/fec rates obtained above is defined relative to total number
     440             :   // of packets (total rate: source+fec) FEC in RTP module assumes protection
     441             :   // factor is defined relative to source number of packets so we should
     442             :   // convert the factor to reduce mismatch between mediaOpt suggested rate and
     443             :   // the actual rate
     444           0 :   _protectionFactorK = ConvertFECRate(_protectionFactorK);
     445           0 :   _protectionFactorD = ConvertFECRate(_protectionFactorD);
     446             : 
     447           0 :   return true;
     448             : }
     449           0 : VCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs)
     450             :     : _currentParameters(),
     451             :       _rtt(0),
     452             :       _lossPr(0.0f),
     453             :       _bitRate(0.0f),
     454             :       _frameRate(0.0f),
     455             :       _keyFrameSize(0.0f),
     456             :       _fecRateKey(0),
     457             :       _fecRateDelta(0),
     458             :       _lastPrUpdateT(0),
     459             :       _lossPr255(0.9999f),
     460             :       _lossPrHistory(),
     461             :       _shortMaxLossPr255(0),
     462             :       _packetsPerFrame(0.9999f),
     463             :       _packetsPerFrameKey(0.9999f),
     464             :       _codecWidth(0),
     465             :       _codecHeight(0),
     466           0 :       _numLayers(1) {
     467           0 :   Reset(nowMs);
     468           0 : }
     469             : 
     470           0 : VCMLossProtectionLogic::~VCMLossProtectionLogic() {
     471           0 :   Release();
     472           0 : }
     473             : 
     474           0 : void VCMLossProtectionLogic::SetMethod(
     475             :     enum VCMProtectionMethodEnum newMethodType) {
     476           0 :   if (_selectedMethod && _selectedMethod->Type() == newMethodType)
     477           0 :     return;
     478             : 
     479           0 :   switch (newMethodType) {
     480             :     case kNack:
     481           0 :       _selectedMethod.reset(new VCMNackMethod());
     482           0 :       break;
     483             :     case kFec:
     484           0 :       _selectedMethod.reset(new VCMFecMethod());
     485           0 :       break;
     486             :     case kNackFec:
     487           0 :       _selectedMethod.reset(new VCMNackFecMethod(kLowRttNackMs, -1));
     488           0 :       break;
     489             :     case kNone:
     490           0 :       _selectedMethod.reset();
     491           0 :       break;
     492             :   }
     493           0 :   UpdateMethod();
     494             : }
     495             : 
     496           0 : void VCMLossProtectionLogic::UpdateRtt(int64_t rtt) {
     497           0 :   _rtt = rtt;
     498           0 : }
     499             : 
     500           0 : void VCMLossProtectionLogic::UpdateMaxLossHistory(uint8_t lossPr255,
     501             :                                                   int64_t now) {
     502           0 :   if (_lossPrHistory[0].timeMs >= 0 &&
     503           0 :       now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs) {
     504           0 :     if (lossPr255 > _shortMaxLossPr255) {
     505           0 :       _shortMaxLossPr255 = lossPr255;
     506             :     }
     507             :   } else {
     508             :     // Only add a new value to the history once a second
     509           0 :     if (_lossPrHistory[0].timeMs == -1) {
     510             :       // First, no shift
     511           0 :       _shortMaxLossPr255 = lossPr255;
     512             :     } else {
     513             :       // Shift
     514           0 :       for (int32_t i = (kLossPrHistorySize - 2); i >= 0; i--) {
     515           0 :         _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
     516           0 :         _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
     517             :       }
     518             :     }
     519           0 :     if (_shortMaxLossPr255 == 0) {
     520           0 :       _shortMaxLossPr255 = lossPr255;
     521             :     }
     522             : 
     523           0 :     _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
     524           0 :     _lossPrHistory[0].timeMs = now;
     525           0 :     _shortMaxLossPr255 = 0;
     526             :   }
     527           0 : }
     528             : 
     529           0 : uint8_t VCMLossProtectionLogic::MaxFilteredLossPr(int64_t nowMs) const {
     530           0 :   uint8_t maxFound = _shortMaxLossPr255;
     531           0 :   if (_lossPrHistory[0].timeMs == -1) {
     532           0 :     return maxFound;
     533             :   }
     534           0 :   for (int32_t i = 0; i < kLossPrHistorySize; i++) {
     535           0 :     if (_lossPrHistory[i].timeMs == -1) {
     536           0 :       break;
     537             :     }
     538           0 :     if (nowMs - _lossPrHistory[i].timeMs >
     539             :         kLossPrHistorySize * kLossPrShortFilterWinMs) {
     540             :       // This sample (and all samples after this) is too old
     541           0 :       break;
     542             :     }
     543           0 :     if (_lossPrHistory[i].lossPr255 > maxFound) {
     544             :       // This sample is the largest one this far into the history
     545           0 :       maxFound = _lossPrHistory[i].lossPr255;
     546             :     }
     547             :   }
     548           0 :   return maxFound;
     549             : }
     550             : 
     551           0 : uint8_t VCMLossProtectionLogic::FilteredLoss(int64_t nowMs,
     552             :                                              FilterPacketLossMode filter_mode,
     553             :                                              uint8_t lossPr255) {
     554             :   // Update the max window filter.
     555           0 :   UpdateMaxLossHistory(lossPr255, nowMs);
     556             : 
     557             :   // Update the recursive average filter.
     558           0 :   _lossPr255.Apply(static_cast<float>(nowMs - _lastPrUpdateT),
     559           0 :                    static_cast<float>(lossPr255));
     560           0 :   _lastPrUpdateT = nowMs;
     561             : 
     562             :   // Filtered loss: default is received loss (no filtering).
     563           0 :   uint8_t filtered_loss = lossPr255;
     564             : 
     565           0 :   switch (filter_mode) {
     566             :     case kNoFilter:
     567           0 :       break;
     568             :     case kAvgFilter:
     569           0 :       filtered_loss = static_cast<uint8_t>(_lossPr255.filtered() + 0.5);
     570           0 :       break;
     571             :     case kMaxFilter:
     572           0 :       filtered_loss = MaxFilteredLossPr(nowMs);
     573           0 :       break;
     574             :   }
     575             : 
     576           0 :   return filtered_loss;
     577             : }
     578             : 
     579           0 : void VCMLossProtectionLogic::UpdateFilteredLossPr(uint8_t packetLossEnc) {
     580           0 :   _lossPr = static_cast<float>(packetLossEnc) / 255.0;
     581           0 : }
     582             : 
     583           0 : void VCMLossProtectionLogic::UpdateBitRate(float bitRate) {
     584           0 :   _bitRate = bitRate;
     585           0 : }
     586             : 
     587           0 : void VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets,
     588             :                                                    int64_t nowMs) {
     589           0 :   _packetsPerFrame.Apply(static_cast<float>(nowMs - _lastPacketPerFrameUpdateT),
     590           0 :                          nPackets);
     591           0 :   _lastPacketPerFrameUpdateT = nowMs;
     592           0 : }
     593             : 
     594           0 : void VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets,
     595             :                                                       int64_t nowMs) {
     596           0 :   _packetsPerFrameKey.Apply(
     597           0 :       static_cast<float>(nowMs - _lastPacketPerFrameUpdateTKey), nPackets);
     598           0 :   _lastPacketPerFrameUpdateTKey = nowMs;
     599           0 : }
     600             : 
     601           0 : void VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize) {
     602           0 :   _keyFrameSize = keyFrameSize;
     603           0 : }
     604             : 
     605           0 : void VCMLossProtectionLogic::UpdateFrameSize(size_t width, size_t height) {
     606           0 :   _codecWidth = width;
     607           0 :   _codecHeight = height;
     608           0 : }
     609             : 
     610           0 : void VCMLossProtectionLogic::UpdateNumLayers(int numLayers) {
     611           0 :   _numLayers = (numLayers == 0) ? 1 : numLayers;
     612           0 : }
     613             : 
     614           0 : bool VCMLossProtectionLogic::UpdateMethod() {
     615           0 :   if (!_selectedMethod)
     616           0 :     return false;
     617           0 :   _currentParameters.rtt = _rtt;
     618           0 :   _currentParameters.lossPr = _lossPr;
     619           0 :   _currentParameters.bitRate = _bitRate;
     620           0 :   _currentParameters.frameRate = _frameRate;  // rename actual frame rate?
     621           0 :   _currentParameters.keyFrameSize = _keyFrameSize;
     622           0 :   _currentParameters.fecRateDelta = _fecRateDelta;
     623           0 :   _currentParameters.fecRateKey = _fecRateKey;
     624           0 :   _currentParameters.packetsPerFrame = _packetsPerFrame.filtered();
     625           0 :   _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered();
     626           0 :   _currentParameters.codecWidth = _codecWidth;
     627           0 :   _currentParameters.codecHeight = _codecHeight;
     628           0 :   _currentParameters.numLayers = _numLayers;
     629           0 :   return _selectedMethod->UpdateParameters(&_currentParameters);
     630             : }
     631             : 
     632           0 : VCMProtectionMethod* VCMLossProtectionLogic::SelectedMethod() const {
     633           0 :   return _selectedMethod.get();
     634             : }
     635             : 
     636           0 : VCMProtectionMethodEnum VCMLossProtectionLogic::SelectedType() const {
     637           0 :   return _selectedMethod ? _selectedMethod->Type() : kNone;
     638             : }
     639             : 
     640           0 : void VCMLossProtectionLogic::Reset(int64_t nowMs) {
     641           0 :   _lastPrUpdateT = nowMs;
     642           0 :   _lastPacketPerFrameUpdateT = nowMs;
     643           0 :   _lastPacketPerFrameUpdateTKey = nowMs;
     644           0 :   _lossPr255.Reset(0.9999f);
     645           0 :   _packetsPerFrame.Reset(0.9999f);
     646           0 :   _fecRateDelta = _fecRateKey = 0;
     647           0 :   for (int32_t i = 0; i < kLossPrHistorySize; i++) {
     648           0 :     _lossPrHistory[i].lossPr255 = 0;
     649           0 :     _lossPrHistory[i].timeMs = -1;
     650             :   }
     651           0 :   _shortMaxLossPr255 = 0;
     652           0 :   Release();
     653           0 : }
     654             : 
     655           0 : void VCMLossProtectionLogic::Release() {
     656           0 :   _selectedMethod.reset();
     657           0 : }
     658             : 
     659             : }  // namespace media_optimization
     660             : }  // namespace webrtc

Generated by: LCOV version 1.13