diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index b29884e585..8c4dae57b5 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -106,7 +106,8 @@ SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( max_sent_width_per_timestamp_(0), max_sent_height_per_timestamp_(0), input_frame_rate_tracker_(100, 10u), - sent_frame_rate_tracker_(100, 10u), + input_fps_counter_(clock, nullptr, true), + sent_fps_counter_(clock, nullptr, true), first_rtcp_stats_time_ms_(-1), first_rtp_stats_time_ms_(-1), start_stats_(stats) {} @@ -132,28 +133,38 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( const VideoSendStream::Stats& current_stats) { RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix); const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0; + const int kMinRequiredPeriodicSamples = 6; int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples); int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples); - int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate()); if (in_width != -1) { RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels", in_width); RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels", in_height); - RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond", - in_fps); } + AggregatedStats in_fps = input_fps_counter_.GetStats(); + if (in_fps.num_samples >= kMinRequiredPeriodicSamples) { + RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond", + in_fps.average); + LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString(); + } + int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples); int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples); - int sent_fps = round(sent_frame_rate_tracker_.ComputeTotalRate()); if (sent_width != -1) { RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels", sent_width); RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels", sent_height); - RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond", - sent_fps); } + AggregatedStats sent_fps = sent_fps_counter_.GetStats(); + if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) { + RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond", + sent_fps.average); + LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, " + << sent_fps.ToString(); + } + int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples); if (encode_ms != -1) { RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs", @@ -389,6 +400,11 @@ void SendStatisticsProxy::OnEncodedFrameTimeMeasured( void SendStatisticsProxy::OnSuspendChange(bool is_suspended) { rtc::CritScope lock(&crit_); stats_.suspended = is_suspended; + // Pause framerate stats. + if (is_suspended) { + uma_container_->input_fps_counter_.ProcessAndPause(); + uma_container_->sent_fps_counter_.ProcessAndPause(); + } } VideoSendStream::Stats SendStatisticsProxy::GetStats() { @@ -541,7 +557,7 @@ void SendStatisticsProxy::OnSendEncodedImage( // are encoded before the next start. if (last_sent_frame_timestamp_ > 0 && encoded_image._timeStamp != last_sent_frame_timestamp_) { - uma_container_->sent_frame_rate_tracker_.AddSamples(1); + uma_container_->sent_fps_counter_.Add(1); uma_container_->sent_width_counter_.Add( uma_container_->max_sent_width_per_timestamp_); uma_container_->sent_height_counter_.Add( @@ -566,6 +582,7 @@ int SendStatisticsProxy::GetSendFrameRate() const { void SendStatisticsProxy::OnIncomingFrame(int width, int height) { rtc::CritScope lock(&crit_); uma_container_->input_frame_rate_tracker_.AddSamples(1); + uma_container_->input_fps_counter_.Add(1); uma_container_->input_width_counter_.Add(width); uma_container_->input_height_counter_.Add(height); uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution); diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index fff2d8ded8..803fb61f14 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -26,6 +26,7 @@ #include "webrtc/system_wrappers/include/clock.h" #include "webrtc/video/overuse_frame_detector.h" #include "webrtc/video/report_block_stats.h" +#include "webrtc/video/stats_counter.h" #include "webrtc/video/vie_encoder.h" #include "webrtc/video_send_stream.h" @@ -187,7 +188,8 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, SampleCounter delay_counter_; SampleCounter max_delay_counter_; rtc::RateTracker input_frame_rate_tracker_; - rtc::RateTracker sent_frame_rate_tracker_; + RateCounter input_fps_counter_; + RateCounter sent_fps_counter_; int64_t first_rtcp_stats_time_ms_; int64_t first_rtp_stats_time_ms_; ReportBlockStats report_block_stats_; diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index f88d026516..aa7c14f1a1 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -26,7 +26,9 @@ const uint32_t kSecondSsrc = 42; const uint32_t kFirstRtxSsrc = 18; const uint32_t kSecondRtxSsrc = 43; const uint32_t kFlexFecSsrc = 55; - +const int kFpsPeriodicIntervalMs = 2000; +const int kWidth = 640; +const int kHeight = 480; const int kQpIdx0 = 21; const int kQpIdx1 = 39; } // namespace @@ -353,9 +355,6 @@ TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) { } TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { - const int kWidth = 640; - const int kHeight = 480; - for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight); @@ -371,10 +370,110 @@ TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); } -TEST_F(SendStatisticsProxyTest, CpuLimitedResolutionUpdated) { - const int kWidth = 640; - const int kHeight = 480; +TEST_F(SendStatisticsProxyTest, InputResolutionHistogramsAreUpdated) { + for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) + statistics_proxy_->OnIncomingFrame(kWidth, kHeight); + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputWidthInPixels", kWidth)); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputHeightInPixels")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputHeightInPixels", kHeight)); +} + +TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) { + EncodedImage encoded_image; + encoded_image._encodedWidth = kWidth; + encoded_image._encodedHeight = kHeight; + for (int i = 0; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) { + encoded_image._timeStamp = i + 1; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentWidthInPixels")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentWidthInPixels", kWidth)); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentHeightInPixels")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentHeightInPixels", kHeight)); +} + +TEST_F(SendStatisticsProxyTest, InputFpsHistogramIsUpdated) { + const int kFps = 20; + const int kMinPeriodicSamples = 6; + int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000; + for (int i = 0; i <= frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + statistics_proxy_->OnIncomingFrame(kWidth, kHeight); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps)); +} + +TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) { + EncodedImage encoded_image; + const int kFps = 20; + const int kMinPeriodicSamples = 6; + int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1; + for (int i = 0; i <= frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp = i + 1; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps)); +} + +TEST_F(SendStatisticsProxyTest, InputFpsHistogramExcludesSuspendedTime) { + const int kFps = 20; + const int kSuspendTimeMs = 10000; + const int kMinPeriodicSamples = 6; + int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000; + for (int i = 0; i < frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + statistics_proxy_->OnIncomingFrame(kWidth, kHeight); + } + // Suspend. + statistics_proxy_->OnSuspendChange(true); + fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs); + + for (int i = 0; i < frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + statistics_proxy_->OnIncomingFrame(kWidth, kHeight); + } + // Suspended time interval should not affect the framerate. + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps)); +} + +TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) { + EncodedImage encoded_image; + const int kFps = 20; + const int kSuspendTimeMs = 10000; + const int kMinPeriodicSamples = 6; + int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000; + for (int i = 0; i <= frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp = i + 1; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } + // Suspend. + statistics_proxy_->OnSuspendChange(true); + fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs); + + for (int i = 0; i <= frames; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp = i + 1; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } + // Suspended time interval should not affect the framerate. + statistics_proxy_.reset(); + EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond")); + EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps)); +} + +TEST_F(SendStatisticsProxyTest, CpuLimitedResolutionUpdated) { for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight);