1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/main/source/media_opt_util.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <algorithm>
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <float.h>
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <limits.h>
16a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include <math.h>
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
18a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/interface/module_common_types.h"
19a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
20a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/main/interface/video_coding_defines.h"
21a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/main/source/er_tables_xor.h"
22a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/main/source/fec_tables_xor.h"
23a557f436b9d694d5a0a045e0295e1794f2df48eapbos@webrtc.org#include "webrtc/modules/video_coding/main/source/nack_fec_tables.h"
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
26bb78b2c7ce8cc4445811d0e881890a29b14a4f2bstefan@webrtc.orgnamespace media_optimization {
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod::VCMProtectionMethod():
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_effectivePacketLoss(0),
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_protectionFactorK(0),
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_protectionFactorD(0),
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_residualPacketLossFec(0.0f),
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_scaleProtKey(2.0f),
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_maxPayloadSize(1460),
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_qmRobustness(new VCMQmRobustness()),
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_useUepProtectionK(false),
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_useUepProtectionD(true),
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_corrFecCost(1.0),
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_type(kNone),
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_efficiency(0)
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod::~VCMProtectionMethod()
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete _qmRobustness;
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod::UpdateContentMetrics(const
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                          VideoContentMetrics* contentMetrics)
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _qmRobustness->UpdateContent(contentMetrics);
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackFecMethod::VCMNackFecMethod(int lowRttNackThresholdMs,
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                   int highRttNackThresholdMs)
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    : VCMFecMethod(),
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _lowRttNackMs(lowRttNackThresholdMs),
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _highRttNackMs(highRttNackThresholdMs),
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _maxFramesFec(1) {
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(highRttNackThresholdMs == -1 ||
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         lowRttNackThresholdMs <= highRttNackThresholdMs);
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  _type = kNackFec;
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackFecMethod::~VCMNackFecMethod()
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Hybrid Nack FEC has three operational modes:
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    (_protectionFactorD) to zero. -1 means no FEC.
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    -1 means always allow NACK.
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // 3. Medium RTT values - Hybrid mode: We will only nack the
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    residual following the decoding of the FEC (refer to JB logic). FEC
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //    delta protection factor will be adjusted based on the RTT.
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Otherwise: we count on FEC; if the RTT is below a threshold, then we
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // nack the residual, based on a decision made in the JB.
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the protection factors
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    VCMFecMethod::ProtectionFactor(parameters);
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs)
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _protectionFactorD = 0;
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // When in Hybrid mode (RTT range), adjust FEC rates based on the
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // TODO(mikhal): Disabling adjustment temporarily.
101dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org        // uint16_t rttIndex = (uint16_t) parameters->rtt;
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        float adjustRtt = 1.0f;// (float)VCMNackFecTable[rttIndex] / 100.0f;
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Adjust FEC with NACK on (for delta frame only)
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // table depends on RTT relative to rttMax (NACK Threshold)
106dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org        _protectionFactorD = static_cast<uint8_t>
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            (adjustRtt *
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             static_cast<float>(_protectionFactorD));
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // update FEC rates after applying adjustment
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VCMNackFecMethod::ComputeMaxFramesFec(
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const VCMProtectionParameters* parameters) {
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (parameters->numLayers > 2) {
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // For more than 2 temporal layers we will only have FEC on the base layer,
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // and the base layers will be pretty far apart. Therefore we force one
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // frame FEC.
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 1;
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // We set the max number of frames to base the FEC on so that on average
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // we will have complete frames in one RTT. Note that this is an upper
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // bound, and that the actual number of frames used for FEC is decided by the
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // RTP module based on the actual number of packets and the protection factor.
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float base_layer_framerate = parameters->frameRate /
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      static_cast<float>(1 << (parameters->numLayers - 1));
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int max_frames_fec = std::max(static_cast<int>(
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      2.0f * base_layer_framerate * parameters->rtt /
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      1000.0f + 0.5f), 1);
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // |kUpperLimitFramesFec| is the upper limit on how many frames we
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // allow any FEC to be based on.
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (max_frames_fec > kUpperLimitFramesFec) {
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    max_frames_fec = kUpperLimitFramesFec;
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return max_frames_fec;
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VCMNackFecMethod::MaxFramesFec() const {
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return _maxFramesFec;
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool VCMNackFecMethod::BitRateTooLowForFec(
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const VCMProtectionParameters* parameters) {
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Bitrate below which we turn off FEC, regardless of reported packet loss.
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The condition should depend on resolution and content. For now, use
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // threshold on bytes per frame, with some effect for the frame size.
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The condition for turning off FEC is also based on other factors,
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // such as |_numLayers|, |_maxFramesFec|, and |_rtt|.
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int estimate_bytes_per_frame = 1000 * BitsPerFrame(parameters) / 8;
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int max_bytes_per_frame = kMaxBytesPerFrameForFec;
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  int num_pixels = parameters->codecWidth * parameters->codecHeight;
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (num_pixels <= 352 * 288) {
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    max_bytes_per_frame = kMaxBytesPerFrameForFecLow;
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  } else if (num_pixels > 640 * 480) {
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    max_bytes_per_frame = kMaxBytesPerFrameForFecHigh;
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // TODO (marpan): add condition based on maximum frames used for FEC,
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // and expand condition based on frame size.
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (estimate_bytes_per_frame < max_bytes_per_frame &&
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      parameters->numLayers < 3 &&
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      parameters->rtt < kMaxRttTurnOffFec) {
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return false;
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set the effective packet loss for encoder (based on FEC code).
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the effective packet loss and residual packet loss due to FEC.
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    VCMFecMethod::EffectivePacketLoss(parameters);
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ProtectionFactor(parameters);
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EffectivePacketLoss(parameters);
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _maxFramesFec = ComputeMaxFramesFec(parameters);
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (BitRateTooLowForFec(parameters)) {
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _protectionFactorK = 0;
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _protectionFactorD = 0;
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Efficiency computation is based on FEC and NACK
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Add FEC cost: ignore I frames for now
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _efficiency = parameters->bitRate * fecRate * _corrFecCost;
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Add NACK cost, when applicable
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // nackCost  = (bitRate - nackCost) * (lossPr)
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _efficiency += parameters->bitRate * _residualPacketLossFec /
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                       (1.0f + _residualPacketLossFec);
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Protection/fec rates obtained above are defined relative to total number
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // of packets (total rate: source + fec) FEC in RTP module assumes
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // protection factor is defined relative to source number of packets so we
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // should convert the factor to reduce mismatch between mediaOpt's rate and
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // the actual one
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorK = VCMFecMethod::ConvertFECRate(_protectionFactorK);
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorD = VCMFecMethod::ConvertFECRate(_protectionFactorD);
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackMethod::VCMNackMethod():
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod()
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _type = kNack;
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackMethod::~VCMNackMethod()
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackMethod::EffectivePacketLoss(const VCMProtectionParameters* parameter)
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Effective Packet Loss, NA in current version.
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _effectivePacketLoss = 0;
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the effective packet loss
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EffectivePacketLoss(parameters);
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // nackCost  = (bitRate - nackCost) * (lossPr)
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _efficiency = parameters->bitRate * parameters->lossPr /
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  (1.0f + parameters->lossPr);
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::VCMFecMethod():
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod()
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _type = kFec;
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::~VCMFecMethod()
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
256dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orguint8_t
257dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMFecMethod::BoostCodeRateKey(uint8_t packetFrameDelta,
258dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org                               uint8_t packetFrameKey) const
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
260dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t boostRateKey = 2;
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Default: ratio scales the FEC protection up for I frames
262dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t ratio = 1;
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (packetFrameDelta > 0)
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
266dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org        ratio = (int8_t) (packetFrameKey / packetFrameDelta);
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ratio = VCM_MAX(boostRateKey, ratio);
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return ratio;
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
273dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orguint8_t
274dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMFecMethod::ConvertFECRate(uint8_t codeRateRTP) const
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
276dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    return static_cast<uint8_t> (VCM_MIN(255,(0.5 + 255.0 * codeRateRTP /
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                      (float)(255 - codeRateRTP))));
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Update FEC with protectionFactorD
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
282dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMFecMethod::UpdateProtectionFactorD(uint8_t protectionFactorD)
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorD = protectionFactorD;
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Update FEC with protectionFactorK
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
289dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMFecMethod::UpdateProtectionFactorK(uint8_t protectionFactorK)
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorK = protectionFactorK;
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// AvgRecoveryFEC: computes the residual packet loss (RPL) function.
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// This is the average recovery from the FEC, assuming random packet loss model.
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Computed off-line for a range of FEC code parameters and loss rates.
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgfloat
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Total (avg) bits available per frame: total rate over actual/sent frame
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // rate units are kbits/frame
302dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint16_t bitRatePerFrame = static_cast<uint16_t>
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        (parameters->bitRate / (parameters->frameRate));
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Total (average) number of packets per frame (source and fec):
306dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t avgTotPackets = 1 + static_cast<uint8_t>
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        (static_cast<float> (bitRatePerFrame * 1000.0) /
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         static_cast<float> (8.0 * _maxPayloadSize) + 0.5);
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const float protectionFactor = static_cast<float>(_protectionFactorD) /
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                      255.0;
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
31311b3eb19f84236e8416d1bd7a53a00fca9fa22e1marpan@webrtc.org    // Round down for estimated #FEC packets/frame, to keep
31411b3eb19f84236e8416d1bd7a53a00fca9fa22e1marpan@webrtc.org    // |fecPacketsPerFrame| <= |sourcePacketsPerFrame|.
315dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t fecPacketsPerFrame = static_cast<uint8_t>
31611b3eb19f84236e8416d1bd7a53a00fca9fa22e1marpan@webrtc.org                                      (protectionFactor * avgTotPackets);
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
318dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if ( (fecPacketsPerFrame == 0) || (sourcePacketsPerFrame == 0) )
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // No protection, or rate too low: so average recovery from FEC == 0.
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0.0;
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Table defined up to kMaxNumPackets
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (sourcePacketsPerFrame > kMaxNumPackets)
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        sourcePacketsPerFrame = kMaxNumPackets;
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Table defined up to kMaxNumPackets
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (fecPacketsPerFrame > kMaxNumPackets)
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        fecPacketsPerFrame = kMaxNumPackets;
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Code index for tables: up to (kMaxNumPackets * kMaxNumPackets)
339dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint16_t codeIndexTable[kMaxNumPackets * kMaxNumPackets];
340dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint16_t k = 0;
341dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    for (uint8_t i = 1; i <= kMaxNumPackets; i++)
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
343dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org        for (uint8_t j = 1; j <= i; j++)
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            codeIndexTable[(j - 1) * kMaxNumPackets + i - 1] = k;
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            k += 1;
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
350dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t lossRate = static_cast<uint8_t> (255.0 *
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             parameters->lossPr + 0.5f);
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Constrain lossRate to 50%: tables defined up to 50%
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (lossRate >= kPacketLossMax)
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        lossRate = kPacketLossMax - 1;
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
359dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint16_t codeIndex = (fecPacketsPerFrame - 1) * kMaxNumPackets +
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     (sourcePacketsPerFrame - 1);
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
362dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint16_t indexTable = codeIndexTable[codeIndex] * kPacketLossMax +
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                      lossRate;
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check on table index
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(indexTable < kSizeAvgFECRecoveryXOR);
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float avgFecRecov = static_cast<float>(kAvgFECRecoveryXOR[indexTable]);
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return avgFecRecov;
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // No protection if (filtered) packetLoss is 0
378dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t packetLoss = (uint8_t) (255 * parameters->lossPr);
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (packetLoss == 0)
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _protectionFactorK = 0;
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _protectionFactorD = 0;
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org         return true;
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Parameters for FEC setting:
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // first partition size, thresholds, table pars, spatial resoln fac.
388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // First partition protection: ~ 20%
390dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t firstPartitionProt = (uint8_t) (255 * 0.20);
391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Minimum protection level needed to generate one FEC packet for one
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // source packet/frame (in RTP sender)
394dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t minProtLevelFec = 85;
395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // above which we allocate protection to cover at least first partition.
398dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t lossThr = 0;
399dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t packetNumThr = 1;
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Parameters for range of rate index of table.
402dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t ratePar1 = 5;
403dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t ratePar2 = 49;
404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Spatial resolution size, relative to a reference size.
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float spatialSizeToRef = static_cast<float>
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                           (parameters->codecWidth * parameters->codecHeight) /
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                           (static_cast<float>(704 * 576));
409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // resolnFac: This parameter will generally increase/decrease the FEC rate
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // (for fixed bitRate and packetLoss) based on system size.
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Use a smaller exponent (< 1) to control/soften system size effect.
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const float resolnFac = 1.0 / powf(spatialSizeToRef, 0.3f);
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const int bitRatePerFrame = BitsPerFrame(parameters);
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Average number of packets per frame (source and fec):
418dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t avgTotPackets = 1 + (uint8_t)
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        ((float) bitRatePerFrame * 1000.0
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       / (float) (8.0 * _maxPayloadSize) + 0.5);
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // FEC rate parameters: for P and I frame
423dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t codeRateDelta = 0;
424dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t codeRateKey = 0;
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Get index for table: the FEC protection depends on an effective rate.
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The range on the rate index corresponds to rates (bps)
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // from ~200k to ~8000k, for 30fps
429dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint16_t effRateFecTable = static_cast<uint16_t>
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           (resolnFac * bitRatePerFrame);
431dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t rateIndexTable =
432dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org        (uint8_t) VCM_MAX(VCM_MIN((effRateFecTable - ratePar1) /
433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         ratePar1, ratePar2), 0);
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Restrict packet loss range to 50:
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // current tables defined only up to 50%
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (packetLoss >= kPacketLossMax)
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        packetLoss = kPacketLossMax - 1;
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
441dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint16_t indexTable = rateIndexTable * kPacketLossMax + packetLoss;
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check on table index
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(indexTable < kSizeCodeRateXORTable);
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Protection factor for P frame
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    codeRateDelta = kCodeRateXORTable[indexTable];
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (packetLoss > lossThr && avgTotPackets > packetNumThr)
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Set a minimum based on first partition size.
452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (codeRateDelta < firstPartitionProt)
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            codeRateDelta = firstPartitionProt;
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check limit on amount of protection for P frame; 50% is max.
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (codeRateDelta >= kPacketLossMax)
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        codeRateDelta = kPacketLossMax - 1;
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
463b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float adjustFec = 1.0f;
465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Avoid additional adjustments when layers are active.
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // TODO(mikhal/marco): Update adjusmtent based on layer info.
467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (parameters->numLayers == 1)
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        adjustFec = _qmRobustness->AdjustFecFactor(codeRateDelta,
470b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   parameters->bitRate,
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   parameters->frameRate,
472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   parameters->rtt,
473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   packetLoss);
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
476dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    codeRateDelta = static_cast<uint8_t>(codeRateDelta * adjustFec);
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // For Key frame:
479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Effectively at a higher rate, so we scale/boost the rate
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The boost factor may depend on several factors: ratio of packet
481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // number of I to P frames, how much protection placed on P frames, etc.
482dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t packetFrameDelta = (uint8_t)
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           (0.5 + parameters->packetsPerFrame);
484dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t packetFrameKey = (uint8_t)
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         (0.5 + parameters->packetsPerFrameKey);
486dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    const uint8_t boostKey = BoostCodeRateKey(packetFrameDelta,
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                    packetFrameKey);
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
489dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    rateIndexTable = (uint8_t) VCM_MAX(VCM_MIN(
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                      1 + (boostKey * effRateFecTable - ratePar1) /
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                      ratePar1,ratePar2),0);
492dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint16_t indexTableKey = rateIndexTable * kPacketLossMax + packetLoss;
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    indexTableKey = VCM_MIN(indexTableKey, kSizeCodeRateXORTable);
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check on table index
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(indexTableKey < kSizeCodeRateXORTable);
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Protection factor for I frame
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    codeRateKey = kCodeRateXORTable[indexTableKey];
501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Boosting for Key frame.
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int boostKeyProt = _scaleProtKey * codeRateDelta;
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (boostKeyProt >= kPacketLossMax)
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        boostKeyProt = kPacketLossMax - 1;
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Make sure I frame protection is at least larger than P frame protection,
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // and at least as high as filtered packet loss.
511dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    codeRateKey = static_cast<uint8_t> (VCM_MAX(packetLoss,
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VCM_MAX(boostKeyProt, codeRateKey)));
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Check limit on amount of protection for I frame: 50% is max.
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (codeRateKey >= kPacketLossMax)
516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        codeRateKey = kPacketLossMax - 1;
518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorK = codeRateKey;
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorD = codeRateDelta;
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Generally there is a rate mis-match between the FEC cost estimated
524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // in mediaOpt and the actual FEC cost sent out in RTP module.
525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // This is more significant at low rates (small # of source packets), where
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // the granularity of the FEC decreases. In this case, non-zero protection
527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // in mediaOpt may generate 0 FEC packets in RTP sender (since actual #FEC
528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // is based on rounding off protectionFactor on actual source packet number).
529b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The correction factor (_corrFecCost) attempts to corrects this, at least
530b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // for cases of low rates (small #packets) and low protection levels.
531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float numPacketsFl = 1.0f + ((float) bitRatePerFrame * 1000.0
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                / (float) (8.0 * _maxPayloadSize) + 0.5);
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    const float estNumFecGen = 0.5f + static_cast<float> (_protectionFactorD *
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         numPacketsFl / 255.0f);
537b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
538b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
539b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // We reduce cost factor (which will reduce overhead for FEC and
540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // hybrid method) and not the protectionFactor.
541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _corrFecCost = 1.0f;
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (estNumFecGen < 1.1f && _protectionFactorD < minProtLevelFec)
543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _corrFecCost = 0.5f;
545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (estNumFecGen < 0.9f && _protectionFactorD < minProtLevelFec)
547b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
548b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _corrFecCost = 0.0f;
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     // TODO (marpan): Set the UEP protection on/off for Key and Delta frames
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _useUepProtectionK = _qmRobustness->SetUepProtection(codeRateKey,
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         parameters->bitRate,
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         packetLoss,
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         0);
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _useUepProtectionD = _qmRobustness->SetUepProtection(codeRateDelta,
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         parameters->bitRate,
559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         packetLoss,
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                         1);
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // DONE WITH FEC PROTECTION SETTINGS
563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VCMFecMethod::BitsPerFrame(const VCMProtectionParameters* parameters) {
567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // When temporal layers are available FEC will only be applied on the base
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // layer.
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const float bitRateRatio =
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    kVp8LayerRateAlloction[parameters->numLayers - 1][0];
571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float frameRateRatio = powf(1 / 2.0, parameters->numLayers - 1);
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float bitRate = parameters->bitRate * bitRateRatio;
573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float frameRate = parameters->frameRate * frameRateRatio;
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // TODO(mikhal): Update factor following testing.
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  float adjustmentFactor = 1;
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Average bits per frame (units of kbits)
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return static_cast<int>(adjustmentFactor * bitRate / frameRate);
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Effective packet loss to encoder is based on RPL (residual packet loss)
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // this is a soft setting based on degree of FEC protection
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // RPL = received/input packet loss - average_FEC_recovery
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // note: received/input packet loss may be filtered based on FilteredLoss
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The packet loss:
591dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t packetLoss = (uint8_t) (255 * parameters->lossPr);
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float avgFecRecov = AvgRecoveryFEC(parameters);
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Residual Packet Loss:
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _residualPacketLossFec = (float) (packetLoss - avgFecRecov) / 255.0f;
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Effective Packet Loss, NA in current version.
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _effectivePacketLoss = 0;
600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the protection factor
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ProtectionFactor(parameters);
609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the effective packet loss
611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EffectivePacketLoss(parameters);
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Compute the bit cost
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Ignore key frames for now.
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (fecRate >= 0.0f)
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // use this formula if the fecRate (protection factor) is defined
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // relative to number of source packets
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // this is the case for the previous tables:
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // in the new tables, the fecRate is defined relative to total number of
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // packets (total rate), so overhead cost is:
625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _efficiency = parameters->bitRate * fecRate * _corrFecCost;
626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _efficiency = 0.0f;
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Protection/fec rates obtained above is defined relative to total number
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // of packets (total rate: source+fec) FEC in RTP module assumes protection
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // factor is defined relative to source number of packets so we should
635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // convert the factor to reduce mismatch between mediaOpt suggested rate and
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // the actual rate
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorK = ConvertFECRate(_protectionFactorK);
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _protectionFactorD = ConvertFECRate(_protectionFactorD);
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::VCMLossProtectionLogic(int64_t nowMs):
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_selectedMethod(NULL),
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_currentParameters(),
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_rtt(0),
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_lossPr(0.0f),
647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_bitRate(0.0f),
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_frameRate(0.0f),
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_keyFrameSize(0.0f),
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_fecRateKey(0),
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_fecRateDelta(0),
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_lastPrUpdateT(0),
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_lossPr255(0.9999f),
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_lossPrHistory(),
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_shortMaxLossPr255(0),
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_packetsPerFrame(0.9999f),
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_packetsPerFrameKey(0.9999f),
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_residualPacketLossFec(0),
659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_codecWidth(0),
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_codecHeight(0),
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org_numLayers(1)
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Reset(nowMs);
664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::~VCMLossProtectionLogic()
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Release();
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::SetMethod(enum VCMProtectionMethodEnum newMethodType)
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_selectedMethod != NULL)
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_selectedMethod->Type() == newMethodType)
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Nothing to update
679b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return false;
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // New method - delete existing one
682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _selectedMethod;
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    VCMProtectionMethod *newMethod = NULL;
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    switch (newMethodType)
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        case kNack:
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            newMethod = new VCMNackMethod();
690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            break;
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        case kFec:
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            newMethod  = new VCMFecMethod();
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            break;
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        case kNackFec:
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Default to always having NACK enabled for the hybrid mode.
700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            newMethod =  new VCMNackFecMethod(kLowRttNackMs, -1);
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            break;
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        default:
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          return false;
706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          break;
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _selectedMethod = newMethod;
711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::RemoveMethod(enum VCMProtectionMethodEnum method)
715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_selectedMethod == NULL)
717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else if (_selectedMethod->Type() == method)
721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete _selectedMethod;
723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _selectedMethod = NULL;
724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return true;
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgfloat
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::RequiredBitRate() const
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    float RequiredBitRate = 0.0f;
732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_selectedMethod != NULL)
733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RequiredBitRate = _selectedMethod->RequiredBitRate();
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return RequiredBitRate;
737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
740dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMLossProtectionLogic::UpdateRtt(uint32_t rtt)
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _rtt = rtt;
743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _residualPacketLossFec = residualPacketLoss;
749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
752dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMLossProtectionLogic::UpdateMaxLossHistory(uint8_t lossPr255,
753dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org                                             int64_t now)
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_lossPrHistory[0].timeMs >= 0 &&
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (lossPr255 > _shortMaxLossPr255)
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shortMaxLossPr255 = lossPr255;
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Only add a new value to the history once a second
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_lossPrHistory[0].timeMs == -1)
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // First, no shift
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shortMaxLossPr255 = lossPr255;
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        else
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Shift
774dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org            for (int32_t i = (kLossPrHistorySize - 2); i >= 0; i--)
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shortMaxLossPr255 == 0)
781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shortMaxLossPr255 = lossPr255;
783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _lossPrHistory[0].timeMs = now;
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shortMaxLossPr255 = 0;
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
791dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orguint8_t
792dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMLossProtectionLogic::MaxFilteredLossPr(int64_t nowMs) const
793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
794dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t maxFound = _shortMaxLossPr255;
795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_lossPrHistory[0].timeMs == -1)
796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
797b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return maxFound;
798b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
799dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    for (int32_t i = 0; i < kLossPrHistorySize; i++)
800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_lossPrHistory[i].timeMs == -1)
802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            break;
804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (nowMs - _lossPrHistory[i].timeMs >
806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            kLossPrHistorySize * kLossPrShortFilterWinMs)
807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // This sample (and all samples after this) is too old
809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            break;
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_lossPrHistory[i].lossPr255 > maxFound)
812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // This sample is the largest one this far into the history
814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            maxFound = _lossPrHistory[i].lossPr255;
815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return maxFound;
818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
820dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orguint8_t VCMLossProtectionLogic::FilteredLoss(
821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int64_t nowMs,
822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    FilterPacketLossMode filter_mode,
823dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    uint8_t lossPr255) {
824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Update the max window filter.
826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  UpdateMaxLossHistory(lossPr255, nowMs);
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Update the recursive average filter.
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  _lossPr255.Apply(static_cast<float> (nowMs - _lastPrUpdateT),
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                   static_cast<float> (lossPr255));
831b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  _lastPrUpdateT = nowMs;
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
833b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Filtered loss: default is received loss (no filtering).
834dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org  uint8_t filtered_loss = lossPr255;
835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
836b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  switch (filter_mode) {
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case kNoFilter:
838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      break;
839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case kAvgFilter:
84031b38da0e2ba9778d241267f0cf1ba8dd2f36e83minyue@webrtc.org      filtered_loss = static_cast<uint8_t>(_lossPr255.filtered() + 0.5);
841b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      break;
842b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    case kMaxFilter:
843b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      filtered_loss = MaxFilteredLossPr(nowMs);
844b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      break;
845b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
846b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
847b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return filtered_loss;
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
851dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMLossProtectionLogic::UpdateFilteredLossPr(uint8_t packetLossEnc)
852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lossPr = (float) packetLossEnc / (float) 255.0;
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
855b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdateBitRate(float bitRate)
858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _bitRate = bitRate;
860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets, int64_t nowMs)
864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _packetsPerFrame.Apply(static_cast<float>(nowMs - _lastPacketPerFrameUpdateT),
866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                           nPackets);
867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastPacketPerFrameUpdateT = nowMs;
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets, int64_t nowMs)
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _packetsPerFrameKey.Apply(static_cast<float>(nowMs -
874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                              _lastPacketPerFrameUpdateTKey), nPackets);
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastPacketPerFrameUpdateTKey = nowMs;
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _keyFrameSize = keyFrameSize;
882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
883b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
884b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
885dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.orgVCMLossProtectionLogic::UpdateFrameSize(uint16_t width,
886dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org                                        uint16_t height)
887b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
888b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _codecWidth = width;
889b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _codecHeight = height;
890b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
891b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
892b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid VCMLossProtectionLogic::UpdateNumLayers(int numLayers) {
893b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  _numLayers = (numLayers == 0) ? 1 : numLayers;
894b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
896b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool
897b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::UpdateMethod()
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_selectedMethod == NULL)
900b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return false;
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.rtt = _rtt;
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.lossPr = _lossPr;
905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.bitRate = _bitRate;
906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.frameRate = _frameRate; // rename actual frame rate?
907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.keyFrameSize = _keyFrameSize;
908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.fecRateDelta = _fecRateDelta;
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.fecRateKey = _fecRateKey;
91031b38da0e2ba9778d241267f0cf1ba8dd2f36e83minyue@webrtc.org    _currentParameters.packetsPerFrame = _packetsPerFrame.filtered();
91131b38da0e2ba9778d241267f0cf1ba8dd2f36e83minyue@webrtc.org    _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered();
912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.residualPacketLossFec = _residualPacketLossFec;
913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.codecWidth = _codecWidth;
914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.codecHeight = _codecHeight;
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _currentParameters.numLayers = _numLayers;
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _selectedMethod->UpdateParameters(&_currentParameters);
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethod*
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::SelectedMethod() const
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _selectedMethod;
923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMProtectionMethodEnum
926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::SelectedType() const
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _selectedMethod->Type();
929b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::Reset(int64_t nowMs)
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastPrUpdateT = nowMs;
935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastPacketPerFrameUpdateT = nowMs;
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastPacketPerFrameUpdateTKey = nowMs;
937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lossPr255.Reset(0.9999f);
938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _packetsPerFrame.Reset(0.9999f);
939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _fecRateDelta = _fecRateKey = 0;
940dba5f4541529da6ce75cc634834a9197e610731bpbos@webrtc.org    for (int32_t i = 0; i < kLossPrHistorySize; i++)
941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _lossPrHistory[i].lossPr255 = 0;
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _lossPrHistory[i].timeMs = -1;
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _shortMaxLossPr255 = 0;
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    Release();
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid
950b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVCMLossProtectionLogic::Release()
951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete _selectedMethod;
953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _selectedMethod = NULL;
954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
956bb78b2c7ce8cc4445811d0e881890a29b14a4f2bstefan@webrtc.org}  // namespace media_optimization
957bb78b2c7ce8cc4445811d0e881890a29b14a4f2bstefan@webrtc.org}  // namespace webrtc
958