blob: 9bd722696ac0d8aa2a7613ed0f4c4d1d61979f66 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Henrik Kjellander2557b862015-11-18 22:00:21 +010011#include "webrtc/modules/video_coding/media_opt_util.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +000013#include <algorithm>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <float.h>
15#include <limits.h>
pbos@webrtc.orga4407322013-07-16 12:32:05 +000016#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000017
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010018#include "webrtc/modules/include/module_common_types.h"
pbos@webrtc.orga4407322013-07-16 12:32:05 +000019#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010020#include "webrtc/modules/video_coding/include/video_coding_defines.h"
21#include "webrtc/modules/video_coding/fec_tables_xor.h"
22#include "webrtc/modules/video_coding/nack_fec_tables.h"
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +000023
niklase@google.com470e71d2011-07-07 08:21:25 +000024namespace webrtc {
Peter Boström9cb1f302015-04-01 11:39:49 +020025// Max value of loss rates in off-line model
26static const int kPacketLossMax = 129;
27
stefan@webrtc.orga64300a2013-03-04 15:24:40 +000028namespace media_optimization {
niklase@google.com470e71d2011-07-07 08:21:25 +000029
Peter Boström9cb1f302015-04-01 11:39:49 +020030VCMProtectionMethod::VCMProtectionMethod()
31 : _effectivePacketLoss(0),
32 _protectionFactorK(0),
33 _protectionFactorD(0),
34 _scaleProtKey(2.0f),
35 _maxPayloadSize(1460),
36 _qmRobustness(new VCMQmRobustness()),
37 _useUepProtectionK(false),
38 _useUepProtectionD(true),
39 _corrFecCost(1.0),
40 _type(kNone) {
mikhal@webrtc.orga057a952011-08-26 21:17:34 +000041}
42
43VCMProtectionMethod::~VCMProtectionMethod()
44{
45 delete _qmRobustness;
46}
marpan@google.com86548c62011-07-12 17:12:57 +000047void
mikhal@google.com022716b2011-07-20 23:12:57 +000048VCMProtectionMethod::UpdateContentMetrics(const
49 VideoContentMetrics* contentMetrics)
marpan@google.com86548c62011-07-12 17:12:57 +000050{
mikhal@webrtc.orga057a952011-08-26 21:17:34 +000051 _qmRobustness->UpdateContent(contentMetrics);
marpan@google.com86548c62011-07-12 17:12:57 +000052}
53
pkasting@chromium.org16825b12015-01-12 21:51:21 +000054VCMNackFecMethod::VCMNackFecMethod(int64_t lowRttNackThresholdMs,
55 int64_t highRttNackThresholdMs)
stefan@webrtc.org932ab182011-11-29 11:33:31 +000056 : VCMFecMethod(),
57 _lowRttNackMs(lowRttNackThresholdMs),
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +000058 _highRttNackMs(highRttNackThresholdMs),
59 _maxFramesFec(1) {
stefan@webrtc.org932ab182011-11-29 11:33:31 +000060 assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
61 assert(highRttNackThresholdMs == -1 ||
62 lowRttNackThresholdMs <= highRttNackThresholdMs);
63 assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
64 _type = kNackFec;
mikhal@google.com77408882011-07-22 22:05:25 +000065}
66
67VCMNackFecMethod::~VCMNackFecMethod()
68{
mikhal@webrtc.orga057a952011-08-26 21:17:34 +000069 //
mikhal@google.com77408882011-07-22 22:05:25 +000070}
niklase@google.com470e71d2011-07-07 08:21:25 +000071bool
stefan@webrtc.org932ab182011-11-29 11:33:31 +000072VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
niklase@google.com470e71d2011-07-07 08:21:25 +000073{
74 // Hybrid Nack FEC has three operational modes:
mikhal@google.com679450f2011-08-01 22:14:58 +000075 // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
stefan@webrtc.org932ab182011-11-29 11:33:31 +000076 // (_protectionFactorD) to zero. -1 means no FEC.
77 // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
78 // -1 means always allow NACK.
mikhal@google.com679450f2011-08-01 22:14:58 +000079 // 3. Medium RTT values - Hybrid mode: We will only nack the
80 // residual following the decoding of the FEC (refer to JB logic). FEC
81 // delta protection factor will be adjusted based on the RTT.
mikhal@google.com022716b2011-07-20 23:12:57 +000082
83 // Otherwise: we count on FEC; if the RTT is below a threshold, then we
niklase@google.com470e71d2011-07-07 08:21:25 +000084 // nack the residual, based on a decision made in the JB.
mikhal@google.com022716b2011-07-20 23:12:57 +000085
mikhal@google.com022716b2011-07-20 23:12:57 +000086 // Compute the protection factors
mikhal@webrtc.orga057a952011-08-26 21:17:34 +000087 VCMFecMethod::ProtectionFactor(parameters);
stefan@webrtc.org932ab182011-11-29 11:33:31 +000088 if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs)
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +000089 {
90 _protectionFactorD = 0;
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +000091 VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +000092 }
mikhal@google.com320813c2011-08-03 20:47:50 +000093
mikhal@google.com679450f2011-08-01 22:14:58 +000094 // When in Hybrid mode (RTT range), adjust FEC rates based on the
95 // RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
stefan@webrtc.org932ab182011-11-29 11:33:31 +000096 else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
niklase@google.com470e71d2011-07-07 08:21:25 +000097 {
mikhal@webrtc.orgae7a0522011-10-03 22:54:34 +000098 // TODO(mikhal): Disabling adjustment temporarily.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +000099 // uint16_t rttIndex = (uint16_t) parameters->rtt;
mikhal@webrtc.orgae7a0522011-10-03 22:54:34 +0000100 float adjustRtt = 1.0f;// (float)VCMNackFecTable[rttIndex] / 100.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
mikhal@google.com679450f2011-08-01 22:14:58 +0000102 // Adjust FEC with NACK on (for delta frame only)
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 // table depends on RTT relative to rttMax (NACK Threshold)
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000104 _protectionFactorD = static_cast<uint8_t>
mikhal@google.com679450f2011-08-01 22:14:58 +0000105 (adjustRtt *
106 static_cast<float>(_protectionFactorD));
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +0000107 // update FEC rates after applying adjustment
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000108 VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 }
mikhal@google.com679450f2011-08-01 22:14:58 +0000110
mikhal@google.com022716b2011-07-20 23:12:57 +0000111 return true;
112}
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000114int VCMNackFecMethod::ComputeMaxFramesFec(
115 const VCMProtectionParameters* parameters) {
116 if (parameters->numLayers > 2) {
117 // For more than 2 temporal layers we will only have FEC on the base layer,
118 // and the base layers will be pretty far apart. Therefore we force one
119 // frame FEC.
120 return 1;
121 }
122 // We set the max number of frames to base the FEC on so that on average
123 // we will have complete frames in one RTT. Note that this is an upper
124 // bound, and that the actual number of frames used for FEC is decided by the
125 // RTP module based on the actual number of packets and the protection factor.
126 float base_layer_framerate = parameters->frameRate /
127 static_cast<float>(1 << (parameters->numLayers - 1));
128 int max_frames_fec = std::max(static_cast<int>(
129 2.0f * base_layer_framerate * parameters->rtt /
130 1000.0f + 0.5f), 1);
131 // |kUpperLimitFramesFec| is the upper limit on how many frames we
132 // allow any FEC to be based on.
133 if (max_frames_fec > kUpperLimitFramesFec) {
134 max_frames_fec = kUpperLimitFramesFec;
135 }
136 return max_frames_fec;
137}
138
139int VCMNackFecMethod::MaxFramesFec() const {
140 return _maxFramesFec;
141}
142
marpan@webrtc.org88ad06b2012-04-20 16:05:24 +0000143bool VCMNackFecMethod::BitRateTooLowForFec(
144 const VCMProtectionParameters* parameters) {
145 // Bitrate below which we turn off FEC, regardless of reported packet loss.
146 // The condition should depend on resolution and content. For now, use
147 // threshold on bytes per frame, with some effect for the frame size.
148 // The condition for turning off FEC is also based on other factors,
149 // such as |_numLayers|, |_maxFramesFec|, and |_rtt|.
150 int estimate_bytes_per_frame = 1000 * BitsPerFrame(parameters) / 8;
151 int max_bytes_per_frame = kMaxBytesPerFrameForFec;
152 int num_pixels = parameters->codecWidth * parameters->codecHeight;
153 if (num_pixels <= 352 * 288) {
154 max_bytes_per_frame = kMaxBytesPerFrameForFecLow;
155 } else if (num_pixels > 640 * 480) {
156 max_bytes_per_frame = kMaxBytesPerFrameForFecHigh;
157 }
158 // TODO (marpan): add condition based on maximum frames used for FEC,
159 // and expand condition based on frame size.
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000160 // Max round trip time threshold in ms.
161 const int64_t kMaxRttTurnOffFec = 200;
marpan@webrtc.org88ad06b2012-04-20 16:05:24 +0000162 if (estimate_bytes_per_frame < max_bytes_per_frame &&
163 parameters->numLayers < 3 &&
164 parameters->rtt < kMaxRttTurnOffFec) {
165 return true;
166 }
167 return false;
168}
169
mikhal@google.com022716b2011-07-20 23:12:57 +0000170bool
stefan@webrtc.org932ab182011-11-29 11:33:31 +0000171VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
mikhal@google.com022716b2011-07-20 23:12:57 +0000172{
mikhal@google.com022716b2011-07-20 23:12:57 +0000173 // Set the effective packet loss for encoder (based on FEC code).
mikhal@google.com022716b2011-07-20 23:12:57 +0000174 // Compute the effective packet loss and residual packet loss due to FEC.
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000175 VCMFecMethod::EffectivePacketLoss(parameters);
mikhal@google.com022716b2011-07-20 23:12:57 +0000176 return true;
177}
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
mikhal@google.com022716b2011-07-20 23:12:57 +0000179bool
180VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
181{
182 ProtectionFactor(parameters);
183 EffectivePacketLoss(parameters);
stefan@webrtc.orgc35f5ce2012-04-11 07:42:25 +0000184 _maxFramesFec = ComputeMaxFramesFec(parameters);
marpan@webrtc.org88ad06b2012-04-20 16:05:24 +0000185 if (BitRateTooLowForFec(parameters)) {
186 _protectionFactorK = 0;
187 _protectionFactorD = 0;
188 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000189
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 // Protection/fec rates obtained above are defined relative to total number
191 // of packets (total rate: source + fec) FEC in RTP module assumes
192 // protection factor is defined relative to source number of packets so we
193 // should convert the factor to reduce mismatch between mediaOpt's rate and
194 // the actual one
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000195 _protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK);
196 _protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD);
niklase@google.com470e71d2011-07-07 08:21:25 +0000197
198 return true;
199}
200
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000201VCMNackMethod::VCMNackMethod():
202VCMProtectionMethod()
203{
204 _type = kNack;
205}
206
207VCMNackMethod::~VCMNackMethod()
208{
209 //
210}
211
niklase@google.com470e71d2011-07-07 08:21:25 +0000212bool
mikhal@google.comb29d9402011-08-01 16:39:20 +0000213VCMNackMethod::EffectivePacketLoss(const VCMProtectionParameters* parameter)
niklase@google.com470e71d2011-07-07 08:21:25 +0000214{
mikhal@google.comb29d9402011-08-01 16:39:20 +0000215 // Effective Packet Loss, NA in current version.
216 _effectivePacketLoss = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 return true;
218}
219
220bool
221VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
222{
mikhal@google.comb29d9402011-08-01 16:39:20 +0000223 // Compute the effective packet loss
224 EffectivePacketLoss(parameters);
niklase@google.com470e71d2011-07-07 08:21:25 +0000225
mikhal@google.comb29d9402011-08-01 16:39:20 +0000226 // nackCost = (bitRate - nackCost) * (lossPr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 return true;
228}
229
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000230VCMFecMethod::VCMFecMethod():
231VCMProtectionMethod()
232{
233 _type = kFec;
234}
235VCMFecMethod::~VCMFecMethod()
236{
237 //
238}
239
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000240uint8_t
241VCMFecMethod::BoostCodeRateKey(uint8_t packetFrameDelta,
242 uint8_t packetFrameKey) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000243{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000244 uint8_t boostRateKey = 2;
mikhal@google.com022716b2011-07-20 23:12:57 +0000245 // Default: ratio scales the FEC protection up for I frames
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000246 uint8_t ratio = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247
248 if (packetFrameDelta > 0)
249 {
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000250 ratio = (int8_t) (packetFrameKey / packetFrameDelta);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 }
252 ratio = VCM_MAX(boostRateKey, ratio);
253
254 return ratio;
255}
256
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000257uint8_t
258VCMFecMethod::ConvertFECRate(uint8_t codeRateRTP) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000259{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000260 return static_cast<uint8_t> (VCM_MIN(255,(0.5 + 255.0 * codeRateRTP /
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 (float)(255 - codeRateRTP))));
262}
263
mikhal@google.com679450f2011-08-01 22:14:58 +0000264// Update FEC with protectionFactorD
265void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000266VCMFecMethod::UpdateProtectionFactorD(uint8_t protectionFactorD)
mikhal@google.com679450f2011-08-01 22:14:58 +0000267{
268 _protectionFactorD = protectionFactorD;
mikhal@google.com679450f2011-08-01 22:14:58 +0000269}
270
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +0000271// Update FEC with protectionFactorK
272void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000273VCMFecMethod::UpdateProtectionFactorK(uint8_t protectionFactorK)
mikhal@webrtc.orgd0752c32011-10-19 15:48:30 +0000274{
275 _protectionFactorK = protectionFactorK;
276}
277
niklase@google.com470e71d2011-07-07 08:21:25 +0000278bool
279VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
280{
281 // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
282
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 // No protection if (filtered) packetLoss is 0
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000284 uint8_t packetLoss = (uint8_t) (255 * parameters->lossPr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 if (packetLoss == 0)
286 {
287 _protectionFactorK = 0;
288 _protectionFactorD = 0;
289 return true;
290 }
291
marpan@google.com11d986a2011-07-28 17:42:57 +0000292 // Parameters for FEC setting:
293 // first partition size, thresholds, table pars, spatial resoln fac.
294
295 // First partition protection: ~ 20%
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000296 uint8_t firstPartitionProt = (uint8_t) (255 * 0.20);
marpan@google.com11d986a2011-07-28 17:42:57 +0000297
marpan@google.com3f280612011-09-09 16:39:40 +0000298 // Minimum protection level needed to generate one FEC packet for one
299 // source packet/frame (in RTP sender)
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000300 uint8_t minProtLevelFec = 85;
marpan@google.com3f280612011-09-09 16:39:40 +0000301
marpan@google.com11d986a2011-07-28 17:42:57 +0000302 // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
303 // above which we allocate protection to cover at least first partition.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000304 uint8_t lossThr = 0;
305 uint8_t packetNumThr = 1;
marpan@google.com11d986a2011-07-28 17:42:57 +0000306
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000307 // Parameters for range of rate index of table.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000308 const uint8_t ratePar1 = 5;
309 const uint8_t ratePar2 = 49;
niklase@google.com470e71d2011-07-07 08:21:25 +0000310
marpan@google.com11d986a2011-07-28 17:42:57 +0000311 // Spatial resolution size, relative to a reference size.
312 float spatialSizeToRef = static_cast<float>
313 (parameters->codecWidth * parameters->codecHeight) /
314 (static_cast<float>(704 * 576));
315 // resolnFac: This parameter will generally increase/decrease the FEC rate
316 // (for fixed bitRate and packetLoss) based on system size.
317 // Use a smaller exponent (< 1) to control/soften system size effect.
ajm@google.comb0d9f3e2011-07-28 18:43:18 +0000318 const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
marpan@google.com11d986a2011-07-28 17:42:57 +0000319
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000320 const int bitRatePerFrame = BitsPerFrame(parameters);
niklase@google.com470e71d2011-07-07 08:21:25 +0000321
niklase@google.com470e71d2011-07-07 08:21:25 +0000322
marpan@google.com11d986a2011-07-28 17:42:57 +0000323 // Average number of packets per frame (source and fec):
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000324 const uint8_t avgTotPackets = 1 + (uint8_t)
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 ((float) bitRatePerFrame * 1000.0
326 / (float) (8.0 * _maxPayloadSize) + 0.5);
327
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 // FEC rate parameters: for P and I frame
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000329 uint8_t codeRateDelta = 0;
330 uint8_t codeRateKey = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331
marpan@google.com11d986a2011-07-28 17:42:57 +0000332 // Get index for table: the FEC protection depends on an effective rate.
333 // The range on the rate index corresponds to rates (bps)
334 // from ~200k to ~8000k, for 30fps
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000335 const uint16_t effRateFecTable = static_cast<uint16_t>
marpan@google.com11d986a2011-07-28 17:42:57 +0000336 (resolnFac * bitRatePerFrame);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000337 uint8_t rateIndexTable =
338 (uint8_t) VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) /
marpan@google.com11d986a2011-07-28 17:42:57 +0000339 ratePar1, ratePar2), 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000340
341 // Restrict packet loss range to 50:
342 // current tables defined only up to 50%
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000343 if (packetLoss >= kPacketLossMax)
niklase@google.com470e71d2011-07-07 08:21:25 +0000344 {
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000345 packetLoss = kPacketLossMax - 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000347 uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss;
niklase@google.com470e71d2011-07-07 08:21:25 +0000348
349 // Check on table index
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000350 assert(indexTable < kSizeCodeRateXORTable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000351
352 // Protection factor for P frame
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000353 codeRateDelta = kCodeRateXORTable[indexTable];
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
355 if (packetLoss > lossThr && avgTotPackets > packetNumThr)
356 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000357 // Set a minimum based on first partition size.
358 if (codeRateDelta < firstPartitionProt)
359 {
360 codeRateDelta = firstPartitionProt;
361 }
362 }
363
364 // Check limit on amount of protection for P frame; 50% is max.
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000365 if (codeRateDelta >= kPacketLossMax)
niklase@google.com470e71d2011-07-07 08:21:25 +0000366 {
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000367 codeRateDelta = kPacketLossMax - 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 }
369
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000370 float adjustFec = 1.0f;
371 // Avoid additional adjustments when layers are active.
372 // TODO(mikhal/marco): Update adjusmtent based on layer info.
373 if (parameters->numLayers == 1)
374 {
375 adjustFec = _qmRobustness->AdjustFecFactor(codeRateDelta,
376 parameters->bitRate,
377 parameters->frameRate,
378 parameters->rtt,
379 packetLoss);
380 }
marpan@google.com59fd0f12011-07-13 17:19:49 +0000381
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000382 codeRateDelta = static_cast<uint8_t>(codeRateDelta * adjustFec);
marpan@google.com86548c62011-07-12 17:12:57 +0000383
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 // For Key frame:
385 // Effectively at a higher rate, so we scale/boost the rate
386 // The boost factor may depend on several factors: ratio of packet
387 // number of I to P frames, how much protection placed on P frames, etc.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000388 const uint8_t packetFrameDelta = (uint8_t)
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 (0.5 + parameters->packetsPerFrame);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000390 const uint8_t packetFrameKey = (uint8_t)
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 (0.5 + parameters->packetsPerFrameKey);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000392 const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta,
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 packetFrameKey);
394
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000395 rateIndexTable = (uint8_t) VCM_MAX(VCM_MIN(
marpan@google.com11d986a2011-07-28 17:42:57 +0000396 1 + (boostKey * effRateFecTable - ratePar1) /
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 ratePar1,ratePar2),0);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000398 uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
niklase@google.com470e71d2011-07-07 08:21:25 +0000399
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000400 indexTableKey = VCM_MIN(indexTableKey, kSizeCodeRateXORTable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000401
402 // Check on table index
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000403 assert(indexTableKey < kSizeCodeRateXORTable);
niklase@google.com470e71d2011-07-07 08:21:25 +0000404
405 // Protection factor for I frame
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000406 codeRateKey = kCodeRateXORTable[indexTableKey];
niklase@google.com470e71d2011-07-07 08:21:25 +0000407
408 // Boosting for Key frame.
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000409 int boostKeyProt = _scaleProtKey * codeRateDelta;
410 if (boostKeyProt >= kPacketLossMax)
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 {
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000412 boostKeyProt = kPacketLossMax - 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 }
414
415 // Make sure I frame protection is at least larger than P frame protection,
416 // and at least as high as filtered packet loss.
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000417 codeRateKey = static_cast<uint8_t> (VCM_MAX(packetLoss,
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 VCM_MAX(boostKeyProt, codeRateKey)));
419
420 // Check limit on amount of protection for I frame: 50% is max.
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000421 if (codeRateKey >= kPacketLossMax)
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 {
andrew@webrtc.org413b9932011-09-02 22:03:56 +0000423 codeRateKey = kPacketLossMax - 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 }
425
426 _protectionFactorK = codeRateKey;
427 _protectionFactorD = codeRateDelta;
428
marpan@google.com191b7802011-08-01 19:59:57 +0000429 // Generally there is a rate mis-match between the FEC cost estimated
430 // in mediaOpt and the actual FEC cost sent out in RTP module.
431 // This is more significant at low rates (small # of source packets), where
432 // the granularity of the FEC decreases. In this case, non-zero protection
433 // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
434 // is based on rounding off protectionFactor on actual source packet number).
435 // The correction factor (_corrFecCost) attempts to corrects this, at least
marpan@google.com3f280612011-09-09 16:39:40 +0000436 // for cases of low rates (small #packets) and low protection levels.
marpan@google.comf1f3fb32011-10-03 19:09:45 +0000437
438 float numPacketsFl = 1.0f + ((float) bitRatePerFrame * 1000.0
439 / (float) (8.0 * _maxPayloadSize) + 0.5);
440
marpan@google.com191b7802011-08-01 19:59:57 +0000441 const float estNumFecGen = 0.5f + static_cast<float> (_protectionFactorD *
marpan@google.comf1f3fb32011-10-03 19:09:45 +0000442 numPacketsFl / 255.0f);
443
444
marpan@google.com3f280612011-09-09 16:39:40 +0000445 // We reduce cost factor (which will reduce overhead for FEC and
marpan@google.com191b7802011-08-01 19:59:57 +0000446 // hybrid method) and not the protectionFactor.
447 _corrFecCost = 1.0f;
marpan@google.comf1f3fb32011-10-03 19:09:45 +0000448 if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec)
marpan@google.com191b7802011-08-01 19:59:57 +0000449 {
450 _corrFecCost = 0.5f;
451 }
marpan@google.com3f280612011-09-09 16:39:40 +0000452 if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec)
marpan@google.com191b7802011-08-01 19:59:57 +0000453 {
454 _corrFecCost = 0.0f;
455 }
marpan@google.com86548c62011-07-12 17:12:57 +0000456
marpan@google.com59fd0f12011-07-13 17:19:49 +0000457 // TODO (marpan): Set the UEP protection on/off for Key and Delta frames
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000458 _useUepProtectionK = _qmRobustness->SetUepProtection(codeRateKey,
459 parameters->bitRate,
460 packetLoss,
461 0);
marpan@google.com86548c62011-07-12 17:12:57 +0000462
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000463 _useUepProtectionD = _qmRobustness->SetUepProtection(codeRateDelta,
464 parameters->bitRate,
465 packetLoss,
466 1);
marpan@google.com86548c62011-07-12 17:12:57 +0000467
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 // DONE WITH FEC PROTECTION SETTINGS
469 return true;
470}
471
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000472int VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) {
473 // When temporal layers are available FEC will only be applied on the base
474 // layer.
475 const float bitRateRatio =
476 kVp8LayerRateAlloction[parameters->numLayers - 1][0];
thakis@chromium.org65bc2542012-08-13 19:26:12 +0000477 float frameRateRatio = powf(1 / 2.0, parameters->numLayers - 1);
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000478 float bitRate = parameters->bitRate * bitRateRatio;
479 float frameRate = parameters->frameRate * frameRateRatio;
480
481 // TODO(mikhal): Update factor following testing.
482 float adjustmentFactor = 1;
483
484 // Average bits per frame (units of kbits)
485 return static_cast<int>(adjustmentFactor * bitRate / frameRate);
486}
487
niklase@google.com470e71d2011-07-07 08:21:25 +0000488bool
489VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
490{
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 // Effective packet loss to encoder is based on RPL (residual packet loss)
492 // this is a soft setting based on degree of FEC protection
493 // RPL = received/input packet loss - average_FEC_recovery
494 // note: received/input packet loss may be filtered based on FilteredLoss
495
mikhal@google.com022716b2011-07-20 23:12:57 +0000496 // Effective Packet Loss, NA in current version.
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 _effectivePacketLoss = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000498
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 return true;
500}
501
502bool
503VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
504{
505 // Compute the protection factor
506 ProtectionFactor(parameters);
507
508 // Compute the effective packet loss
509 EffectivePacketLoss(parameters);
510
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 // Protection/fec rates obtained above is defined relative to total number
512 // of packets (total rate: source+fec) FEC in RTP module assumes protection
513 // factor is defined relative to source number of packets so we should
514 // convert the factor to reduce mismatch between mediaOpt suggested rate and
515 // the actual rate
516 _protectionFactorK = ConvertFECRate(_protectionFactorK);
517 _protectionFactorD = ConvertFECRate(_protectionFactorD);
518
519 return true;
520}
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000521VCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs):
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000522_currentParameters(),
523_rtt(0),
524_lossPr(0.0f),
525_bitRate(0.0f),
526_frameRate(0.0f),
527_keyFrameSize(0.0f),
528_fecRateKey(0),
529_fecRateDelta(0),
530_lastPrUpdateT(0),
531_lossPr255(0.9999f),
532_lossPrHistory(),
533_shortMaxLossPr255(0),
534_packetsPerFrame(0.9999f),
535_packetsPerFrameKey(0.9999f),
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000536_codecWidth(0),
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000537_codecHeight(0),
538_numLayers(1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000539{
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000540 Reset(nowMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000541}
542
niklase@google.com470e71d2011-07-07 08:21:25 +0000543VCMLossProtectionLogic::~VCMLossProtectionLogic()
544{
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000545 Release();
niklase@google.com470e71d2011-07-07 08:21:25 +0000546}
547
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000548void VCMLossProtectionLogic::SetMethod(
549 enum VCMProtectionMethodEnum newMethodType) {
pbosba8c15b2015-07-14 09:36:34 -0700550 if (_selectedMethod && _selectedMethod->Type() == newMethodType)
551 return;
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000552
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000553 switch(newMethodType) {
554 case kNack:
pbosba8c15b2015-07-14 09:36:34 -0700555 _selectedMethod.reset(new VCMNackMethod());
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000556 break;
557 case kFec:
pbosba8c15b2015-07-14 09:36:34 -0700558 _selectedMethod.reset(new VCMFecMethod());
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000559 break;
560 case kNackFec:
pbosba8c15b2015-07-14 09:36:34 -0700561 _selectedMethod.reset(new VCMNackFecMethod(kLowRttNackMs, -1));
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000562 break;
563 case kNone:
pbosba8c15b2015-07-14 09:36:34 -0700564 _selectedMethod.reset();
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000565 break;
566 }
567 UpdateMethod();
niklase@google.com470e71d2011-07-07 08:21:25 +0000568}
569
niklase@google.com470e71d2011-07-07 08:21:25 +0000570void
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000571VCMLossProtectionLogic::UpdateRtt(int64_t rtt)
niklase@google.com470e71d2011-07-07 08:21:25 +0000572{
573 _rtt = rtt;
574}
575
576void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000577VCMLossProtectionLogic::UpdateMaxLossHistory(uint8_t lossPr255,
578 int64_t now)
niklase@google.com470e71d2011-07-07 08:21:25 +0000579{
580 if (_lossPrHistory[0].timeMs >= 0 &&
581 now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
582 {
583 if (lossPr255 > _shortMaxLossPr255)
584 {
585 _shortMaxLossPr255 = lossPr255;
586 }
587 }
588 else
589 {
590 // Only add a new value to the history once a second
591 if (_lossPrHistory[0].timeMs == -1)
592 {
593 // First, no shift
594 _shortMaxLossPr255 = lossPr255;
595 }
596 else
597 {
598 // Shift
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000599 for (int32_t i = (kLossPrHistorySize - 2); i >= 0; i--)
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 {
601 _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
602 _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
603 }
604 }
605 if (_shortMaxLossPr255 == 0)
606 {
607 _shortMaxLossPr255 = lossPr255;
608 }
609
610 _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
611 _lossPrHistory[0].timeMs = now;
612 _shortMaxLossPr255 = 0;
613 }
614}
615
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000616uint8_t
617VCMLossProtectionLogic::MaxFilteredLossPr(int64_t nowMs) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000618{
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000619 uint8_t maxFound = _shortMaxLossPr255;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 if (_lossPrHistory[0].timeMs == -1)
621 {
622 return maxFound;
623 }
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000624 for (int32_t i = 0; i < kLossPrHistorySize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 {
626 if (_lossPrHistory[i].timeMs == -1)
627 {
628 break;
629 }
630 if (nowMs - _lossPrHistory[i].timeMs >
631 kLossPrHistorySize * kLossPrShortFilterWinMs)
632 {
633 // This sample (and all samples after this) is too old
634 break;
635 }
636 if (_lossPrHistory[i].lossPr255 > maxFound)
637 {
638 // This sample is the largest one this far into the history
639 maxFound = _lossPrHistory[i].lossPr255;
640 }
641 }
642 return maxFound;
643}
644
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000645uint8_t VCMLossProtectionLogic::FilteredLoss(
marpan@webrtc.org2dad3fb2012-01-09 18:18:36 +0000646 int64_t nowMs,
647 FilterPacketLossMode filter_mode,
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000648 uint8_t lossPr255) {
marpan@webrtc.org2dad3fb2012-01-09 18:18:36 +0000649
650 // Update the max window filter.
651 UpdateMaxLossHistory(lossPr255, nowMs);
652
653 // Update the recursive average filter.
654 _lossPr255.Apply(static_cast<float> (nowMs - _lastPrUpdateT),
655 static_cast<float> (lossPr255));
656 _lastPrUpdateT = nowMs;
657
658 // Filtered loss: default is received loss (no filtering).
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000659 uint8_t filtered_loss = lossPr255;
marpan@webrtc.org2dad3fb2012-01-09 18:18:36 +0000660
661 switch (filter_mode) {
662 case kNoFilter:
663 break;
664 case kAvgFilter:
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000665 filtered_loss = static_cast<uint8_t>(_lossPr255.filtered() + 0.5);
marpan@webrtc.org2dad3fb2012-01-09 18:18:36 +0000666 break;
667 case kMaxFilter:
668 filtered_loss = MaxFilteredLossPr(nowMs);
669 break;
670 }
671
672 return filtered_loss;
niklase@google.com470e71d2011-07-07 08:21:25 +0000673}
674
675void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000676VCMLossProtectionLogic::UpdateFilteredLossPr(uint8_t packetLossEnc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000677{
678 _lossPr = (float) packetLossEnc / (float) 255.0;
679}
680
681void
682VCMLossProtectionLogic::UpdateBitRate(float bitRate)
683{
684 _bitRate = bitRate;
685}
686
687void
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000688VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000689{
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000690 _packetsPerFrame.Apply(static_cast<float>(nowMs - _lastPacketPerFrameUpdateT),
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 nPackets);
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000692 _lastPacketPerFrameUpdateT = nowMs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000693}
694
695void
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000696VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets, int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000697{
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000698 _packetsPerFrameKey.Apply(static_cast<float>(nowMs -
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 _lastPacketPerFrameUpdateTKey), nPackets);
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000700 _lastPacketPerFrameUpdateTKey = nowMs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701}
702
703void
704VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
705{
706 _keyFrameSize = keyFrameSize;
707}
708
709void
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000710VCMLossProtectionLogic::UpdateFrameSize(uint16_t width,
711 uint16_t height)
niklase@google.com470e71d2011-07-07 08:21:25 +0000712{
713 _codecWidth = width;
714 _codecHeight = height;
715}
716
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000717void VCMLossProtectionLogic::UpdateNumLayers(int numLayers) {
718 _numLayers = (numLayers == 0) ? 1 : numLayers;
719}
720
niklase@google.com470e71d2011-07-07 08:21:25 +0000721bool
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000722VCMLossProtectionLogic::UpdateMethod()
niklase@google.com470e71d2011-07-07 08:21:25 +0000723{
pbosba8c15b2015-07-14 09:36:34 -0700724 if (!_selectedMethod)
725 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 _currentParameters.rtt = _rtt;
727 _currentParameters.lossPr = _lossPr;
728 _currentParameters.bitRate = _bitRate;
729 _currentParameters.frameRate = _frameRate; // rename actual frame rate?
730 _currentParameters.keyFrameSize = _keyFrameSize;
731 _currentParameters.fecRateDelta = _fecRateDelta;
732 _currentParameters.fecRateKey = _fecRateKey;
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000733 _currentParameters.packetsPerFrame = _packetsPerFrame.filtered();
734 _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered();
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 _currentParameters.codecWidth = _codecWidth;
736 _currentParameters.codecHeight = _codecHeight;
mikhal@webrtc.org0e7d9d82011-12-19 19:04:49 +0000737 _currentParameters.numLayers = _numLayers;
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000738 return _selectedMethod->UpdateParameters(&_currentParameters);
niklase@google.com470e71d2011-07-07 08:21:25 +0000739}
740
741VCMProtectionMethod*
742VCMLossProtectionLogic::SelectedMethod() const
743{
pbosba8c15b2015-07-14 09:36:34 -0700744 return _selectedMethod.get();
niklase@google.com470e71d2011-07-07 08:21:25 +0000745}
746
pbos@webrtc.orgcade82c2015-03-12 10:39:24 +0000747VCMProtectionMethodEnum VCMLossProtectionLogic::SelectedType() const {
pbosba8c15b2015-07-14 09:36:34 -0700748 return _selectedMethod ? _selectedMethod->Type() : kNone;
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000749}
750
mikhal@google.com022716b2011-07-20 23:12:57 +0000751void
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000752VCMLossProtectionLogic::Reset(int64_t nowMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000753{
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +0000754 _lastPrUpdateT = nowMs;
755 _lastPacketPerFrameUpdateT = nowMs;
756 _lastPacketPerFrameUpdateTKey = nowMs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 _lossPr255.Reset(0.9999f);
758 _packetsPerFrame.Reset(0.9999f);
759 _fecRateDelta = _fecRateKey = 0;
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000760 for (int32_t i = 0; i < kLossPrHistorySize; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 {
762 _lossPrHistory[i].lossPr255 = 0;
763 _lossPrHistory[i].timeMs = -1;
764 }
765 _shortMaxLossPr255 = 0;
mikhal@webrtc.orga057a952011-08-26 21:17:34 +0000766 Release();
767}
768
pbosba8c15b2015-07-14 09:36:34 -0700769void VCMLossProtectionLogic::Release() {
770 _selectedMethod.reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000771}
772
stefan@webrtc.orga64300a2013-03-04 15:24:40 +0000773} // namespace media_optimization
774} // namespace webrtc