File webrtc-aom3.8-AV1E_SET_MAX_CONSEC_FRAME_DROP_CBR.patch of Package nodejs-electron

From f7a15067031cae07b1dac031fa263a9f01902f1c Mon Sep 17 00:00:00 2001
From: Sergey Silkin <ssilkin@webrtc.org>
Date: Tue, 9 Jul 2024 15:03:10 +0200
Subject: [PATCH] Adjust max consecutive drops depending on target frame rate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Current thresholds were tuned to guarantee no buffer overshoot in an extreme scenario (encoding a high complexity video in a low bitrate).

Bug: b/337757868, webrtc:351644568
Change-Id: I832b2564af6f18f06550338cc9b3618f8acdf831
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/356580
Reviewed-by: Dan Tan <dwtan@google.com>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42620}
---
 experiments/field_trials.py                   |  6 +--
 modules/video_coding/codecs/av1/BUILD.gn      |  2 +
 .../codecs/av1/libaom_av1_encoder.cc          | 42 +++++++++------
 .../codecs/av1/libaom_av1_encoder_unittest.cc | 53 ++++++++++++++-----
 4 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn
index 7d93de7a3a..197e1f3e19 100644
--- a/third_party/webrtc/modules/video_coding/codecs/av1/BUILD.gn
+++ b/third_party/webrtc/modules/video_coding/codecs/av1/BUILD.gn
@@ -60,6 +60,7 @@ rtc_library("libaom_av1_encoder") {
     "../../../../api/video_codecs:scalability_mode",
     "../../../../api/video_codecs:video_codecs_api",
     "../../../../common_video",
+    "../../../../modules/rtp_rtcp:rtp_rtcp_format",
     "../../../../rtc_base:checks",
     "../../../../rtc_base:logging",
     "../../../../rtc_base:rtc_numerics",
@@ -104,6 +105,7 @@ if (rtc_include_tests) {
         "../../../../api/units:data_size",
         "../../../../api/units:time_delta",
         "../../../../api/video:video_frame",
+        "../../../../modules/rtp_rtcp:rtp_rtcp_format",
         "../../../../test:scoped_key_value_config",
         "../../svc:scalability_mode_util",
         "../../svc:scalability_structures",
diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
index 3a8830252d..258d3d3b88 100644
--- a/third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
+++ b/third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder.cc
@@ -30,6 +30,7 @@
 #include "api/video_codecs/scalability_mode.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_encoder.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/include/video_error_codes.h"
 #include "modules/video_coding/svc/create_scalability_structure.h"
@@ -65,7 +66,6 @@ constexpr int kLowQindex = 145;   // Low qindex threshold for QP scaling.
 constexpr int kHighQindex = 205;  // High qindex threshold for QP scaling.
 constexpr int kBitDepth = 8;
 constexpr int kLagInFrames = 0;  // No look ahead.
-constexpr int kRtpTicksPerSecond = 90000;
 constexpr double kMinFrameRateFps = 1.0;
 
 aom_superblock_size_t GetSuperblockSize(int width, int height, int threads) {
@@ -133,7 +133,9 @@ class LibaomAv1Encoder final : public VideoEncoder {
   double framerate_fps_;  // Current target frame rate.
   int64_t timestamp_;
   const LibaomAv1EncoderInfoSettings encoder_info_override_;
-  int max_consec_frame_drop_;
+  // TODO(webrtc:351644568): Remove this kill-switch after the feature is fully
+  // deployed.
+  bool adaptive_max_consec_drops_;
 };
 
 int32_t VerifyCodecSettings(const VideoCodec& codec_settings) {
@@ -164,12 +166,12 @@ int32_t VerifyCodecSettings(const VideoCodec& codec_settings) {
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
-int GetMaxConsecutiveFrameDrop(const FieldTrialsView& field_trials) {
-  webrtc::FieldTrialParameter<int> maxdrop("maxdrop", 0);
-  webrtc::ParseFieldTrial(
-      {&maxdrop},
-      field_trials.Lookup("WebRTC-LibaomAv1Encoder-MaxConsecFrameDrop"));
-  return maxdrop;
+int GetMaxConsecDrops(double framerate_fps) {
+  // Consecutive frame drops result in a video freeze. We want to minimize the
+  // max number of consecutive drops and, at the same time, keep the value high
+  // enough to let encoder drain the buffer at overshoot.
+  constexpr double kMaxFreezeSeconds = 0.25;
+  return std::ceil(kMaxFreezeSeconds * framerate_fps);
 }
 
 LibaomAv1Encoder::LibaomAv1Encoder(const Environment& env,
@@ -182,7 +184,8 @@ LibaomAv1Encoder::LibaomAv1Encoder(const Environment& env,
       framerate_fps_(0),
       timestamp_(0),
       encoder_info_override_(env.field_trials()),
-      max_consec_frame_drop_(GetMaxConsecutiveFrameDrop(env.field_trials())) {}
+      adaptive_max_consec_drops_(!env.field_trials().IsDisabled(
+          "WebRTC-LibaomAv1Encoder-AdaptiveMaxConsecDrops")) {}
 
 LibaomAv1Encoder::~LibaomAv1Encoder() {
   Release();
@@ -242,7 +245,7 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
   cfg_.g_threads =
       NumberOfThreads(cfg_.g_w, cfg_.g_h, settings.number_of_cores);
   cfg_.g_timebase.num = 1;
-  cfg_.g_timebase.den = kRtpTicksPerSecond;
+  cfg_.g_timebase.den = kVideoPayloadTypeFrequency;
   cfg_.rc_target_bitrate = encoder_settings_.startBitrate;  // kilobits/sec.
   cfg_.rc_dropframe_thresh = encoder_settings_.GetFrameDropEnabled() ? 30 : 0;
   cfg_.g_input_bit_depth = kBitDepth;
@@ -304,12 +307,6 @@ int LibaomAv1Encoder::InitEncode(const VideoCodec* codec_settings,
     SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_ENABLE_PALETTE, 0);
   }
 
-  if (codec_settings->mode == VideoCodecMode::kRealtimeVideo &&
-      encoder_settings_.GetFrameDropEnabled() && max_consec_frame_drop_ > 0) {
-    SET_ENCODER_PARAM_OR_RETURN_ERROR(AV1E_SET_MAX_CONSEC_FRAME_DROP_CBR,
-                                      max_consec_frame_drop_);
-  }
-
   if (cfg_.g_threads == 8) {
     // Values passed to AV1E_SET_TILE_ROWS and AV1E_SET_TILE_COLUMNS are log2()
     // based.
@@ -659,7 +656,7 @@ int32_t LibaomAv1Encoder::Encode(
       return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
   }
 
-  const uint32_t duration = kRtpTicksPerSecond / framerate_fps_;
+  const uint32_t duration = kVideoPayloadTypeFrequency / framerate_fps_;
   timestamp_ += duration;
 
   const size_t num_spatial_layers =
@@ -836,6 +833,17 @@ void LibaomAv1Encoder::SetRates(const RateControlParameters& parameters) {
     SetEncoderControlParameters(AV1E_SET_SVC_PARAMS, &*svc_params_);
   }
 
+  if (adaptive_max_consec_drops_ &&
+      (!rates_configured_ || framerate_fps_ != parameters.framerate_fps)) {
+    int max_consec_drops = GetMaxConsecDrops(parameters.framerate_fps);
+    if (!SetEncoderControlParameters(AV1E_SET_MAX_CONSEC_FRAME_DROP_CBR,
+                                     max_consec_drops)) {
+      RTC_LOG(LS_WARNING)
+          << "Failed to set AV1E_SET_MAX_CONSEC_FRAME_DROP_CBR to "
+          << max_consec_drops;
+    }
+  }
+
   framerate_fps_ = parameters.framerate_fps;
 
   rates_configured_ = true;
diff --git a/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc b/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc
index abb6fce0cf..a00b03aeda 100644
--- a/third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc
+++ b/third_party/webrtc/modules/video_coding/codecs/av1/libaom_av1_encoder_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
 
+#include <algorithm>
 #include <limits>
 #include <memory>
 #include <utility>
@@ -22,6 +23,7 @@
 #include "api/test/frame_generator_interface.h"
 #include "api/video_codecs/video_codec.h"
 #include "api/video_codecs/video_encoder.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/video_coding/codecs/test/encoded_video_frame_producer.h"
 #include "modules/video_coding/include/video_error_codes.h"
 #include "test/gmock.h"
@@ -37,6 +39,7 @@ using ::testing::Eq;
 using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::SizeIs;
+using ::testing::Values;
 
 VideoCodec DefaultCodecSettings() {
   VideoCodec codec_settings;
@@ -199,32 +202,54 @@ TEST(LibaomAv1EncoderTest, CheckOddDimensionsWithSpatialLayers) {
   ASSERT_THAT(encoded_frames, SizeIs(6));
 }
 
-TEST(LibaomAv1EncoderTest, WithMaximumConsecutiveFrameDrop) {
-  auto field_trials = std::make_unique<ScopedKeyValueConfig>(
-      "WebRTC-LibaomAv1Encoder-MaxConsecFrameDrop/maxdrop:2/");
-  const Environment env = CreateEnvironment(std::move(field_trials));
+class LibaomAv1EncoderMaxConsecDropTest
+    : public ::testing::TestWithParam</*framerate_fps=*/int> {};
+
+TEST_P(LibaomAv1EncoderMaxConsecDropTest, MaxConsecDrops) {
   VideoBitrateAllocation allocation;
-  allocation.SetBitrate(0, 0, 1000);  // some very low bitrate
-  std::unique_ptr<VideoEncoder> encoder = CreateLibaomAv1Encoder(env);
+  allocation.SetBitrate(0, 0,
+                        1000);  // Very low bitrate to provoke frame drops.
+  std::unique_ptr<VideoEncoder> encoder =
+      CreateLibaomAv1Encoder(CreateEnvironment());
   VideoCodec codec_settings = DefaultCodecSettings();
   codec_settings.SetFrameDropEnabled(true);
   codec_settings.SetScalabilityMode(ScalabilityMode::kL1T1);
   codec_settings.startBitrate = allocation.get_sum_kbps();
+  codec_settings.maxFramerate = GetParam();
   ASSERT_EQ(encoder->InitEncode(&codec_settings, DefaultEncoderSettings()),
             WEBRTC_VIDEO_CODEC_OK);
   encoder->SetRates(VideoEncoder::RateControlParameters(
       allocation, codec_settings.maxFramerate));
-  EncodedVideoFrameProducer evfp(*encoder);
-  evfp.SetResolution(
-      RenderResolution{codec_settings.width, codec_settings.height});
-  // We should code the first frame, skip two, then code another frame.
   std::vector<EncodedVideoFrameProducer::EncodedFrame> encoded_frames =
-      evfp.SetNumInputFrames(4).Encode();
-  ASSERT_THAT(encoded_frames, SizeIs(2));
-  // The 4 frames have default Rtp-timestamps of 1000, 4000, 7000, 10000.
-  ASSERT_THAT(encoded_frames[1].encoded_image.RtpTimestamp(), 10000);
+      EncodedVideoFrameProducer(*encoder)
+          .SetNumInputFrames(60)
+          .SetFramerateFps(codec_settings.maxFramerate)
+          .SetResolution(RenderResolution{320, 180})
+          .Encode();
+  ASSERT_GE(encoded_frames.size(), 2u);
+
+  int max_consec_drops = 0;
+  for (size_t i = 1; i < encoded_frames.size(); ++i) {
+    uint32_t frame_duration_rtp =
+        encoded_frames[i].encoded_image.RtpTimestamp() -
+        encoded_frames[i - 1].encoded_image.RtpTimestamp();
+    // X consecutive drops result in a freeze of (X + 1) frame duration.
+    // Subtract 1 to get pure number of drops.
+    int num_drops = frame_duration_rtp * codec_settings.maxFramerate /
+                        kVideoPayloadTypeFrequency -
+                    1;
+    max_consec_drops = std::max(max_consec_drops, num_drops);
+  }
+
+  const int expected_max_consec_drops =
+      std::ceil(0.25 * codec_settings.maxFramerate);
+  EXPECT_EQ(max_consec_drops, expected_max_consec_drops);
 }
 
+INSTANTIATE_TEST_SUITE_P(LibaomAv1EncoderMaxConsecDropTests,
+                         LibaomAv1EncoderMaxConsecDropTest,
+                         Values(1, 2, 5, 15, 30, 60));
+
 TEST(LibaomAv1EncoderTest, EncoderInfoWithoutResolutionBitrateLimits) {
   std::unique_ptr<VideoEncoder> encoder =
       CreateLibaomAv1Encoder(CreateEnvironment());
openSUSE Build Service is sponsored by