| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/modules/video_coding/main/source/internal_defines.h" | |
| 12 #include "webrtc/modules/video_coding/main/source/jitter_estimator.h" | |
| 13 #include "webrtc/modules/video_coding/main/source/rtt_filter.h" | |
| 14 #include "webrtc/system_wrappers/include/clock.h" | |
| 15 #include "webrtc/system_wrappers/include/field_trial.h" | |
| 16 | |
| 17 #include <assert.h> | |
| 18 #include <math.h> | |
| 19 #include <stdlib.h> | |
| 20 #include <string.h> | |
| 21 | |
| 22 namespace webrtc { | |
| 23 | |
| 24 enum { kStartupDelaySamples = 30 }; | |
| 25 enum { kFsAccuStartupSamples = 5 }; | |
| 26 enum { kMaxFramerateEstimate = 200 }; | |
| 27 | |
| 28 VCMJitterEstimator::VCMJitterEstimator(const Clock* clock, | |
| 29 int32_t vcmId, | |
| 30 int32_t receiverId) | |
| 31 : _vcmId(vcmId), | |
| 32 _receiverId(receiverId), | |
| 33 _phi(0.97), | |
| 34 _psi(0.9999), | |
| 35 _alphaCountMax(400), | |
| 36 _thetaLow(0.000001), | |
| 37 _nackLimit(3), | |
| 38 _numStdDevDelayOutlier(15), | |
| 39 _numStdDevFrameSizeOutlier(3), | |
| 40 _noiseStdDevs(2.33), // ~Less than 1% chance | |
| 41 // (look up in normal distribution table)... | |
| 42 _noiseStdDevOffset(30.0), // ...of getting 30 ms freezes | |
| 43 _rttFilter(), | |
| 44 fps_counter_(30), // TODO(sprang): Use an estimator with limit based on | |
| 45 // time, rather than number of samples. | |
| 46 low_rate_experiment_(kInit), | |
| 47 clock_(clock) { | |
| 48 Reset(); | |
| 49 } | |
| 50 | |
| 51 VCMJitterEstimator::~VCMJitterEstimator() { | |
| 52 } | |
| 53 | |
| 54 VCMJitterEstimator& | |
| 55 VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs) | |
| 56 { | |
| 57 if (this != &rhs) | |
| 58 { | |
| 59 memcpy(_thetaCov, rhs._thetaCov, sizeof(_thetaCov)); | |
| 60 memcpy(_Qcov, rhs._Qcov, sizeof(_Qcov)); | |
| 61 | |
| 62 _vcmId = rhs._vcmId; | |
| 63 _receiverId = rhs._receiverId; | |
| 64 _avgFrameSize = rhs._avgFrameSize; | |
| 65 _varFrameSize = rhs._varFrameSize; | |
| 66 _maxFrameSize = rhs._maxFrameSize; | |
| 67 _fsSum = rhs._fsSum; | |
| 68 _fsCount = rhs._fsCount; | |
| 69 _lastUpdateT = rhs._lastUpdateT; | |
| 70 _prevEstimate = rhs._prevEstimate; | |
| 71 _prevFrameSize = rhs._prevFrameSize; | |
| 72 _avgNoise = rhs._avgNoise; | |
| 73 _alphaCount = rhs._alphaCount; | |
| 74 _filterJitterEstimate = rhs._filterJitterEstimate; | |
| 75 _startupCount = rhs._startupCount; | |
| 76 _latestNackTimestamp = rhs._latestNackTimestamp; | |
| 77 _nackCount = rhs._nackCount; | |
| 78 _rttFilter = rhs._rttFilter; | |
| 79 } | |
| 80 return *this; | |
| 81 } | |
| 82 | |
| 83 // Resets the JitterEstimate | |
| 84 void | |
| 85 VCMJitterEstimator::Reset() | |
| 86 { | |
| 87 _theta[0] = 1/(512e3/8); | |
| 88 _theta[1] = 0; | |
| 89 _varNoise = 4.0; | |
| 90 | |
| 91 _thetaCov[0][0] = 1e-4; | |
| 92 _thetaCov[1][1] = 1e2; | |
| 93 _thetaCov[0][1] = _thetaCov[1][0] = 0; | |
| 94 _Qcov[0][0] = 2.5e-10; | |
| 95 _Qcov[1][1] = 1e-10; | |
| 96 _Qcov[0][1] = _Qcov[1][0] = 0; | |
| 97 _avgFrameSize = 500; | |
| 98 _maxFrameSize = 500; | |
| 99 _varFrameSize = 100; | |
| 100 _lastUpdateT = -1; | |
| 101 _prevEstimate = -1.0; | |
| 102 _prevFrameSize = 0; | |
| 103 _avgNoise = 0.0; | |
| 104 _alphaCount = 1; | |
| 105 _filterJitterEstimate = 0.0; | |
| 106 _latestNackTimestamp = 0; | |
| 107 _nackCount = 0; | |
| 108 _fsSum = 0; | |
| 109 _fsCount = 0; | |
| 110 _startupCount = 0; | |
| 111 _rttFilter.Reset(); | |
| 112 fps_counter_.Reset(); | |
| 113 } | |
| 114 | |
| 115 void | |
| 116 VCMJitterEstimator::ResetNackCount() | |
| 117 { | |
| 118 _nackCount = 0; | |
| 119 } | |
| 120 | |
| 121 // Updates the estimates with the new measurements | |
| 122 void | |
| 123 VCMJitterEstimator::UpdateEstimate(int64_t frameDelayMS, uint32_t frameSizeBytes
, | |
| 124 bool incompleteFrame /* = false */) | |
| 125 { | |
| 126 if (frameSizeBytes == 0) | |
| 127 { | |
| 128 return; | |
| 129 } | |
| 130 int deltaFS = frameSizeBytes - _prevFrameSize; | |
| 131 if (_fsCount < kFsAccuStartupSamples) | |
| 132 { | |
| 133 _fsSum += frameSizeBytes; | |
| 134 _fsCount++; | |
| 135 } | |
| 136 else if (_fsCount == kFsAccuStartupSamples) | |
| 137 { | |
| 138 // Give the frame size filter | |
| 139 _avgFrameSize = static_cast<double>(_fsSum) / | |
| 140 static_cast<double>(_fsCount); | |
| 141 _fsCount++; | |
| 142 } | |
| 143 if (!incompleteFrame || frameSizeBytes > _avgFrameSize) | |
| 144 { | |
| 145 double avgFrameSize = _phi * _avgFrameSize + | |
| 146 (1 - _phi) * frameSizeBytes; | |
| 147 if (frameSizeBytes < _avgFrameSize + 2 * sqrt(_varFrameSize)) | |
| 148 { | |
| 149 // Only update the average frame size if this sample wasn't a | |
| 150 // key frame | |
| 151 _avgFrameSize = avgFrameSize; | |
| 152 } | |
| 153 // Update the variance anyway since we want to capture cases where we on
ly get | |
| 154 // key frames. | |
| 155 _varFrameSize = VCM_MAX(_phi * _varFrameSize + (1 - _phi) * | |
| 156 (frameSizeBytes - avgFrameSize) * | |
| 157 (frameSizeBytes - avgFrameSize), 1.0); | |
| 158 } | |
| 159 | |
| 160 // Update max frameSize estimate | |
| 161 _maxFrameSize = VCM_MAX(_psi * _maxFrameSize, static_cast<double>(frameSizeB
ytes)); | |
| 162 | |
| 163 if (_prevFrameSize == 0) | |
| 164 { | |
| 165 _prevFrameSize = frameSizeBytes; | |
| 166 return; | |
| 167 } | |
| 168 _prevFrameSize = frameSizeBytes; | |
| 169 | |
| 170 // Only update the Kalman filter if the sample is not considered | |
| 171 // an extreme outlier. Even if it is an extreme outlier from a | |
| 172 // delay point of view, if the frame size also is large the | |
| 173 // deviation is probably due to an incorrect line slope. | |
| 174 double deviation = DeviationFromExpectedDelay(frameDelayMS, deltaFS); | |
| 175 | |
| 176 if (fabs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) || | |
| 177 frameSizeBytes > _avgFrameSize + _numStdDevFrameSizeOutlier * sqrt(_varF
rameSize)) | |
| 178 { | |
| 179 // Update the variance of the deviation from the | |
| 180 // line given by the Kalman filter | |
| 181 EstimateRandomJitter(deviation, incompleteFrame); | |
| 182 // Prevent updating with frames which have been congested by a large | |
| 183 // frame, and therefore arrives almost at the same time as that frame. | |
| 184 // This can occur when we receive a large frame (key frame) which | |
| 185 // has been delayed. The next frame is of normal size (delta frame), | |
| 186 // and thus deltaFS will be << 0. This removes all frame samples | |
| 187 // which arrives after a key frame. | |
| 188 if ((!incompleteFrame || deviation >= 0.0) && | |
| 189 static_cast<double>(deltaFS) > - 0.25 * _maxFrameSize) | |
| 190 { | |
| 191 // Update the Kalman filter with the new data | |
| 192 KalmanEstimateChannel(frameDelayMS, deltaFS); | |
| 193 } | |
| 194 } | |
| 195 else | |
| 196 { | |
| 197 int nStdDev = (deviation >= 0) ? _numStdDevDelayOutlier : -_numStdDevDel
ayOutlier; | |
| 198 EstimateRandomJitter(nStdDev * sqrt(_varNoise), incompleteFrame); | |
| 199 } | |
| 200 // Post process the total estimated jitter | |
| 201 if (_startupCount >= kStartupDelaySamples) | |
| 202 { | |
| 203 PostProcessEstimate(); | |
| 204 } | |
| 205 else | |
| 206 { | |
| 207 _startupCount++; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 // Updates the nack/packet ratio | |
| 212 void | |
| 213 VCMJitterEstimator::FrameNacked() | |
| 214 { | |
| 215 // Wait until _nackLimit retransmissions has been received, | |
| 216 // then always add ~1 RTT delay. | |
| 217 // TODO(holmer): Should we ever remove the additional delay if the | |
| 218 // the packet losses seem to have stopped? We could for instance scale | |
| 219 // the number of RTTs to add with the amount of retransmissions in a given | |
| 220 // time interval, or similar. | |
| 221 if (_nackCount < _nackLimit) | |
| 222 { | |
| 223 _nackCount++; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 // Updates Kalman estimate of the channel | |
| 228 // The caller is expected to sanity check the inputs. | |
| 229 void | |
| 230 VCMJitterEstimator::KalmanEstimateChannel(int64_t frameDelayMS, | |
| 231 int32_t deltaFSBytes) | |
| 232 { | |
| 233 double Mh[2]; | |
| 234 double hMh_sigma; | |
| 235 double kalmanGain[2]; | |
| 236 double measureRes; | |
| 237 double t00, t01; | |
| 238 | |
| 239 // Kalman filtering | |
| 240 | |
| 241 // Prediction | |
| 242 // M = M + Q | |
| 243 _thetaCov[0][0] += _Qcov[0][0]; | |
| 244 _thetaCov[0][1] += _Qcov[0][1]; | |
| 245 _thetaCov[1][0] += _Qcov[1][0]; | |
| 246 _thetaCov[1][1] += _Qcov[1][1]; | |
| 247 | |
| 248 // Kalman gain | |
| 249 // K = M*h'/(sigma2n + h*M*h') = M*h'/(1 + h*M*h') | |
| 250 // h = [dFS 1] | |
| 251 // Mh = M*h' | |
| 252 // hMh_sigma = h*M*h' + R | |
| 253 Mh[0] = _thetaCov[0][0] * deltaFSBytes + _thetaCov[0][1]; | |
| 254 Mh[1] = _thetaCov[1][0] * deltaFSBytes + _thetaCov[1][1]; | |
| 255 // sigma weights measurements with a small deltaFS as noisy and | |
| 256 // measurements with large deltaFS as good | |
| 257 if (_maxFrameSize < 1.0) | |
| 258 { | |
| 259 return; | |
| 260 } | |
| 261 double sigma = (300.0 * exp(-fabs(static_cast<double>(deltaFSBytes)) / | |
| 262 (1e0 * _maxFrameSize)) + 1) * sqrt(_varNoise); | |
| 263 if (sigma < 1.0) | |
| 264 { | |
| 265 sigma = 1.0; | |
| 266 } | |
| 267 hMh_sigma = deltaFSBytes * Mh[0] + Mh[1] + sigma; | |
| 268 if ((hMh_sigma < 1e-9 && hMh_sigma >= 0) || (hMh_sigma > -1e-9 && hMh_sigma
<= 0)) | |
| 269 { | |
| 270 assert(false); | |
| 271 return; | |
| 272 } | |
| 273 kalmanGain[0] = Mh[0] / hMh_sigma; | |
| 274 kalmanGain[1] = Mh[1] / hMh_sigma; | |
| 275 | |
| 276 // Correction | |
| 277 // theta = theta + K*(dT - h*theta) | |
| 278 measureRes = frameDelayMS - (deltaFSBytes * _theta[0] + _theta[1]); | |
| 279 _theta[0] += kalmanGain[0] * measureRes; | |
| 280 _theta[1] += kalmanGain[1] * measureRes; | |
| 281 | |
| 282 if (_theta[0] < _thetaLow) | |
| 283 { | |
| 284 _theta[0] = _thetaLow; | |
| 285 } | |
| 286 | |
| 287 // M = (I - K*h)*M | |
| 288 t00 = _thetaCov[0][0]; | |
| 289 t01 = _thetaCov[0][1]; | |
| 290 _thetaCov[0][0] = (1 - kalmanGain[0] * deltaFSBytes) * t00 - | |
| 291 kalmanGain[0] * _thetaCov[1][0]; | |
| 292 _thetaCov[0][1] = (1 - kalmanGain[0] * deltaFSBytes) * t01 - | |
| 293 kalmanGain[0] * _thetaCov[1][1]; | |
| 294 _thetaCov[1][0] = _thetaCov[1][0] * (1 - kalmanGain[1]) - | |
| 295 kalmanGain[1] * deltaFSBytes * t00; | |
| 296 _thetaCov[1][1] = _thetaCov[1][1] * (1 - kalmanGain[1]) - | |
| 297 kalmanGain[1] * deltaFSBytes * t01; | |
| 298 | |
| 299 // Covariance matrix, must be positive semi-definite | |
| 300 assert(_thetaCov[0][0] + _thetaCov[1][1] >= 0 && | |
| 301 _thetaCov[0][0] * _thetaCov[1][1] - _thetaCov[0][1] * _thetaCov[1][0]
>= 0 && | |
| 302 _thetaCov[0][0] >= 0); | |
| 303 } | |
| 304 | |
| 305 // Calculate difference in delay between a sample and the | |
| 306 // expected delay estimated by the Kalman filter | |
| 307 double | |
| 308 VCMJitterEstimator::DeviationFromExpectedDelay(int64_t frameDelayMS, | |
| 309 int32_t deltaFSBytes) const | |
| 310 { | |
| 311 return frameDelayMS - (_theta[0] * deltaFSBytes + _theta[1]); | |
| 312 } | |
| 313 | |
| 314 // Estimates the random jitter by calculating the variance of the | |
| 315 // sample distance from the line given by theta. | |
| 316 void VCMJitterEstimator::EstimateRandomJitter(double d_dT, | |
| 317 bool incompleteFrame) { | |
| 318 uint64_t now = clock_->TimeInMicroseconds(); | |
| 319 if (_lastUpdateT != -1) { | |
| 320 fps_counter_.AddSample(now - _lastUpdateT); | |
| 321 } | |
| 322 _lastUpdateT = now; | |
| 323 | |
| 324 if (_alphaCount == 0) { | |
| 325 assert(false); | |
| 326 return; | |
| 327 } | |
| 328 double alpha = | |
| 329 static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount); | |
| 330 _alphaCount++; | |
| 331 if (_alphaCount > _alphaCountMax) | |
| 332 _alphaCount = _alphaCountMax; | |
| 333 | |
| 334 if (LowRateExperimentEnabled()) { | |
| 335 // In order to avoid a low frame rate stream to react slower to changes, | |
| 336 // scale the alpha weight relative a 30 fps stream. | |
| 337 double fps = GetFrameRate(); | |
| 338 if (fps > 0.0) { | |
| 339 double rate_scale = 30.0 / fps; | |
| 340 // At startup, there can be a lot of noise in the fps estimate. | |
| 341 // Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps | |
| 342 // at sample #kStartupDelaySamples. | |
| 343 if (_alphaCount < kStartupDelaySamples) { | |
| 344 rate_scale = | |
| 345 (_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) / | |
| 346 kStartupDelaySamples; | |
| 347 } | |
| 348 alpha = pow(alpha, rate_scale); | |
| 349 } | |
| 350 } | |
| 351 | |
| 352 double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT; | |
| 353 double varNoise = | |
| 354 alpha * _varNoise + (1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise); | |
| 355 if (!incompleteFrame || varNoise > _varNoise) { | |
| 356 _avgNoise = avgNoise; | |
| 357 _varNoise = varNoise; | |
| 358 } | |
| 359 if (_varNoise < 1.0) { | |
| 360 // The variance should never be zero, since we might get | |
| 361 // stuck and consider all samples as outliers. | |
| 362 _varNoise = 1.0; | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 double | |
| 367 VCMJitterEstimator::NoiseThreshold() const | |
| 368 { | |
| 369 double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset
; | |
| 370 if (noiseThreshold < 1.0) | |
| 371 { | |
| 372 noiseThreshold = 1.0; | |
| 373 } | |
| 374 return noiseThreshold; | |
| 375 } | |
| 376 | |
| 377 // Calculates the current jitter estimate from the filtered estimates | |
| 378 double | |
| 379 VCMJitterEstimator::CalculateEstimate() | |
| 380 { | |
| 381 double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold(); | |
| 382 | |
| 383 // A very low estimate (or negative) is neglected | |
| 384 if (ret < 1.0) { | |
| 385 if (_prevEstimate <= 0.01) | |
| 386 { | |
| 387 ret = 1.0; | |
| 388 } | |
| 389 else | |
| 390 { | |
| 391 ret = _prevEstimate; | |
| 392 } | |
| 393 } | |
| 394 if (ret > 10000.0) // Sanity | |
| 395 { | |
| 396 ret = 10000.0; | |
| 397 } | |
| 398 _prevEstimate = ret; | |
| 399 return ret; | |
| 400 } | |
| 401 | |
| 402 void | |
| 403 VCMJitterEstimator::PostProcessEstimate() | |
| 404 { | |
| 405 _filterJitterEstimate = CalculateEstimate(); | |
| 406 } | |
| 407 | |
| 408 void | |
| 409 VCMJitterEstimator::UpdateRtt(int64_t rttMs) | |
| 410 { | |
| 411 _rttFilter.Update(rttMs); | |
| 412 } | |
| 413 | |
| 414 void | |
| 415 VCMJitterEstimator::UpdateMaxFrameSize(uint32_t frameSizeBytes) | |
| 416 { | |
| 417 if (_maxFrameSize < frameSizeBytes) | |
| 418 { | |
| 419 _maxFrameSize = frameSizeBytes; | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 // Returns the current filtered estimate if available, | |
| 424 // otherwise tries to calculate an estimate. | |
| 425 int VCMJitterEstimator::GetJitterEstimate(double rttMultiplier) { | |
| 426 double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER; | |
| 427 if (_filterJitterEstimate > jitterMS) | |
| 428 jitterMS = _filterJitterEstimate; | |
| 429 if (_nackCount >= _nackLimit) | |
| 430 jitterMS += _rttFilter.RttMs() * rttMultiplier; | |
| 431 | |
| 432 if (LowRateExperimentEnabled()) { | |
| 433 static const double kJitterScaleLowThreshold = 5.0; | |
| 434 static const double kJitterScaleHighThreshold = 10.0; | |
| 435 double fps = GetFrameRate(); | |
| 436 // Ignore jitter for very low fps streams. | |
| 437 if (fps < kJitterScaleLowThreshold) { | |
| 438 if (fps == 0.0) { | |
| 439 return jitterMS; | |
| 440 } | |
| 441 return 0; | |
| 442 } | |
| 443 | |
| 444 // Semi-low frame rate; scale by factor linearly interpolated from 0.0 at | |
| 445 // kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold. | |
| 446 if (fps < kJitterScaleHighThreshold) { | |
| 447 jitterMS = | |
| 448 (1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) * | |
| 449 (fps - kJitterScaleLowThreshold) * jitterMS; | |
| 450 } | |
| 451 } | |
| 452 | |
| 453 return static_cast<uint32_t>(jitterMS + 0.5); | |
| 454 } | |
| 455 | |
| 456 bool VCMJitterEstimator::LowRateExperimentEnabled() { | |
| 457 if (low_rate_experiment_ == kInit) { | |
| 458 std::string group = | |
| 459 webrtc::field_trial::FindFullName("WebRTC-ReducedJitterDelay"); | |
| 460 if (group == "Disabled") { | |
| 461 low_rate_experiment_ = kDisabled; | |
| 462 } else { | |
| 463 low_rate_experiment_ = kEnabled; | |
| 464 } | |
| 465 } | |
| 466 return low_rate_experiment_ == kEnabled ? true : false; | |
| 467 } | |
| 468 | |
| 469 double VCMJitterEstimator::GetFrameRate() const { | |
| 470 if (fps_counter_.count() == 0) | |
| 471 return 0; | |
| 472 | |
| 473 double fps = 1000000.0 / fps_counter_.ComputeMean(); | |
| 474 // Sanity check. | |
| 475 assert(fps >= 0.0); | |
| 476 if (fps > kMaxFramerateEstimate) { | |
| 477 fps = kMaxFramerateEstimate; | |
| 478 } | |
| 479 return fps; | |
| 480 } | |
| 481 | |
| 482 } | |
| OLD | NEW |