From b9b07eaf281ab29e004565296f49fe39e76c8fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85sa=20Persson?= Date: Wed, 24 Jan 2018 17:04:07 +0100 Subject: [PATCH] Move stats for decoded frames per second from VCMTiming to ReceiveStatisticsProxy. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: none Change-Id: I631a2b1cb550dded6d1e1daf47ac35583298d30d Reviewed-on: https://webrtc-review.googlesource.com/36121 Commit-Queue: Åsa Persson Reviewed-by: Rasmus Brandt Cr-Commit-Position: refs/heads/master@{#21757} --- modules/video_coding/timing.cc | 4 +- video/receive_statistics_proxy.cc | 15 ++++++++ video/receive_statistics_proxy.h | 1 + video/receive_statistics_proxy_unittest.cc | 45 ++++++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/modules/video_coding/timing.cc b/modules/video_coding/timing.cc index 8df86dcd63..64e2465a9d 100644 --- a/modules/video_coding/timing.cc +++ b/modules/video_coding/timing.cc @@ -50,6 +50,7 @@ VCMTiming::~VCMTiming() { } } +// TODO(asapersson): Move stats to ReceiveStatisticsProxy. void VCMTiming::UpdateHistograms() const { rtc::CritScope cs(&crit_sect_); if (num_decoded_frames_ == 0) { @@ -60,9 +61,6 @@ void VCMTiming::UpdateHistograms() const { if (elapsed_sec < metrics::kMinRunTimeInSeconds) { return; } - RTC_HISTOGRAM_COUNTS_100( - "WebRTC.Video.DecodedFramesPerSecond", - static_cast((num_decoded_frames_ / elapsed_sec) + 0.5f)); RTC_HISTOGRAM_PERCENTAGE( "WebRTC.Video.DelayedFramesToRenderer", num_delayed_decoded_frames_ * 100 / num_decoded_frames_); diff --git a/video/receive_statistics_proxy.cc b/video/receive_statistics_proxy.cc index 7bde5d00d9..9e652c1195 100644 --- a/video/receive_statistics_proxy.cc +++ b/video/receive_statistics_proxy.cc @@ -18,6 +18,7 @@ #include "modules/video_coding/include/video_codec_interface.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" +#include "rtc_base/timeutils.h" #include "system_wrappers/include/clock.h" #include "system_wrappers/include/metrics.h" @@ -146,6 +147,18 @@ void ReceiveStatisticsProxy::UpdateHistograms() { } } + if (first_decoded_frame_time_ms_) { + const int64_t elapsed_ms = + (clock_->TimeInMilliseconds() - *first_decoded_frame_time_ms_); + if (elapsed_ms >= + metrics::kMinRunTimeInSeconds * rtc::kNumMillisecsPerSec) { + RTC_HISTOGRAM_COUNTS_100( + "WebRTC.Video.DecodedFramesPerSecond", + static_cast((stats_.frames_decoded * 1000.0f / elapsed_ms) + + 0.5f)); + } + } + const int kMinRequiredSamples = 200; int samples = static_cast(render_fps_tracker_.TotalSampleCount()); if (samples >= kMinRequiredSamples) { @@ -664,6 +677,8 @@ void ReceiveStatisticsProxy::OnDecodedFrame(rtc::Optional qp, interframe_delay_ms); content_specific_stats->flow_duration_ms += interframe_delay_ms; } + if (stats_.frames_decoded == 1) + first_decoded_frame_time_ms_.emplace(now); last_decoded_frame_time_ms_.emplace(now); } diff --git a/video/receive_statistics_proxy.h b/video/receive_statistics_proxy.h index 0e0c5b45b5..bdeee86343 100644 --- a/video/receive_statistics_proxy.h +++ b/video/receive_statistics_proxy.h @@ -182,6 +182,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback, int64_t avg_rtt_ms_ RTC_GUARDED_BY(crit_); mutable std::map frame_window_ RTC_GUARDED_BY(&crit_); VideoContentType last_content_type_ RTC_GUARDED_BY(&crit_); + rtc::Optional first_decoded_frame_time_ms_ RTC_GUARDED_BY(&crit_); rtc::Optional last_decoded_frame_time_ms_ RTC_GUARDED_BY(&crit_); // Mutable because calling Max() on MovingMaxCounter is not const. Yet it is // called from const GetStats(). diff --git a/video/receive_statistics_proxy_unittest.cc b/video/receive_statistics_proxy_unittest.cc index 2a536907ec..d604429939 100644 --- a/video/receive_statistics_proxy_unittest.cc +++ b/video/receive_statistics_proxy_unittest.cc @@ -76,6 +76,51 @@ TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameIncreasesFramesDecoded) { } } +TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsReported) { + const int kFps = 20; + const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps; + for (int i = 0; i < kRequiredSamples; ++i) { + statistics_proxy_->OnDecodedFrame(rtc::Optional(), + VideoContentType::UNSPECIFIED); + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps)); +} + +TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsNotReportedForTooFewSamples) { + const int kFps = 20; + const int kRequiredSamples = metrics::kMinRunTimeInSeconds * kFps; + for (int i = 0; i < kRequiredSamples - 1; ++i) { + statistics_proxy_->OnDecodedFrame(rtc::Optional(), + VideoContentType::UNSPECIFIED); + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + } + statistics_proxy_.reset(); + EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond")); +} + +TEST_F(ReceiveStatisticsProxyTest, DecodedFpsIsReportedWithQpReset) { + const int kFps1 = 10; + for (int i = 0; i < metrics::kMinRunTimeInSeconds * kFps1; ++i) { + statistics_proxy_->OnDecodedFrame(rtc::Optional(), + VideoContentType::UNSPECIFIED); + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps1); + } + // First QP value received, resets frames decoded. + const int kFps2 = 20; + for (int i = 0; i < metrics::kMinRunTimeInSeconds * kFps2; ++i) { + statistics_proxy_->OnDecodedFrame(rtc::Optional(1u), + VideoContentType::UNSPECIFIED); + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps2); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond")); + EXPECT_EQ(1, + metrics::NumEvents("WebRTC.Video.DecodedFramesPerSecond", kFps2)); +} + TEST_F(ReceiveStatisticsProxyTest, OnDecodedFrameWithQpResetsFramesDecoded) { EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_decoded); for (uint32_t i = 1; i <= 3; ++i) {