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