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