Increase AV1 QP threshold for quality convergence from 40 to 60.

Bug: chromium:328598314
Change-Id: I132b4c30f132ace2bbef6359edd994c1ad75c9ad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/362620
Reviewed-by: Johannes Kron <kron@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43035}
diff --git a/video/quality_convergence_controller.cc b/video/quality_convergence_controller.cc
index d897635..c063f62 100644
--- a/video/quality_convergence_controller.cc
+++ b/video/quality_convergence_controller.cc
@@ -10,7 +10,11 @@
 
 #include "video/quality_convergence_controller.h"
 
+#include <algorithm>
+
 #include "rtc_base/checks.h"
+#include "rtc_base/experiments/struct_parameters_parser.h"
+#include "rtc_base/logging.h"
 
 namespace webrtc {
 namespace {
@@ -19,16 +23,38 @@
 // default configurations used for the software encoders.
 constexpr int kVp8DefaultStaticQpThreshold = 15;
 constexpr int kVp9DefaultStaticQpThreshold = 32;
-constexpr int kAv1DefaultStaticQpThreshold = 40;
+constexpr int kAv1DefaultStaticQpThreshold = 60;
 
-int GetDefaultStaticQpThreshold(VideoCodecType codec) {
+struct StaticDetectionConfig {
+  // Overrides the static QP threshold if set to a higher value than what is
+  // reported by the encoder.
+  std::optional<int> static_qp_threshold_override;
+  std::unique_ptr<StructParametersParser> Parser();
+};
+
+std::unique_ptr<StructParametersParser> StaticDetectionConfig::Parser() {
+  // The empty comments ensures that each pair is on a separate line.
+  return StructParametersParser::Create("static_qp_threshold",
+                                        &static_qp_threshold_override);
+}
+
+int GetDefaultStaticQpThreshold(VideoCodecType codec,
+                                const FieldTrialsView& trials) {
+  StaticDetectionConfig static_config;
+  int default_static_qp_threhsold = 0;
   switch (codec) {
     case kVideoCodecVP8:
-      return kVp8DefaultStaticQpThreshold;
+      default_static_qp_threhsold = kVp8DefaultStaticQpThreshold;
+      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-VP8"));
+      break;
     case kVideoCodecVP9:
-      return kVp9DefaultStaticQpThreshold;
+      default_static_qp_threhsold = kVp9DefaultStaticQpThreshold;
+      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-VP9"));
+      break;
     case kVideoCodecAV1:
-      return kAv1DefaultStaticQpThreshold;
+      default_static_qp_threhsold = kAv1DefaultStaticQpThreshold;
+      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-AV1"));
+      break;
     case kVideoCodecGeneric:
     case kVideoCodecH264:
     case kVideoCodecH265:
@@ -36,21 +62,31 @@
       // always >= 0.
       return -1;
   }
+
+  if (static_config.static_qp_threshold_override.has_value()) {
+    RTC_LOG(LS_INFO) << "static_qp_threshold_override: "
+                     << *static_config.static_qp_threshold_override;
+    return *static_config.static_qp_threshold_override;
+  }
+
+  return default_static_qp_threhsold;
 }
 }  // namespace
 
-void QualityConvergenceController::Initialize(
-    int number_of_layers,
-    std::optional<int> static_qp_threshold,
-    VideoCodecType codec,
-    const FieldTrialsView& trials) {
+void QualityConvergenceController::Initialize(int number_of_layers,
+                                              std::optional<int> encoder_min_qp,
+                                              VideoCodecType codec,
+                                              const FieldTrialsView& trials) {
   RTC_DCHECK(sequence_checker_.IsCurrent());
   RTC_CHECK(number_of_layers > 0);
   number_of_layers_ = number_of_layers;
   convergence_monitors_.clear();
 
-  int qp_threshold =
-      static_qp_threshold.value_or(GetDefaultStaticQpThreshold(codec));
+  int qp_threshold = GetDefaultStaticQpThreshold(codec, trials);
+  if (encoder_min_qp.has_value()) {
+    qp_threshold = std::max(qp_threshold, *encoder_min_qp);
+  }
+
   for (int i = 0; i < number_of_layers_; ++i) {
     convergence_monitors_.push_back(
         QualityConvergenceMonitor::Create(qp_threshold, codec, trials));
diff --git a/video/quality_convergence_controller_unittest.cc b/video/quality_convergence_controller_unittest.cc
index c1378e0..46965d4 100644
--- a/video/quality_convergence_controller_unittest.cc
+++ b/video/quality_convergence_controller_unittest.cc
@@ -10,56 +10,124 @@
  */
 #include "video/quality_convergence_controller.h"
 
+#include <optional>
+
 #include "test/gtest.h"
 #include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 namespace {
-constexpr int kStaticQpThreshold = 15;
+constexpr int kVp8DefaultStaticQpThreshold = 15;
 
 TEST(QualityConvergenceController, Singlecast) {
   test::ScopedKeyValueConfig field_trials;
   QualityConvergenceController controller;
-  controller.Initialize(1, kStaticQpThreshold, kVideoCodecVP8, field_trials);
+  controller.Initialize(1, /*encoder_min_qp=*/std::nullopt, kVideoCodecVP8,
+                        field_trials);
 
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/0, kStaticQpThreshold + 1, /*is_refresh_frame=*/false));
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/false));
   EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/0, kStaticQpThreshold, /*is_refresh_frame=*/false));
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold,
+      /*is_refresh_frame=*/false));
 }
 
 TEST(QualityConvergenceController, Simulcast) {
   test::ScopedKeyValueConfig field_trials;
   QualityConvergenceController controller;
-  controller.Initialize(2, kStaticQpThreshold, kVideoCodecVP8, field_trials);
+  controller.Initialize(2, /*encoder_min_qp=*/std::nullopt, kVideoCodecVP8,
+                        field_trials);
 
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/0, kStaticQpThreshold + 1, /*is_refresh_frame=*/false));
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/false));
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/1, kStaticQpThreshold + 1, /*is_refresh_frame=*/false));
+      /*layer_index=*/1, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/false));
 
   // Layer 0 reaches target quality.
   EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/0, kStaticQpThreshold, /*is_refresh_frame=*/false));
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold,
+      /*is_refresh_frame=*/false));
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/1, kStaticQpThreshold + 1, /*is_refresh_frame=*/false));
+      /*layer_index=*/1, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/false));
 
   // Frames are repeated for both layers. Layer 0 still at target quality.
   EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/0, kStaticQpThreshold, /*is_refresh_frame=*/true));
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold,
+      /*is_refresh_frame=*/true));
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/1, kStaticQpThreshold + 1, /*is_refresh_frame=*/true));
+      /*layer_index=*/1, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/true));
 }
 
 TEST(QualityConvergenceController, InvalidLayerIndex) {
   test::ScopedKeyValueConfig field_trials;
   QualityConvergenceController controller;
-  controller.Initialize(2, kStaticQpThreshold, kVideoCodecVP8, field_trials);
+  controller.Initialize(2, /*encoder_min_qp=*/std::nullopt, kVideoCodecVP8,
+                        field_trials);
 
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/-1, kStaticQpThreshold, /*is_refresh_frame=*/false));
+      /*layer_index=*/-1, kVp8DefaultStaticQpThreshold,
+      /*is_refresh_frame=*/false));
   EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
-      /*layer_index=*/3, kStaticQpThreshold, /*is_refresh_frame=*/false));
+      /*layer_index=*/3, kVp8DefaultStaticQpThreshold,
+      /*is_refresh_frame=*/false));
+}
+
+TEST(QualityConvergenceController, UseMaxOfEncoderMinAndDefaultQpThresholds) {
+  test::ScopedKeyValueConfig field_trials;
+  QualityConvergenceController controller;
+  controller.Initialize(1, kVp8DefaultStaticQpThreshold + 1, kVideoCodecVP8,
+                        field_trials);
+
+  EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold + 2,
+      /*is_refresh_frame=*/false));
+  EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, kVp8DefaultStaticQpThreshold + 1,
+      /*is_refresh_frame=*/false));
+}
+
+TEST(QualityConvergenceController, OverrideVp8StaticThreshold) {
+  test::ScopedKeyValueConfig field_trials(
+      "WebRTC-QCM-Static-VP8/static_qp_threshold:22/");
+  QualityConvergenceController controller;
+  controller.Initialize(1, /*encoder_min_qp=*/std::nullopt, kVideoCodecVP8,
+                        field_trials);
+
+  EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/23, /*is_refresh_frame=*/false));
+  EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/22, /*is_refresh_frame=*/false));
+}
+
+TEST(QualityConvergenceMonitorSetup, OverrideVp9StaticThreshold) {
+  test::ScopedKeyValueConfig field_trials(
+      "WebRTC-QCM-Static-VP9/static_qp_threshold:44/");
+  QualityConvergenceController controller;
+  controller.Initialize(1, /*encoder_min_qp=*/std::nullopt, kVideoCodecVP9,
+                        field_trials);
+
+  EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/45, /*is_refresh_frame=*/false));
+  EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/44, /*is_refresh_frame=*/false));
+}
+
+TEST(QualityConvergenceMonitorSetup, OverrideAv1StaticThreshold) {
+  test::ScopedKeyValueConfig field_trials(
+      "WebRTC-QCM-Static-AV1/static_qp_threshold:46/");
+  QualityConvergenceController controller;
+  controller.Initialize(1, /*encoder_min_qp=*/std::nullopt, kVideoCodecAV1,
+                        field_trials);
+
+  EXPECT_FALSE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/47, /*is_refresh_frame=*/false));
+  EXPECT_TRUE(controller.AddSampleAndCheckTargetQuality(
+      /*layer_index=*/0, /*qp=*/46, /*is_refresh_frame=*/false));
 }
 
 }  // namespace
diff --git a/video/quality_convergence_monitor.cc b/video/quality_convergence_monitor.cc
index 4094c7f..98b4703 100644
--- a/video/quality_convergence_monitor.cc
+++ b/video/quality_convergence_monitor.cc
@@ -22,19 +22,6 @@
 constexpr size_t kDefaultPastWindowLength = 6;
 constexpr float kDefaultAlpha = 0.06;
 
-struct StaticDetectionConfig {
-  // Overrides the static QP threshold if set to a higher value than what is
-  // reported by the encoder.
-  int static_qp_threshold_override = 0;
-  std::unique_ptr<StructParametersParser> Parser();
-};
-
-std::unique_ptr<StructParametersParser> StaticDetectionConfig::Parser() {
-  // The empty comments ensures that each pair is on a separate line.
-  return StructParametersParser::Create("static_qp_threshold",
-                                        &static_qp_threshold_override);
-}
-
 struct DynamicDetectionConfig {
   bool enabled = false;
   // alpha is a percentage of the codec-specific max QP value that is used to
@@ -58,30 +45,27 @@
 }
 
 QualityConvergenceMonitor::Parameters GetParameters(
-    int static_min_qp_threshold,
+    int static_qp_threshold,
     VideoCodecType codec,
     const FieldTrialsView& trials) {
   QualityConvergenceMonitor::Parameters params;
+  params.static_qp_threshold = static_qp_threshold;
 
-  StaticDetectionConfig static_config;
   DynamicDetectionConfig dynamic_config;
   // Apply codec specific settings.
   int max_qp = 0;
   switch (codec) {
     case kVideoCodecVP8:
-      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-VP8"));
       dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-VP8"));
       max_qp = 127;
       break;
     case kVideoCodecVP9:
-      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-VP9"));
       // Change to enabled by default for VP9.
       dynamic_config.enabled = true;
       dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-VP9"));
       max_qp = 255;
       break;
     case kVideoCodecAV1:
-      static_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Static-AV1"));
       // Change to enabled by default for AV1.
       dynamic_config.enabled = true;
       dynamic_config.Parser()->Parse(trials.Lookup("WebRTC-QCM-Dynamic-AV1"));
@@ -93,13 +77,10 @@
       break;
   }
 
-  params.static_qp_threshold = std::max(
-      static_min_qp_threshold, static_config.static_qp_threshold_override);
-
   if (dynamic_config.enabled) {
     params.dynamic_detection_enabled = dynamic_config.enabled;
     params.dynamic_qp_threshold =
-        static_min_qp_threshold + max_qp * dynamic_config.alpha;
+        static_qp_threshold + max_qp * dynamic_config.alpha;
     params.recent_window_length = dynamic_config.recent_length;
     params.past_window_length = dynamic_config.past_length;
   }
diff --git a/video/quality_convergence_monitor_unittest.cc b/video/quality_convergence_monitor_unittest.cc
index 4560308..2cb888d 100644
--- a/video/quality_convergence_monitor_unittest.cc
+++ b/video/quality_convergence_monitor_unittest.cc
@@ -18,7 +18,6 @@
 namespace webrtc {
 namespace {
 constexpr int kStaticQpThreshold = 13;
-constexpr int kDefaultDynamicThreshold = 28;  // 13 + 0.06 * 255.
 
 constexpr QualityConvergenceMonitor::Parameters kParametersOnlyStaticThreshold =
     {.static_qp_threshold = kStaticQpThreshold,
@@ -300,46 +299,5 @@
   EXPECT_FALSE(p.dynamic_detection_enabled);
 }
 
-TEST(QualityConvergenceMonitorSetup, OverrideVp8StaticThreshold) {
-  test::ScopedKeyValueConfig field_trials(
-      "WebRTC-QCM-Static-VP8/static_qp_threshold:22/");
-
-  auto monitor = QualityConvergenceMonitor::Create(
-      kStaticQpThreshold, kVideoCodecVP8, field_trials);
-  ASSERT_TRUE(monitor);
-  QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
-  EXPECT_EQ(p.static_qp_threshold, 22);
-  EXPECT_NE(p.static_qp_threshold, kStaticQpThreshold);
-  // Dynamic threshold is not tested since it's not enabled by default for VP8.
-}
-
-TEST(QualityConvergenceMonitorSetup, OverrideVp9StaticThreshold) {
-  test::ScopedKeyValueConfig field_trials(
-      "WebRTC-QCM-Static-VP9/static_qp_threshold:44/");
-
-  auto monitor = QualityConvergenceMonitor::Create(
-      kStaticQpThreshold, kVideoCodecVP9, field_trials);
-  ASSERT_TRUE(monitor);
-  QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
-  EXPECT_EQ(p.static_qp_threshold, 44);
-  EXPECT_NE(p.static_qp_threshold, kStaticQpThreshold);
-  // Dynamic QP threshold is unchanged.
-  EXPECT_EQ(p.dynamic_qp_threshold, kDefaultDynamicThreshold);
-}
-
-TEST(QualityConvergenceMonitorSetup, OverrideAv1StaticThreshold) {
-  test::ScopedKeyValueConfig field_trials(
-      "WebRTC-QCM-Static-AV1/static_qp_threshold:46/");
-
-  auto monitor = QualityConvergenceMonitor::Create(
-      kStaticQpThreshold, kVideoCodecAV1, field_trials);
-  ASSERT_TRUE(monitor);
-  QualityConvergenceMonitor::Parameters p = monitor->GetParametersForTesting();
-  EXPECT_EQ(p.static_qp_threshold, 46);
-  EXPECT_NE(p.static_qp_threshold, kStaticQpThreshold);
-  // Dynamic QP threshold is unchanged.
-  EXPECT_EQ(p.dynamic_qp_threshold, kDefaultDynamicThreshold);
-}
-
 }  // namespace
 }  // namespace webrtc