WebRTC-DeprecateGlobalFieldTrialString/Enabled/ - part 10/inf

This patch takes a stab at modules/video_coding,
but reaches only about half.

Bug: webrtc:10335
Change-Id: I0d47d0468b818145470c51ae4e8e75ff58d499ae
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/256112
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36335}
diff --git a/api/video/BUILD.gn b/api/video/BUILD.gn
index 34b7f22..6b34b6f 100644
--- a/api/video/BUILD.gn
+++ b/api/video/BUILD.gn
@@ -267,6 +267,7 @@
 
   deps = [
     ":video_stream_decoder",
+    "../../api:webrtc_key_value_config",
     "../../rtc_base:rtc_base_approved",
     "../../video:video_stream_decoder_impl",
     "../task_queue",
diff --git a/api/video/video_stream_decoder_create.cc b/api/video/video_stream_decoder_create.cc
index 8d70556..c64a2d8 100644
--- a/api/video/video_stream_decoder_create.cc
+++ b/api/video/video_stream_decoder_create.cc
@@ -20,10 +20,13 @@
     VideoStreamDecoderInterface::Callbacks* callbacks,
     VideoDecoderFactory* decoder_factory,
     TaskQueueFactory* task_queue_factory,
-    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings) {
-  return std::make_unique<VideoStreamDecoderImpl>(callbacks, decoder_factory,
-                                                  task_queue_factory,
-                                                  std::move(decoder_settings));
+    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings,
+    // TODO(jonaso, webrtc:10335): Consider what to do with factories
+    // vs. field trials.
+    const WebRtcKeyValueConfig* field_trials) {
+  return std::make_unique<VideoStreamDecoderImpl>(
+      callbacks, decoder_factory, task_queue_factory,
+      std::move(decoder_settings), field_trials);
 }
 
 }  // namespace webrtc
diff --git a/api/video/video_stream_decoder_create.h b/api/video/video_stream_decoder_create.h
index 9c898ec..9591412 100644
--- a/api/video/video_stream_decoder_create.h
+++ b/api/video/video_stream_decoder_create.h
@@ -18,6 +18,7 @@
 #include "api/task_queue/task_queue_factory.h"
 #include "api/video/video_stream_decoder.h"
 #include "api/video_codecs/sdp_video_format.h"
+#include "api/webrtc_key_value_config.h"
 
 namespace webrtc {
 // The `decoder_settings` parameter is a map between:
@@ -28,7 +29,8 @@
     VideoStreamDecoderInterface::Callbacks* callbacks,
     VideoDecoderFactory* decoder_factory,
     TaskQueueFactory* task_queue_factory,
-    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings);
+    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings,
+    const WebRtcKeyValueConfig* field_trials = nullptr);
 
 }  // namespace webrtc
 
diff --git a/call/call.cc b/call/call.cc
index 9db3adc..22907b92 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -1154,7 +1154,7 @@
   VideoReceiveStream2* receive_stream = new VideoReceiveStream2(
       task_queue_factory_, this, num_cpu_cores_,
       transport_send_->packet_router(), std::move(configuration),
-      call_stats_.get(), clock_, std::make_unique<VCMTiming>(clock_),
+      call_stats_.get(), clock_, std::make_unique<VCMTiming>(clock_, trials()),
       &nack_periodic_processor_, decode_sync_.get());
   // TODO(bugs.webrtc.org/11993): Set this up asynchronously on the network
   // thread.
diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h
index 96d881b..498efcf 100644
--- a/media/engine/fake_webrtc_call.h
+++ b/media/engine/fake_webrtc_call.h
@@ -360,6 +360,10 @@
         *trials_, field_trial_string);
   }
 
+  const webrtc::WebRtcKeyValueConfig& trials() const override {
+    return *trials_;
+  }
+
  private:
   webrtc::AudioSendStream* CreateAudioSendStream(
       const webrtc::AudioSendStream::Config& config) override;
@@ -401,10 +405,6 @@
 
   webrtc::Call::Stats GetStats() const override;
 
-  const webrtc::WebRtcKeyValueConfig& trials() const override {
-    return *trials_;
-  }
-
   webrtc::TaskQueueBase* network_thread() const override;
   webrtc::TaskQueueBase* worker_thread() const override;
 
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index 7d6b5da..a328d91 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -82,6 +82,7 @@
   deps = [
     "..:module_api",
     "../../api:sequence_checker",
+    "../../api:webrtc_key_value_config",
     "../../api/task_queue",
     "../../api/units:time_delta",
     "../../api/units:timestamp",
@@ -93,7 +94,6 @@
     "../../rtc_base/task_utils:pending_task_safety_flag",
     "../../rtc_base/task_utils:repeating_task",
     "../../system_wrappers",
-    "../../system_wrappers:field_trial",
     "../utility",
   ]
 }
@@ -167,11 +167,11 @@
   ]
   deps = [
     ":video_coding_utility",
+    "../../api:webrtc_key_value_config",
     "../../api/units:timestamp",
     "../../api/video:encoded_frame",
     "../../rtc_base:logging",
     "../../rtc_base:rtc_numerics",
-    "../../system_wrappers:field_trial",
   ]
   absl_deps = [
     "//third_party/abseil-cpp/absl/algorithm:container",
@@ -188,6 +188,7 @@
     "timing.h",
   ]
   deps = [
+    "../../api:webrtc_key_value_config",
     "../../api/units:time_delta",
     "../../api/video:video_rtp_headers",
     "../../rtc_base:logging",
@@ -197,7 +198,6 @@
     "../../rtc_base/synchronization:mutex",
     "../../rtc_base/time:timestamp_extrapolator",
     "../../system_wrappers",
-    "../../system_wrappers:field_trial",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
 }
@@ -221,6 +221,7 @@
   ]
   deps = [
     ":rtt_filter",
+    "../../api:webrtc_key_value_config",
     "../../api/units:data_size",
     "../../api/units:frequency",
     "../../api/units:time_delta",
@@ -229,7 +230,6 @@
     "../../rtc_base:safe_conversions",
     "../../rtc_base/experiments:jitter_upper_bound_experiment",
     "../../system_wrappers",
-    "../../system_wrappers:field_trial",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
 }
@@ -314,6 +314,7 @@
     "../../api:rtp_packet_info",
     "../../api:scoped_refptr",
     "../../api:sequence_checker",
+    "../../api:webrtc_key_value_config",
     "../../api/task_queue",
     "../../api/units:data_rate",
     "../../api/units:data_size",
@@ -424,6 +425,8 @@
     "../../api:rtp_headers",
     "../../api:rtp_packet_info",
     "../../api:sequence_checker",
+    "../../api:webrtc_key_value_config",
+    "../../api/transport:field_trial_based_config",
     "../../api/units:timestamp",
     "../../api/video:encoded_image",
     "../../api/video:video_frame",
@@ -436,6 +439,7 @@
     "../../rtc_base:logging",
     "../../rtc_base:rtc_base_approved",
     "../../rtc_base:rtc_event",
+    "../../rtc_base/memory:always_valid_pointer",
     "../../rtc_base/synchronization:mutex",
     "../../system_wrappers",
     "../rtp_rtcp:rtp_rtcp_format",
@@ -497,6 +501,7 @@
     "../../api:array_view",
     "../../api:scoped_refptr",
     "../../api:sequence_checker",
+    "../../api:webrtc_key_value_config",
     "../../api/video:encoded_frame",
     "../../api/video:encoded_image",
     "../../api/video:video_adaptation",
@@ -1233,6 +1238,7 @@
       "../../test:fake_video_codecs",
       "../../test:field_trial",
       "../../test:fileutils",
+      "../../test:scoped_key_value_config",
       "../../test:test_common",
       "../../test:test_support",
       "../../test:video_test_common",
diff --git a/modules/video_coding/deprecated/BUILD.gn b/modules/video_coding/deprecated/BUILD.gn
index a6fa790..9e4b65f 100644
--- a/modules/video_coding/deprecated/BUILD.gn
+++ b/modules/video_coding/deprecated/BUILD.gn
@@ -17,6 +17,7 @@
   deps = [
     "..:nack_requester",
     "../..:module_api",
+    "../../../api:webrtc_key_value_config",
     "../../../api/units:time_delta",
     "../../../api/units:timestamp",
     "../../../rtc_base:checks",
@@ -27,7 +28,6 @@
     "../../../rtc_base/experiments:field_trial_parser",
     "../../../rtc_base/synchronization:mutex",
     "../../../system_wrappers",
-    "../../../system_wrappers:field_trial",
     "../../utility",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/base:core_headers" ]
diff --git a/modules/video_coding/deprecated/nack_module.cc b/modules/video_coding/deprecated/nack_module.cc
index 334eb82..4a6ae09 100644
--- a/modules/video_coding/deprecated/nack_module.cc
+++ b/modules/video_coding/deprecated/nack_module.cc
@@ -18,7 +18,6 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/logging.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
@@ -33,10 +32,9 @@
 const int kNumReorderingBuckets = 10;
 const int kDefaultSendNackDelayMs = 0;
 
-int64_t GetSendNackDelay() {
+int64_t GetSendNackDelay(const WebRtcKeyValueConfig& field_trials) {
   int64_t delay_ms = strtol(
-      webrtc::field_trial::FindFullName("WebRTC-SendNackDelayMs").c_str(),
-      nullptr, 10);
+      field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10);
   if (delay_ms > 0 && delay_ms <= 20) {
     RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms;
     return delay_ms;
@@ -63,7 +61,8 @@
     : min_retry_interval(min_retry), max_rtt(max_rtt), base(base) {}
 
 absl::optional<DEPRECATED_NackModule::BackoffSettings>
-DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials() {
+DEPRECATED_NackModule::BackoffSettings::ParseFromFieldTrials(
+    const WebRtcKeyValueConfig& field_trials) {
   // Matches magic number in RTPSender::OnReceivedNack().
   const TimeDelta kDefaultMinRetryInterval = TimeDelta::Millis(5);
   // Upper bound on link-delay considered for exponential backoff.
@@ -79,7 +78,7 @@
   FieldTrialParameter<TimeDelta> max_rtt("max_rtt", kDefaultMaxRtt);
   FieldTrialParameter<double> base("base", kDefaultBase);
   ParseFieldTrial({&enabled, &min_retry, &max_rtt, &base},
-                  field_trial::FindFullName("WebRTC-ExponentialNackBackoff"));
+                  field_trials.Lookup("WebRTC-ExponentialNackBackoff"));
 
   if (enabled) {
     return DEPRECATED_NackModule::BackoffSettings(min_retry.Get(),
@@ -91,7 +90,8 @@
 DEPRECATED_NackModule::DEPRECATED_NackModule(
     Clock* clock,
     NackSender* nack_sender,
-    KeyFrameRequestSender* keyframe_request_sender)
+    KeyFrameRequestSender* keyframe_request_sender,
+    const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
       nack_sender_(nack_sender),
       keyframe_request_sender_(keyframe_request_sender),
@@ -100,8 +100,8 @@
       rtt_ms_(kDefaultRttMs),
       newest_seq_num_(0),
       next_process_time_ms_(-1),
-      send_nack_delay_ms_(GetSendNackDelay()),
-      backoff_settings_(BackoffSettings::ParseFromFieldTrials()) {
+      send_nack_delay_ms_(GetSendNackDelay(field_trials)),
+      backoff_settings_(BackoffSettings::ParseFromFieldTrials(field_trials)) {
   RTC_DCHECK(clock_);
   RTC_DCHECK(nack_sender_);
   RTC_DCHECK(keyframe_request_sender_);
diff --git a/modules/video_coding/deprecated/nack_module.h b/modules/video_coding/deprecated/nack_module.h
index ec1a688..8d17fff 100644
--- a/modules/video_coding/deprecated/nack_module.h
+++ b/modules/video_coding/deprecated/nack_module.h
@@ -19,6 +19,7 @@
 
 #include "absl/base/attributes.h"
 #include "api/units/time_delta.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/include/module.h"
 #include "modules/include/module_common_types.h"
 #include "modules/video_coding/histogram.h"
@@ -33,7 +34,8 @@
  public:
   DEPRECATED_NackModule(Clock* clock,
                         NackSender* nack_sender,
-                        KeyFrameRequestSender* keyframe_request_sender);
+                        KeyFrameRequestSender* keyframe_request_sender,
+                        const WebRtcKeyValueConfig& field_trials);
 
   int OnReceivedPacket(uint16_t seq_num, bool is_keyframe);
   int OnReceivedPacket(uint16_t seq_num, bool is_keyframe, bool is_recovered);
@@ -69,7 +71,8 @@
 
   struct BackoffSettings {
     BackoffSettings(TimeDelta min_retry, TimeDelta max_rtt, double base);
-    static absl::optional<BackoffSettings> ParseFromFieldTrials();
+    static absl::optional<BackoffSettings> ParseFromFieldTrials(
+        const WebRtcKeyValueConfig& field_trials);
 
     // Min time between nacks.
     const TimeDelta min_retry_interval;
diff --git a/modules/video_coding/frame_buffer2.cc b/modules/video_coding/frame_buffer2.cc
index b4b9c11..bfa3b36 100644
--- a/modules/video_coding/frame_buffer2.cc
+++ b/modules/video_coding/frame_buffer2.cc
@@ -33,7 +33,6 @@
 #include "rtc_base/numerics/sequence_number_util.h"
 #include "rtc_base/trace_event.h"
 #include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace video_coding {
@@ -58,11 +57,12 @@
 
 FrameBuffer::FrameBuffer(Clock* clock,
                          VCMTiming* timing,
-                         VCMReceiveStatisticsCallback* stats_callback)
+                         VCMReceiveStatisticsCallback* stats_callback,
+                         const WebRtcKeyValueConfig& field_trials)
     : decoded_frames_history_(kMaxFramesHistory),
       clock_(clock),
       callback_queue_(nullptr),
-      jitter_estimator_(clock),
+      jitter_estimator_(clock, field_trials),
       timing_(timing),
       stopped_(false),
       protection_mode_(kProtectionNack),
@@ -73,7 +73,7 @@
           "max_decode_queue_size",
           kZeroPlayoutDelayDefaultMaxDecodeQueueSize) {
   ParseFieldTrial({&zero_playout_delay_max_decode_queue_size_},
-                  field_trial::FindFullName("WebRTC-ZeroPlayoutDelay"));
+                  field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
   callback_checker_.Detach();
 }
 
diff --git a/modules/video_coding/frame_buffer2.h b/modules/video_coding/frame_buffer2.h
index 5cefa8b..cd4cbcd 100644
--- a/modules/video_coding/frame_buffer2.h
+++ b/modules/video_coding/frame_buffer2.h
@@ -20,6 +20,7 @@
 #include "absl/container/inlined_vector.h"
 #include "api/sequence_checker.h"
 #include "api/video/encoded_frame.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/include/video_coding_defines.h"
 #include "modules/video_coding/inter_frame_delay.h"
 #include "modules/video_coding/jitter_estimator.h"
@@ -47,7 +48,8 @@
  public:
   FrameBuffer(Clock* clock,
               VCMTiming* timing,
-              VCMReceiveStatisticsCallback* stats_callback);
+              VCMReceiveStatisticsCallback* stats_callback,
+              const WebRtcKeyValueConfig& field_trials);
 
   FrameBuffer() = delete;
   FrameBuffer(const FrameBuffer&) = delete;
diff --git a/modules/video_coding/frame_buffer2_unittest.cc b/modules/video_coding/frame_buffer2_unittest.cc
index d8ba863..b0e3f1d 100644
--- a/modules/video_coding/frame_buffer2_unittest.cc
+++ b/modules/video_coding/frame_buffer2_unittest.cc
@@ -28,6 +28,7 @@
 #include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 #include "test/time_controller/simulated_time_controller.h"
 
 using ::testing::_;
@@ -40,7 +41,8 @@
 
 class VCMTimingFake : public VCMTiming {
  public:
-  explicit VCMTimingFake(Clock* clock) : VCMTiming(clock) {}
+  explicit VCMTimingFake(Clock* clock, const WebRtcKeyValueConfig& field_trials)
+      : VCMTiming(clock, field_trials) {}
 
   Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const override {
     if (last_render_time_.IsMinusInfinity()) {
@@ -131,10 +133,11 @@
             time_controller_.GetTaskQueueFactory()->CreateTaskQueue(
                 "extract queue",
                 TaskQueueFactory::Priority::NORMAL)),
-        timing_(time_controller_.GetClock()),
+        timing_(time_controller_.GetClock(), field_trials_),
         buffer_(new FrameBuffer(time_controller_.GetClock(),
                                 &timing_,
-                                &stats_callback_)),
+                                &stats_callback_,
+                                field_trials_)),
         rand_(0x34678213) {}
 
   template <typename... T>
@@ -213,6 +216,7 @@
 
   uint32_t Rand() { return rand_.Rand<uint32_t>(); }
 
+  test::ScopedKeyValueConfig field_trials_;
   webrtc::GlobalSimulatedTimeController time_controller_;
   rtc::TaskQueue time_task_queue_;
   VCMTimingFake timing_;
@@ -276,9 +280,10 @@
 }
 
 TEST_F(TestFrameBuffer2, ZeroPlayoutDelay) {
-  VCMTiming timing(time_controller_.GetClock());
-  buffer_.reset(
-      new FrameBuffer(time_controller_.GetClock(), &timing, &stats_callback_));
+  test::ScopedKeyValueConfig field_trials;
+  VCMTiming timing(time_controller_.GetClock(), field_trials);
+  buffer_.reset(new FrameBuffer(time_controller_.GetClock(), &timing,
+                                &stats_callback_, field_trials));
   const VideoPlayoutDelay kPlayoutDelayMs = {0, 0};
   std::unique_ptr<FrameObjectFake> test_frame(new FrameObjectFake());
   test_frame->SetId(0);
diff --git a/modules/video_coding/frame_buffer3.cc b/modules/video_coding/frame_buffer3.cc
index d02a997..7be5ffa 100644
--- a/modules/video_coding/frame_buffer3.cc
+++ b/modules/video_coding/frame_buffer3.cc
@@ -19,7 +19,6 @@
 #include "absl/container/inlined_vector.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/sequence_number_util.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
@@ -63,9 +62,11 @@
 }
 }  // namespace
 
-FrameBuffer::FrameBuffer(int max_size, int max_decode_history)
+FrameBuffer::FrameBuffer(int max_size,
+                         int max_decode_history,
+                         const WebRtcKeyValueConfig& field_trials)
     : legacy_frame_id_jump_behavior_(
-          !field_trial::IsDisabled("WebRTC-LegacyFrameIdJumpBehavior")),
+          !field_trials.IsDisabled("WebRTC-LegacyFrameIdJumpBehavior")),
       max_size_(max_size),
       decoded_frame_history_(max_decode_history) {}
 
diff --git a/modules/video_coding/frame_buffer3.h b/modules/video_coding/frame_buffer3.h
index 1f3f71a..9683195 100644
--- a/modules/video_coding/frame_buffer3.h
+++ b/modules/video_coding/frame_buffer3.h
@@ -19,6 +19,7 @@
 #include "absl/types/optional.h"
 #include "api/units/timestamp.h"
 #include "api/video/encoded_frame.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/utility/decoded_frames_history.h"
 
 namespace webrtc {
@@ -33,7 +34,10 @@
   // The `max_size` determines the maxmimum number of frames the buffer will
   // store, and max_decode_history determines how far back (by frame ID) the
   // buffer will store if a frame was decoded or not.
-  FrameBuffer(int max_size, int max_decode_history);
+  FrameBuffer(int max_size,
+              int max_decode_history,
+              // TODO(hta): remove field trials!
+              const WebRtcKeyValueConfig& field_trials);
   FrameBuffer(const FrameBuffer&) = delete;
   FrameBuffer& operator=(const FrameBuffer&) = delete;
   ~FrameBuffer() = default;
diff --git a/modules/video_coding/frame_buffer3_unittest.cc b/modules/video_coding/frame_buffer3_unittest.cc
index b70cd14..27a25f2 100644
--- a/modules/video_coding/frame_buffer3_unittest.cc
+++ b/modules/video_coding/frame_buffer3_unittest.cc
@@ -15,6 +15,7 @@
 #include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 namespace {
@@ -79,7 +80,9 @@
 };
 
 TEST(FrameBuffer3Test, RejectInvalidRefs) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   // Ref must be less than the id of this frame.
   buffer.InsertFrame(Builder().Time(0).Id(0).Refs({0}).AsLast().Build());
   EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt));
@@ -91,7 +94,9 @@
 }
 
 TEST(FrameBuffer3Test, LastContinuousUpdatesOnInsertedFrames) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   EXPECT_THAT(buffer.LastContinuousFrameId(), Eq(absl::nullopt));
   EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
 
@@ -105,7 +110,9 @@
 }
 
 TEST(FrameBuffer3Test, LastContinuousFrameReordering) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build());
@@ -116,7 +123,9 @@
 }
 
 TEST(FrameBuffer3Test, LastContinuousTemporalUnit) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(10).Id(1).Build());
   EXPECT_THAT(buffer.LastContinuousTemporalUnitFrameId(), Eq(absl::nullopt));
@@ -125,7 +134,9 @@
 }
 
 TEST(FrameBuffer3Test, LastContinuousTemporalUnitReordering) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(10).Id(1).Build());
   buffer.InsertFrame(Builder().Time(20).Id(3).Refs({1}).Build());
@@ -137,7 +148,9 @@
 }
 
 TEST(FrameBuffer3Test, NextDecodable) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(),
               Eq(absl::nullopt));
@@ -146,7 +159,9 @@
 }
 
 TEST(FrameBuffer3Test, AdvanceNextDecodableOnExtraction) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build());
@@ -164,7 +179,9 @@
 }
 
 TEST(FrameBuffer3Test, AdvanceLastDecodableOnExtraction) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
@@ -177,7 +194,9 @@
 }
 
 TEST(FrameBuffer3Test, FrameUpdatesNextDecodable) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
 
   buffer.InsertFrame(Builder().Time(20).Id(2).AsLast().Build());
   EXPECT_THAT(buffer.NextDecodableTemporalUnitRtpTimestamp(), Eq(20U));
@@ -187,7 +206,9 @@
 }
 
 TEST(FrameBuffer3Test, KeyframeClearsFullBuffer) {
-  FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/5, /*max_decode_history=*/10,
+                     field_trials);
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
   buffer.InsertFrame(Builder().Time(30).Id(3).Refs({2}).AsLast().Build());
@@ -204,7 +225,9 @@
 }
 
 TEST(FrameBuffer3Test, DropNextDecodableTemporalUnit) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
   buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
@@ -216,7 +239,9 @@
 }
 
 TEST(FrameBuffer3Test, OldFramesAreIgnored) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
 
@@ -232,7 +257,9 @@
 }
 
 TEST(FrameBuffer3Test, ReturnFullTemporalUnitKSVC) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   buffer.InsertFrame(Builder().Time(10).Id(1).Build());
   buffer.InsertFrame(Builder().Time(10).Id(2).Refs({1}).Build());
   buffer.InsertFrame(Builder().Time(10).Id(3).Refs({2}).AsLast().Build());
@@ -245,7 +272,9 @@
 }
 
 TEST(FrameBuffer3Test, InterleavedStream) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
   buffer.InsertFrame(Builder().Time(20).Id(2).Refs({1}).AsLast().Build());
   buffer.InsertFrame(Builder().Time(30).Id(3).Refs({1}).AsLast().Build());
@@ -275,9 +304,10 @@
 
 TEST(FrameBuffer3Test, LegacyFrameIdJumpBehavior) {
   {
-    test::ScopedFieldTrials field_trial(
+    test::ScopedKeyValueConfig field_trials(
         "WebRTC-LegacyFrameIdJumpBehavior/Disabled/");
-    FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+    FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                       field_trials);
 
     buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
     EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
@@ -288,7 +318,9 @@
 
   {
     // WebRTC-LegacyFrameIdJumpBehavior is disabled by default.
-    FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+    test::ScopedKeyValueConfig field_trials;
+    FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                       field_trials);
 
     buffer.InsertFrame(Builder().Time(20).Id(3).AsLast().Build());
     EXPECT_THAT(buffer.ExtractNextDecodableTemporalUnit(),
@@ -302,7 +334,9 @@
 }
 
 TEST(FrameBuffer3Test, TotalNumberOfContinuousTemporalUnits) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   EXPECT_THAT(buffer.GetTotalNumberOfContinuousTemporalUnits(), Eq(0));
 
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
@@ -321,7 +355,9 @@
 }
 
 TEST(FrameBuffer3Test, TotalNumberOfDroppedFrames) {
-  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/10, /*max_decode_history=*/100,
+                     field_trials);
   EXPECT_THAT(buffer.GetTotalNumberOfDroppedFrames(), Eq(0));
 
   buffer.InsertFrame(Builder().Time(10).Id(1).AsLast().Build());
diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc
index 4b55f85b..78d77d3 100644
--- a/modules/video_coding/generic_decoder.cc
+++ b/modules/video_coding/generic_decoder.cc
@@ -23,12 +23,13 @@
 #include "rtc_base/time_utils.h"
 #include "rtc_base/trace_event.h"
 #include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
-VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming* timing,
-                                                 Clock* clock)
+VCMDecodedFrameCallback::VCMDecodedFrameCallback(
+    VCMTiming* timing,
+    Clock* clock,
+    const WebRtcKeyValueConfig& field_trials)
     : _clock(clock),
       _timing(timing),
       _timestampMap(kDecoderFrameMemoryLength),
@@ -40,10 +41,10 @@
       _clock->CurrentNtpInMilliseconds() - _clock->TimeInMilliseconds();
 
   ParseFieldTrial({&_extra_decode_time},
-                  field_trial::FindFullName("WebRTC-SlowDownDecoder"));
+                  field_trials.Lookup("WebRTC-SlowDownDecoder"));
   ParseFieldTrial({&low_latency_renderer_enabled_,
                    &low_latency_renderer_include_predecode_buffer_},
-                  field_trial::FindFullName("WebRTC-LowLatencyRenderer"));
+                  field_trials.Lookup("WebRTC-LowLatencyRenderer"));
 }
 
 VCMDecodedFrameCallback::~VCMDecodedFrameCallback() {}
diff --git a/modules/video_coding/generic_decoder.h b/modules/video_coding/generic_decoder.h
index 31d8460..34f22c4 100644
--- a/modules/video_coding/generic_decoder.h
+++ b/modules/video_coding/generic_decoder.h
@@ -16,6 +16,7 @@
 #include "api/sequence_checker.h"
 #include "api/units/time_delta.h"
 #include "api/video_codecs/video_decoder.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/encoded_frame.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/timestamp_map.h"
@@ -31,7 +32,9 @@
 
 class VCMDecodedFrameCallback : public DecodedImageCallback {
  public:
-  VCMDecodedFrameCallback(VCMTiming* timing, Clock* clock);
+  VCMDecodedFrameCallback(VCMTiming* timing,
+                          Clock* clock,
+                          const WebRtcKeyValueConfig& field_trials);
   ~VCMDecodedFrameCallback() override;
   void SetUserReceiveCallback(VCMReceiveCallback* receiveCallback);
   VCMReceiveCallback* UserReceiveCallback();
diff --git a/modules/video_coding/generic_decoder_unittest.cc b/modules/video_coding/generic_decoder_unittest.cc
index 466459e..d9ca8c6 100644
--- a/modules/video_coding/generic_decoder_unittest.cc
+++ b/modules/video_coding/generic_decoder_unittest.cc
@@ -24,6 +24,7 @@
 #include "test/fake_decoder.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 namespace video_coding {
@@ -66,10 +67,10 @@
  protected:
   GenericDecoderTest()
       : clock_(0),
-        timing_(&clock_),
+        timing_(&clock_, field_trials_),
         task_queue_factory_(CreateDefaultTaskQueueFactory()),
         decoder_(task_queue_factory_.get()),
-        vcm_callback_(&timing_, &clock_),
+        vcm_callback_(&timing_, &clock_, field_trials_),
         generic_decoder_(&decoder_) {}
 
   void SetUp() override {
@@ -82,6 +83,7 @@
     generic_decoder_.Configure(settings);
   }
 
+  test::ScopedKeyValueConfig field_trials_;
   SimulatedClock clock_;
   VCMTiming timing_;
   std::unique_ptr<TaskQueueFactory> task_queue_factory_;
diff --git a/modules/video_coding/include/video_coding.h b/modules/video_coding/include/video_coding.h
index 77b3eac..8cedc4a 100644
--- a/modules/video_coding/include/video_coding.h
+++ b/modules/video_coding/include/video_coding.h
@@ -13,6 +13,7 @@
 
 #include "api/video/video_frame.h"
 #include "api/video_codecs/video_decoder.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/include/module.h"
 #include "modules/rtp_rtcp/source/rtp_video_header.h"
 #include "modules/video_coding/include/video_coding_defines.h"
@@ -28,7 +29,9 @@
 class VideoCodingModule : public Module {
  public:
   // DEPRECATED.
-  static VideoCodingModule* Create(Clock* clock);
+  static VideoCodingModule* Create(
+      Clock* clock,
+      const WebRtcKeyValueConfig* field_trials = nullptr);
 
   /*
    *   Receiver
diff --git a/modules/video_coding/jitter_buffer.cc b/modules/video_coding/jitter_buffer.cc
index f51b6ec..5983bc1 100644
--- a/modules/video_coding/jitter_buffer.cc
+++ b/modules/video_coding/jitter_buffer.cc
@@ -109,7 +109,8 @@
 }
 
 VCMJitterBuffer::VCMJitterBuffer(Clock* clock,
-                                 std::unique_ptr<EventWrapper> event)
+                                 std::unique_ptr<EventWrapper> event,
+                                 const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
       running_(false),
       frame_event_(std::move(event)),
@@ -122,7 +123,7 @@
       num_consecutive_old_packets_(0),
       num_packets_(0),
       num_duplicated_packets_(0),
-      jitter_estimate_(clock),
+      jitter_estimate_(clock, field_trials),
       missing_sequence_numbers_(SequenceNumberLessThan()),
       latest_received_sequence_number_(0),
       max_nack_list_size_(0),
diff --git a/modules/video_coding/jitter_buffer.h b/modules/video_coding/jitter_buffer.h
index df7581a..70e65be 100644
--- a/modules/video_coding/jitter_buffer.h
+++ b/modules/video_coding/jitter_buffer.h
@@ -17,6 +17,7 @@
 #include <set>
 #include <vector>
 
+#include "api/webrtc_key_value_config.h"
 #include "modules/include/module_common_types.h"
 #include "modules/include/module_common_types_public.h"
 #include "modules/video_coding/decoding_state.h"
@@ -69,7 +70,9 @@
 
 class VCMJitterBuffer {
  public:
-  VCMJitterBuffer(Clock* clock, std::unique_ptr<EventWrapper> event);
+  VCMJitterBuffer(Clock* clock,
+                  std::unique_ptr<EventWrapper> event,
+                  const WebRtcKeyValueConfig& field_trials);
 
   ~VCMJitterBuffer();
 
diff --git a/modules/video_coding/jitter_buffer_unittest.cc b/modules/video_coding/jitter_buffer_unittest.cc
index 801eeb6..930eca5 100644
--- a/modules/video_coding/jitter_buffer_unittest.cc
+++ b/modules/video_coding/jitter_buffer_unittest.cc
@@ -23,11 +23,10 @@
 #include "modules/video_coding/test/stream_generator.h"
 #include "rtc_base/location.h"
 #include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/field_trial.h"
 #include "system_wrappers/include/metrics.h"
-#include "test/field_trial.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 
@@ -37,7 +36,7 @@
   void SetUp() override {
     clock_.reset(new SimulatedClock(0));
     jitter_buffer_.reset(new VCMJitterBuffer(
-        clock_.get(), absl::WrapUnique(EventWrapper::Create())));
+        clock_.get(), absl::WrapUnique(EventWrapper::Create()), field_trials_));
     jitter_buffer_->Start();
     seq_num_ = 1234;
     timestamp_ = 0;
@@ -118,6 +117,7 @@
   uint32_t timestamp_;
   int size_;
   uint8_t data_[1500];
+  test::ScopedKeyValueConfig field_trials_;
   std::unique_ptr<VCMPacket> packet_;
   std::unique_ptr<SimulatedClock> clock_;
   std::unique_ptr<VCMJitterBuffer> jitter_buffer_;
@@ -132,7 +132,7 @@
     max_nack_list_size_ = 150;
     oldest_packet_to_nack_ = 250;
     jitter_buffer_ = new VCMJitterBuffer(
-        clock_.get(), absl::WrapUnique(EventWrapper::Create()));
+        clock_.get(), absl::WrapUnique(EventWrapper::Create()), field_trials_);
     stream_generator_ = new StreamGenerator(0, clock_->TimeInMilliseconds());
     jitter_buffer_->Start();
     jitter_buffer_->SetNackSettings(max_nack_list_size_, oldest_packet_to_nack_,
@@ -212,6 +212,7 @@
     return ret;
   }
 
+  test::ScopedKeyValueConfig field_trials_;
   VCMJitterBuffer* jitter_buffer_;
   StreamGenerator* stream_generator_;
   std::unique_ptr<SimulatedClock> clock_;
diff --git a/modules/video_coding/jitter_estimator.cc b/modules/video_coding/jitter_estimator.cc
index 5ecd545..e38dfaa 100644
--- a/modules/video_coding/jitter_estimator.cc
+++ b/modules/video_coding/jitter_estimator.cc
@@ -21,11 +21,11 @@
 #include "api/units/frequency.h"
 #include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/rtt_filter.h"
 #include "rtc_base/experiments/jitter_upper_bound_experiment.h"
 #include "rtc_base/numerics/safe_conversions.h"
 #include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
@@ -49,14 +49,15 @@
 
 }  // namespace
 
-VCMJitterEstimator::VCMJitterEstimator(Clock* clock)
+VCMJitterEstimator::VCMJitterEstimator(Clock* clock,
+                                       const WebRtcKeyValueConfig& field_trials)
     : fps_counter_(30),  // TODO(sprang): Use an estimator with limit based on
                          // time, rather than number of samples.
       time_deviation_upper_bound_(
           JitterUpperBoundExperiment::GetUpperBoundSigmas().value_or(
               kDefaultMaxTimestampDeviationInSigmas)),
       enable_reduced_delay_(
-          !field_trial::IsEnabled("WebRTC-ReducedJitterDelayKillSwitch")),
+          !field_trials.IsEnabled("WebRTC-ReducedJitterDelayKillSwitch")),
       clock_(clock) {
   Reset();
 }
diff --git a/modules/video_coding/jitter_estimator.h b/modules/video_coding/jitter_estimator.h
index 026fb7e..9672d88 100644
--- a/modules/video_coding/jitter_estimator.h
+++ b/modules/video_coding/jitter_estimator.h
@@ -16,6 +16,7 @@
 #include "api/units/frequency.h"
 #include "api/units/time_delta.h"
 #include "api/units/timestamp.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/rtt_filter.h"
 #include "rtc_base/rolling_accumulator.h"
 
@@ -25,7 +26,8 @@
 
 class VCMJitterEstimator {
  public:
-  explicit VCMJitterEstimator(Clock* clock);
+  explicit VCMJitterEstimator(Clock* clock,
+                              const WebRtcKeyValueConfig& field_trials);
   virtual ~VCMJitterEstimator();
   VCMJitterEstimator(const VCMJitterEstimator&) = delete;
   VCMJitterEstimator& operator=(const VCMJitterEstimator&) = delete;
diff --git a/modules/video_coding/jitter_estimator_tests.cc b/modules/video_coding/jitter_estimator_tests.cc
index f4bb7fc..b1df95b 100644
--- a/modules/video_coding/jitter_estimator_tests.cc
+++ b/modules/video_coding/jitter_estimator_tests.cc
@@ -23,8 +23,8 @@
 #include "rtc_base/strings/string_builder.h"
 #include "rtc_base/time_utils.h"
 #include "system_wrappers/include/clock.h"
-#include "test/field_trial.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 
@@ -33,10 +33,12 @@
   TestVCMJitterEstimator() : fake_clock_(0) {}
 
   virtual void SetUp() {
-    estimator_ = std::make_unique<VCMJitterEstimator>(&fake_clock_);
+    estimator_ =
+        std::make_unique<VCMJitterEstimator>(&fake_clock_, field_trials_);
   }
 
   SimulatedClock fake_clock_;
+  test::ScopedKeyValueConfig field_trials_;
   std::unique_ptr<VCMJitterEstimator> estimator_;
 };
 
@@ -78,8 +80,8 @@
 }
 
 TEST_F(TestVCMJitterEstimator, TestLowRateDisabled) {
-  test::ScopedFieldTrials field_trials(
-      "WebRTC-ReducedJitterDelayKillSwitch/Enabled/");
+  test::ScopedKeyValueConfig field_trials(
+      field_trials_, "WebRTC-ReducedJitterDelayKillSwitch/Enabled/");
   SetUp();
 
   ValueGenerator gen(10);
@@ -132,7 +134,7 @@
     rtc::SimpleStringBuilder ssb(string_buf);
     ssb << JitterUpperBoundExperiment::kJitterUpperBoundExperimentName
         << "/Enabled-" << context.upper_bound << "/";
-    test::ScopedFieldTrials field_trials(ssb.str());
+    test::ScopedKeyValueConfig field_trials(field_trials_, ssb.str());
     SetUp();
 
     ValueGenerator gen(50);
diff --git a/modules/video_coding/nack_module_unittest.cc b/modules/video_coding/nack_module_unittest.cc
index f91eb75..704f2cd 100644
--- a/modules/video_coding/nack_module_unittest.cc
+++ b/modules/video_coding/nack_module_unittest.cc
@@ -16,8 +16,8 @@
 #include <memory>
 
 #include "system_wrappers/include/clock.h"
-#include "test/field_trial.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 class TestNackModule : public ::testing::TestWithParam<bool>,
@@ -29,7 +29,7 @@
         field_trial_(GetParam()
                          ? "WebRTC-ExponentialNackBackoff/enabled:true/"
                          : "WebRTC-ExponentialNackBackoff/enabled:false/"),
-        nack_module_(clock_.get(), this, this),
+        nack_module_(clock_.get(), this, this, field_trial_),
         keyframes_requested_(0) {}
 
   void SetUp() override { nack_module_.UpdateRtt(kDefaultRttMs); }
@@ -44,7 +44,7 @@
 
   static constexpr int64_t kDefaultRttMs = 20;
   std::unique_ptr<SimulatedClock> clock_;
-  test::ScopedFieldTrials field_trial_;
+  test::ScopedKeyValueConfig field_trial_;
   DEPRECATED_NackModule nack_module_;
   std::vector<uint16_t> sent_nacks_;
   int keyframes_requested_;
@@ -339,7 +339,7 @@
   TestNackModuleWithFieldTrial()
       : nack_delay_field_trial_("WebRTC-SendNackDelayMs/10/"),
         clock_(new SimulatedClock(0)),
-        nack_module_(clock_.get(), this, this),
+        nack_module_(clock_.get(), this, this, nack_delay_field_trial_),
         keyframes_requested_(0) {}
 
   void SendNack(const std::vector<uint16_t>& sequence_numbers,
@@ -350,7 +350,7 @@
 
   void RequestKeyFrame() override { ++keyframes_requested_; }
 
-  test::ScopedFieldTrials nack_delay_field_trial_;
+  test::ScopedKeyValueConfig nack_delay_field_trial_;
   std::unique_ptr<SimulatedClock> clock_;
   DEPRECATED_NackModule nack_module_;
   std::vector<uint16_t> sent_nacks_;
diff --git a/modules/video_coding/nack_requester.cc b/modules/video_coding/nack_requester.cc
index dac85fc..7cd824e 100644
--- a/modules/video_coding/nack_requester.cc
+++ b/modules/video_coding/nack_requester.cc
@@ -20,7 +20,6 @@
 #include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/task_queue.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
@@ -33,10 +32,9 @@
 const int kNumReorderingBuckets = 10;
 const int kDefaultSendNackDelayMs = 0;
 
-int64_t GetSendNackDelay() {
+int64_t GetSendNackDelay(const WebRtcKeyValueConfig& field_trials) {
   int64_t delay_ms = strtol(
-      webrtc::field_trial::FindFullName("WebRTC-SendNackDelayMs").c_str(),
-      nullptr, 10);
+      field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10);
   if (delay_ms > 0 && delay_ms <= 20) {
     RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms;
     return delay_ms;
@@ -110,7 +108,8 @@
     : min_retry_interval(min_retry), max_rtt(max_rtt), base(base) {}
 
 absl::optional<NackRequester::BackoffSettings>
-NackRequester::BackoffSettings::ParseFromFieldTrials() {
+NackRequester::BackoffSettings::ParseFromFieldTrials(
+    const WebRtcKeyValueConfig& field_trials) {
   // Matches magic number in RTPSender::OnReceivedNack().
   const TimeDelta kDefaultMinRetryInterval = TimeDelta::Millis(5);
   // Upper bound on link-delay considered for exponential backoff.
@@ -126,7 +125,7 @@
   FieldTrialParameter<TimeDelta> max_rtt("max_rtt", kDefaultMaxRtt);
   FieldTrialParameter<double> base("base", kDefaultBase);
   ParseFieldTrial({&enabled, &min_retry, &max_rtt, &base},
-                  field_trial::FindFullName("WebRTC-ExponentialNackBackoff"));
+                  field_trials.Lookup("WebRTC-ExponentialNackBackoff"));
 
   if (enabled) {
     return NackRequester::BackoffSettings(min_retry.Get(), max_rtt.Get(),
@@ -139,7 +138,8 @@
                              NackPeriodicProcessor* periodic_processor,
                              Clock* clock,
                              NackSender* nack_sender,
-                             KeyFrameRequestSender* keyframe_request_sender)
+                             KeyFrameRequestSender* keyframe_request_sender,
+                             const WebRtcKeyValueConfig& field_trials)
     : worker_thread_(current_queue),
       clock_(clock),
       nack_sender_(nack_sender),
@@ -148,8 +148,8 @@
       initialized_(false),
       rtt_ms_(kDefaultRttMs),
       newest_seq_num_(0),
-      send_nack_delay_ms_(GetSendNackDelay()),
-      backoff_settings_(BackoffSettings::ParseFromFieldTrials()),
+      send_nack_delay_ms_(GetSendNackDelay(field_trials)),
+      backoff_settings_(BackoffSettings::ParseFromFieldTrials(field_trials)),
       processor_registration_(this, periodic_processor) {
   RTC_DCHECK(clock_);
   RTC_DCHECK(nack_sender_);
diff --git a/modules/video_coding/nack_requester.h b/modules/video_coding/nack_requester.h
index 46d904b..a01fb7c 100644
--- a/modules/video_coding/nack_requester.h
+++ b/modules/video_coding/nack_requester.h
@@ -19,6 +19,7 @@
 
 #include "api/sequence_checker.h"
 #include "api/units/time_delta.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/include/module_common_types.h"
 #include "modules/video_coding/histogram.h"
 #include "rtc_base/numerics/sequence_number_util.h"
@@ -70,7 +71,8 @@
                 NackPeriodicProcessor* periodic_processor,
                 Clock* clock,
                 NackSender* nack_sender,
-                KeyFrameRequestSender* keyframe_request_sender);
+                KeyFrameRequestSender* keyframe_request_sender,
+                const WebRtcKeyValueConfig& field_trials);
   ~NackRequester();
 
   void ProcessNacks() override;
@@ -104,7 +106,8 @@
 
   struct BackoffSettings {
     BackoffSettings(TimeDelta min_retry, TimeDelta max_rtt, double base);
-    static absl::optional<BackoffSettings> ParseFromFieldTrials();
+    static absl::optional<BackoffSettings> ParseFromFieldTrials(
+        const WebRtcKeyValueConfig& field_trials);
 
     // Min time between nacks.
     const TimeDelta min_retry_interval;
diff --git a/modules/video_coding/nack_requester_unittest.cc b/modules/video_coding/nack_requester_unittest.cc
index 0e5d415..2234249 100644
--- a/modules/video_coding/nack_requester_unittest.cc
+++ b/modules/video_coding/nack_requester_unittest.cc
@@ -16,9 +16,9 @@
 #include <memory>
 
 #include "system_wrappers/include/clock.h"
-#include "test/field_trial.h"
 #include "test/gtest.h"
 #include "test/run_loop.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 // TODO(bugs.webrtc.org/11594): Use the use the GlobalSimulatedTimeController
@@ -86,7 +86,7 @@
         std::make_unique<NackPeriodicProcessor>(interval);
     nack_module_ = std::make_unique<NackRequester>(
         TaskQueueBase::Current(), nack_periodic_processor_.get(), clock_.get(),
-        this, this);
+        this, this, field_trial_);
     nack_module_->UpdateRtt(kDefaultRttMs);
     return *nack_module_.get();
   }
@@ -94,7 +94,7 @@
   static constexpr int64_t kDefaultRttMs = 20;
   test::RunLoop loop_;
   std::unique_ptr<SimulatedClock> clock_;
-  test::ScopedFieldTrials field_trial_;
+  test::ScopedKeyValueConfig field_trial_;
   std::unique_ptr<NackPeriodicProcessor> nack_periodic_processor_;
   std::unique_ptr<NackRequester> nack_module_;
   std::vector<uint16_t> sent_nacks_;
@@ -387,7 +387,8 @@
                      &nack_periodic_processor_,
                      clock_.get(),
                      this,
-                     this),
+                     this,
+                     nack_delay_field_trial_),
         keyframes_requested_(0) {}
 
   void SendNack(const std::vector<uint16_t>& sequence_numbers,
@@ -398,7 +399,7 @@
 
   void RequestKeyFrame() override { ++keyframes_requested_; }
 
-  test::ScopedFieldTrials nack_delay_field_trial_;
+  test::ScopedKeyValueConfig nack_delay_field_trial_;
   std::unique_ptr<SimulatedClock> clock_;
   NackPeriodicProcessor nack_periodic_processor_;
   NackRequester nack_module_;
diff --git a/modules/video_coding/receiver.cc b/modules/video_coding/receiver.cc
index e09a056..1503731 100644
--- a/modules/video_coding/receiver.cc
+++ b/modules/video_coding/receiver.cc
@@ -30,18 +30,22 @@
 
 enum { kMaxReceiverDelayMs = 10000 };
 
-VCMReceiver::VCMReceiver(VCMTiming* timing, Clock* clock)
+VCMReceiver::VCMReceiver(VCMTiming* timing,
+                         Clock* clock,
+                         const WebRtcKeyValueConfig& field_trials)
     : VCMReceiver::VCMReceiver(timing,
                                clock,
                                absl::WrapUnique(EventWrapper::Create()),
-                               absl::WrapUnique(EventWrapper::Create())) {}
+                               absl::WrapUnique(EventWrapper::Create()),
+                               field_trials) {}
 
 VCMReceiver::VCMReceiver(VCMTiming* timing,
                          Clock* clock,
                          std::unique_ptr<EventWrapper> receiver_event,
-                         std::unique_ptr<EventWrapper> jitter_buffer_event)
+                         std::unique_ptr<EventWrapper> jitter_buffer_event,
+                         const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
-      jitter_buffer_(clock_, std::move(jitter_buffer_event)),
+      jitter_buffer_(clock_, std::move(jitter_buffer_event), field_trials),
       timing_(timing),
       render_wait_event_(std::move(receiver_event)),
       max_video_delay_ms_(kMaxVideoDelayMs) {
diff --git a/modules/video_coding/receiver.h b/modules/video_coding/receiver.h
index 8f6b041..c82ec2d 100644
--- a/modules/video_coding/receiver.h
+++ b/modules/video_coding/receiver.h
@@ -14,6 +14,7 @@
 #include <memory>
 #include <vector>
 
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/event_wrapper.h"
 #include "modules/video_coding/include/video_coding.h"
 #include "modules/video_coding/include/video_coding_defines.h"
@@ -28,7 +29,9 @@
 
 class VCMReceiver {
  public:
-  VCMReceiver(VCMTiming* timing, Clock* clock);
+  VCMReceiver(VCMTiming* timing,
+              Clock* clock,
+              const WebRtcKeyValueConfig& field_trials);
 
   // Using this constructor, you can specify a different event implemetation for
   // the jitter buffer. Useful for unit tests when you want to simulate incoming
@@ -37,7 +40,8 @@
   VCMReceiver(VCMTiming* timing,
               Clock* clock,
               std::unique_ptr<EventWrapper> receiver_event,
-              std::unique_ptr<EventWrapper> jitter_buffer_event);
+              std::unique_ptr<EventWrapper> jitter_buffer_event,
+              const WebRtcKeyValueConfig& field_trials);
 
   ~VCMReceiver();
 
diff --git a/modules/video_coding/receiver_unittest.cc b/modules/video_coding/receiver_unittest.cc
index e38f9c5..a9755b7 100644
--- a/modules/video_coding/receiver_unittest.cc
+++ b/modules/video_coding/receiver_unittest.cc
@@ -24,6 +24,7 @@
 #include "rtc_base/checks.h"
 #include "system_wrappers/include/clock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 
@@ -31,8 +32,8 @@
  protected:
   TestVCMReceiver()
       : clock_(0),
-        timing_(&clock_),
-        receiver_(&timing_, &clock_),
+        timing_(&clock_, field_trials_),
+        receiver_(&timing_, &clock_, field_trials_),
         stream_generator_(0, clock_.TimeInMilliseconds()) {}
 
   int32_t InsertPacket(int index) {
@@ -78,6 +79,7 @@
     return true;
   }
 
+  test::ScopedKeyValueConfig field_trials_;
   SimulatedClock clock_;
   VCMTiming timing_;
   VCMReceiver receiver_;
@@ -365,16 +367,17 @@
   VCMReceiverTimingTest()
       : clock_(&stream_generator_, &receiver_),
         stream_generator_(0, clock_.TimeInMilliseconds()),
-        timing_(&clock_),
+        timing_(&clock_, field_trials_),
         receiver_(
             &timing_,
             &clock_,
             std::unique_ptr<EventWrapper>(new FrameInjectEvent(&clock_, false)),
-            std::unique_ptr<EventWrapper>(
-                new FrameInjectEvent(&clock_, true))) {}
+            std::unique_ptr<EventWrapper>(new FrameInjectEvent(&clock_, true)),
+            field_trials_) {}
 
   virtual void SetUp() {}
 
+  test::ScopedKeyValueConfig field_trials_;
   SimulatedClockWithFrames clock_;
   StreamGenerator stream_generator_;
   VCMTiming timing_;
diff --git a/modules/video_coding/timing.cc b/modules/video_coding/timing.cc
index 72d1414..da71279 100644
--- a/modules/video_coding/timing.cc
+++ b/modules/video_coding/timing.cc
@@ -16,7 +16,6 @@
 #include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/time/timestamp_extrapolator.h"
 #include "system_wrappers/include/clock.h"
-#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace {
@@ -25,7 +24,7 @@
 constexpr TimeDelta kZeroPlayoutDelayDefaultMinPacing = TimeDelta::Millis(8);
 }  // namespace
 
-VCMTiming::VCMTiming(Clock* clock)
+VCMTiming::VCMTiming(Clock* clock, const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
       ts_extrapolator_(
           std::make_unique<TimestampExtrapolator>(clock_->CurrentTime())),
@@ -42,9 +41,9 @@
                                      kZeroPlayoutDelayDefaultMinPacing),
       last_decode_scheduled_(Timestamp::Zero()) {
   ParseFieldTrial({&low_latency_renderer_enabled_},
-                  field_trial::FindFullName("WebRTC-LowLatencyRenderer"));
+                  field_trials.Lookup("WebRTC-LowLatencyRenderer"));
   ParseFieldTrial({&zero_playout_delay_min_pacing_},
-                  field_trial::FindFullName("WebRTC-ZeroPlayoutDelay"));
+                  field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
 }
 
 void VCMTiming::Reset() {
diff --git a/modules/video_coding/timing.h b/modules/video_coding/timing.h
index c1f1c3a..7471740 100644
--- a/modules/video_coding/timing.h
+++ b/modules/video_coding/timing.h
@@ -16,6 +16,7 @@
 #include "absl/types/optional.h"
 #include "api/units/time_delta.h"
 #include "api/video/video_timing.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/codec_timer.h"
 #include "rtc_base/experiments/field_trial_parser.h"
 #include "rtc_base/synchronization/mutex.h"
@@ -32,7 +33,7 @@
   static constexpr auto kDefaultRenderDelay = TimeDelta::Millis(10);
   static constexpr auto kDelayMaxChangeMsPerS = 100;
 
-  explicit VCMTiming(Clock* clock);
+  VCMTiming(Clock* clock, const WebRtcKeyValueConfig& field_trials);
   virtual ~VCMTiming() = default;
 
   // Resets the timing to the initial state.
diff --git a/modules/video_coding/timing_unittest.cc b/modules/video_coding/timing_unittest.cc
index 1f5c12f..20667c9 100644
--- a/modules/video_coding/timing_unittest.cc
+++ b/modules/video_coding/timing_unittest.cc
@@ -13,8 +13,8 @@
 #include "api/units/frequency.h"
 #include "api/units/time_delta.h"
 #include "system_wrappers/include/clock.h"
-#include "test/field_trial.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 namespace {
@@ -25,8 +25,9 @@
 }  // namespace
 
 TEST(ReceiverTimingTest, JitterDelay) {
+  test::ScopedKeyValueConfig field_trials;
   SimulatedClock clock(0);
-  VCMTiming timing(&clock);
+  VCMTiming timing(&clock, field_trials);
   timing.Reset();
 
   uint32_t timestamp = 0;
@@ -118,8 +119,9 @@
 
 TEST(ReceiverTimingTest, TimestampWrapAround) {
   constexpr auto kStartTime = Timestamp::Millis(1337);
+  test::ScopedKeyValueConfig field_trials;
   SimulatedClock clock(kStartTime);
-  VCMTiming timing(&clock);
+  VCMTiming timing(&clock, field_trials);
 
   // Provoke a wrap-around. The fifth frame will have wrapped at 25 fps.
   constexpr uint32_t kRtpTicksPerFrame = k90kHz / k25Fps;
@@ -143,7 +145,8 @@
   constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60);
   constexpr Timestamp kZeroRenderTime = Timestamp::Zero();
   SimulatedClock clock(kStartTimeUs);
-  VCMTiming timing(&clock);
+  test::ScopedKeyValueConfig field_trials;
+  VCMTiming timing(&clock, field_trials);
   timing.Reset();
   timing.set_max_playout_delay(TimeDelta::Zero());
   for (int i = 0; i < 10; ++i) {
@@ -175,13 +178,13 @@
   // The minimum pacing is enabled by a field trial and active if the RTP
   // playout delay header extension is set to min==0.
   constexpr TimeDelta kMinPacing = TimeDelta::Millis(3);
-  test::ScopedFieldTrials override_field_trials(
+  test::ScopedKeyValueConfig field_trials(
       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
   constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60);
   constexpr auto kZeroRenderTime = Timestamp::Zero();
   SimulatedClock clock(kStartTimeUs);
-  VCMTiming timing(&clock);
+  VCMTiming timing(&clock, field_trials);
   timing.Reset();
   // MaxWaitingTime() returns zero for evenly spaced video frames.
   for (int i = 0; i < 10; ++i) {
@@ -224,12 +227,12 @@
 TEST(ReceiverTimingTest, DefaultMaxWaitingTimeUnaffectedByPacingExperiment) {
   // The minimum pacing is enabled by a field trial but should not have any
   // effect if render_time_ms is greater than 0;
-  test::ScopedFieldTrials override_field_trials(
+  test::ScopedKeyValueConfig field_trials(
       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
   const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0);
   SimulatedClock clock(kStartTimeUs);
-  VCMTiming timing(&clock);
+  VCMTiming timing(&clock, field_trials);
   timing.Reset();
   clock.AdvanceTime(kTimeDelta);
   auto now = clock.CurrentTime();
@@ -255,13 +258,13 @@
   // The minimum pacing is enabled by a field trial and active if the RTP
   // playout delay header extension is set to min==0.
   constexpr TimeDelta kMinPacing = TimeDelta::Millis(3);
-  test::ScopedFieldTrials override_field_trials(
+  test::ScopedKeyValueConfig field_trials(
       "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/");
   constexpr int64_t kStartTimeUs = 3.15e13;  // About one year in us.
   const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0);
   constexpr auto kZeroRenderTime = Timestamp::Zero();
   SimulatedClock clock(kStartTimeUs);
-  VCMTiming timing(&clock);
+  VCMTiming timing(&clock, field_trials);
   timing.Reset();
   // MaxWaitingTime() returns zero for evenly spaced video frames.
   for (int i = 0; i < 10; ++i) {
diff --git a/modules/video_coding/video_coding_impl.cc b/modules/video_coding/video_coding_impl.cc
index 0129aa1..f3187d9 100644
--- a/modules/video_coding/video_coding_impl.cc
+++ b/modules/video_coding/video_coding_impl.cc
@@ -14,9 +14,12 @@
 #include <memory>
 
 #include "api/sequence_checker.h"
+#include "api/transport/field_trial_based_config.h"
 #include "api/video/encoded_image.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "modules/video_coding/timing.h"
+#include "rtc_base/memory/always_valid_pointer.h"
 #include "system_wrappers/include/clock.h"
 
 namespace webrtc {
@@ -41,10 +44,12 @@
 
 class VideoCodingModuleImpl : public VideoCodingModule {
  public:
-  explicit VideoCodingModuleImpl(Clock* clock)
+  explicit VideoCodingModuleImpl(Clock* clock,
+                                 const WebRtcKeyValueConfig* field_trials)
       : VideoCodingModule(),
-        timing_(new VCMTiming(clock)),
-        receiver_(clock, timing_.get()) {}
+        field_trials_(field_trials),
+        timing_(new VCMTiming(clock, *field_trials_)),
+        receiver_(clock, timing_.get(), *field_trials_) {}
 
   ~VideoCodingModuleImpl() override {}
 
@@ -104,6 +109,8 @@
   }
 
  private:
+  AlwaysValidPointer<const WebRtcKeyValueConfig, FieldTrialBasedConfig>
+      field_trials_;
   SequenceChecker construction_thread_;
   const std::unique_ptr<VCMTiming> timing_;
   vcm::VideoReceiver receiver_;
@@ -112,9 +119,11 @@
 
 // DEPRECATED.  Create method for current interface, will be removed when the
 // new jitter buffer is in place.
-VideoCodingModule* VideoCodingModule::Create(Clock* clock) {
+VideoCodingModule* VideoCodingModule::Create(
+    Clock* clock,
+    const WebRtcKeyValueConfig* field_trials) {
   RTC_DCHECK(clock);
-  return new VideoCodingModuleImpl(clock);
+  return new VideoCodingModuleImpl(clock, field_trials);
 }
 
 }  // namespace webrtc
diff --git a/modules/video_coding/video_coding_impl.h b/modules/video_coding/video_coding_impl.h
index 10ebd41..10adf55 100644
--- a/modules/video_coding/video_coding_impl.h
+++ b/modules/video_coding/video_coding_impl.h
@@ -17,6 +17,7 @@
 
 #include "absl/types/optional.h"
 #include "api/sequence_checker.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/decoder_database.h"
 #include "modules/video_coding/frame_buffer.h"
 #include "modules/video_coding/generic_decoder.h"
@@ -56,7 +57,9 @@
 
 class VideoReceiver : public Module {
  public:
-  VideoReceiver(Clock* clock, VCMTiming* timing);
+  VideoReceiver(Clock* clock,
+                VCMTiming* timing,
+                const WebRtcKeyValueConfig& field_trials);
   ~VideoReceiver() override;
 
   void RegisterReceiveCodec(uint8_t payload_type,
diff --git a/modules/video_coding/video_receiver.cc b/modules/video_coding/video_receiver.cc
index 055d524..ebfdd1b 100644
--- a/modules/video_coding/video_receiver.cc
+++ b/modules/video_coding/video_receiver.cc
@@ -40,11 +40,13 @@
 namespace webrtc {
 namespace vcm {
 
-VideoReceiver::VideoReceiver(Clock* clock, VCMTiming* timing)
+VideoReceiver::VideoReceiver(Clock* clock,
+                             VCMTiming* timing,
+                             const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
       _timing(timing),
-      _receiver(_timing, clock_),
-      _decodedFrameCallback(_timing, clock_),
+      _receiver(_timing, clock_, field_trials),
+      _decodedFrameCallback(_timing, clock_, field_trials),
       _frameTypeCallback(nullptr),
       _packetRequestCallback(nullptr),
       _scheduleKeyRequest(false),
diff --git a/modules/video_coding/video_receiver2.cc b/modules/video_coding/video_receiver2.cc
index ef6dcf9..e0df761 100644
--- a/modules/video_coding/video_receiver2.cc
+++ b/modules/video_coding/video_receiver2.cc
@@ -28,10 +28,12 @@
 
 namespace webrtc {
 
-VideoReceiver2::VideoReceiver2(Clock* clock, VCMTiming* timing)
+VideoReceiver2::VideoReceiver2(Clock* clock,
+                               VCMTiming* timing,
+                               const WebRtcKeyValueConfig& field_trials)
     : clock_(clock),
       timing_(timing),
-      decodedFrameCallback_(timing_, clock_),
+      decodedFrameCallback_(timing_, clock_, field_trials),
       codecDataBase_() {
   decoder_sequence_checker_.Detach();
 }
diff --git a/modules/video_coding/video_receiver2.h b/modules/video_coding/video_receiver2.h
index 5e087d3..45d774b 100644
--- a/modules/video_coding/video_receiver2.h
+++ b/modules/video_coding/video_receiver2.h
@@ -13,6 +13,7 @@
 
 #include "api/sequence_checker.h"
 #include "api/video_codecs/video_decoder.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/decoder_database.h"
 #include "modules/video_coding/encoded_frame.h"
 #include "modules/video_coding/generic_decoder.h"
@@ -28,7 +29,9 @@
 // VideoCodingModule api.
 class VideoReceiver2 {
  public:
-  VideoReceiver2(Clock* clock, VCMTiming* timing);
+  VideoReceiver2(Clock* clock,
+                 VCMTiming* timing,
+                 const WebRtcKeyValueConfig& field_trials);
   ~VideoReceiver2();
 
   void RegisterReceiveCodec(uint8_t payload_type,
diff --git a/modules/video_coding/video_receiver_unittest.cc b/modules/video_coding/video_receiver_unittest.cc
index fc83141..148ec0d 100644
--- a/modules/video_coding/video_receiver_unittest.cc
+++ b/modules/video_coding/video_receiver_unittest.cc
@@ -15,6 +15,7 @@
 #include "modules/video_coding/video_coding_impl.h"
 #include "system_wrappers/include/clock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -51,7 +52,9 @@
   static const uint16_t kMaxWaitTimeMs = 100;
 
   TestVideoReceiver()
-      : clock_(0), timing_(&clock_), receiver_(&clock_, &timing_) {}
+      : clock_(0),
+        timing_(&clock_, field_trials_),
+        receiver_(&clock_, &timing_, field_trials_) {}
 
   virtual void SetUp() {
     // Register decoder.
@@ -118,6 +121,7 @@
     EXPECT_EQ(0, receiver_.Decode(kMaxWaitTimeMs));
   }
 
+  test::ScopedKeyValueConfig field_trials_;
   SimulatedClock clock_;
   NiceMock<MockVideoDecoder> decoder_;
   NiceMock<MockPacketRequestCallback> packet_request_callback_;
diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn
index 1e19dba..3278e7f 100644
--- a/test/fuzzers/BUILD.gn
+++ b/test/fuzzers/BUILD.gn
@@ -613,6 +613,7 @@
   deps = [
     "../../modules/video_coding:timing",
     "../../modules/video_coding/",
+    "../../test:scoped_key_value_config",
     "../time_controller:time_controller",
   ]
 }
@@ -625,6 +626,7 @@
     "../../api/video:encoded_frame",
     "../../modules/video_coding:frame_buffer",
     "../../rtc_base:rtc_numerics",
+    "../../test:scoped_key_value_config",
   ]
 }
 
diff --git a/test/fuzzers/frame_buffer2_fuzzer.cc b/test/fuzzers/frame_buffer2_fuzzer.cc
index a20efae..da6c89a 100644
--- a/test/fuzzers/frame_buffer2_fuzzer.cc
+++ b/test/fuzzers/frame_buffer2_fuzzer.cc
@@ -10,6 +10,7 @@
 
 #include "modules/video_coding/frame_buffer2.h"
 #include "modules/video_coding/timing.h"
+#include "test/scoped_key_value_config.h"
 #include "test/time_controller/simulated_time_controller.h"
 
 namespace webrtc {
@@ -68,9 +69,10 @@
   rtc::TaskQueue task_queue(
       time_controller.GetTaskQueueFactory()->CreateTaskQueue(
           "time_tq", TaskQueueFactory::Priority::NORMAL));
-  VCMTiming timing(time_controller.GetClock());
+  test::ScopedKeyValueConfig field_trials;
+  VCMTiming timing(time_controller.GetClock(), field_trials);
   video_coding::FrameBuffer frame_buffer(time_controller.GetClock(), &timing,
-                                         nullptr);
+                                         nullptr, field_trials);
 
   bool next_frame_task_running = false;
 
diff --git a/test/fuzzers/frame_buffer3_fuzzer.cc b/test/fuzzers/frame_buffer3_fuzzer.cc
index 75906ac..e4222b2 100644
--- a/test/fuzzers/frame_buffer3_fuzzer.cc
+++ b/test/fuzzers/frame_buffer3_fuzzer.cc
@@ -13,6 +13,7 @@
 #include "modules/video_coding/frame_buffer3.h"
 #include "rtc_base/numerics/sequence_number_util.h"
 #include "test/fuzzers/fuzz_data_helper.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 namespace {
@@ -31,7 +32,9 @@
     return;
   }
 
-  FrameBuffer buffer(/*max_frame_slots=*/100, /*max_decode_history=*/1000);
+  test::ScopedKeyValueConfig field_trials;
+  FrameBuffer buffer(/*max_frame_slots=*/100, /*max_decode_history=*/1000,
+                     field_trials);
   test::FuzzDataHelper helper(rtc::MakeArrayView(data, size));
   SeqNumUnwrapper<uint16_t, kFrameIdLength> unwrapper;
 
diff --git a/video/BUILD.gn b/video/BUILD.gn
index e290abe..b57aa26 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -232,7 +232,9 @@
 
   deps = [
     "../api:sequence_checker",
+    "../api:webrtc_key_value_config",
     "../api/task_queue",
+    "../api/transport:field_trial_based_config",
     "../api/video:encoded_frame",
     "../api/video:video_frame",
     "../api/video:video_rtp_headers",
@@ -242,6 +244,7 @@
     "../modules/video_coding:timing",
     "../rtc_base:rtc_base_approved",
     "../rtc_base:rtc_task_queue",
+    "../rtc_base/memory:always_valid_pointer",
     "../rtc_base/synchronization:mutex",
     "../system_wrappers",
   ]
diff --git a/video/frame_buffer_proxy.cc b/video/frame_buffer_proxy.cc
index c3d01c5..c09c56a 100644
--- a/video/frame_buffer_proxy.cc
+++ b/video/frame_buffer_proxy.cc
@@ -42,10 +42,11 @@
                     rtc::TaskQueue* decode_queue,
                     FrameSchedulingReceiver* receiver,
                     TimeDelta max_wait_for_keyframe,
-                    TimeDelta max_wait_for_frame)
+                    TimeDelta max_wait_for_frame,
+                    const WebRtcKeyValueConfig& field_trials)
       : max_wait_for_keyframe_(max_wait_for_keyframe),
         max_wait_for_frame_(max_wait_for_frame),
-        frame_buffer_(clock, timing, stats_proxy),
+        frame_buffer_(clock, timing, stats_proxy, field_trials),
         decode_queue_(decode_queue),
         stats_proxy_(stats_proxy),
         receiver_(receiver) {
@@ -182,7 +183,8 @@
       TimeDelta max_wait_for_frame,
       std::unique_ptr<FrameDecodeScheduler> frame_decode_scheduler,
       const WebRtcKeyValueConfig& field_trials)
-      : max_wait_for_keyframe_(max_wait_for_keyframe),
+      : field_trials_(field_trials),
+        max_wait_for_keyframe_(max_wait_for_keyframe),
         max_wait_for_frame_(max_wait_for_frame),
         clock_(clock),
         worker_queue_(worker_queue),
@@ -191,9 +193,10 @@
         receiver_(receiver),
         timing_(timing),
         frame_decode_scheduler_(std::move(frame_decode_scheduler)),
-        jitter_estimator_(clock_),
+        jitter_estimator_(clock_, field_trials),
         buffer_(std::make_unique<FrameBuffer>(kMaxFramesBuffered,
-                                              kMaxFramesHistory)),
+                                              kMaxFramesHistory,
+                                              field_trials)),
         decode_timing_(clock_, timing_),
         timeout_tracker_(clock_,
                          worker_queue_,
@@ -237,8 +240,8 @@
   void Clear() override {
     RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
     stats_proxy_->OnDroppedFrames(buffer_->CurrentSize());
-    buffer_ =
-        std::make_unique<FrameBuffer>(kMaxFramesBuffered, kMaxFramesHistory);
+    buffer_ = std::make_unique<FrameBuffer>(kMaxFramesBuffered,
+                                            kMaxFramesHistory, field_trials_);
     frame_decode_scheduler_->CancelOutstanding();
   }
 
@@ -485,6 +488,7 @@
   }
 
   RTC_NO_UNIQUE_ADDRESS SequenceChecker worker_sequence_checker_;
+  const WebRtcKeyValueConfig& field_trials_;
   const TimeDelta max_wait_for_keyframe_;
   const TimeDelta max_wait_for_frame_;
   const absl::optional<RttMultExperiment::Settings> rtt_mult_settings_ =
@@ -597,7 +601,7 @@
     default:
       return std::make_unique<FrameBuffer2Proxy>(
           clock, timing, stats_proxy, decode_queue, receiver,
-          max_wait_for_keyframe, max_wait_for_frame);
+          max_wait_for_keyframe, max_wait_for_frame, field_trials);
   }
 }
 
diff --git a/video/frame_buffer_proxy_unittest.cc b/video/frame_buffer_proxy_unittest.cc
index a6f3713..b133a94 100644
--- a/video/frame_buffer_proxy_unittest.cc
+++ b/video/frame_buffer_proxy_unittest.cc
@@ -221,7 +221,7 @@
         fake_metronome_(time_controller_.GetTaskQueueFactory(),
                         TimeDelta::Millis(16)),
         decode_sync_(clock_, &fake_metronome_, run_loop_.task_queue()),
-        timing_(clock_),
+        timing_(clock_, field_trials_),
         proxy_(FrameBufferProxy::CreateFromFieldTrial(clock_,
                                                       run_loop_.task_queue(),
                                                       &timing_,
diff --git a/video/frame_decode_timing_unittest.cc b/video/frame_decode_timing_unittest.cc
index 0d99847..743e722 100644
--- a/video/frame_decode_timing_unittest.cc
+++ b/video/frame_decode_timing_unittest.cc
@@ -18,6 +18,7 @@
 #include "rtc_base/containers/flat_map.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 
 namespace webrtc {
 
@@ -30,7 +31,8 @@
 
 class FakeVCMTiming : public webrtc::VCMTiming {
  public:
-  explicit FakeVCMTiming(Clock* clock) : webrtc::VCMTiming(clock) {}
+  explicit FakeVCMTiming(Clock* clock, const WebRtcKeyValueConfig& field_trials)
+      : webrtc::VCMTiming(clock, field_trials) {}
 
   Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const override {
     RTC_DCHECK(render_time_map_.contains(frame_timestamp));
@@ -63,10 +65,11 @@
  public:
   FrameDecodeTimingTest()
       : clock_(Timestamp::Millis(1000)),
-        timing_(&clock_),
+        timing_(&clock_, field_trials_),
         frame_decode_scheduler_(&clock_, &timing_) {}
 
  protected:
+  test::ScopedKeyValueConfig field_trials_;
   SimulatedClock clock_;
   FakeVCMTiming timing_;
   FrameDecodeTiming frame_decode_scheduler_;
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index 093a232..1788823e 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -322,7 +322,7 @@
 
   if (config_.rtp.nack.rtp_history_ms != 0) {
     nack_module_ = std::make_unique<DEPRECATED_NackModule>(
-        clock_, &rtcp_feedback_buffer_, &rtcp_feedback_buffer_);
+        clock_, &rtcp_feedback_buffer_, &rtcp_feedback_buffer_, field_trials_);
     process_thread_->RegisterModule(nack_module_.get(), RTC_FROM_HERE);
   }
 
diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc
index 5e9788e..25687b3 100644
--- a/video/rtp_video_stream_receiver2.cc
+++ b/video/rtp_video_stream_receiver2.cc
@@ -108,14 +108,15 @@
     const VideoReceiveStream::Config& config,
     Clock* clock,
     NackSender* nack_sender,
-    KeyFrameRequestSender* keyframe_request_sender) {
+    KeyFrameRequestSender* keyframe_request_sender,
+    const WebRtcKeyValueConfig& field_trials) {
   if (config.rtp.nack.rtp_history_ms == 0)
     return nullptr;
 
   // TODO(bugs.webrtc.org/12420): pass rtp_history_ms to the nack module.
   return std::make_unique<NackRequester>(current_queue, nack_periodic_processor,
                                          clock, nack_sender,
-                                         keyframe_request_sender);
+                                         keyframe_request_sender, field_trials);
 }
 
 static const int kPacketLogIntervalMs = 10000;
@@ -252,7 +253,8 @@
                                             config_,
                                             clock_,
                                             &rtcp_feedback_buffer_,
-                                            &rtcp_feedback_buffer_)),
+                                            &rtcp_feedback_buffer_,
+                                            field_trials_)),
       packet_buffer_(kPacketBufferStartSize,
                      PacketBufferMaxSize(field_trials_)),
       reference_finder_(std::make_unique<RtpFrameReferenceFinder>()),
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index 572feaa..df99866 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -226,7 +226,7 @@
                    call->trials()),
       rtp_receive_statistics_(ReceiveStatistics::Create(clock_)),
       timing_(std::move(timing)),
-      video_receiver_(clock_, timing_.get()),
+      video_receiver_(clock_, timing_.get(), call->trials()),
       rtp_video_stream_receiver_(call->worker_thread(),
                                  clock_,
                                  &transport_adapter_,
diff --git a/video/video_receive_stream2_unittest.cc b/video/video_receive_stream2_unittest.cc
index b90deaa..4111e8e 100644
--- a/video/video_receive_stream2_unittest.cc
+++ b/video/video_receive_stream2_unittest.cc
@@ -102,7 +102,7 @@
     config_.decoders.push_back(h264_decoder);
 
     clock_ = Clock::GetRealTimeClock();
-    timing_ = new VCMTiming(clock_);
+    timing_ = new VCMTiming(clock_, fake_call_.trials());
 
     video_receive_stream_ =
         std::make_unique<webrtc::internal::VideoReceiveStream2>(
@@ -292,7 +292,7 @@
       video_receive_stream_->UnregisterFromTransport();
       video_receive_stream_ = nullptr;
     }
-    timing_ = new VCMTiming(clock_);
+    timing_ = new VCMTiming(clock_, fake_call_.trials());
     video_receive_stream_ =
         std::make_unique<webrtc::internal::VideoReceiveStream2>(
             task_queue_factory_.get(), &fake_call_, kDefaultNumCpuCores,
@@ -564,7 +564,8 @@
             config_.Copy(),
             &call_stats_,
             time_controller_.GetClock(),
-            std::make_unique<VCMTiming>(time_controller_.GetClock()),
+            std::make_unique<VCMTiming>(time_controller_.GetClock(),
+                                        fake_call_.trials()),
             &nack_periodic_processor_,
             nullptr) {
     if (std::get<1>(GetParam())) {
@@ -748,7 +749,7 @@
     config_.decoders.push_back(h264_decoder);
 
     clock_ = Clock::GetRealTimeClock();
-    timing_ = new VCMTiming(clock_);
+    timing_ = new VCMTiming(clock_, fake_call_.trials());
 
     video_receive_stream_ =
         std::make_unique<webrtc::internal::VideoReceiveStream2>(
diff --git a/video/video_stream_decoder_impl.cc b/video/video_stream_decoder_impl.cc
index 907b8b0..8704a6ef 100644
--- a/video/video_stream_decoder_impl.cc
+++ b/video/video_stream_decoder_impl.cc
@@ -23,8 +23,10 @@
     VideoStreamDecoderInterface::Callbacks* callbacks,
     VideoDecoderFactory* decoder_factory,
     TaskQueueFactory* task_queue_factory,
-    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings)
-    : timing_(Clock::GetRealTimeClock()),
+    std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings,
+    const WebRtcKeyValueConfig* field_trials)
+    : field_trials_(field_trials),
+      timing_(Clock::GetRealTimeClock(), *field_trials_),
       decode_callbacks_(this),
       next_frame_info_index_(0),
       callbacks_(callbacks),
@@ -32,7 +34,10 @@
       decoder_factory_(decoder_factory),
       decoder_settings_(std::move(decoder_settings)),
       shut_down_(false),
-      frame_buffer_(Clock::GetRealTimeClock(), &timing_, nullptr),
+      frame_buffer_(Clock::GetRealTimeClock(),
+                    &timing_,
+                    nullptr,
+                    *field_trials_),
       bookkeeping_queue_(task_queue_factory->CreateTaskQueue(
           "video_stream_decoder_bookkeeping_queue",
           TaskQueueFactory::Priority::NORMAL)),
diff --git a/video/video_stream_decoder_impl.h b/video/video_stream_decoder_impl.h
index 9d028a2..d4fe1f7 100644
--- a/video/video_stream_decoder_impl.h
+++ b/video/video_stream_decoder_impl.h
@@ -17,9 +17,12 @@
 
 #include "absl/types/optional.h"
 #include "api/sequence_checker.h"
+#include "api/transport/field_trial_based_config.h"
 #include "api/video/video_stream_decoder.h"
+#include "api/webrtc_key_value_config.h"
 #include "modules/video_coding/frame_buffer2.h"
 #include "modules/video_coding/timing.h"
+#include "rtc_base/memory/always_valid_pointer.h"
 #include "rtc_base/platform_thread.h"
 #include "rtc_base/synchronization/mutex.h"
 #include "rtc_base/task_queue.h"
@@ -33,7 +36,8 @@
       VideoStreamDecoderInterface::Callbacks* callbacks,
       VideoDecoderFactory* decoder_factory,
       TaskQueueFactory* task_queue_factory,
-      std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings);
+      std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings,
+      const WebRtcKeyValueConfig* field_trials);
 
   ~VideoStreamDecoderImpl() override;
 
@@ -82,6 +86,8 @@
   VideoStreamDecoderImpl::DecodeResult DecodeFrame(
       std::unique_ptr<EncodedFrame> frame) RTC_RUN_ON(decode_queue_);
 
+  AlwaysValidPointer<const WebRtcKeyValueConfig, FieldTrialBasedConfig>
+      field_trials_;
   VCMTiming timing_;
   DecodeCallbacks decode_callbacks_;
 
diff --git a/video/video_stream_decoder_impl_unittest.cc b/video/video_stream_decoder_impl_unittest.cc
index 4cb4344..dd11e8c 100644
--- a/video/video_stream_decoder_impl_unittest.cc
+++ b/video/video_stream_decoder_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "api/video_codecs/video_decoder.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
+#include "test/scoped_key_value_config.h"
 #include "test/time_controller/simulated_time_controller.h"
 
 namespace webrtc {
@@ -163,12 +164,14 @@
                               &decoder_factory_,
                               time_controller_.GetTaskQueueFactory(),
                               {{1, std::make_pair(SdpVideoFormat("VP8"), 1)},
-                               {2, std::make_pair(SdpVideoFormat("AV1"), 1)}}) {
+                               {2, std::make_pair(SdpVideoFormat("AV1"), 1)}},
+                              &field_trials_) {
     // Set the min playout delay to a value greater than zero to not activate
     // the low-latency renderer.
     video_stream_decoder_.SetMinPlayoutDelay(TimeDelta::Millis(10));
   }
 
+  test::ScopedKeyValueConfig field_trials_;
   NiceMock<MockVideoStreamDecoderCallbacks> callbacks_;
   FakeVideoDecoderFactory decoder_factory_;
   GlobalSimulatedTimeController time_controller_;