From fc6f3e5873da1098fd6513dd8566dbd8deeab234 Mon Sep 17 00:00:00 2001 From: Sergey Silkin Date: Wed, 3 Apr 2019 10:57:26 +0200 Subject: [PATCH] Include duration of pauses into sum of squared frames duration. Bug: webrtc:10502 Change-Id: Ie905c0c9e8ca8fe07be585ce5a0d75e9eed6e865 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/130499 Commit-Queue: Sergey Silkin Reviewed-by: Ilya Nikolaevskiy Cr-Commit-Position: refs/heads/master@{#27435} --- video/receive_statistics_proxy_unittest.cc | 35 ++++++++++------ video/video_quality_observer.cc | 49 ++++++++++++---------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/video/receive_statistics_proxy_unittest.cc b/video/receive_statistics_proxy_unittest.cc index e050137462..6f04588278 100644 --- a/video/receive_statistics_proxy_unittest.cc +++ b/video/receive_statistics_proxy_unittest.cc @@ -1263,30 +1263,41 @@ TEST_P(ReceiveStatisticsProxyTestWithContent, FreezesAreReported) { } TEST_P(ReceiveStatisticsProxyTestWithContent, HarmonicFrameRateIsReported) { - const int kInterFrameDelayMs = 33; - const int kFreezeDelayMs = 200; - const int kCallDurationMs = - kMinRequiredSamples * kInterFrameDelayMs + kFreezeDelayMs; + const int kFrameDurationMs = 33; + const int kFreezeDurationMs = 200; + const int kPauseDurationMs = 10000; + const int kCallDurationMs = kMinRequiredSamples * kFrameDurationMs + + kFreezeDurationMs + kPauseDurationMs; webrtc::VideoFrame frame = CreateFrame(kWidth, kHeight); for (int i = 0; i < kMinRequiredSamples; ++i) { - fake_clock_.AdvanceTimeMilliseconds(kInterFrameDelayMs); + fake_clock_.AdvanceTimeMilliseconds(kFrameDurationMs); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_); statistics_proxy_->OnRenderedFrame(frame); } - // Add extra freeze. - fake_clock_.AdvanceTimeMilliseconds(kFreezeDelayMs); + + // Freezes and pauses should be included into harmonic frame rate. + // Add freeze. + fake_clock_.AdvanceTimeMilliseconds(kFreezeDurationMs); + statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_); + statistics_proxy_->OnRenderedFrame(frame); + + // Add pause. + fake_clock_.AdvanceTimeMilliseconds(kPauseDurationMs); + statistics_proxy_->OnStreamInactive(); statistics_proxy_->OnDecodedFrame(frame, absl::nullopt, content_type_); statistics_proxy_->OnRenderedFrame(frame); statistics_proxy_.reset(); - double kSumSquaredInterframeDelaysSecs = + double kSumSquaredFrameDurationSecs = (kMinRequiredSamples - 1) * - (kInterFrameDelayMs / 1000.0 * kInterFrameDelayMs / 1000.0); - kSumSquaredInterframeDelaysSecs += - kFreezeDelayMs / 1000.0 * kFreezeDelayMs / 1000.0; + (kFrameDurationMs / 1000.0 * kFrameDurationMs / 1000.0); + kSumSquaredFrameDurationSecs += + kFreezeDurationMs / 1000.0 * kFreezeDurationMs / 1000.0; + kSumSquaredFrameDurationSecs += + kPauseDurationMs / 1000.0 * kPauseDurationMs / 1000.0; const int kExpectedHarmonicFrameRateFps = - std::round(kCallDurationMs / (1000 * kSumSquaredInterframeDelaysSecs)); + std::round(kCallDurationMs / (1000 * kSumSquaredFrameDurationSecs)); if (videocontenttypehelpers::IsScreenshare(content_type_)) { EXPECT_EQ(kExpectedHarmonicFrameRateFps, metrics::MinSample("WebRTC.Video.Screenshare.HarmonicFrameRate")); diff --git a/video/video_quality_observer.cc b/video/video_quality_observer.cc index 2f1bb1b925..df7d52fae0 100644 --- a/video/video_quality_observer.cc +++ b/video/video_quality_observer.cc @@ -146,35 +146,42 @@ void VideoQualityObserver::OnRenderedFrame(const VideoFrame& frame, auto blocky_frame_it = blocky_frames_.find(frame.timestamp()); - if (!is_paused_ && num_frames_rendered_ > 0) { + if (num_frames_rendered_ > 0) { // Process inter-frame delay. const int64_t interframe_delay_ms = now_ms - last_frame_rendered_ms_; const double interframe_delays_secs = interframe_delay_ms / 1000.0; + + // Sum of squared inter frame intervals is used to calculate the harmonic + // frame rate metric. The metric aims to reflect overall experience related + // to smoothness of video playback and includes both freezes and pauses. sum_squared_interframe_delays_secs_ += interframe_delays_secs * interframe_delays_secs; - render_interframe_delays_.AddSample(interframe_delay_ms); - bool was_freeze = false; - if (render_interframe_delays_.Size() >= kMinFrameSamplesToDetectFreeze) { - const absl::optional avg_interframe_delay = - render_interframe_delays_.GetAverageRoundedDown(); - RTC_DCHECK(avg_interframe_delay); - was_freeze = interframe_delay_ms >= - std::max(3 * *avg_interframe_delay, - *avg_interframe_delay + kMinIncreaseForFreezeMs); - } + if (!is_paused_) { + render_interframe_delays_.AddSample(interframe_delay_ms); - if (was_freeze) { - freezes_durations_.Add(interframe_delay_ms); - smooth_playback_durations_.Add(last_frame_rendered_ms_ - - last_unfreeze_time_ms_); - last_unfreeze_time_ms_ = now_ms; - } else { - // Count spatial metrics if there were no freeze. - time_in_resolution_ms_[current_resolution_] += interframe_delay_ms; + bool was_freeze = false; + if (render_interframe_delays_.Size() >= kMinFrameSamplesToDetectFreeze) { + const absl::optional avg_interframe_delay = + render_interframe_delays_.GetAverageRoundedDown(); + RTC_DCHECK(avg_interframe_delay); + was_freeze = interframe_delay_ms >= + std::max(3 * *avg_interframe_delay, + *avg_interframe_delay + kMinIncreaseForFreezeMs); + } - if (is_last_frame_blocky_) { - time_in_blocky_video_ms_ += interframe_delay_ms; + if (was_freeze) { + freezes_durations_.Add(interframe_delay_ms); + smooth_playback_durations_.Add(last_frame_rendered_ms_ - + last_unfreeze_time_ms_); + last_unfreeze_time_ms_ = now_ms; + } else { + // Count spatial metrics if there were no freeze. + time_in_resolution_ms_[current_resolution_] += interframe_delay_ms; + + if (is_last_frame_blocky_) { + time_in_blocky_video_ms_ += interframe_delay_ms; + } } } }