JitterEstimator: Remove old LowRate exp and add trial for upper bound.
The frame time deltas are now capped based on the current noise. This has been tested in various conditions using both screen content and typical mobile video settings, to produce delays that are not overly high screen content, and simultaneously not negatively affect mobile calls on really bad network that may have high natural jitter. Bug: webrtc:9898 Change-Id: I51ad279af156aba1b5cc75ae203334a34bce9d48 Reviewed-on: https://webrtc-review.googlesource.com/c/107349 Reviewed-by: Stefan Holmer <stefan@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25469}
This commit is contained in:
@ -14,19 +14,24 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "modules/video_coding/internal_defines.h"
|
||||
#include "modules/video_coding/rtt_filter.h"
|
||||
#include "rtc_base/experiments/jitter_upper_bound_experiment.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum { kStartupDelaySamples = 30 };
|
||||
enum { kFsAccuStartupSamples = 5 };
|
||||
enum { kMaxFramerateEstimate = 200 };
|
||||
enum { kNackCountTimeoutMs = 60000 };
|
||||
namespace {
|
||||
static constexpr uint32_t kStartupDelaySamples = 30;
|
||||
static constexpr int64_t kFsAccuStartupSamples = 5;
|
||||
static constexpr double kMaxFramerateEstimate = 200.0;
|
||||
static constexpr int64_t kNackCountTimeoutMs = 60000;
|
||||
static constexpr double kDefaultMaxTimestampDeviationInSigmas = 3.5;
|
||||
} // namespace
|
||||
|
||||
VCMJitterEstimator::VCMJitterEstimator(const Clock* clock,
|
||||
int32_t vcmId,
|
||||
@ -46,7 +51,9 @@ VCMJitterEstimator::VCMJitterEstimator(const Clock* clock,
|
||||
_rttFilter(),
|
||||
fps_counter_(30), // TODO(sprang): Use an estimator with limit based on
|
||||
// time, rather than number of samples.
|
||||
low_rate_experiment_(kInit),
|
||||
time_deviation_upper_bound_(
|
||||
JitterUpperBoundExperiment::GetUpperBoundSigmas().value_or(
|
||||
kDefaultMaxTimestampDeviationInSigmas)),
|
||||
clock_(clock) {
|
||||
Reset();
|
||||
}
|
||||
@ -76,6 +83,7 @@ VCMJitterEstimator& VCMJitterEstimator::operator=(
|
||||
_latestNackTimestamp = rhs._latestNackTimestamp;
|
||||
_nackCount = rhs._nackCount;
|
||||
_rttFilter = rhs._rttFilter;
|
||||
clock_ = rhs.clock_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -157,6 +165,12 @@ void VCMJitterEstimator::UpdateEstimate(int64_t frameDelayMS,
|
||||
}
|
||||
_prevFrameSize = frameSizeBytes;
|
||||
|
||||
// Cap frameDelayMS based on the current time deviation noise.
|
||||
int64_t max_time_deviation_ms =
|
||||
static_cast<int64_t>(time_deviation_upper_bound_ * sqrt(_varNoise) + 0.5);
|
||||
frameDelayMS = std::max(std::min(frameDelayMS, max_time_deviation_ms),
|
||||
-max_time_deviation_ms);
|
||||
|
||||
// Only update the Kalman filter if the sample is not considered
|
||||
// an extreme outlier. Even if it is an extreme outlier from a
|
||||
// delay point of view, if the frame size also is large the
|
||||
@ -306,22 +320,20 @@ void VCMJitterEstimator::EstimateRandomJitter(double d_dT,
|
||||
if (_alphaCount > _alphaCountMax)
|
||||
_alphaCount = _alphaCountMax;
|
||||
|
||||
if (LowRateExperimentEnabled()) {
|
||||
// In order to avoid a low frame rate stream to react slower to changes,
|
||||
// scale the alpha weight relative a 30 fps stream.
|
||||
double fps = GetFrameRate();
|
||||
if (fps > 0.0) {
|
||||
double rate_scale = 30.0 / fps;
|
||||
// At startup, there can be a lot of noise in the fps estimate.
|
||||
// Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
|
||||
// at sample #kStartupDelaySamples.
|
||||
if (_alphaCount < kStartupDelaySamples) {
|
||||
rate_scale =
|
||||
(_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) /
|
||||
kStartupDelaySamples;
|
||||
}
|
||||
alpha = pow(alpha, rate_scale);
|
||||
// In order to avoid a low frame rate stream to react slower to changes,
|
||||
// scale the alpha weight relative a 30 fps stream.
|
||||
double fps = GetFrameRate();
|
||||
if (fps > 0.0) {
|
||||
double rate_scale = 30.0 / fps;
|
||||
// At startup, there can be a lot of noise in the fps estimate.
|
||||
// Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
|
||||
// at sample #kStartupDelaySamples.
|
||||
if (_alphaCount < kStartupDelaySamples) {
|
||||
rate_scale =
|
||||
(_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) /
|
||||
kStartupDelaySamples;
|
||||
}
|
||||
alpha = pow(alpha, rate_scale);
|
||||
}
|
||||
|
||||
double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
|
||||
@ -393,41 +405,25 @@ int VCMJitterEstimator::GetJitterEstimate(double rttMultiplier) {
|
||||
if (_nackCount >= _nackLimit)
|
||||
jitterMS += _rttFilter.RttMs() * rttMultiplier;
|
||||
|
||||
if (LowRateExperimentEnabled()) {
|
||||
static const double kJitterScaleLowThreshold = 5.0;
|
||||
static const double kJitterScaleHighThreshold = 10.0;
|
||||
double fps = GetFrameRate();
|
||||
// Ignore jitter for very low fps streams.
|
||||
if (fps < kJitterScaleLowThreshold) {
|
||||
if (fps == 0.0) {
|
||||
return jitterMS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
|
||||
// kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
|
||||
if (fps < kJitterScaleHighThreshold) {
|
||||
jitterMS =
|
||||
(1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
|
||||
(fps - kJitterScaleLowThreshold) * jitterMS;
|
||||
static const double kJitterScaleLowThreshold = 5.0;
|
||||
static const double kJitterScaleHighThreshold = 10.0;
|
||||
double fps = GetFrameRate();
|
||||
// Ignore jitter for very low fps streams.
|
||||
if (fps < kJitterScaleLowThreshold) {
|
||||
if (fps == 0.0) {
|
||||
return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(jitterMS + 0.5);
|
||||
}
|
||||
|
||||
bool VCMJitterEstimator::LowRateExperimentEnabled() {
|
||||
if (low_rate_experiment_ == kInit) {
|
||||
std::string group =
|
||||
webrtc::field_trial::FindFullName("WebRTC-ReducedJitterDelay");
|
||||
if (group == "Disabled") {
|
||||
low_rate_experiment_ = kDisabled;
|
||||
} else {
|
||||
low_rate_experiment_ = kEnabled;
|
||||
}
|
||||
// Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
|
||||
// kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
|
||||
if (fps < kJitterScaleHighThreshold) {
|
||||
jitterMS = (1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
|
||||
(fps - kJitterScaleLowThreshold) * jitterMS;
|
||||
}
|
||||
return low_rate_experiment_ == kEnabled ? true : false;
|
||||
|
||||
return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
|
||||
}
|
||||
|
||||
double VCMJitterEstimator::GetFrameRate() const {
|
||||
|
||||
Reference in New Issue
Block a user