| Index: webrtc/video/receive_statistics_proxy.cc
|
| diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc
|
| index 15a2206589efd1b66eff41f3002429354bbbcd9f..6bf9a74cf9fdc8ba9273a37f136c50131e82697e 100644
|
| --- a/webrtc/video/receive_statistics_proxy.cc
|
| +++ b/webrtc/video/receive_statistics_proxy.cc
|
| @@ -13,6 +13,7 @@
|
| #include <cmath>
|
|
|
| #include "webrtc/base/checks.h"
|
| +#include "webrtc/base/logging.h"
|
| #include "webrtc/modules/video_coding/include/video_codec_interface.h"
|
| #include "webrtc/system_wrappers/include/clock.h"
|
| #include "webrtc/system_wrappers/include/field_trial.h"
|
| @@ -22,6 +23,22 @@ namespace webrtc {
|
| namespace {
|
| // Periodic time interval for processing samples for |freq_offset_counter_|.
|
| const int64_t kFreqOffsetProcessIntervalMs = 40000;
|
| +
|
| +// Configuration for bad call detection.
|
| +const int kMinSampleLengthMs = 990;
|
| +const int kNumMeasurements = 10;
|
| +const int kNumMeasurementsVariance = kNumMeasurements * 1.5;
|
| +const float kBadFraction = 0.8f;
|
| +// For fps:
|
| +// Low means low enough to be bad, high means high enough to be good
|
| +const int kLowFpsThreshold = 12;
|
| +const int kHighFpsThreshold = 14;
|
| +// For qp and fps variance:
|
| +// Low means low enough to be good, high means high enough to be bad
|
| +const int kLowQpThresholdVp8 = 60;
|
| +const int kHighQpThresholdVp8 = 70;
|
| +const int kLowVarianceThreshold = 1;
|
| +const int kHighVarianceThreshold = 2;
|
| } // namespace
|
|
|
| ReceiveStatisticsProxy::ReceiveStatisticsProxy(
|
| @@ -30,6 +47,19 @@ ReceiveStatisticsProxy::ReceiveStatisticsProxy(
|
| : clock_(clock),
|
| config_(*config),
|
| start_ms_(clock->TimeInMilliseconds()),
|
| + last_sample_time_(clock->TimeInMilliseconds()),
|
| + fps_threshold_(kLowFpsThreshold,
|
| + kHighFpsThreshold,
|
| + kBadFraction,
|
| + kNumMeasurements),
|
| + qp_threshold_(kLowQpThresholdVp8,
|
| + kHighQpThresholdVp8,
|
| + kBadFraction,
|
| + kNumMeasurements),
|
| + variance_threshold_(kLowVarianceThreshold,
|
| + kHighVarianceThreshold,
|
| + kBadFraction,
|
| + kNumMeasurementsVariance),
|
| // 1000ms window, scale 1000 for ms to s.
|
| decode_fps_estimator_(1000, 1000),
|
| renders_fps_estimator_(1000, 1000),
|
| @@ -173,6 +203,67 @@ void ReceiveStatisticsProxy::UpdateHistograms() {
|
| }
|
| }
|
|
|
| +void ReceiveStatisticsProxy::QualitySample() {
|
| + int64_t now = clock_->TimeInMilliseconds();
|
| + if (last_sample_time_ + kMinSampleLengthMs > now)
|
| + return;
|
| +
|
| + double fps =
|
| + render_fps_tracker_.ComputeRateForInterval(now - last_sample_time_);
|
| + int qp = qp_sample_.Avg(1);
|
| +
|
| + bool prev_fps_bad = !fps_threshold_.IsHigh().value_or(true);
|
| + bool prev_qp_bad = qp_threshold_.IsHigh().value_or(false);
|
| + bool prev_variance_bad = variance_threshold_.IsHigh().value_or(false);
|
| + bool prev_any_bad = prev_fps_bad || prev_qp_bad || prev_variance_bad;
|
| +
|
| + fps_threshold_.AddMeasurement(static_cast<int>(fps));
|
| + if (qp != -1)
|
| + qp_threshold_.AddMeasurement(qp);
|
| + rtc::Optional<double> fps_variance_opt = fps_threshold_.CalculateVariance();
|
| + double fps_variance = fps_variance_opt.value_or(0);
|
| + if (fps_variance_opt) {
|
| + variance_threshold_.AddMeasurement(static_cast<int>(fps_variance));
|
| + }
|
| +
|
| + bool fps_bad = !fps_threshold_.IsHigh().value_or(true);
|
| + bool qp_bad = qp_threshold_.IsHigh().value_or(false);
|
| + bool variance_bad = variance_threshold_.IsHigh().value_or(false);
|
| + bool any_bad = fps_bad || qp_bad || variance_bad;
|
| +
|
| + if (!prev_any_bad && any_bad) {
|
| + LOG(LS_WARNING) << "Bad call (any) start: " << now;
|
| + } else if (prev_any_bad && !any_bad) {
|
| + LOG(LS_WARNING) << "Bad call (any) end: " << now;
|
| + }
|
| +
|
| + if (!prev_fps_bad && fps_bad) {
|
| + LOG(LS_WARNING) << "Bad call (fps) start: " << now;
|
| + } else if (prev_fps_bad && !fps_bad) {
|
| + LOG(LS_WARNING) << "Bad call (fps) end: " << now;
|
| + }
|
| +
|
| + if (!prev_qp_bad && qp_bad) {
|
| + LOG(LS_WARNING) << "Bad call (qp) start: " << now;
|
| + } else if (prev_qp_bad && !qp_bad) {
|
| + LOG(LS_WARNING) << "Bad call (qp) end: " << now;
|
| + }
|
| +
|
| + if (!prev_variance_bad && variance_bad) {
|
| + LOG(LS_WARNING) << "Bad call (variance) start: " << now;
|
| + } else if (prev_variance_bad && !variance_bad) {
|
| + LOG(LS_WARNING) << "Bad call (variance) end: " << now;
|
| + }
|
| +
|
| + LOG(LS_INFO) << "SAMPLE: sample_length: " << (now - last_sample_time_)
|
| + << " fps: " << fps << " fps_bad: " << fps_bad << " qp: " << qp
|
| + << " qp_bad: " << qp_bad << " variance_bad: " << variance_bad
|
| + << " fps_variance: " << fps_variance;
|
| +
|
| + last_sample_time_ = now;
|
| + qp_sample_.Reset();
|
| +}
|
| +
|
| VideoReceiveStream::Stats ReceiveStatisticsProxy::GetStats() const {
|
| rtc::CritScope lock(&crit_);
|
| return stats_;
|
| @@ -191,6 +282,7 @@ void ReceiveStatisticsProxy::OnDecoderImplementationName(
|
| void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate,
|
| unsigned int bitrate_bps) {
|
| rtc::CritScope lock(&crit_);
|
| + QualitySample();
|
| stats_.network_frame_rate = framerate;
|
| stats_.total_bitrate_bps = bitrate_bps;
|
| }
|
| @@ -340,6 +432,8 @@ void ReceiveStatisticsProxy::OnPreDecode(
|
| }
|
| if (codec_specific_info->codecType == kVideoCodecVP8) {
|
| qp_counters_.vp8.Add(encoded_image.qp_);
|
| + rtc::CritScope lock(&crit_);
|
| + qp_sample_.Add(encoded_image.qp_);
|
| }
|
| }
|
|
|
| @@ -354,4 +448,9 @@ int ReceiveStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
|
| return sum / num_samples;
|
| }
|
|
|
| +void ReceiveStatisticsProxy::SampleCounter::Reset() {
|
| + num_samples = 0;
|
| + sum = 0;
|
| +}
|
| +
|
| } // namespace webrtc
|
|
|