Update adaptation stats to support degradations in both resolution and framerate.
Add AdaptCounter class which holds the number of downgrade counts per degradation way (resolution/fps) and reason (cpu/quality).
BUG=webrtc:7607
Review-Url: https://codereview.webrtc.org/2871623002
Cr-Commit-Position: refs/heads/master@{#18156}
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index 71d980a..cea9ce7 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -305,8 +305,8 @@
}
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 @@
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 @@
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 @@
"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 @@
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 10d72c7..763a7a8 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -57,10 +57,14 @@
// 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 @@
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 @@
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 edb7564..4f09e48 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -367,61 +367,99 @@
EXPECT_EQ(rtc::Optional<uint64_t>(), 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_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 @@
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, 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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, 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, 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, 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 @@
// 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, 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, 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,
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,
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,
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 @@
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 cd0f3eb..a3b071a 100644
--- a/webrtc/video/vie_encoder.cc
+++ b/webrtc/video/vie_encoder.cc
@@ -73,6 +73,22 @@
return std::numeric_limits<uint32_t>::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::SetSource(
rtc::VideoSourceInterface<VideoFrame>* 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 @@
const bool quality_scaling_allowed =
degradation_preference_allows_scaling && scaling_settings.enabled;
- const std::vector<int>& 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 @@
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 @@
}
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 @@
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 @@
last_adaptation_request_.emplace(adaptation_request);
- IncrementScaleCounter(reason, 1);
+ UpdateAdaptationStats(reason);
- // Update stats.
- const std::vector<int>& 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 @@
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 @@
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<int>& 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<int>::max());
@@ -936,9 +930,10 @@
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<int>::max());
@@ -947,6 +942,7 @@
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 @@
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<int>& 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<int>& 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<int>& counters) const {
+ return std::accumulate(counters.begin(), counters.end(), 0);
+}
+
+std::string ViEEncoder::AdaptCounter::ToString(
+ const std::vector<int>& 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 8481117..f2d7cfd 100644
--- a/webrtc/video/vie_encoder.h
+++ b/webrtc/video/vie_encoder.h
@@ -62,6 +62,12 @@
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 @@
void TraceFrameDropStart();
void TraceFrameDropEnd();
- const std::vector<int>& 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<int>& counters) const;
+ int Count(const std::vector<int>& counters) const;
+
+ // Degradation counters holding number of framerate/resolution reductions
+ // per adapt reason.
+ std::vector<int> fps_counters_;
+ std::vector<int> 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 @@
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<const VideoSendStream::DegradationPreference, std::vector<int>>
- scale_counters_ ACCESS_ON(&encoder_queue_);
- // Set depending on degradation preferences
+ std::map<const VideoSendStream::DegradationPreference, AdaptCounter>
+ 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 d2f46e6..eb39bf7 100644
--- a/webrtc/video/vie_encoder_unittest.cc
+++ b/webrtc/video/vie_encoder_unittest.cc
@@ -139,6 +139,11 @@
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 @@
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* 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 @@
}
void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
- EXPECT_FALSE(wants.target_pixel_count);
- EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
+ EXPECT_EQ(std::numeric_limits<int>::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<int>::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<int>::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<int>::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<int>::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<int>::max(), wants.max_pixel_count);
+ EXPECT_FALSE(wants.target_pixel_count);
}
class TestEncoder : public test::FakeEncoder {
@@ -946,6 +977,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
&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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 f608394..45d1a55 100644
--- a/webrtc/video_send_stream.h
+++ b/webrtc/video_send_stream.h
@@ -69,6 +69,8 @@
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;