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
|