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