diff options
Diffstat (limited to 'third_party/libwebrtc/modules/video_coding/media_opt_util.cc')
-rw-r--r-- | third_party/libwebrtc/modules/video_coding/media_opt_util.cc | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/video_coding/media_opt_util.cc b/third_party/libwebrtc/modules/video_coding/media_opt_util.cc new file mode 100644 index 0000000000..7580c95fc7 --- /dev/null +++ b/third_party/libwebrtc/modules/video_coding/media_opt_util.cc @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/video_coding/media_opt_util.h" + +#include <math.h> + +#include <algorithm> + +#include "modules/video_coding/fec_rate_table.h" +#include "modules/video_coding/internal_defines.h" +#include "modules/video_coding/utility/simulcast_rate_allocator.h" +#include "rtc_base/checks.h" +#include "rtc_base/experiments/rate_control_settings.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { +// Max value of loss rates in off-line model +static const int kPacketLossMax = 129; + +namespace media_optimization { + +VCMProtectionParameters::VCMProtectionParameters() + : rtt(0), + lossPr(0.0f), + bitRate(0.0f), + packetsPerFrame(0.0f), + packetsPerFrameKey(0.0f), + frameRate(0.0f), + keyFrameSize(0.0f), + fecRateDelta(0), + fecRateKey(0), + codecWidth(0), + codecHeight(0), + numLayers(1) {} + +VCMProtectionMethod::VCMProtectionMethod() + : _effectivePacketLoss(0), + _protectionFactorK(0), + _protectionFactorD(0), + _scaleProtKey(2.0f), + _maxPayloadSize(1460), + _corrFecCost(1.0), + _type(kNone) {} + +VCMProtectionMethod::~VCMProtectionMethod() {} + +enum VCMProtectionMethodEnum VCMProtectionMethod::Type() const { + return _type; +} + +uint8_t VCMProtectionMethod::RequiredPacketLossER() { + return _effectivePacketLoss; +} + +uint8_t VCMProtectionMethod::RequiredProtectionFactorK() { + return _protectionFactorK; +} + +uint8_t VCMProtectionMethod::RequiredProtectionFactorD() { + return _protectionFactorD; +} + +bool VCMProtectionMethod::RequiredUepProtectionK() { + return _useUepProtectionK; +} + +bool VCMProtectionMethod::RequiredUepProtectionD() { + return _useUepProtectionD; +} + +int VCMProtectionMethod::MaxFramesFec() const { + return 1; +} + +VCMNackFecMethod::VCMNackFecMethod(int64_t lowRttNackThresholdMs, + int64_t highRttNackThresholdMs) + : VCMFecMethod(), + _lowRttNackMs(lowRttNackThresholdMs), + _highRttNackMs(highRttNackThresholdMs), + _maxFramesFec(1) { + RTC_DCHECK(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1); + RTC_DCHECK(highRttNackThresholdMs == -1 || + lowRttNackThresholdMs <= highRttNackThresholdMs); + RTC_DCHECK(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1); + _type = kNackFec; +} + +VCMNackFecMethod::~VCMNackFecMethod() { + // +} +bool VCMNackFecMethod::ProtectionFactor( + const VCMProtectionParameters* parameters) { + // Hybrid Nack FEC has three operational modes: + // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate + // (_protectionFactorD) to zero. -1 means no FEC. + // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors. + // -1 means always allow NACK. + // 3. Medium RTT values - Hybrid mode: We will only nack the + // residual following the decoding of the FEC (refer to JB logic). FEC + // delta protection factor will be adjusted based on the RTT. + + // Otherwise: we count on FEC; if the RTT is below a threshold, then we + // nack the residual, based on a decision made in the JB. + + // Compute the protection factors + VCMFecMethod::ProtectionFactor(parameters); + if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs) { + _protectionFactorD = 0; + VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD); + + // When in Hybrid mode (RTT range), adjust FEC rates based on the + // RTT (NACK effectiveness) - adjustment factor is in the range [0,1]. + } else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs) { + // TODO(mikhal): Disabling adjustment temporarily. + // uint16_t rttIndex = (uint16_t) parameters->rtt; + float adjustRtt = 1.0f; // (float)VCMNackFecTable[rttIndex] / 100.0f; + + // Adjust FEC with NACK on (for delta frame only) + // table depends on RTT relative to rttMax (NACK Threshold) + _protectionFactorD = rtc::saturated_cast<uint8_t>( + adjustRtt * rtc::saturated_cast<float>(_protectionFactorD)); + // update FEC rates after applying adjustment + VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD); + } + + return true; +} + +int VCMNackFecMethod::ComputeMaxFramesFec( + const VCMProtectionParameters* parameters) { + if (parameters->numLayers > 2) { + // For more than 2 temporal layers we will only have FEC on the base layer, + // and the base layers will be pretty far apart. Therefore we force one + // frame FEC. + return 1; + } + // We set the max number of frames to base the FEC on so that on average + // we will have complete frames in one RTT. Note that this is an upper + // bound, and that the actual number of frames used for FEC is decided by the + // RTP module based on the actual number of packets and the protection factor. + float base_layer_framerate = + parameters->frameRate / + rtc::saturated_cast<float>(1 << (parameters->numLayers - 1)); + int max_frames_fec = std::max( + rtc::saturated_cast<int>( + 2.0f * base_layer_framerate * parameters->rtt / 1000.0f + 0.5f), + 1); + // `kUpperLimitFramesFec` is the upper limit on how many frames we + // allow any FEC to be based on. + if (max_frames_fec > kUpperLimitFramesFec) { + max_frames_fec = kUpperLimitFramesFec; + } + return max_frames_fec; +} + +int VCMNackFecMethod::MaxFramesFec() const { + return _maxFramesFec; +} + +bool VCMNackFecMethod::BitRateTooLowForFec( + const VCMProtectionParameters* parameters) { + // Bitrate below which we turn off FEC, regardless of reported packet loss. + // The condition should depend on resolution and content. For now, use + // threshold on bytes per frame, with some effect for the frame size. + // The condition for turning off FEC is also based on other factors, + // such as `_numLayers`, `_maxFramesFec`, and `_rtt`. + int estimate_bytes_per_frame = 1000 * BitsPerFrame(parameters) / 8; + int max_bytes_per_frame = kMaxBytesPerFrameForFec; + int num_pixels = parameters->codecWidth * parameters->codecHeight; + if (num_pixels <= 352 * 288) { + max_bytes_per_frame = kMaxBytesPerFrameForFecLow; + } else if (num_pixels > 640 * 480) { + max_bytes_per_frame = kMaxBytesPerFrameForFecHigh; + } + // TODO(marpan): add condition based on maximum frames used for FEC, + // and expand condition based on frame size. + // Max round trip time threshold in ms. + const int64_t kMaxRttTurnOffFec = 200; + if (estimate_bytes_per_frame < max_bytes_per_frame && + parameters->numLayers < 3 && parameters->rtt < kMaxRttTurnOffFec) { + return true; + } + return false; +} + +bool VCMNackFecMethod::EffectivePacketLoss( + const VCMProtectionParameters* parameters) { + // Set the effective packet loss for encoder (based on FEC code). + // Compute the effective packet loss and residual packet loss due to FEC. + VCMFecMethod::EffectivePacketLoss(parameters); + return true; +} + +bool VCMNackFecMethod::UpdateParameters( + const VCMProtectionParameters* parameters) { + ProtectionFactor(parameters); + EffectivePacketLoss(parameters); + _maxFramesFec = ComputeMaxFramesFec(parameters); + if (BitRateTooLowForFec(parameters)) { + _protectionFactorK = 0; + _protectionFactorD = 0; + } + + // Protection/fec rates obtained above are defined relative to total number + // of packets (total rate: source + fec) FEC in RTP module assumes + // protection factor is defined relative to source number of packets so we + // should convert the factor to reduce mismatch between mediaOpt's rate and + // the actual one + _protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK); + _protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD); + + return true; +} + +VCMNackMethod::VCMNackMethod() : VCMProtectionMethod() { + _type = kNack; +} + +VCMNackMethod::~VCMNackMethod() { + // +} + +bool VCMNackMethod::EffectivePacketLoss( + const VCMProtectionParameters* parameter) { + // Effective Packet Loss, NA in current version. + _effectivePacketLoss = 0; + return true; +} + +bool VCMNackMethod::UpdateParameters( + const VCMProtectionParameters* parameters) { + // Compute the effective packet loss + EffectivePacketLoss(parameters); + + // nackCost = (bitRate - nackCost) * (lossPr) + return true; +} + +VCMFecMethod::VCMFecMethod() + : VCMProtectionMethod(), + rate_control_settings_(RateControlSettings::ParseFromFieldTrials()) { + _type = kFec; +} + +VCMFecMethod::~VCMFecMethod() = default; + +uint8_t VCMFecMethod::BoostCodeRateKey(uint8_t packetFrameDelta, + uint8_t packetFrameKey) const { + uint8_t boostRateKey = 2; + // Default: ratio scales the FEC protection up for I frames + uint8_t ratio = 1; + + if (packetFrameDelta > 0) { + ratio = (int8_t)(packetFrameKey / packetFrameDelta); + } + ratio = VCM_MAX(boostRateKey, ratio); + + return ratio; +} + +uint8_t VCMFecMethod::ConvertFECRate(uint8_t codeRateRTP) const { + return rtc::saturated_cast<uint8_t>( + VCM_MIN(255, (0.5 + 255.0 * codeRateRTP / + rtc::saturated_cast<float>(255 - codeRateRTP)))); +} + +// Update FEC with protectionFactorD +void VCMFecMethod::UpdateProtectionFactorD(uint8_t protectionFactorD) { + _protectionFactorD = protectionFactorD; +} + +// Update FEC with protectionFactorK +void VCMFecMethod::UpdateProtectionFactorK(uint8_t protectionFactorK) { + _protectionFactorK = protectionFactorK; +} + +bool VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters) { + // FEC PROTECTION SETTINGS: varies with packet loss and bitrate + + // No protection if (filtered) packetLoss is 0 + uint8_t packetLoss = rtc::saturated_cast<uint8_t>(255 * parameters->lossPr); + if (packetLoss == 0) { + _protectionFactorK = 0; + _protectionFactorD = 0; + return true; + } + + // Parameters for FEC setting: + // first partition size, thresholds, table pars, spatial resoln fac. + + // First partition protection: ~ 20% + uint8_t firstPartitionProt = rtc::saturated_cast<uint8_t>(255 * 0.20); + + // Minimum protection level needed to generate one FEC packet for one + // source packet/frame (in RTP sender) + uint8_t minProtLevelFec = 85; + + // Threshold on packetLoss and bitRrate/frameRate (=average #packets), + // above which we allocate protection to cover at least first partition. + uint8_t lossThr = 0; + uint8_t packetNumThr = 1; + + // Parameters for range of rate index of table. + const uint8_t ratePar1 = 5; + const uint8_t ratePar2 = 49; + + // Spatial resolution size, relative to a reference size. + float spatialSizeToRef = rtc::saturated_cast<float>(parameters->codecWidth * + parameters->codecHeight) / + (rtc::saturated_cast<float>(704 * 576)); + // resolnFac: This parameter will generally increase/decrease the FEC rate + // (for fixed bitRate and packetLoss) based on system size. + // Use a smaller exponent (< 1) to control/soften system size effect. + const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f); + + const int bitRatePerFrame = BitsPerFrame(parameters); + + // Average number of packets per frame (source and fec): + const uint8_t avgTotPackets = rtc::saturated_cast<uint8_t>( + 1.5f + rtc::saturated_cast<float>(bitRatePerFrame) * 1000.0f / + rtc::saturated_cast<float>(8.0 * _maxPayloadSize)); + + // FEC rate parameters: for P and I frame + uint8_t codeRateDelta = 0; + uint8_t codeRateKey = 0; + + // Get index for table: the FEC protection depends on an effective rate. + // The range on the rate index corresponds to rates (bps) + // from ~200k to ~8000k, for 30fps + const uint16_t effRateFecTable = + rtc::saturated_cast<uint16_t>(resolnFac * bitRatePerFrame); + uint8_t rateIndexTable = rtc::saturated_cast<uint8_t>( + VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) / ratePar1, ratePar2), 0)); + + // Restrict packet loss range to 50: + // current tables defined only up to 50% + if (packetLoss >= kPacketLossMax) { + packetLoss = kPacketLossMax - 1; + } + uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss; + + // Check on table index + RTC_DCHECK_LT(indexTable, kFecRateTableSize); + + // Protection factor for P frame + codeRateDelta = kFecRateTable[indexTable]; + + if (packetLoss > lossThr && avgTotPackets > packetNumThr) { + // Set a minimum based on first partition size. + if (codeRateDelta < firstPartitionProt) { + codeRateDelta = firstPartitionProt; + } + } + + // Check limit on amount of protection for P frame; 50% is max. + if (codeRateDelta >= kPacketLossMax) { + codeRateDelta = kPacketLossMax - 1; + } + + // For Key frame: + // Effectively at a higher rate, so we scale/boost the rate + // The boost factor may depend on several factors: ratio of packet + // number of I to P frames, how much protection placed on P frames, etc. + const uint8_t packetFrameDelta = + rtc::saturated_cast<uint8_t>(0.5 + parameters->packetsPerFrame); + const uint8_t packetFrameKey = + rtc::saturated_cast<uint8_t>(0.5 + parameters->packetsPerFrameKey); + const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta, packetFrameKey); + + rateIndexTable = rtc::saturated_cast<uint8_t>(VCM_MAX( + VCM_MIN(1 + (boostKey * effRateFecTable - ratePar1) / ratePar1, ratePar2), + 0)); + uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss; + + indexTableKey = VCM_MIN(indexTableKey, kFecRateTableSize); + + // Check on table index + RTC_DCHECK_LT(indexTableKey, kFecRateTableSize); + + // Protection factor for I frame + codeRateKey = kFecRateTable[indexTableKey]; + + // Boosting for Key frame. + int boostKeyProt = _scaleProtKey * codeRateDelta; + if (boostKeyProt >= kPacketLossMax) { + boostKeyProt = kPacketLossMax - 1; + } + + // Make sure I frame protection is at least larger than P frame protection, + // and at least as high as filtered packet loss. + codeRateKey = rtc::saturated_cast<uint8_t>( + VCM_MAX(packetLoss, VCM_MAX(boostKeyProt, codeRateKey))); + + // Check limit on amount of protection for I frame: 50% is max. + if (codeRateKey >= kPacketLossMax) { + codeRateKey = kPacketLossMax - 1; + } + + _protectionFactorK = codeRateKey; + _protectionFactorD = codeRateDelta; + + // Generally there is a rate mis-match between the FEC cost estimated + // in mediaOpt and the actual FEC cost sent out in RTP module. + // This is more significant at low rates (small # of source packets), where + // the granularity of the FEC decreases. In this case, non-zero protection + // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC + // is based on rounding off protectionFactor on actual source packet number). + // The correction factor (_corrFecCost) attempts to corrects this, at least + // for cases of low rates (small #packets) and low protection levels. + + float numPacketsFl = + 1.0f + (rtc::saturated_cast<float>(bitRatePerFrame) * 1000.0 / + rtc::saturated_cast<float>(8.0 * _maxPayloadSize) + + 0.5); + + const float estNumFecGen = + 0.5f + + rtc::saturated_cast<float>(_protectionFactorD * numPacketsFl / 255.0f); + + // We reduce cost factor (which will reduce overhead for FEC and + // hybrid method) and not the protectionFactor. + _corrFecCost = 1.0f; + if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec) { + _corrFecCost = 0.5f; + } + if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec) { + _corrFecCost = 0.0f; + } + + // DONE WITH FEC PROTECTION SETTINGS + return true; +} + +int VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) { + // When temporal layers are available FEC will only be applied on the base + // layer. + const float bitRateRatio = + webrtc::SimulcastRateAllocator::GetTemporalRateAllocation( + parameters->numLayers, 0, + rate_control_settings_.Vp8BaseHeavyTl3RateAllocation()); + float frameRateRatio = powf(1 / 2.0, parameters->numLayers - 1); + float bitRate = parameters->bitRate * bitRateRatio; + float frameRate = parameters->frameRate * frameRateRatio; + + // TODO(mikhal): Update factor following testing. + float adjustmentFactor = 1; + + if (frameRate < 1.0f) + frameRate = 1.0f; + // Average bits per frame (units of kbits) + return rtc::saturated_cast<int>(adjustmentFactor * bitRate / frameRate); +} + +bool VCMFecMethod::EffectivePacketLoss( + const VCMProtectionParameters* parameters) { + // Effective packet loss to encoder is based on RPL (residual packet loss) + // this is a soft setting based on degree of FEC protection + // RPL = received/input packet loss - average_FEC_recovery + // note: received/input packet loss may be filtered based on FilteredLoss + + // Effective Packet Loss, NA in current version. + _effectivePacketLoss = 0; + + return true; +} + +bool VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters) { + // Compute the protection factor + ProtectionFactor(parameters); + + // Compute the effective packet loss + EffectivePacketLoss(parameters); + + // Protection/fec rates obtained above is defined relative to total number + // of packets (total rate: source+fec) FEC in RTP module assumes protection + // factor is defined relative to source number of packets so we should + // convert the factor to reduce mismatch between mediaOpt suggested rate and + // the actual rate + _protectionFactorK = ConvertFECRate(_protectionFactorK); + _protectionFactorD = ConvertFECRate(_protectionFactorD); + + return true; +} +VCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs) + : _currentParameters(), + _rtt(0), + _lossPr(0.0f), + _bitRate(0.0f), + _frameRate(0.0f), + _keyFrameSize(0.0f), + _fecRateKey(0), + _fecRateDelta(0), + _lastPrUpdateT(0), + _lossPr255(0.9999f), + _lossPrHistory(), + _shortMaxLossPr255(0), + _packetsPerFrame(0.9999f), + _packetsPerFrameKey(0.9999f), + _codecWidth(704), + _codecHeight(576), + _numLayers(1) { + Reset(nowMs); +} + +VCMLossProtectionLogic::~VCMLossProtectionLogic() { + Release(); +} + +void VCMLossProtectionLogic::SetMethod( + enum VCMProtectionMethodEnum newMethodType) { + if (_selectedMethod && _selectedMethod->Type() == newMethodType) + return; + + switch (newMethodType) { + case kNack: + _selectedMethod.reset(new VCMNackMethod()); + break; + case kFec: + _selectedMethod.reset(new VCMFecMethod()); + break; + case kNackFec: + _selectedMethod.reset(new VCMNackFecMethod(kLowRttNackMs, -1)); + break; + case kNone: + _selectedMethod.reset(); + break; + } + UpdateMethod(); +} + +void VCMLossProtectionLogic::UpdateRtt(int64_t rtt) { + _rtt = rtt; +} + +void VCMLossProtectionLogic::UpdateMaxLossHistory(uint8_t lossPr255, + int64_t now) { + if (_lossPrHistory[0].timeMs >= 0 && + now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs) { + if (lossPr255 > _shortMaxLossPr255) { + _shortMaxLossPr255 = lossPr255; + } + } else { + // Only add a new value to the history once a second + if (_lossPrHistory[0].timeMs == -1) { + // First, no shift + _shortMaxLossPr255 = lossPr255; + } else { + // Shift + for (int32_t i = (kLossPrHistorySize - 2); i >= 0; i--) { + _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255; + _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs; + } + } + if (_shortMaxLossPr255 == 0) { + _shortMaxLossPr255 = lossPr255; + } + + _lossPrHistory[0].lossPr255 = _shortMaxLossPr255; + _lossPrHistory[0].timeMs = now; + _shortMaxLossPr255 = 0; + } +} + +uint8_t VCMLossProtectionLogic::MaxFilteredLossPr(int64_t nowMs) const { + uint8_t maxFound = _shortMaxLossPr255; + if (_lossPrHistory[0].timeMs == -1) { + return maxFound; + } + for (int32_t i = 0; i < kLossPrHistorySize; i++) { + if (_lossPrHistory[i].timeMs == -1) { + break; + } + if (nowMs - _lossPrHistory[i].timeMs > + kLossPrHistorySize * kLossPrShortFilterWinMs) { + // This sample (and all samples after this) is too old + break; + } + if (_lossPrHistory[i].lossPr255 > maxFound) { + // This sample is the largest one this far into the history + maxFound = _lossPrHistory[i].lossPr255; + } + } + return maxFound; +} + +uint8_t VCMLossProtectionLogic::FilteredLoss(int64_t nowMs, + FilterPacketLossMode filter_mode, + uint8_t lossPr255) { + // Update the max window filter. + UpdateMaxLossHistory(lossPr255, nowMs); + + // Update the recursive average filter. + _lossPr255.Apply(rtc::saturated_cast<float>(nowMs - _lastPrUpdateT), + rtc::saturated_cast<float>(lossPr255)); + _lastPrUpdateT = nowMs; + + // Filtered loss: default is received loss (no filtering). + uint8_t filtered_loss = lossPr255; + + switch (filter_mode) { + case kNoFilter: + break; + case kAvgFilter: + filtered_loss = rtc::saturated_cast<uint8_t>(_lossPr255.filtered() + 0.5); + break; + case kMaxFilter: + filtered_loss = MaxFilteredLossPr(nowMs); + break; + } + + return filtered_loss; +} + +void VCMLossProtectionLogic::UpdateFilteredLossPr(uint8_t packetLossEnc) { + _lossPr = rtc::saturated_cast<float>(packetLossEnc) / 255.0; +} + +void VCMLossProtectionLogic::UpdateBitRate(float bitRate) { + _bitRate = bitRate; +} + +void VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets, + int64_t nowMs) { + _packetsPerFrame.Apply( + rtc::saturated_cast<float>(nowMs - _lastPacketPerFrameUpdateT), nPackets); + _lastPacketPerFrameUpdateT = nowMs; +} + +void VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets, + int64_t nowMs) { + _packetsPerFrameKey.Apply( + rtc::saturated_cast<float>(nowMs - _lastPacketPerFrameUpdateTKey), + nPackets); + _lastPacketPerFrameUpdateTKey = nowMs; +} + +void VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize) { + _keyFrameSize = keyFrameSize; +} + +void VCMLossProtectionLogic::UpdateFrameSize(size_t width, size_t height) { + _codecWidth = width; + _codecHeight = height; +} + +void VCMLossProtectionLogic::UpdateNumLayers(int numLayers) { + _numLayers = (numLayers == 0) ? 1 : numLayers; +} + +bool VCMLossProtectionLogic::UpdateMethod() { + if (!_selectedMethod) + return false; + _currentParameters.rtt = _rtt; + _currentParameters.lossPr = _lossPr; + _currentParameters.bitRate = _bitRate; + _currentParameters.frameRate = _frameRate; // rename actual frame rate? + _currentParameters.keyFrameSize = _keyFrameSize; + _currentParameters.fecRateDelta = _fecRateDelta; + _currentParameters.fecRateKey = _fecRateKey; + _currentParameters.packetsPerFrame = _packetsPerFrame.filtered(); + _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered(); + _currentParameters.codecWidth = _codecWidth; + _currentParameters.codecHeight = _codecHeight; + _currentParameters.numLayers = _numLayers; + return _selectedMethod->UpdateParameters(&_currentParameters); +} + +VCMProtectionMethod* VCMLossProtectionLogic::SelectedMethod() const { + return _selectedMethod.get(); +} + +VCMProtectionMethodEnum VCMLossProtectionLogic::SelectedType() const { + return _selectedMethod ? _selectedMethod->Type() : kNone; +} + +void VCMLossProtectionLogic::Reset(int64_t nowMs) { + _lastPrUpdateT = nowMs; + _lastPacketPerFrameUpdateT = nowMs; + _lastPacketPerFrameUpdateTKey = nowMs; + _lossPr255.Reset(0.9999f); + _packetsPerFrame.Reset(0.9999f); + _fecRateDelta = _fecRateKey = 0; + for (int32_t i = 0; i < kLossPrHistorySize; i++) { + _lossPrHistory[i].lossPr255 = 0; + _lossPrHistory[i].timeMs = -1; + } + _shortMaxLossPr255 = 0; + Release(); +} + +void VCMLossProtectionLogic::Release() { + _selectedMethod.reset(); +} + +} // namespace media_optimization +} // namespace webrtc |