Add ability to specify if rate controller of video encoder is trusted.

If rate controller is trusted, we disable the frame dropper in the
media optimization module.

This is a re-land of
https://webrtc-review.googlesource.com/c/src/+/105020

Bug: webrtc:9890
Change-Id: I418e47a43a1a98cb2fd5295c03360b954f2288f2
Reviewed-on: https://webrtc-review.googlesource.com/c/109141
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25570}
diff --git a/api/video_codecs/test/BUILD.gn b/api/video_codecs/test/BUILD.gn
index fa19162..6f9dcaa 100644
--- a/api/video_codecs/test/BUILD.gn
+++ b/api/video_codecs/test/BUILD.gn
@@ -21,6 +21,7 @@
       "..:builtin_video_encoder_factory",
       "..:rtc_software_fallback_wrappers",
       "..:video_codecs_api",
+      "../..:mock_video_encoder",
       "../../../modules/video_coding:video_codec_interface",
       "../../../modules/video_coding:video_coding_utility",
       "../../../modules/video_coding:webrtc_vp8",
diff --git a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
index 555914e..b374f3d 100644
--- a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
+++ b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
@@ -10,6 +10,7 @@
 
 #include <utility>
 
+#include "api/test/mock_video_encoder.h"
 #include "api/video/i420_buffer.h"
 #include "api/video/video_bitrate_allocation.h"
 #include "api/video_codecs/video_encoder_software_fallback_wrapper.h"
@@ -21,9 +22,12 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/fakeclock.h"
 #include "test/field_trial.h"
+#include "test/gmock.h"
 #include "test/gtest.h"
 
 namespace webrtc {
+using ::testing::Return;
+
 namespace {
 const int kWidth = 320;
 const int kHeight = 240;
@@ -33,6 +37,12 @@
 const int kDefaultMinPixelsPerFrame = 320 * 180;
 const int kLowThreshold = 10;
 const int kHighThreshold = 20;
+
+VideoEncoder::EncoderInfo GetEncoderInfo(bool trusted_rate_controller) {
+  VideoEncoder::EncoderInfo info;
+  info.has_trusted_rate_controller = trusted_rate_controller;
+  return info;
+}
 }  // namespace
 
 class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
@@ -512,4 +522,73 @@
   EXPECT_FALSE(settings.thresholds.has_value());
 }
 
+TEST(SoftwareFallbackEncoderTest, BothRateControllersNotTrusted) {
+  auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
+
+  EXPECT_CALL(*sw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(false)));
+  EXPECT_CALL(*hw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(false)));
+
+  std::unique_ptr<VideoEncoder> wrapper =
+      CreateVideoEncoderSoftwareFallbackWrapper(
+          std::unique_ptr<VideoEncoder>(sw_encoder),
+          std::unique_ptr<VideoEncoder>(hw_encoder));
+  EXPECT_FALSE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
+}
+
+TEST(SoftwareFallbackEncoderTest, SwRateControllerTrusted) {
+  auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  EXPECT_CALL(*sw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(true)));
+  EXPECT_CALL(*hw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(false)));
+
+  std::unique_ptr<VideoEncoder> wrapper =
+      CreateVideoEncoderSoftwareFallbackWrapper(
+          std::unique_ptr<VideoEncoder>(sw_encoder),
+          std::unique_ptr<VideoEncoder>(hw_encoder));
+  EXPECT_FALSE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
+}
+
+TEST(SoftwareFallbackEncoderTest, HwRateControllerTrusted) {
+  auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  EXPECT_CALL(*sw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(false)));
+  EXPECT_CALL(*hw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(true)));
+
+  std::unique_ptr<VideoEncoder> wrapper =
+      CreateVideoEncoderSoftwareFallbackWrapper(
+          std::unique_ptr<VideoEncoder>(sw_encoder),
+          std::unique_ptr<VideoEncoder>(hw_encoder));
+  EXPECT_TRUE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
+
+  // Trigger fallback to software.
+  EXPECT_CALL(*hw_encoder, Encode)
+      .WillOnce(Return(WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE));
+  VideoFrame frame = VideoFrame::Builder().build();
+  wrapper->Encode(frame, nullptr, nullptr);
+
+  EXPECT_FALSE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
+}
+
+TEST(SoftwareFallbackEncoderTest, BothRateControllersTrusted) {
+  auto* sw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  auto* hw_encoder = new testing::NiceMock<MockVideoEncoder>();
+  EXPECT_CALL(*sw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(true)));
+  EXPECT_CALL(*hw_encoder, GetEncoderInfo())
+      .WillRepeatedly(Return(GetEncoderInfo(true)));
+
+  std::unique_ptr<VideoEncoder> wrapper =
+      CreateVideoEncoderSoftwareFallbackWrapper(
+          std::unique_ptr<VideoEncoder>(sw_encoder),
+          std::unique_ptr<VideoEncoder>(hw_encoder));
+  EXPECT_TRUE(wrapper->GetEncoderInfo().has_trusted_rate_controller);
+}
+
 }  // namespace webrtc
diff --git a/api/video_codecs/video_encoder.cc b/api/video_codecs/video_encoder.cc
index 0963886..363edbf 100644
--- a/api/video_codecs/video_encoder.cc
+++ b/api/video_codecs/video_encoder.cc
@@ -86,7 +86,8 @@
 VideoEncoder::EncoderInfo::EncoderInfo()
     : scaling_settings(VideoEncoder::ScalingSettings::kOff),
       supports_native_handle(false),
-      implementation_name("unknown") {}
+      implementation_name("unknown"),
+      has_trusted_rate_controller(false) {}
 
 VideoEncoder::EncoderInfo::~EncoderInfo() = default;
 
diff --git a/api/video_codecs/video_encoder.h b/api/video_codecs/video_encoder.h
index f8f0313..d881f8a 100644
--- a/api/video_codecs/video_encoder.h
+++ b/api/video_codecs/video_encoder.h
@@ -132,6 +132,19 @@
 
     // The name of this particular encoder implementation, e.g. "libvpx".
     std::string implementation_name;
+
+    // If this field is true, the encoder rate controller must perform
+    // well even in difficult situations, and produce close to the specified
+    // target bitrate seen over a reasonable time window, drop frames if
+    // necessary in order to keep the rate correct, and react quickly to
+    // changing bitrate targets. If this method returns true, we disable the
+    // frame dropper in the media optimization module and rely entirely on the
+    // encoder to produce media at a bitrate that closely matches the target.
+    // Any overshooting may result in delay buildup. If this method returns
+    // false (default behavior), the media opt frame dropper will drop input
+    // frames if it suspect encoder misbehavior. Misbehavior is common,
+    // especially in hardware codecs. Disable media opt at your own risk.
+    bool has_trusted_rate_controller;
   };
 
   static VideoCodecVP8 GetDefaultVp8Settings();
@@ -220,6 +233,10 @@
   virtual bool SupportsNativeHandle() const;
   virtual const char* ImplementationName() const;
 
+  // Returns meta-data about the encoder, such as implementation name.
+  // The output of this method may change during runtime. For instance if a
+  // hardware encoder fails, it may fall back to doing software encoding using
+  // an implementation with different characteristics.
   virtual EncoderInfo GetEncoderInfo() const;
 };
 }  // namespace webrtc