diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index 71d980addc..cea9ce73d4 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -305,8 +305,8 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( } if (first_rtp_stats_time_ms_ != -1) { - quality_scaling_timer_.Stop(clock_->TimeInMilliseconds()); - int64_t elapsed_sec = quality_scaling_timer_.total_ms / 1000; + quality_adapt_timer_.Stop(clock_->TimeInMilliseconds()); + int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000; if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { int quality_changes = current_stats.number_of_quality_adapt_changes - start_stats_.number_of_quality_adapt_changes; @@ -314,8 +314,8 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( uma_prefix_ + "AdaptChangesPerMinute.Quality", quality_changes * 60 / elapsed_sec); } - cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds()); - elapsed_sec = cpu_scaling_timer_.total_ms / 1000; + cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds()); + elapsed_sec = cpu_adapt_timer_.total_ms / 1000; if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { int cpu_changes = current_stats.number_of_cpu_adapt_changes - start_stats_.number_of_cpu_adapt_changes; @@ -510,14 +510,14 @@ void SendStatisticsProxy::OnSuspendChange(bool is_suspended) { uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs); uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs); // Stop adaptation stats. - uma_container_->cpu_scaling_timer_.Stop(now_ms); - uma_container_->quality_scaling_timer_.Stop(now_ms); + uma_container_->cpu_adapt_timer_.Stop(now_ms); + uma_container_->quality_adapt_timer_.Stop(now_ms); } else { // Start adaptation stats if scaling is enabled. if (cpu_downscales_ >= 0) - uma_container_->cpu_scaling_timer_.Start(now_ms); + uma_container_->cpu_adapt_timer_.Start(now_ms); if (quality_downscales_ >= 0) - uma_container_->quality_scaling_timer_.Start(now_ms); + uma_container_->quality_adapt_timer_.Start(now_ms); // Stop pause explicitly for stats that may be zero/not updated for some // time. uma_container_->rtx_byte_counter_.ProcessAndStopPause(); @@ -734,50 +734,53 @@ void SendStatisticsProxy::OnIncomingFrame(int width, int height) { "ssrc", rtp_config_.ssrcs[0]); } -void SendStatisticsProxy::SetCpuScalingStats(int num_cpu_downscales) { +void SendStatisticsProxy::SetAdaptationStats( + const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts) { rtc::CritScope lock(&crit_); - cpu_downscales_ = num_cpu_downscales; - stats_.cpu_limited_resolution = num_cpu_downscales > 0; - - if (num_cpu_downscales >= 0) { - // Scaling enabled. - if (!stats_.suspended) - uma_container_->cpu_scaling_timer_.Start(clock_->TimeInMilliseconds()); - return; - } - uma_container_->cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds()); + SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_); + SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_); + UpdateAdaptationStats(cpu_counts, quality_counts); } -void SendStatisticsProxy::SetQualityScalingStats(int num_quality_downscales) { +void SendStatisticsProxy::OnCpuAdaptationChanged( + const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts) { rtc::CritScope lock(&crit_); - quality_downscales_ = num_quality_downscales; - stats_.bw_limited_resolution = quality_downscales_ > 0; - - if (num_quality_downscales >= 0) { - // Scaling enabled. - if (!stats_.suspended) { - uma_container_->quality_scaling_timer_.Start( - clock_->TimeInMilliseconds()); - } - return; - } - uma_container_->quality_scaling_timer_.Stop(clock_->TimeInMilliseconds()); -} - -void SendStatisticsProxy::OnCpuRestrictedResolutionChanged( - bool cpu_restricted_resolution) { - rtc::CritScope lock(&crit_); - stats_.cpu_limited_resolution = cpu_restricted_resolution; ++stats_.number_of_cpu_adapt_changes; + UpdateAdaptationStats(cpu_counts, quality_counts); TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.CpuAdaptationChanges"); } -void SendStatisticsProxy::OnQualityRestrictedResolutionChanged( - int num_quality_downscales) { +void SendStatisticsProxy::OnQualityAdaptationChanged( + const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts) { rtc::CritScope lock(&crit_); ++stats_.number_of_quality_adapt_changes; - quality_downscales_ = num_quality_downscales; - stats_.bw_limited_resolution = quality_downscales_ > 0; + UpdateAdaptationStats(cpu_counts, quality_counts); +} + +void SendStatisticsProxy::UpdateAdaptationStats( + const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts) { + cpu_downscales_ = cpu_counts.resolution; + quality_downscales_ = quality_counts.resolution; + + stats_.cpu_limited_resolution = cpu_counts.resolution > 0; + stats_.cpu_limited_framerate = cpu_counts.fps > 0; + stats_.bw_limited_resolution = quality_counts.resolution > 0; + stats_.bw_limited_framerate = quality_counts.fps > 0; +} + +void SendStatisticsProxy::SetAdaptTimer(const ViEEncoder::AdaptCounts& counts, + StatsTimer* timer) { + if (counts.resolution >= 0 || counts.fps >= 0) { + // Adaptation enabled. + if (!stats_.suspended) + timer->Start(clock_->TimeInMilliseconds()); + return; + } + timer->Stop(clock_->TimeInMilliseconds()); } void SendStatisticsProxy::RtcpPacketTypesCounterUpdated( @@ -833,8 +836,8 @@ void SendStatisticsProxy::DataCountersUpdated( if (uma_container_->first_rtp_stats_time_ms_ == -1) { int64_t now_ms = clock_->TimeInMilliseconds(); uma_container_->first_rtp_stats_time_ms_ = now_ms; - uma_container_->cpu_scaling_timer_.Restart(now_ms); - uma_container_->quality_scaling_timer_.Restart(now_ms); + uma_container_->cpu_adapt_timer_.Restart(now_ms); + uma_container_->quality_adapt_timer_.Restart(now_ms); } uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(), diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index 10d72c7796..763a7a8f87 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -57,10 +57,14 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, // Used to update incoming frame rate. void OnIncomingFrame(int width, int height); - void OnCpuRestrictedResolutionChanged(bool cpu_restricted_resolution); - void OnQualityRestrictedResolutionChanged(int num_quality_downscales); - void SetCpuScalingStats(int num_cpu_downscales); // -1: disabled. - void SetQualityScalingStats(int num_quality_downscales); // -1: disabled. + // Adaptation stats. + void SetAdaptationStats(const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts); + void OnCpuAdaptationChanged(const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts); + void OnQualityAdaptationChanged( + const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts); void OnEncoderStatsUpdate(uint32_t framerate, uint32_t bitrate); void OnSuspendChange(bool is_suspended); @@ -160,6 +164,12 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, VideoSendStream::StreamStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_); + void SetAdaptTimer(const ViEEncoder::AdaptCounts& counts, StatsTimer* timer) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + void UpdateAdaptationStats(const ViEEncoder::AdaptCounts& cpu_counts, + const ViEEncoder::AdaptCounts& quality_counts) + EXCLUSIVE_LOCKS_REQUIRED(crit_); + Clock* const clock_; const std::string payload_name_; const VideoSendStream::Config::Rtp rtp_config_; @@ -215,8 +225,8 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, RateAccCounter fec_byte_counter_; int64_t first_rtcp_stats_time_ms_; int64_t first_rtp_stats_time_ms_; - StatsTimer cpu_scaling_timer_; - StatsTimer quality_scaling_timer_; + StatsTimer cpu_adapt_timer_; + StatsTimer quality_adapt_timer_; BoolSampleCounter paused_time_counter_; TargetRateUpdates target_rate_updates_; ReportBlockStats report_block_stats_; diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index edb756433b..4f09e48bd4 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -367,61 +367,99 @@ TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) { EXPECT_EQ(rtc::Optional(), statistics_proxy_->GetStats().qp_sum); } -TEST_F(SendStatisticsProxyTest, SetCpuScalingUpdatesStats) { +TEST_F(SendStatisticsProxyTest, GetCpuAdaptationStats) { + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate); EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); - statistics_proxy_->SetCpuScalingStats(-1); + cpu_counts.fps = 1; + cpu_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate); EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); - statistics_proxy_->SetCpuScalingStats(0); - EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); - statistics_proxy_->SetCpuScalingStats(1); + cpu_counts.fps = 0; + cpu_counts.resolution = 1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate); EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution); -} - -TEST_F(SendStatisticsProxyTest, SetQualityScalingUpdatesStats) { - EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - statistics_proxy_->SetQualityScalingStats(-1); - EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - statistics_proxy_->SetQualityScalingStats(0); - EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - statistics_proxy_->SetQualityScalingStats(1); - EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); -} - -TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuResolutionChanges) { + cpu_counts.fps = 1; + cpu_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate); EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); + cpu_counts.fps = -1; + cpu_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); +} + +TEST_F(SendStatisticsProxyTest, GetQualityAdaptationStats) { + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); + quality_counts.fps = 1; + quality_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); + quality_counts.fps = 0; + quality_counts.resolution = 1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); + quality_counts.fps = 1; + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); + quality_counts.fps = -1; + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); +} + +TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuAdaptChanges) { + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + cpu_counts.resolution = 1; + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate); EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_cpu_adapt_changes); - statistics_proxy_->OnCpuRestrictedResolutionChanged(false); - EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution); + cpu_counts.resolution = 2; + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate); + EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes); + EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes); } -TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityResolutionChanges) { - EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); +TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityAdaptChanges) { + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes); - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); - EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); + quality_counts.fps = 1; + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_quality_adapt_changes); - statistics_proxy_->OnQualityRestrictedResolutionChanged(2); - EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); - EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes); - - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); - EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); - EXPECT_EQ(3, statistics_proxy_->GetStats().number_of_quality_adapt_changes); - - statistics_proxy_->OnQualityRestrictedResolutionChanged(0); + quality_counts.fps = 0; + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate); EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - EXPECT_EQ(4, statistics_proxy_->GetStats().number_of_quality_adapt_changes); + EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes); + EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes); } -TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_ScalingNotEnabled) { +TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_AdaptationNotEnabled) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); // Min runtime has passed. @@ -435,9 +473,10 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_ScalingNotEnabled) { TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); - // Enable scaling. - statistics_proxy_->SetQualityScalingStats(0); - statistics_proxy_->SetCpuScalingStats(0); + // Enable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Min runtime has not passed. fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1); statistics_proxy_.reset(); @@ -446,26 +485,18 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) { metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality")); } -TEST_F(SendStatisticsProxyTest, ZeroCpuAdaptChangesReported) { +TEST_F(SendStatisticsProxyTest, ZeroAdaptChangesReported) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); - // Enable scaling. - statistics_proxy_->SetCpuScalingStats(0); + // Enable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Min runtime has passed. fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000); statistics_proxy_.reset(); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu")); EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 0)); -} - -TEST_F(SendStatisticsProxyTest, ZeroQualityAdaptChangesReported) { - // First RTP packet sent. - UpdateDataCounters(kFirstSsrc); - // Enable scaling. - statistics_proxy_->SetQualityScalingStats(0); - // Min runtime has passed. - fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000); - statistics_proxy_.reset(); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality")); EXPECT_EQ( @@ -475,10 +506,12 @@ TEST_F(SendStatisticsProxyTest, ZeroQualityAdaptChangesReported) { TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); - // Enable scaling. + // Enable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Adapt changes: 1, elapsed time: 10 sec => 6 per minute. - statistics_proxy_->SetCpuScalingStats(0); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); statistics_proxy_.reset(); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu")); @@ -489,34 +522,42 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); - // Disable scaling. - statistics_proxy_->SetQualityScalingStats(-1); + // Disable quality adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.fps = -1; + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); - // Enable scaling. + // Enable quality adaptation. // Adapt changes: 2, elapsed time: 20 sec. - statistics_proxy_->SetQualityScalingStats(0); + quality_counts.fps = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(5000); - statistics_proxy_->SetQualityScalingStats(1); + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(9000); - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(6000); - statistics_proxy_->OnQualityRestrictedResolutionChanged(2); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); - // Disable scaling. - statistics_proxy_->SetQualityScalingStats(-1); + // Disable quality adaptation. + quality_counts.fps = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(30000); - // Enable scaling. + // Enable quality adaptation. // Adapt changes: 1, elapsed time: 10 sec. - statistics_proxy_->SetQualityScalingStats(0); - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); + quality_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); - // Disable scaling. - statistics_proxy_->SetQualityScalingStats(-1); + // Disable quality adaptation. + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(5000); - statistics_proxy_->SetQualityScalingStats(-1); + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(20000); // Adapt changes: 3, elapsed time: 30 sec => 6 per minute. @@ -549,12 +590,14 @@ TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) { // First RTP packet sent. UpdateDataCounters(kFirstSsrc); - // Enable scaling. + // Enable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; // Adapt changes: 2, elapsed time: 20 sec. - statistics_proxy_->SetQualityScalingStats(0); + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(20000); - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); - statistics_proxy_->OnQualityRestrictedResolutionChanged(2); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); // Suspend and resume video. statistics_proxy_->OnSuspendChange(true); @@ -562,7 +605,7 @@ TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) { statistics_proxy_->OnSuspendChange(false); // Adapt changes: 1, elapsed time: 10 sec. - statistics_proxy_->OnQualityRestrictedResolutionChanged(3); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); // Adapt changes: 3, elapsed time: 30 sec => 6 per minute. @@ -581,18 +624,22 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) { statistics_proxy_->OnSuspendChange(false); fake_clock_.AdvanceTimeMilliseconds(30000); - // Enable scaling. + // Enable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; // Adapt changes: 1, elapsed time: 20 sec. - statistics_proxy_->SetCpuScalingStats(0); + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); // Video not suspended, stats time already started. statistics_proxy_->OnSuspendChange(false); fake_clock_.AdvanceTimeMilliseconds(10000); - // Disable scaling. - statistics_proxy_->SetCpuScalingStats(-1); + // Disable adaptation. + cpu_counts.fps = -1; + cpu_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(30000); // Suspend and resume video, stats time not started when scaling not enabled. @@ -601,11 +648,13 @@ TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) { statistics_proxy_->OnSuspendChange(false); fake_clock_.AdvanceTimeMilliseconds(30000); - // Enable scaling. + // Enable adaptation. // Adapt changes: 1, elapsed time: 10 sec. - statistics_proxy_->SetCpuScalingStats(0); + cpu_counts.fps = 0; + cpu_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); // Adapt changes: 2, elapsed time: 30 sec => 4 per minute. statistics_proxy_.reset(); @@ -620,15 +669,17 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) { // Video suspended. statistics_proxy_->OnSuspendChange(true); - // Enable scaling, stats time not started when suspended. - statistics_proxy_->SetCpuScalingStats(0); + // Enable adaptation, stats time not started when suspended. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); // Resume video, stats time started. // Adapt changes: 1, elapsed time: 10 sec. statistics_proxy_->OnSuspendChange(false); fake_clock_.AdvanceTimeMilliseconds(10000); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); // Adapt changes: 1, elapsed time: 10 sec => 6 per minute. statistics_proxy_.reset(); @@ -637,15 +688,17 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) { } TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) { - // Send first packet, scaling enabled. + // Send first packet, adaptation enabled. // Elapsed time before first packet is sent should be excluded. - statistics_proxy_->SetQualityScalingStats(0); + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); UpdateDataCounters(kFirstSsrc); // Adapt changes: 1, elapsed time: 10 sec. fake_clock_.AdvanceTimeMilliseconds(10000); - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); UpdateDataCounters(kFirstSsrc); // Adapt changes: 1, elapsed time: 10 sec => 6 per minute. @@ -657,24 +710,29 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) { } TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) { - // Enable and disable scaling. - statistics_proxy_->SetCpuScalingStats(0); + // Enable and disable adaptation. + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(60000); - statistics_proxy_->SetCpuScalingStats(-1); + cpu_counts.fps = -1; + cpu_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Send first packet, scaling disabled. // Elapsed time before first packet is sent should be excluded. UpdateDataCounters(kFirstSsrc); fake_clock_.AdvanceTimeMilliseconds(60000); - // Enable scaling. - statistics_proxy_->SetCpuScalingStats(0); + // Enable adaptation. + cpu_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(10000); UpdateDataCounters(kFirstSsrc); // Adapt changes: 1, elapsed time: 20 sec. fake_clock_.AdvanceTimeMilliseconds(10000); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); // Adapt changes: 1, elapsed time: 20 sec => 3 per minute. statistics_proxy_.reset(); @@ -683,14 +741,18 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) { } TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) { - // First RTP packet sent, scaling enabled. + // First RTP packet sent, cpu adaptation enabled. UpdateDataCounters(kFirstSsrc); - statistics_proxy_->SetCpuScalingStats(0); + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.fps = -1; + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Adapt changes: 2, elapsed time: 15 sec => 8 per minute. - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(6000); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(9000); // Switch content type, real-time stats should be updated. @@ -704,13 +766,13 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) { // First RTP packet sent, scaling enabled. UpdateDataCounters(kFirstSsrc); - statistics_proxy_->SetCpuScalingStats(0); + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); // Adapt changes: 4, elapsed time: 120 sec => 2 per minute. - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); fake_clock_.AdvanceTimeMilliseconds(120000); statistics_proxy_.reset(); @@ -842,8 +904,10 @@ TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) { } TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) { - const int kNumDownscales = -1; - statistics_proxy_->SetQualityScalingStats(kNumDownscales); + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + cpu_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight); @@ -854,13 +918,16 @@ TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) { } TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramUpdated) { - const int kNumDownscales = 0; - statistics_proxy_->SetCpuScalingStats(kNumDownscales); + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + cpu_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight); - statistics_proxy_->OnCpuRestrictedResolutionChanged(true); + cpu_counts.resolution = 1; + statistics_proxy_->OnCpuAdaptationChanged(cpu_counts, quality_counts); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight); @@ -1149,9 +1216,11 @@ TEST_F(SendStatisticsProxyTest, TEST_F(SendStatisticsProxyTest, QualityLimitedHistogramsNotUpdatedWhenDisabled) { - const int kNumDownscales = -1; + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.resolution = -1; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); EncodedImage encoded_image; - statistics_proxy_->SetQualityScalingStats(kNumDownscales); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo); @@ -1165,9 +1234,11 @@ TEST_F(SendStatisticsProxyTest, TEST_F(SendStatisticsProxyTest, QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale) { - const int kNumDownscales = 0; + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.resolution = 0; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); EncodedImage encoded_image; - statistics_proxy_->SetQualityScalingStats(kNumDownscales); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo); @@ -1185,8 +1256,11 @@ TEST_F(SendStatisticsProxyTest, TEST_F(SendStatisticsProxyTest, QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales) { const int kDownscales = 2; + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.resolution = kDownscales; + statistics_proxy_->SetAdaptationStats(cpu_counts, quality_counts); EncodedImage encoded_image; - statistics_proxy_->OnQualityRestrictedResolutionChanged(kDownscales); for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo); // Histograms are updated when the statistics_proxy_ is deleted. @@ -1221,7 +1295,10 @@ TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) { EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); // Resolution scaled due to quality. - statistics_proxy_->OnQualityRestrictedResolutionChanged(1); + ViEEncoder::AdaptCounts cpu_counts; + ViEEncoder::AdaptCounts quality_counts; + quality_counts.resolution = 1; + statistics_proxy_->OnQualityAdaptationChanged(cpu_counts, quality_counts); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); } diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc index cd0f3eb897..a3b071ac00 100644 --- a/webrtc/video/vie_encoder.cc +++ b/webrtc/video/vie_encoder.cc @@ -73,6 +73,22 @@ uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) { return std::numeric_limits::max(); } +bool IsResolutionScalingEnabled( + VideoSendStream::DegradationPreference degradation_preference) { + return degradation_preference == + VideoSendStream::DegradationPreference::kMaintainFramerate || + degradation_preference == + VideoSendStream::DegradationPreference::kBalanced; +} + +bool IsFramerateScalingEnabled( + VideoSendStream::DegradationPreference degradation_preference) { + return degradation_preference == + VideoSendStream::DegradationPreference::kMaintainResolution || + degradation_preference == + VideoSendStream::DegradationPreference::kBalanced; +} + } // namespace class ViEEncoder::ConfigureEncoderTask : public rtc::QueuedTask { @@ -420,8 +436,7 @@ void ViEEncoder::SetBitrateObserver( void ViEEncoder::SetSource( rtc::VideoSourceInterface* source, - const VideoSendStream::VideoSendStream::DegradationPreference& - degradation_preference) { + const VideoSendStream::DegradationPreference& degradation_preference) { RTC_DCHECK_RUN_ON(&thread_checker_); source_proxy_->SetSource(source, degradation_preference); encoder_queue_.PostTask([this, degradation_preference] { @@ -547,27 +562,24 @@ void ViEEncoder::ConfigureQualityScaler() { const bool quality_scaling_allowed = degradation_preference_allows_scaling && scaling_settings.enabled; - const std::vector& scale_counters = GetScaleCounters(); - stats_proxy_->SetCpuScalingStats( - degradation_preference_allows_scaling ? scale_counters[kCpu] : -1); - stats_proxy_->SetQualityScalingStats( - quality_scaling_allowed ? scale_counters[kQuality] : -1); - if (quality_scaling_allowed) { - // Abort if quality scaler has already been configured. - if (quality_scaler_.get() != nullptr) - return; - // Drop frames and scale down until desired quality is achieved. - if (scaling_settings.thresholds) { - quality_scaler_.reset( - new QualityScaler(this, *(scaling_settings.thresholds))); - } else { - quality_scaler_.reset(new QualityScaler(this, codec_type_)); + if (quality_scaler_.get() == nullptr) { + // Quality scaler has not already been configured. + // Drop frames and scale down until desired quality is achieved. + if (scaling_settings.thresholds) { + quality_scaler_.reset( + new QualityScaler(this, *(scaling_settings.thresholds))); + } else { + quality_scaler_.reset(new QualityScaler(this, codec_type_)); + } } } else { quality_scaler_.reset(nullptr); initial_rampup_ = kMaxInitialFramedrop; } + + stats_proxy_->SetAdaptationStats(GetActiveCounts(kCpu), + GetActiveCounts(kQuality)); } void ViEEncoder::OnFrame(const VideoFrame& video_frame) { @@ -797,6 +809,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { last_frame_info_->pixel_count(), stats_proxy_->GetStats().input_frame_rate, AdaptationRequest::Mode::kAdaptDown}; + bool downgrade_requested = last_adaptation_request_ && last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown; @@ -834,8 +847,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { } if (reason == kCpu) { - const int cpu_scale_counter = GetScaleCounters()[reason]; - if (cpu_scale_counter >= max_downgrades) + if (GetConstAdaptCounter().TotalCount(kCpu) >= max_downgrades) return; } @@ -848,11 +860,13 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { return; } LOG(LS_INFO) << "Scaling down resolution."; + GetAdaptCounter().IncrementResolution(reason, 1); break; case VideoSendStream::DegradationPreference::kMaintainResolution: source_proxy_->RequestFramerateLowerThan( adaptation_request.framerate_fps_); LOG(LS_INFO) << "Scaling down framerate."; + GetAdaptCounter().IncrementFramerate(reason, 1); break; case VideoSendStream::DegradationPreference::kDegradationDisabled: RTC_NOTREACHED(); @@ -860,32 +874,20 @@ void ViEEncoder::AdaptDown(AdaptReason reason) { last_adaptation_request_.emplace(adaptation_request); - IncrementScaleCounter(reason, 1); + UpdateAdaptationStats(reason); - // Update stats. - const std::vector& scale_counters = GetScaleCounters(); - switch (reason) { - case kQuality: - stats_proxy_->OnQualityRestrictedResolutionChanged( - scale_counters[reason]); - break; - case kCpu: - stats_proxy_->OnCpuRestrictedResolutionChanged(true); - break; - } - - for (size_t i = 0; i < kScaleReasonSize; ++i) { - LOG(LS_INFO) << "Scaled " << scale_counters[i] - << " times for reason: " << (i ? "cpu" : "quality"); - } + LOG(LS_INFO) << GetConstAdaptCounter().ToString(); } void ViEEncoder::AdaptUp(AdaptReason reason) { RTC_DCHECK_RUN_ON(&encoder_queue_); - int scale_counter = GetScaleCounters()[reason]; - if (scale_counter == 0) + + const AdaptCounter& adapt_counter = GetConstAdaptCounter(); + int num_downgrades = adapt_counter.TotalCount(reason); + if (num_downgrades == 0) return; - RTC_DCHECK_GT(scale_counter, 0); + RTC_DCHECK_GT(num_downgrades, 0); + AdaptationRequest adaptation_request = { last_frame_info_->pixel_count(), stats_proxy_->GetStats().input_frame_rate, @@ -894,6 +896,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { bool adapt_up_requested = last_adaptation_request_ && last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp; + switch (degradation_preference_) { case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); @@ -914,20 +917,11 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { return; } - // Decrease counter of how many times we have scaled down, for this - // degradation preference mode and reason. - IncrementScaleCounter(reason, -1); - - // Get a sum of how many times have scaled down, in total, for this - // degradation preference mode. If it is 0, remove any restraints. - const std::vector& scale_counters = GetScaleCounters(); - const int scale_sum = - std::accumulate(scale_counters.begin(), scale_counters.end(), 0); switch (degradation_preference_) { case VideoSendStream::DegradationPreference::kBalanced: FALLTHROUGH(); case VideoSendStream::DegradationPreference::kMaintainFramerate: - if (scale_sum == 0) { + if (adapt_counter.TotalCount() == 1) { LOG(LS_INFO) << "Removing resolution down-scaling setting."; source_proxy_->RequestHigherResolutionThan( std::numeric_limits::max()); @@ -936,9 +930,10 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { adaptation_request.input_pixel_count_); LOG(LS_INFO) << "Scaling up resolution."; } + GetAdaptCounter().IncrementResolution(reason, -1); break; case VideoSendStream::DegradationPreference::kMaintainResolution: - if (scale_sum == 0) { + if (adapt_counter.TotalCount() == 1) { LOG(LS_INFO) << "Removing framerate down-scaling setting."; source_proxy_->RequestHigherFramerateThan( std::numeric_limits::max()); @@ -947,6 +942,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { adaptation_request.framerate_fps_); LOG(LS_INFO) << "Scaling up framerate."; } + GetAdaptCounter().IncrementFramerate(reason, -1); break; case VideoSendStream::DegradationPreference::kDegradationDisabled: RTC_NOTREACHED(); @@ -954,40 +950,120 @@ void ViEEncoder::AdaptUp(AdaptReason reason) { last_adaptation_request_.emplace(adaptation_request); - // Update stats. + UpdateAdaptationStats(reason); + + LOG(LS_INFO) << adapt_counter.ToString(); +} + +void ViEEncoder::UpdateAdaptationStats(AdaptReason reason) { switch (reason) { - case kQuality: - stats_proxy_->OnQualityRestrictedResolutionChanged( - scale_counters[reason]); - break; case kCpu: - stats_proxy_->OnCpuRestrictedResolutionChanged(scale_counters[reason] > - 0); + stats_proxy_->OnCpuAdaptationChanged(GetActiveCounts(kCpu), + GetActiveCounts(kQuality)); + break; + case kQuality: + stats_proxy_->OnQualityAdaptationChanged(GetActiveCounts(kCpu), + GetActiveCounts(kQuality)); break; } - - for (size_t i = 0; i < kScaleReasonSize; ++i) { - LOG(LS_INFO) << "Scaled " << scale_counters[i] - << " times for reason: " << (i ? "cpu" : "quality"); - } } -const std::vector& ViEEncoder::GetScaleCounters() { - auto it = scale_counters_.find(degradation_preference_); - if (it == scale_counters_.end()) { - scale_counters_[degradation_preference_].resize(kScaleReasonSize); - return scale_counters_[degradation_preference_]; +ViEEncoder::AdaptCounts ViEEncoder::GetActiveCounts(AdaptReason reason) { + ViEEncoder::AdaptCounts counts = GetConstAdaptCounter().Counts(reason); + switch (reason) { + case kCpu: + if (!IsFramerateScalingEnabled(degradation_preference_)) + counts.fps = -1; + if (!IsResolutionScalingEnabled(degradation_preference_)) + counts.resolution = -1; + break; + case kQuality: + if (!IsFramerateScalingEnabled(degradation_preference_) || + !quality_scaler_) { + counts.fps = -1; + } + if (!IsResolutionScalingEnabled(degradation_preference_) || + !quality_scaler_) { + counts.resolution = -1; + } + break; } - return it->second; + return counts; } -void ViEEncoder::IncrementScaleCounter(int reason, int delta) { - // Get the counters and validate. This may also lazily initialize the state. - const std::vector& counter = GetScaleCounters(); - if (delta < 0) { - RTC_DCHECK_GE(counter[reason], delta); +ViEEncoder::AdaptCounter& ViEEncoder::GetAdaptCounter() { + return adapt_counters_[degradation_preference_]; +} + +const ViEEncoder::AdaptCounter& ViEEncoder::GetConstAdaptCounter() { + return adapt_counters_[degradation_preference_]; +} + +// Class holding adaptation information. +ViEEncoder::AdaptCounter::AdaptCounter() { + fps_counters_.resize(kScaleReasonSize); + resolution_counters_.resize(kScaleReasonSize); +} + +ViEEncoder::AdaptCounter::~AdaptCounter() {} + +std::string ViEEncoder::AdaptCounter::ToString() const { + std::stringstream ss; + ss << "Downgrade counts: fps: {" << ToString(fps_counters_); + ss << "}, resolution: {" << ToString(resolution_counters_) << "}"; + return ss.str(); +} + +ViEEncoder::AdaptCounts ViEEncoder::AdaptCounter::Counts(int reason) const { + AdaptCounts counts; + counts.fps = fps_counters_[reason]; + counts.resolution = resolution_counters_[reason]; + return counts; +} + +void ViEEncoder::AdaptCounter::IncrementFramerate(int reason, int delta) { + fps_counters_[reason] += delta; +} + +void ViEEncoder::AdaptCounter::IncrementResolution(int reason, int delta) { + resolution_counters_[reason] += delta; +} + +int ViEEncoder::AdaptCounter::FramerateCount() const { + return Count(fps_counters_); +} + +int ViEEncoder::AdaptCounter::ResolutionCount() const { + return Count(resolution_counters_); +} + +int ViEEncoder::AdaptCounter::TotalCount() const { + return FramerateCount() + ResolutionCount(); +} + +int ViEEncoder::AdaptCounter::FramerateCount(int reason) const { + return fps_counters_[reason]; +} + +int ViEEncoder::AdaptCounter::ResolutionCount(int reason) const { + return resolution_counters_[reason]; +} + +int ViEEncoder::AdaptCounter::TotalCount(int reason) const { + return FramerateCount(reason) + ResolutionCount(reason); +} + +int ViEEncoder::AdaptCounter::Count(const std::vector& counters) const { + return std::accumulate(counters.begin(), counters.end(), 0); +} + +std::string ViEEncoder::AdaptCounter::ToString( + const std::vector& counters) const { + std::stringstream ss; + for (size_t reason = 0; reason < kScaleReasonSize; ++reason) { + ss << (reason ? " cpu" : "quality") << ":" << counters[reason]; } - scale_counters_[degradation_preference_][reason] += delta; + return ss.str(); } } // namespace webrtc diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h index 8481117ef8..f2d7cfdae2 100644 --- a/webrtc/video/vie_encoder.h +++ b/webrtc/video/vie_encoder.h @@ -62,6 +62,12 @@ class ViEEncoder : public rtc::VideoSinkInterface, int min_transmit_bitrate_bps) = 0; }; + // Number of resolution and framerate reductions (-1: disabled). + struct AdaptCounts { + int resolution = 0; + int fps = 0; + }; + // Downscale resolution at most 2 times for CPU reasons. static const int kMaxCpuResolutionDowngrades = 2; // Downscale framerate at most 4 times. @@ -172,10 +178,44 @@ class ViEEncoder : public rtc::VideoSinkInterface, void TraceFrameDropStart(); void TraceFrameDropEnd(); - const std::vector& GetScaleCounters() - EXCLUSIVE_LOCKS_REQUIRED(&encoder_queue_); - void IncrementScaleCounter(int reason, int delta) - EXCLUSIVE_LOCKS_REQUIRED(&encoder_queue_); + // Class holding adaptation information. + class AdaptCounter final { + public: + AdaptCounter(); + ~AdaptCounter(); + + // Get number of adaptation downscales for |reason|. + AdaptCounts Counts(int reason) const; + + std::string ToString() const; + + void IncrementFramerate(int reason, int delta); + void IncrementResolution(int reason, int delta); + + // Gets the total number of downgrades (for all adapt reasons). + int FramerateCount() const; + int ResolutionCount() const; + int TotalCount() const; + + // Gets the total number of downgrades for |reason|. + int FramerateCount(int reason) const; + int ResolutionCount(int reason) const; + int TotalCount(int reason) const; + + private: + std::string ToString(const std::vector& counters) const; + int Count(const std::vector& counters) const; + + // Degradation counters holding number of framerate/resolution reductions + // per adapt reason. + std::vector fps_counters_; + std::vector resolution_counters_; + }; + + AdaptCounter& GetAdaptCounter() RUN_ON(&encoder_queue_); + const AdaptCounter& GetConstAdaptCounter() RUN_ON(&encoder_queue_); + void UpdateAdaptationStats(AdaptReason reason) RUN_ON(&encoder_queue_); + AdaptCounts GetActiveCounts(AdaptReason reason) RUN_ON(&encoder_queue_); rtc::Event shutdown_event_; @@ -214,13 +254,14 @@ class ViEEncoder : public rtc::VideoSinkInterface, uint32_t last_observed_bitrate_bps_ ACCESS_ON(&encoder_queue_); bool encoder_paused_and_dropped_frame_ ACCESS_ON(&encoder_queue_); Clock* const clock_; - // Counters used for deciding if the video resolution is currently - // restricted, and if so, why, on a per degradation preference basis. + // Counters used for deciding if the video resolution or framerate is + // currently restricted, and if so, why, on a per degradation preference + // basis. // TODO(sprang): Replace this with a state holding a relative overuse measure // instead, that can be translated into suitable down-scale or fps limit. - std::map> - scale_counters_ ACCESS_ON(&encoder_queue_); - // Set depending on degradation preferences + std::map + adapt_counters_ ACCESS_ON(&encoder_queue_); + // Set depending on degradation preferences. VideoSendStream::DegradationPreference degradation_preference_ ACCESS_ON(&encoder_queue_); diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc index d2f46e6805..eb39bf7c4d 100644 --- a/webrtc/video/vie_encoder_unittest.cc +++ b/webrtc/video/vie_encoder_unittest.cc @@ -139,6 +139,11 @@ class AdaptingFrameForwarder : public test::FrameForwarder { return adaptation_enabled_; } + rtc::VideoSinkWants last_wants() const { + rtc::CritScope cs(&crit_); + return last_wants_; + } + void IncomingCapturedFrame(const VideoFrame& video_frame) override { int cropped_width = 0; int cropped_height = 0; @@ -163,14 +168,15 @@ class AdaptingFrameForwarder : public test::FrameForwarder { void AddOrUpdateSink(rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) override { rtc::CritScope cs(&crit_); + last_wants_ = sink_wants(); adapter_.OnResolutionFramerateRequest(wants.target_pixel_count, wants.max_pixel_count, wants.max_framerate_fps); test::FrameForwarder::AddOrUpdateSink(sink, wants); } - cricket::VideoAdapter adapter_; bool adaptation_enabled_ GUARDED_BY(crit_); + rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_); }; class MockableSendStatisticsProxy : public SendStatisticsProxy { @@ -281,16 +287,41 @@ class ViEEncoderTest : public ::testing::Test { } void VerifyNoLimitation(const rtc::VideoSinkWants& wants) { - EXPECT_FALSE(wants.target_pixel_count); - EXPECT_EQ(std::numeric_limits::max(), wants.max_pixel_count); EXPECT_EQ(std::numeric_limits::max(), wants.max_framerate_fps); + EXPECT_EQ(std::numeric_limits::max(), wants.max_pixel_count); + EXPECT_FALSE(wants.target_pixel_count); } - void VerifyResolutionLimitationLessThan(const rtc::VideoSinkWants& wants, - int pixel_count) { + void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1, + const rtc::VideoSinkWants& wants2) { + EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps); + EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count); + } + + void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1, + const rtc::VideoSinkWants& wants2) { + EXPECT_EQ(std::numeric_limits::max(), wants1.max_framerate_fps); + EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count); + EXPECT_GT(wants1.max_pixel_count, 0); + } + + void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1, + const rtc::VideoSinkWants& wants2) { + EXPECT_EQ(std::numeric_limits::max(), wants1.max_framerate_fps); + EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count); + } + + void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants, + int pixel_count) { + EXPECT_EQ(std::numeric_limits::max(), wants.max_framerate_fps); EXPECT_LT(wants.max_pixel_count, pixel_count); EXPECT_GT(wants.max_pixel_count, 0); - EXPECT_EQ(std::numeric_limits::max(), wants.max_framerate_fps); + } + + void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) { + EXPECT_LT(wants.max_framerate_fps, fps); + EXPECT_EQ(std::numeric_limits::max(), wants.max_pixel_count); + EXPECT_FALSE(wants.target_pixel_count); } class TestEncoder : public test::FakeEncoder { @@ -946,6 +977,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); sink_.WaitForEncodedFrame(1); VideoSendStream::Stats stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_FALSE(stats.cpu_limited_resolution); EXPECT_EQ(0, stats.number_of_cpu_adapt_changes); @@ -954,6 +986,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight)); sink_.WaitForEncodedFrame(2); stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_TRUE(stats.cpu_limited_resolution); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); @@ -966,6 +999,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight)); sink_.WaitForEncodedFrame(3); stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_TRUE(stats.cpu_limited_resolution); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); @@ -977,6 +1011,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight)); sink_.WaitForEncodedFrame(4); stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_FALSE(stats.cpu_limited_resolution); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); @@ -988,6 +1023,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight)); sink_.WaitForEncodedFrame(5); stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_TRUE(stats.cpu_limited_resolution); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); @@ -996,6 +1032,7 @@ TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) { new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight)); sink_.WaitForEncodedFrame(6); stats = stats_proxy_->GetStats(); + EXPECT_FALSE(stats.bw_limited_resolution); EXPECT_FALSE(stats.cpu_limited_resolution); EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); EXPECT_EQ(0, stats.number_of_quality_adapt_changes); @@ -1138,6 +1175,7 @@ TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) { sink_.WaitForEncodedFrame(sequence++); stats = stats_proxy_->GetStats(); EXPECT_TRUE(stats.cpu_limited_resolution); + EXPECT_FALSE(stats.cpu_limited_framerate); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); // Set cpu adaptation by frame dropping. @@ -1150,10 +1188,11 @@ TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) { stats = stats_proxy_->GetStats(); // Not adapted at first. EXPECT_FALSE(stats.cpu_limited_resolution); + EXPECT_FALSE(stats.cpu_limited_framerate); EXPECT_EQ(1, stats.number_of_cpu_adapt_changes); // Force an input frame rate to be available, or the adaptation call won't - // know what framerate to adapt form. + // know what framerate to adapt from. VideoSendStream::Stats mock_stats = stats_proxy_->GetStats(); mock_stats.input_frame_rate = 30; stats_proxy_->SetMockStats(mock_stats); @@ -1166,7 +1205,8 @@ TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) { // Framerate now adapted. stats = stats_proxy_->GetStats(); - EXPECT_TRUE(stats.cpu_limited_resolution); + EXPECT_FALSE(stats.cpu_limited_resolution); + EXPECT_TRUE(stats.cpu_limited_framerate); EXPECT_EQ(2, stats.number_of_cpu_adapt_changes); // Disable CPU adaptation. @@ -1314,7 +1354,7 @@ TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) { // Trigger adapt down, expect scaled down resolution. vie_encoder_->TriggerCpuOveruse(); - VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight); + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight); const int kLastMaxPixelCount = source.sink_wants().max_pixel_count; EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1366,18 +1406,45 @@ TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) { source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); sink_.WaitForEncodedFrame(kWidth, kHeight); VerifyNoLimitation(source.sink_wants()); - EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate); EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes); // Trigger adapt up, expect no change. vie_encoder_->TriggerCpuNormalUsage(); VerifyNoLimitation(source.sink_wants()); - EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate); EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes); vie_encoder_->Stop(); } +TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) { + const int kWidth = 1280; + const int kHeight = 720; + vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); + + // Enable kDegradationDisabled preference, no initial limitation. + test::FrameForwarder source; + vie_encoder_->SetSource( + &source, VideoSendStream::DegradationPreference::kDegradationDisabled); + + source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); + sink_.WaitForEncodedFrame(kWidth, kHeight); + VerifyNoLimitation(source.sink_wants()); + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate); + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes); + + // Trigger adapt up, expect no change. + vie_encoder_->TriggerQualityHigh(); + VerifyNoLimitation(source.sink_wants()); + EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); + EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate); + EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes); + + vie_encoder_->Stop(); +} + TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) { const int kWidth = 1280; const int kHeight = 720; @@ -1399,7 +1466,7 @@ TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) { vie_encoder_->TriggerQualityLow(); source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight)); sink_.WaitForEncodedFrame(2); - VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight); + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight); EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes); @@ -1413,6 +1480,47 @@ TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) { vie_encoder_->Stop(); } +TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) { + const int kWidth = 1280; + const int kHeight = 720; + const int kInputFps = 30; + vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); + + VideoSendStream::Stats stats = stats_proxy_->GetStats(); + stats.input_frame_rate = kInputFps; + stats_proxy_->SetMockStats(stats); + + // Expect no scaling to begin with (preference: kMaintainFramerate). + video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); + sink_.WaitForEncodedFrame(1); + VerifyNoLimitation(video_source_.sink_wants()); + + // Trigger adapt down, expect scaled down resolution. + vie_encoder_->TriggerQualityLow(); + video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight)); + sink_.WaitForEncodedFrame(2); + VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight); + + // Enable kMaintainResolution preference. + test::FrameForwarder new_video_source; + vie_encoder_->SetSource( + &new_video_source, + VideoSendStream::DegradationPreference::kMaintainResolution); + VerifyNoLimitation(new_video_source.sink_wants()); + + // Trigger adapt down, expect reduced framerate. + vie_encoder_->TriggerQualityLow(); + new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight)); + sink_.WaitForEncodedFrame(3); + VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps); + + // Trigger adapt up, expect no restriction. + vie_encoder_->TriggerQualityHigh(); + VerifyNoLimitation(new_video_source.sink_wants()); + + vie_encoder_->Stop(); +} + TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) { const int kWidth = 1280; const int kHeight = 720; @@ -1461,7 +1569,7 @@ TEST_F(ViEEncoderTest, &source, VideoSendStream::DegradationPreference::kMaintainFramerate); source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight)); - sink_.WaitForEncodedFrame(1); + sink_.WaitForEncodedFrame(kWidth, kHeight); VerifyNoLimitation(source.sink_wants()); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1470,14 +1578,14 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuOveruse(); source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight)); sink_.WaitForEncodedFrame(2); - VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight); + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes); // Trigger adapt up, expect no restriction. vie_encoder_->TriggerCpuNormalUsage(); source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight)); - sink_.WaitForEncodedFrame(3); + sink_.WaitForEncodedFrame(kWidth, kHeight); VerifyNoLimitation(source.sink_wants()); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1486,12 +1594,14 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuOveruse(); source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight)); sink_.WaitForEncodedFrame(4); - VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight); + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes); // Trigger adapt up, expect no restriction. vie_encoder_->TriggerCpuNormalUsage(); + source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight)); + sink_.WaitForEncodedFrame(kWidth, kHeight); VerifyNoLimitation(source.sink_wants()); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1523,8 +1633,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuOveruse(); source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight)); sink_.WaitForEncodedFrame(2); - VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight); - rtc::VideoSinkWants last_wants = source.sink_wants(); + VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1534,8 +1643,8 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuOveruse(); source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight)); sink_.WaitForEncodedFrame(3); - EXPECT_LT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count); - last_wants = source.sink_wants(); + VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants()); + rtc::VideoSinkWants last_wants = source.sink_wants(); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1545,7 +1654,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuOveruse(); source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight)); sink_.WaitForEncodedFrame(4); - EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count); + VerifyFpsEqResolutionEq(source.sink_wants(), last_wants); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1555,8 +1664,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerQualityLow(); source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight)); sink_.WaitForEncodedFrame(5); - EXPECT_LT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count); - last_wants = source.sink_wants(); + VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants()); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1566,8 +1674,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuNormalUsage(); source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight)); sink_.WaitForEncodedFrame(6); - EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count); - last_wants = source.sink_wants(); + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants()); EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1577,7 +1684,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuNormalUsage(); source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight)); sink_.WaitForEncodedFrame(7); - EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count); + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants()); last_wants = source.sink_wants(); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution); @@ -1588,7 +1695,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerCpuNormalUsage(); source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight)); sink_.WaitForEncodedFrame(8); - EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count); + VerifyFpsEqResolutionEq(source.sink_wants(), last_wants); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution); EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes); @@ -1598,7 +1705,7 @@ TEST_F(ViEEncoderTest, vie_encoder_->TriggerQualityHigh(); source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight)); sink_.WaitForEncodedFrame(kWidth, kHeight); - EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count); + VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants()); VerifyNoLimitation(source.sink_wants()); EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution); EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution); @@ -1730,7 +1837,7 @@ TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) { vie_encoder_->Stop(); } -TEST_F(ViEEncoderTest, NrOfDroppedFramesLimitedWhenBitrateIsTooLow) { +TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) { const int kTooLowBitrateForFrameSizeBps = 10000; vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0); const int kWidth = 640; @@ -1774,6 +1881,7 @@ TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) { const int kHeight = 360; fake_encoder_.SetQualityScaling(false); vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0); + // Force quality scaler reconfiguration by resetting the source. vie_encoder_->SetSource(&video_source_, VideoSendStream::DegradationPreference::kBalanced); diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index f608394050..45d1a55365 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -69,6 +69,8 @@ class VideoSendStream { bool suspended = false; bool bw_limited_resolution = false; bool cpu_limited_resolution = false; + bool bw_limited_framerate = false; + bool cpu_limited_framerate = false; // Total number of times resolution as been requested to be changed due to // CPU/quality adaptation. int number_of_cpu_adapt_changes = 0;