Migrate WebRTC on FrameGeneratorInterface and remove FrameGenerator class

Bug: webrtc:10138
Change-Id: If85290581a72f81cf60181de7a7134cc9db7716e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/161327
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30033}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index eba1f04..acc2bd7 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -449,22 +449,22 @@
       "../test/pc/e2e:peerconnection_quality_test",
     ]
   }
+}
 
-  rtc_library("create_frame_generator") {
-    visibility = [ "*" ]
-    testonly = true
-    sources = [
-      "test/create_frame_generator.cc",
-      "test/create_frame_generator.h",
-    ]
-    deps = [
-      ":frame_generator_api",
-      "../system_wrappers",
-      "../test:video_test_common",
-      "../test:video_test_support",
-      "//third_party/abseil-cpp/absl/types:optional",
-    ]
-  }
+rtc_library("create_frame_generator") {
+  visibility = [ "*" ]
+  testonly = true
+  sources = [
+    "test/create_frame_generator.cc",
+    "test/create_frame_generator.h",
+  ]
+  deps = [
+    ":frame_generator_api",
+    "../rtc_base:checks",
+    "../system_wrappers",
+    "../test:frame_generator_impl",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
 }
 
 rtc_source_set("libjingle_logging_api") {
diff --git a/api/test/create_frame_generator.cc b/api/test/create_frame_generator.cc
index 859bc00..7ed0647 100644
--- a/api/test/create_frame_generator.cc
+++ b/api/test/create_frame_generator.cc
@@ -10,8 +10,10 @@
 
 #include "api/test/create_frame_generator.h"
 
+#include <cstdio>
 #include <utility>
 
+#include "rtc_base/checks.h"
 #include "test/frame_generator.h"
 #include "test/testsupport/ivf_video_frame_generator.h"
 
@@ -23,22 +25,31 @@
     int height,
     absl::optional<FrameGeneratorInterface::OutputType> type,
     absl::optional<int> num_squares) {
-  return FrameGenerator::CreateSquareGenerator(width, height, type,
-                                               num_squares);
+  return std::make_unique<SquareGenerator>(
+      width, height, type.value_or(FrameGeneratorInterface::OutputType::kI420),
+      num_squares.value_or(10));
 }
 
 std::unique_ptr<FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
-    std::vector<std::string> files,
+    std::vector<std::string> filenames,
     size_t width,
     size_t height,
     int frame_repeat_count) {
-  return FrameGenerator::CreateFromYuvFile(std::move(files), width, height,
-                                           frame_repeat_count);
+  RTC_DCHECK(!filenames.empty());
+  std::vector<FILE*> files;
+  for (const std::string& filename : filenames) {
+    FILE* file = fopen(filename.c_str(), "rb");
+    RTC_DCHECK(file != nullptr) << "Failed to open: '" << filename << "'\n";
+    files.push_back(file);
+  }
+
+  return std::make_unique<YuvFileGenerator>(files, width, height,
+                                            frame_repeat_count);
 }
 
 std::unique_ptr<FrameGeneratorInterface> CreateFromIvfFileFrameGenerator(
-    std::string file) {
-  return std::make_unique<IvfVideoFrameGenerator>(std::move(file));
+    std::string filename) {
+  return std::make_unique<IvfVideoFrameGenerator>(std::move(filename));
 }
 
 std::unique_ptr<FrameGeneratorInterface>
@@ -51,15 +62,22 @@
     size_t target_height,
     int64_t scroll_time_ms,
     int64_t pause_time_ms) {
-  return FrameGenerator::CreateScrollingInputFromYuvFiles(
-      clock, std::move(filenames), source_width, source_height, target_width,
-      target_height, scroll_time_ms, pause_time_ms);
+  RTC_DCHECK(!filenames.empty());
+  std::vector<FILE*> files;
+  for (const std::string& filename : filenames) {
+    FILE* file = fopen(filename.c_str(), "rb");
+    RTC_DCHECK(file != nullptr);
+    files.push_back(file);
+  }
+
+  return std::make_unique<ScrollingImageFrameGenerator>(
+      clock, files, source_width, source_height, target_width, target_height,
+      scroll_time_ms, pause_time_ms);
 }
 
 std::unique_ptr<FrameGeneratorInterface>
 CreateSlideFrameGenerator(int width, int height, int frame_repeat_count) {
-  return FrameGenerator::CreateSlideGenerator(width, height,
-                                              frame_repeat_count);
+  return std::make_unique<SlideGenerator>(width, height, frame_repeat_count);
 }
 
 }  // namespace test
diff --git a/api/test/create_frame_generator.h b/api/test/create_frame_generator.h
index 02aa38d..1514145 100644
--- a/api/test/create_frame_generator.h
+++ b/api/test/create_frame_generator.h
@@ -36,14 +36,14 @@
 // The frame_repeat_count determines how many times each frame is shown,
 // with 1 = show each frame once, etc.
 std::unique_ptr<FrameGeneratorInterface> CreateFromYuvFileFrameGenerator(
-    std::vector<std::string> files,
+    std::vector<std::string> filenames,
     size_t width,
     size_t height,
     int frame_repeat_count);
 
 // Creates a frame generator that repeatedly plays an ivf file.
 std::unique_ptr<FrameGeneratorInterface> CreateFromIvfFileFrameGenerator(
-    std::string file);
+    std::string filename);
 
 // Creates a frame generator which takes a set of yuv files (wrapping a
 // frame generator created by CreateFromYuvFile() above), but outputs frames
diff --git a/call/BUILD.gn b/call/BUILD.gn
index 2a89f71..e1c04bd 100644
--- a/call/BUILD.gn
+++ b/call/BUILD.gn
@@ -382,6 +382,7 @@
       ":rtp_sender",
       ":simulated_network",
       "../api:array_view",
+      "../api:create_frame_generator",
       "../api:mock_audio_mixer",
       "../api:rtp_headers",
       "../api:rtp_parameters",
diff --git a/call/bitrate_estimator_tests.cc b/call/bitrate_estimator_tests.cc
index b5c4d8e..50da12b 100644
--- a/call/bitrate_estimator_tests.cc
+++ b/call/bitrate_estimator_tests.cc
@@ -12,6 +12,7 @@
 #include <memory>
 #include <string>
 
+#include "api/test/create_frame_generator.h"
 #include "call/call.h"
 #include "call/fake_network_pipe.h"
 #include "call/simulated_network.h"
@@ -180,8 +181,8 @@
       frame_generator_capturer_ =
           std::make_unique<test::FrameGeneratorCapturer>(
               test->clock_,
-              test::FrameGenerator::CreateSquareGenerator(
-                  kDefaultWidth, kDefaultHeight, absl::nullopt, absl::nullopt),
+              test::CreateSquareFrameGenerator(kDefaultWidth, kDefaultHeight,
+                                               absl::nullopt, absl::nullopt),
               kDefaultFramerate, *test->task_queue_factory_);
       frame_generator_capturer_->Init();
       send_stream_->SetSource(frame_generator_capturer_.get(),
diff --git a/call/call_perf_tests.cc b/call/call_perf_tests.cc
index 7e59020..8b96a63 100644
--- a/call/call_perf_tests.cc
+++ b/call/call_perf_tests.cc
@@ -38,7 +38,6 @@
 #include "test/encoder_settings.h"
 #include "test/fake_encoder.h"
 #include "test/field_trial.h"
-#include "test/frame_generator.h"
 #include "test/frame_generator_capturer.h"
 #include "test/gtest.h"
 #include "test/null_transport.h"
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index d22e4fd..f5751d0 100644
--- a/common_video/BUILD.gn
+++ b/common_video/BUILD.gn
@@ -110,6 +110,7 @@
       "../rtc_base:rtc_base_tests_utils",
       "../system_wrappers:system_wrappers",
       "../test:fileutils",
+      "../test:frame_utils",
       "../test:test_main",
       "../test:test_support",
       "../test:video_test_common",
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index 2dd6c54..b3d3608 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -60,7 +60,7 @@
 #include "rtc_base/time_utils.h"
 #include "test/fake_decoder.h"
 #include "test/field_trial.h"
-#include "test/frame_generator.h"
+#include "test/frame_forwarder.h"
 #include "test/gmock.h"
 #include "test/rtp_header_parser.h"
 
diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn
index c3b50ef..acd8e77 100644
--- a/modules/video_capture/BUILD.gn
+++ b/modules/video_capture/BUILD.gn
@@ -132,6 +132,7 @@
         "../../common_video",
         "../../rtc_base:rtc_base_approved",
         "../../system_wrappers",
+        "../../test:frame_utils",
         "../../test:test_support",
         "../../test:video_test_common",
         "../utility",
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index ceee019..be610e7 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -614,6 +614,8 @@
       ":videocodec_test_stats_impl",
       ":webrtc_vp9_helpers",
       "..:module_api",
+      "../../api:create_frame_generator",
+      "../../api:frame_generator_api",
       "../../api:scoped_refptr",
       "../../api:videocodec_test_fixture_api",
       "../../api/task_queue",
@@ -759,7 +761,9 @@
       ":webrtc_vp9",
       ":webrtc_vp9_helpers",
       "../..:webrtc_common",
+      "../../api:create_frame_generator",
       "../../api:create_videocodec_test_fixture_api",
+      "../../api:frame_generator_api",
       "../../api:mock_video_codec_factory",
       "../../api:mock_video_decoder",
       "../../api:mock_video_encoder",
diff --git a/modules/video_coding/codecs/test/video_codec_unittest.cc b/modules/video_coding/codecs/test/video_codec_unittest.cc
index 57fb25d..c6cf1ad 100644
--- a/modules/video_coding/codecs/test/video_codec_unittest.cc
+++ b/modules/video_coding/codecs/test/video_codec_unittest.cc
@@ -12,6 +12,7 @@
 
 #include <utility>
 
+#include "api/test/create_frame_generator.h"
 #include "api/video_codecs/video_encoder.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/video_coding/include/video_error_codes.h"
@@ -73,9 +74,9 @@
 
   ModifyCodecSettings(&codec_settings_);
 
-  input_frame_generator_ = test::FrameGenerator::CreateSquareGenerator(
+  input_frame_generator_ = test::CreateSquareFrameGenerator(
       codec_settings_.width, codec_settings_.height,
-      test::FrameGenerator::OutputType::kI420, absl::optional<int>());
+      test::FrameGeneratorInterface::OutputType::kI420, absl::optional<int>());
 
   encoder_ = CreateEncoder();
   decoder_ = CreateDecoder();
@@ -94,7 +95,7 @@
 void VideoCodecUnitTest::ModifyCodecSettings(VideoCodec* codec_settings) {}
 
 VideoFrame VideoCodecUnitTest::NextInputFrame() {
-  test::FrameGenerator::VideoFrameData frame_data =
+  test::FrameGeneratorInterface::VideoFrameData frame_data =
       input_frame_generator_->NextFrame();
   VideoFrame input_frame = VideoFrame::Builder()
                                .set_video_frame_buffer(frame_data.buffer)
diff --git a/modules/video_coding/codecs/test/video_codec_unittest.h b/modules/video_coding/codecs/test/video_codec_unittest.h
index abf4d96..1ce37a7 100644
--- a/modules/video_coding/codecs/test/video_codec_unittest.h
+++ b/modules/video_coding/codecs/test/video_codec_unittest.h
@@ -14,6 +14,7 @@
 #include <memory>
 #include <vector>
 
+#include "api/test/frame_generator_interface.h"
 #include "api/video_codecs/video_decoder.h"
 #include "api/video_codecs/video_encoder.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -22,7 +23,6 @@
 #include "rtc_base/critical_section.h"
 #include "rtc_base/event.h"
 #include "rtc_base/thread_annotations.h"
-#include "test/frame_generator.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -101,7 +101,7 @@
 
   std::unique_ptr<VideoEncoder> encoder_;
   std::unique_ptr<VideoDecoder> decoder_;
-  std::unique_ptr<test::FrameGenerator> input_frame_generator_;
+  std::unique_ptr<test::FrameGeneratorInterface> input_frame_generator_;
 
  private:
   FakeEncodeCompleteCallback encode_complete_callback_;
diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
index d390534..4c80c05 100644
--- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
@@ -12,6 +12,8 @@
 
 #include <memory>
 
+#include "api/test/create_frame_generator.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/test/mock_video_decoder.h"
 #include "api/test/mock_video_encoder.h"
 #include "api/video_codecs/video_encoder.h"
@@ -487,9 +489,9 @@
 
   // Reset the frame generator with large number of squares, leading to lots of
   // details and high probability of overshoot.
-  input_frame_generator_ = test::FrameGenerator::CreateSquareGenerator(
+  input_frame_generator_ = test::CreateSquareFrameGenerator(
       codec_settings_.width, codec_settings_.height,
-      test::FrameGenerator::OutputType::kI420,
+      test::FrameGeneratorInterface::OutputType::kI420,
       /* num_squares = */ absl::optional<int>(300));
 
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
index ef81547..ed15ee0 100644
--- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
@@ -8,6 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "api/test/create_frame_generator.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/video/color_space.h"
 #include "api/video/i420_buffer.h"
 #include "api/video_codecs/video_encoder.h"
@@ -1616,9 +1618,10 @@
       return;
 
     TestVp9Impl::SetUp();
-    input_frame_generator_ = test::FrameGenerator::CreateSquareGenerator(
+    input_frame_generator_ = test::CreateSquareFrameGenerator(
         codec_settings_.width, codec_settings_.height,
-        test::FrameGenerator::OutputType::kI010, absl::optional<int>());
+        test::FrameGeneratorInterface::OutputType::kI010,
+        absl::optional<int>());
   }
 
   std::unique_ptr<VideoEncoder> CreateEncoder() override {
diff --git a/modules/video_processing/BUILD.gn b/modules/video_processing/BUILD.gn
index a73ac47..8ae7a12 100644
--- a/modules/video_processing/BUILD.gn
+++ b/modules/video_processing/BUILD.gn
@@ -112,6 +112,7 @@
       "../../api/video:video_rtp_headers",
       "../../common_video",
       "../../test:fileutils",
+      "../../test:frame_utils",
       "../../test:test_support",
       "../../test:video_test_common",
     ]
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index c971a37..7541cfa 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -466,6 +466,7 @@
       ":peerconnection",
       ":rtc_pc_base",
       "../api:audio_options_api",
+      "../api:create_frame_generator",
       "../api:create_peerconnection_factory",
       "../api:libjingle_peerconnection_api",
       "../api:media_stream_interface",
diff --git a/pc/test/frame_generator_capturer_video_track_source.h b/pc/test/frame_generator_capturer_video_track_source.h
index c0648ba..50a3d26 100644
--- a/pc/test/frame_generator_capturer_video_track_source.h
+++ b/pc/test/frame_generator_capturer_video_track_source.h
@@ -16,6 +16,7 @@
 
 #include "api/task_queue/default_task_queue_factory.h"
 #include "api/task_queue/task_queue_factory.h"
+#include "api/test/create_frame_generator.h"
 #include "pc/video_track_source.h"
 #include "test/frame_generator_capturer.h"
 
@@ -47,9 +48,9 @@
         is_screencast_(is_screencast) {
     video_capturer_ = std::make_unique<test::FrameGeneratorCapturer>(
         clock,
-        test::FrameGenerator::CreateSquareGenerator(
-            config.width, config.height, absl::nullopt,
-            config.num_squares_generated),
+        test::CreateSquareFrameGenerator(config.width, config.height,
+                                         absl::nullopt,
+                                         config.num_squares_generated),
         config.frames_per_second, *task_queue_factory_);
     video_capturer_->Init();
   }
diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn
index de5b909..00528a4 100644
--- a/rtc_tools/BUILD.gn
+++ b/rtc_tools/BUILD.gn
@@ -153,6 +153,7 @@
     ]
 
     deps = [
+      "../api:create_frame_generator",
       "../api:rtp_parameters",
       "../api:transport_api",
       "../api/rtc_event_log",
diff --git a/rtc_tools/rtp_generator/rtp_generator.cc b/rtc_tools/rtp_generator/rtp_generator.cc
index f7b691d..21826c8 100644
--- a/rtc_tools/rtp_generator/rtp_generator.cc
+++ b/rtc_tools/rtp_generator/rtp_generator.cc
@@ -15,6 +15,7 @@
 #include <utility>
 
 #include "api/task_queue/default_task_queue_factory.h"
+#include "api/test/create_frame_generator.h"
 #include "api/video_codecs/builtin_video_decoder_factory.h"
 #include "api/video_codecs/builtin_video_encoder_factory.h"
 #include "api/video_codecs/video_encoder.h"
@@ -224,9 +225,9 @@
     std::unique_ptr<test::FrameGeneratorCapturer> frame_generator =
         std::make_unique<test::FrameGeneratorCapturer>(
             Clock::GetRealTimeClock(),
-            test::FrameGenerator::CreateSquareGenerator(
-                send_config.video_width, send_config.video_height,
-                absl::nullopt, absl::nullopt),
+            test::CreateSquareFrameGenerator(send_config.video_width,
+                                             send_config.video_height,
+                                             absl::nullopt, absl::nullopt),
             send_config.video_fps, *task_queue_);
     frame_generator->Init();
 
diff --git a/rtc_tools/rtp_generator/rtp_generator.h b/rtc_tools/rtp_generator/rtp_generator.h
index e857b60..6248c6a 100644
--- a/rtc_tools/rtp_generator/rtp_generator.h
+++ b/rtc_tools/rtp_generator/rtp_generator.h
@@ -28,7 +28,6 @@
 #include "call/video_send_stream.h"
 #include "media/engine/webrtc_video_engine.h"
 #include "rtc_base/constructor_magic.h"
-#include "test/frame_generator.h"
 #include "test/frame_generator_capturer.h"
 #include "test/rtp_file_reader.h"
 #include "test/rtp_file_writer.h"
diff --git a/test/BUILD.gn b/test/BUILD.gn
index a5519d2..2316e0f 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -34,18 +34,71 @@
   }
 }
 
+rtc_library("frame_generator_impl") {
+  visibility = [
+    "../api:create_frame_generator",
+    ":*",
+  ]
+  testonly = true
+  sources = [
+    "frame_generator.cc",
+    "frame_generator.h",
+    "testsupport/ivf_video_frame_generator.cc",
+    "testsupport/ivf_video_frame_generator.h",
+  ]
+  deps = [
+    ":frame_utils",
+    "../api:frame_generator_api",
+    "../api:scoped_refptr",
+    "../api/video:encoded_image",
+    "../api/video:video_frame",
+    "../api/video:video_frame_i010",
+    "../api/video:video_frame_i420",
+    "../api/video:video_rtp_headers",
+    "../api/video_codecs:video_codecs_api",
+    "../common_video",
+    "../media:rtc_media_base",
+    "../modules/video_coding:video_codec_interface",
+    "../modules/video_coding:video_coding_utility",
+    "../modules/video_coding:webrtc_h264",
+    "../modules/video_coding:webrtc_vp8",
+    "../modules/video_coding:webrtc_vp9",
+    "../rtc_base",
+    "../rtc_base:checks",
+    "../rtc_base:criticalsection",
+    "../rtc_base:rtc_base_approved",
+    "../rtc_base:rtc_event",
+    "../rtc_base/synchronization:sequence_checker",
+    "../rtc_base/system:file_wrapper",
+    "../system_wrappers",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+rtc_library("frame_utils") {
+  visibility = [ "*" ]
+  testonly = true
+  sources = [
+    "frame_utils.cc",
+    "frame_utils.h",
+  ]
+  deps = [
+    "../api:scoped_refptr",
+    "../api/video:video_frame",
+    "../api/video:video_frame_i420",
+  ]
+}
+
 rtc_library("video_test_common") {
   visibility = [ "*" ]
   testonly = true
   sources = [
     "fake_texture_frame.cc",
     "fake_texture_frame.h",
-    "frame_generator.cc",
-    "frame_generator.h",
+    "frame_forwarder.cc",
+    "frame_forwarder.h",
     "frame_generator_capturer.cc",
     "frame_generator_capturer.h",
-    "frame_utils.cc",
-    "frame_utils.h",
     "test_video_capturer.cc",
     "test_video_capturer.h",
     "video_codec_settings.h",
@@ -53,6 +106,8 @@
 
   deps = [
     ":fileutils",
+    ":frame_utils",
+    "../api:create_frame_generator",
     "../api:frame_generator_api",
     "../api:scoped_refptr",
     "../api/task_queue",
@@ -293,8 +348,6 @@
     sources = [
       "testsupport/frame_reader.h",
       "testsupport/frame_writer.h",
-      "testsupport/ivf_video_frame_generator.cc",
-      "testsupport/ivf_video_frame_generator.h",
       "testsupport/mock/mock_frame_reader.h",
       "testsupport/video_frame_writer.cc",
       "testsupport/video_frame_writer.h",
@@ -306,6 +359,7 @@
 
     deps = [
       ":fileutils",
+      ":frame_utils",
       ":test_support",
       ":video_test_common",
       "../api:scoped_refptr",
@@ -385,6 +439,7 @@
       ":fake_video_codecs",
       ":fileutils",
       ":fileutils_unittests",
+      ":frame_generator_impl",
       ":perf_test",
       ":rtc_expect_death",
       ":rtp_test_utils",
@@ -393,7 +448,9 @@
       ":test_support_test_artifacts",
       ":video_test_common",
       ":video_test_support",
+      "../api:create_frame_generator",
       "../api:create_simulcast_test_fixture_api",
+      "../api:frame_generator_api",
       "../api:scoped_refptr",
       "../api:simulcast_test_fixture_api",
       "../api/task_queue:task_queue_test",
@@ -764,6 +821,8 @@
     ":rtp_test_utils",
     ":test_support",
     ":video_test_common",
+    "../api:create_frame_generator",
+    "../api:frame_generator_api",
     "../api:rtp_headers",
     "../api:rtp_parameters",
     "../api:simulated_network_api",
diff --git a/test/call_test.cc b/test/call_test.cc
index e8c067a..38c5d5b 100644
--- a/test/call_test.cc
+++ b/test/call_test.cc
@@ -17,6 +17,7 @@
 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
 #include "api/task_queue/default_task_queue_factory.h"
 #include "api/task_queue/task_queue_base.h"
+#include "api/test/create_frame_generator.h"
 #include "api/video/builtin_video_bitrate_allocator_factory.h"
 #include "api/video_codecs/video_encoder_config.h"
 #include "call/fake_network_pipe.h"
@@ -468,8 +469,8 @@
   auto frame_generator_capturer =
       std::make_unique<test::FrameGeneratorCapturer>(
           clock,
-          test::FrameGenerator::CreateSquareGenerator(
-              width, height, absl::nullopt, absl::nullopt),
+          test::CreateSquareFrameGenerator(width, height, absl::nullopt,
+                                           absl::nullopt),
           framerate * speed, *task_queue_factory_);
   frame_generator_capturer_ = frame_generator_capturer.get();
   frame_generator_capturer->Init();
@@ -484,8 +485,8 @@
   auto frame_generator_capturer =
       std::make_unique<test::FrameGeneratorCapturer>(
           clock_,
-          test::FrameGenerator::CreateSquareGenerator(
-              width, height, absl::nullopt, absl::nullopt),
+          test::CreateSquareFrameGenerator(width, height, absl::nullopt,
+                                           absl::nullopt),
           framerate, *task_queue_factory_);
   frame_generator_capturer_ = frame_generator_capturer.get();
   frame_generator_capturer->Init();
diff --git a/test/frame_forwarder.cc b/test/frame_forwarder.cc
new file mode 100644
index 0000000..d1a2ddb
--- /dev/null
+++ b/test/frame_forwarder.cc
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#include "test/frame_forwarder.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace test {
+
+FrameForwarder::FrameForwarder() : sink_(nullptr) {}
+FrameForwarder::~FrameForwarder() {}
+
+void FrameForwarder::IncomingCapturedFrame(const VideoFrame& video_frame) {
+  rtc::CritScope lock(&crit_);
+  if (sink_)
+    sink_->OnFrame(video_frame);
+}
+
+void FrameForwarder::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
+                                     const rtc::VideoSinkWants& wants) {
+  rtc::CritScope lock(&crit_);
+  RTC_DCHECK(!sink_ || sink_ == sink);
+  sink_ = sink;
+  sink_wants_ = wants;
+}
+
+void FrameForwarder::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) {
+  rtc::CritScope lock(&crit_);
+  RTC_DCHECK_EQ(sink, sink_);
+  sink_ = nullptr;
+}
+
+rtc::VideoSinkWants FrameForwarder::sink_wants() const {
+  rtc::CritScope lock(&crit_);
+  return sink_wants_;
+}
+
+bool FrameForwarder::has_sinks() const {
+  rtc::CritScope lock(&crit_);
+  return sink_ != nullptr;
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/test/frame_forwarder.h b/test/frame_forwarder.h
new file mode 100644
index 0000000..cf29f5f
--- /dev/null
+++ b/test/frame_forwarder.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef TEST_FRAME_FORWARDER_H_
+#define TEST_FRAME_FORWARDER_H_
+
+#include "api/video/video_frame.h"
+#include "api/video/video_source_interface.h"
+#include "rtc_base/critical_section.h"
+
+namespace webrtc {
+namespace test {
+
+// FrameForwarder can be used as an implementation
+// of rtc::VideoSourceInterface<VideoFrame> where the caller controls when
+// a frame should be forwarded to its sink.
+// Currently this implementation only support one sink.
+class FrameForwarder : public rtc::VideoSourceInterface<VideoFrame> {
+ public:
+  FrameForwarder();
+  ~FrameForwarder() override;
+  // Forwards |video_frame| to the registered |sink_|.
+  virtual void IncomingCapturedFrame(const VideoFrame& video_frame);
+  rtc::VideoSinkWants sink_wants() const;
+  bool has_sinks() const;
+
+ protected:
+  void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
+                       const rtc::VideoSinkWants& wants) override;
+  void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
+
+  rtc::CriticalSection crit_;
+  rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(crit_);
+  rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(crit_);
+};
+
+}  // namespace test
+}  // namespace webrtc
+
+#endif  // TEST_FRAME_FORWARDER_H_
diff --git a/test/frame_generator.cc b/test/frame_generator.cc
index 6c5ac51..e3b4a06 100644
--- a/test/frame_generator.cc
+++ b/test/frame_generator.cc
@@ -15,18 +15,13 @@
 #include <cstdio>
 #include <memory>
 
-#include "api/scoped_refptr.h"
 #include "api/video/i010_buffer.h"
-#include "api/video/i420_buffer.h"
-#include "api/video/video_frame_buffer.h"
 #include "api/video/video_rotation.h"
 #include "common_video/include/video_frame_buffer.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/keep_ref_until_done.h"
-#include "rtc_base/random.h"
-#include "system_wrappers/include/clock.h"
 #include "test/frame_utils.h"
 
 namespace webrtc {
@@ -37,514 +32,345 @@
 void KeepBufferRefs(rtc::scoped_refptr<webrtc::VideoFrameBuffer>,
                     rtc::scoped_refptr<webrtc::VideoFrameBuffer>) {}
 
-// SquareGenerator is a FrameGenerator that draws a given amount of randomly
-// sized and colored squares. Between each new generated frame, the squares
-// are moved slightly towards the lower right corner.
-class SquareGenerator : public FrameGenerator {
- public:
-  SquareGenerator(int width, int height, OutputType type, int num_squares)
-      : type_(type) {
-    ChangeResolution(width, height);
-    for (int i = 0; i < num_squares; ++i) {
-      squares_.emplace_back(new Square(width, height, i + 1));
+}  // namespace
+
+SquareGenerator::SquareGenerator(int width,
+                                 int height,
+                                 OutputType type,
+                                 int num_squares)
+    : type_(type) {
+  ChangeResolution(width, height);
+  for (int i = 0; i < num_squares; ++i) {
+    squares_.emplace_back(new Square(width, height, i + 1));
+  }
+}
+
+void SquareGenerator::ChangeResolution(size_t width, size_t height) {
+  rtc::CritScope lock(&crit_);
+  width_ = static_cast<int>(width);
+  height_ = static_cast<int>(height);
+  RTC_CHECK(width_ > 0);
+  RTC_CHECK(height_ > 0);
+}
+
+rtc::scoped_refptr<I420Buffer> SquareGenerator::CreateI420Buffer(int width,
+                                                                 int height) {
+  rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(width, height));
+  memset(buffer->MutableDataY(), 127, height * buffer->StrideY());
+  memset(buffer->MutableDataU(), 127,
+         buffer->ChromaHeight() * buffer->StrideU());
+  memset(buffer->MutableDataV(), 127,
+         buffer->ChromaHeight() * buffer->StrideV());
+  return buffer;
+}
+
+FrameGeneratorInterface::VideoFrameData SquareGenerator::NextFrame() {
+  rtc::CritScope lock(&crit_);
+
+  rtc::scoped_refptr<VideoFrameBuffer> buffer = nullptr;
+  switch (type_) {
+    case OutputType::kI420:
+    case OutputType::kI010: {
+      buffer = CreateI420Buffer(width_, height_);
+      break;
+    }
+    case OutputType::kI420A: {
+      rtc::scoped_refptr<I420Buffer> yuv_buffer =
+          CreateI420Buffer(width_, height_);
+      rtc::scoped_refptr<I420Buffer> axx_buffer =
+          CreateI420Buffer(width_, height_);
+      buffer = WrapI420ABuffer(
+          yuv_buffer->width(), yuv_buffer->height(), yuv_buffer->DataY(),
+          yuv_buffer->StrideY(), yuv_buffer->DataU(), yuv_buffer->StrideU(),
+          yuv_buffer->DataV(), yuv_buffer->StrideV(), axx_buffer->DataY(),
+          axx_buffer->StrideY(),
+          rtc::Bind(&KeepBufferRefs, yuv_buffer, axx_buffer));
+      break;
+    }
+    default:
+      RTC_NOTREACHED() << "The given output format is not supported.";
+  }
+
+  for (const auto& square : squares_)
+    square->Draw(buffer);
+
+  if (type_ == OutputType::kI010) {
+    buffer = I010Buffer::Copy(*buffer->ToI420());
+  }
+
+  return VideoFrameData(buffer, absl::nullopt);
+}
+
+SquareGenerator::Square::Square(int width, int height, int seed)
+    : random_generator_(seed),
+      x_(random_generator_.Rand(0, width)),
+      y_(random_generator_.Rand(0, height)),
+      length_(random_generator_.Rand(1, width > 4 ? width / 4 : 1)),
+      yuv_y_(random_generator_.Rand(0, 255)),
+      yuv_u_(random_generator_.Rand(0, 255)),
+      yuv_v_(random_generator_.Rand(0, 255)),
+      yuv_a_(random_generator_.Rand(0, 255)) {}
+
+void SquareGenerator::Square::Draw(
+    const rtc::scoped_refptr<VideoFrameBuffer>& frame_buffer) {
+  RTC_DCHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 ||
+             frame_buffer->type() == VideoFrameBuffer::Type::kI420A);
+  rtc::scoped_refptr<I420BufferInterface> buffer = frame_buffer->ToI420();
+  x_ = (x_ + random_generator_.Rand(0, 4)) % (buffer->width() - length_);
+  y_ = (y_ + random_generator_.Rand(0, 4)) % (buffer->height() - length_);
+  for (int y = y_; y < y_ + length_; ++y) {
+    uint8_t* pos_y =
+        (const_cast<uint8_t*>(buffer->DataY()) + x_ + y * buffer->StrideY());
+    memset(pos_y, yuv_y_, length_);
+  }
+
+  for (int y = y_; y < y_ + length_; y = y + 2) {
+    uint8_t* pos_u = (const_cast<uint8_t*>(buffer->DataU()) + x_ / 2 +
+                      y / 2 * buffer->StrideU());
+    memset(pos_u, yuv_u_, length_ / 2);
+    uint8_t* pos_v = (const_cast<uint8_t*>(buffer->DataV()) + x_ / 2 +
+                      y / 2 * buffer->StrideV());
+    memset(pos_v, yuv_v_, length_ / 2);
+  }
+
+  if (frame_buffer->type() == VideoFrameBuffer::Type::kI420)
+    return;
+
+  // Optionally draw on alpha plane if given.
+  const webrtc::I420ABufferInterface* yuva_buffer = frame_buffer->GetI420A();
+  for (int y = y_; y < y_ + length_; ++y) {
+    uint8_t* pos_y = (const_cast<uint8_t*>(yuva_buffer->DataA()) + x_ +
+                      y * yuva_buffer->StrideA());
+    memset(pos_y, yuv_a_, length_);
+  }
+}
+
+YuvFileGenerator::YuvFileGenerator(std::vector<FILE*> files,
+                                   size_t width,
+                                   size_t height,
+                                   int frame_repeat_count)
+    : file_index_(0),
+      frame_index_(std::numeric_limits<size_t>::max()),
+      files_(files),
+      width_(width),
+      height_(height),
+      frame_size_(CalcBufferSize(VideoType::kI420,
+                                 static_cast<int>(width_),
+                                 static_cast<int>(height_))),
+      frame_buffer_(new uint8_t[frame_size_]),
+      frame_display_count_(frame_repeat_count),
+      current_display_count_(0) {
+  RTC_DCHECK_GT(width, 0);
+  RTC_DCHECK_GT(height, 0);
+  RTC_DCHECK_GT(frame_repeat_count, 0);
+}
+
+YuvFileGenerator::~YuvFileGenerator() {
+  for (FILE* file : files_)
+    fclose(file);
+}
+
+FrameGeneratorInterface::VideoFrameData YuvFileGenerator::NextFrame() {
+  // Empty update by default.
+  VideoFrame::UpdateRect update_rect{0, 0, 0, 0};
+  if (current_display_count_ == 0) {
+    const bool got_new_frame = ReadNextFrame();
+    // Full update on a new frame from file.
+    if (got_new_frame) {
+      update_rect = VideoFrame::UpdateRect{0, 0, static_cast<int>(width_),
+                                           static_cast<int>(height_)};
     }
   }
+  if (++current_display_count_ >= frame_display_count_)
+    current_display_count_ = 0;
 
-  void ChangeResolution(size_t width, size_t height) override {
-    rtc::CritScope lock(&crit_);
-    width_ = static_cast<int>(width);
-    height_ = static_cast<int>(height);
-    RTC_CHECK(width_ > 0);
-    RTC_CHECK(height_ > 0);
-  }
+  return VideoFrameData(last_read_buffer_, update_rect);
+}
 
-  rtc::scoped_refptr<I420Buffer> CreateI420Buffer(int width, int height) {
-    rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(width, height));
-    memset(buffer->MutableDataY(), 127, height * buffer->StrideY());
-    memset(buffer->MutableDataU(), 127,
-           buffer->ChromaHeight() * buffer->StrideU());
-    memset(buffer->MutableDataV(), 127,
-           buffer->ChromaHeight() * buffer->StrideV());
-    return buffer;
-  }
+bool YuvFileGenerator::ReadNextFrame() {
+  size_t prev_frame_index = frame_index_;
+  size_t prev_file_index = file_index_;
+  last_read_buffer_ = test::ReadI420Buffer(
+      static_cast<int>(width_), static_cast<int>(height_), files_[file_index_]);
+  ++frame_index_;
+  if (!last_read_buffer_) {
+    // No more frames to read in this file, rewind and move to next file.
+    rewind(files_[file_index_]);
 
-  VideoFrameData NextFrame() override {
-    rtc::CritScope lock(&crit_);
-
-    rtc::scoped_refptr<VideoFrameBuffer> buffer = nullptr;
-    switch (type_) {
-      case OutputType::kI420:
-      case OutputType::kI010: {
-        buffer = CreateI420Buffer(width_, height_);
-        break;
-      }
-      case OutputType::kI420A: {
-        rtc::scoped_refptr<I420Buffer> yuv_buffer =
-            CreateI420Buffer(width_, height_);
-        rtc::scoped_refptr<I420Buffer> axx_buffer =
-            CreateI420Buffer(width_, height_);
-        buffer = WrapI420ABuffer(
-            yuv_buffer->width(), yuv_buffer->height(), yuv_buffer->DataY(),
-            yuv_buffer->StrideY(), yuv_buffer->DataU(), yuv_buffer->StrideU(),
-            yuv_buffer->DataV(), yuv_buffer->StrideV(), axx_buffer->DataY(),
-            axx_buffer->StrideY(),
-            rtc::Bind(&KeepBufferRefs, yuv_buffer, axx_buffer));
-        break;
-      }
-      default:
-        RTC_NOTREACHED() << "The given output format is not supported.";
-    }
-
-    for (const auto& square : squares_)
-      square->Draw(buffer);
-
-    if (type_ == OutputType::kI010) {
-      buffer = I010Buffer::Copy(*buffer->ToI420());
-    }
-
-    return VideoFrameData(buffer, absl::nullopt);
-  }
-
- private:
-  class Square {
-   public:
-    Square(int width, int height, int seed)
-        : random_generator_(seed),
-          x_(random_generator_.Rand(0, width)),
-          y_(random_generator_.Rand(0, height)),
-          length_(random_generator_.Rand(1, width > 4 ? width / 4 : 1)),
-          yuv_y_(random_generator_.Rand(0, 255)),
-          yuv_u_(random_generator_.Rand(0, 255)),
-          yuv_v_(random_generator_.Rand(0, 255)),
-          yuv_a_(random_generator_.Rand(0, 255)) {}
-
-    void Draw(const rtc::scoped_refptr<VideoFrameBuffer>& frame_buffer) {
-      RTC_DCHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 ||
-                 frame_buffer->type() == VideoFrameBuffer::Type::kI420A);
-      rtc::scoped_refptr<I420BufferInterface> buffer = frame_buffer->ToI420();
-      x_ = (x_ + random_generator_.Rand(0, 4)) % (buffer->width() - length_);
-      y_ = (y_ + random_generator_.Rand(0, 4)) % (buffer->height() - length_);
-      for (int y = y_; y < y_ + length_; ++y) {
-        uint8_t* pos_y = (const_cast<uint8_t*>(buffer->DataY()) + x_ +
-                          y * buffer->StrideY());
-        memset(pos_y, yuv_y_, length_);
-      }
-
-      for (int y = y_; y < y_ + length_; y = y + 2) {
-        uint8_t* pos_u = (const_cast<uint8_t*>(buffer->DataU()) + x_ / 2 +
-                          y / 2 * buffer->StrideU());
-        memset(pos_u, yuv_u_, length_ / 2);
-        uint8_t* pos_v = (const_cast<uint8_t*>(buffer->DataV()) + x_ / 2 +
-                          y / 2 * buffer->StrideV());
-        memset(pos_v, yuv_v_, length_ / 2);
-      }
-
-      if (frame_buffer->type() == VideoFrameBuffer::Type::kI420)
-        return;
-
-      // Optionally draw on alpha plane if given.
-      const webrtc::I420ABufferInterface* yuva_buffer =
-          frame_buffer->GetI420A();
-      for (int y = y_; y < y_ + length_; ++y) {
-        uint8_t* pos_y = (const_cast<uint8_t*>(yuva_buffer->DataA()) + x_ +
-                          y * yuva_buffer->StrideA());
-        memset(pos_y, yuv_a_, length_);
-      }
-    }
-
-   private:
-    Random random_generator_;
-    int x_;
-    int y_;
-    const int length_;
-    const uint8_t yuv_y_;
-    const uint8_t yuv_u_;
-    const uint8_t yuv_v_;
-    const uint8_t yuv_a_;
-  };
-
-  rtc::CriticalSection crit_;
-  const OutputType type_;
-  int width_ RTC_GUARDED_BY(&crit_);
-  int height_ RTC_GUARDED_BY(&crit_);
-  std::vector<std::unique_ptr<Square>> squares_ RTC_GUARDED_BY(&crit_);
-};
-
-class YuvFileGenerator : public FrameGenerator {
- public:
-  YuvFileGenerator(std::vector<FILE*> files,
-                   size_t width,
-                   size_t height,
-                   int frame_repeat_count)
-      : file_index_(0),
-        frame_index_(std::numeric_limits<size_t>::max()),
-        files_(files),
-        width_(width),
-        height_(height),
-        frame_size_(CalcBufferSize(VideoType::kI420,
-                                   static_cast<int>(width_),
-                                   static_cast<int>(height_))),
-        frame_buffer_(new uint8_t[frame_size_]),
-        frame_display_count_(frame_repeat_count),
-        current_display_count_(0) {
-    RTC_DCHECK_GT(width, 0);
-    RTC_DCHECK_GT(height, 0);
-    RTC_DCHECK_GT(frame_repeat_count, 0);
-  }
-
-  ~YuvFileGenerator() override {
-    for (FILE* file : files_)
-      fclose(file);
-  }
-
-  VideoFrameData NextFrame() override {
-    // Empty update by default.
-    VideoFrame::UpdateRect update_rect{0, 0, 0, 0};
-    if (current_display_count_ == 0) {
-      const bool got_new_frame = ReadNextFrame();
-      // Full update on a new frame from file.
-      if (got_new_frame) {
-        update_rect = VideoFrame::UpdateRect{0, 0, static_cast<int>(width_),
-                                             static_cast<int>(height_)};
-      }
-    }
-    if (++current_display_count_ >= frame_display_count_)
-      current_display_count_ = 0;
-
-    return VideoFrameData(last_read_buffer_, update_rect);
-  }
-
-  // Returns true if the new frame was loaded.
-  // False only in case of a single file with a single frame in it.
-  bool ReadNextFrame() {
-    size_t prev_frame_index = frame_index_;
-    size_t prev_file_index = file_index_;
+    frame_index_ = 0;
+    file_index_ = (file_index_ + 1) % files_.size();
     last_read_buffer_ =
         test::ReadI420Buffer(static_cast<int>(width_),
                              static_cast<int>(height_), files_[file_index_]);
-    ++frame_index_;
-    if (!last_read_buffer_) {
-      // No more frames to read in this file, rewind and move to next file.
-      rewind(files_[file_index_]);
+    RTC_CHECK(last_read_buffer_);
+  }
+  return frame_index_ != prev_frame_index || file_index_ != prev_file_index;
+}
 
-      frame_index_ = 0;
-      file_index_ = (file_index_ + 1) % files_.size();
-      last_read_buffer_ =
-          test::ReadI420Buffer(static_cast<int>(width_),
-                               static_cast<int>(height_), files_[file_index_]);
-      RTC_CHECK(last_read_buffer_);
+SlideGenerator::SlideGenerator(int width, int height, int frame_repeat_count)
+    : width_(width),
+      height_(height),
+      frame_display_count_(frame_repeat_count),
+      current_display_count_(0),
+      random_generator_(1234) {
+  RTC_DCHECK_GT(width, 0);
+  RTC_DCHECK_GT(height, 0);
+  RTC_DCHECK_GT(frame_repeat_count, 0);
+}
+
+FrameGeneratorInterface::VideoFrameData SlideGenerator::NextFrame() {
+  if (current_display_count_ == 0)
+    GenerateNewFrame();
+  if (++current_display_count_ >= frame_display_count_)
+    current_display_count_ = 0;
+
+  return VideoFrameData(buffer_, absl::nullopt);
+}
+
+void SlideGenerator::GenerateNewFrame() {
+  // The squares should have a varying order of magnitude in order
+  // to simulate variation in the slides' complexity.
+  const int kSquareNum = 1 << (4 + (random_generator_.Rand(0, 3) * 2));
+
+  buffer_ = I420Buffer::Create(width_, height_);
+  memset(buffer_->MutableDataY(), 127, height_ * buffer_->StrideY());
+  memset(buffer_->MutableDataU(), 127,
+         buffer_->ChromaHeight() * buffer_->StrideU());
+  memset(buffer_->MutableDataV(), 127,
+         buffer_->ChromaHeight() * buffer_->StrideV());
+
+  for (int i = 0; i < kSquareNum; ++i) {
+    int length = random_generator_.Rand(1, width_ > 4 ? width_ / 4 : 1);
+    // Limit the length of later squares so that they don't overwrite the
+    // previous ones too much.
+    length = (length * (kSquareNum - i)) / kSquareNum;
+
+    int x = random_generator_.Rand(0, width_ - length);
+    int y = random_generator_.Rand(0, height_ - length);
+    uint8_t yuv_y = random_generator_.Rand(0, 255);
+    uint8_t yuv_u = random_generator_.Rand(0, 255);
+    uint8_t yuv_v = random_generator_.Rand(0, 255);
+
+    for (int yy = y; yy < y + length; ++yy) {
+      uint8_t* pos_y = (buffer_->MutableDataY() + x + yy * buffer_->StrideY());
+      memset(pos_y, yuv_y, length);
     }
-    return frame_index_ != prev_frame_index || file_index_ != prev_file_index;
-  }
-
- private:
-  size_t file_index_;
-  size_t frame_index_;
-  const std::vector<FILE*> files_;
-  const size_t width_;
-  const size_t height_;
-  const size_t frame_size_;
-  const std::unique_ptr<uint8_t[]> frame_buffer_;
-  const int frame_display_count_;
-  int current_display_count_;
-  rtc::scoped_refptr<I420Buffer> last_read_buffer_;
-};
-
-// SlideGenerator works similarly to YuvFileGenerator but it fills the frames
-// with randomly sized and colored squares instead of reading their content
-// from files.
-class SlideGenerator : public FrameGenerator {
- public:
-  SlideGenerator(int width, int height, int frame_repeat_count)
-      : width_(width),
-        height_(height),
-        frame_display_count_(frame_repeat_count),
-        current_display_count_(0),
-        random_generator_(1234) {
-    RTC_DCHECK_GT(width, 0);
-    RTC_DCHECK_GT(height, 0);
-    RTC_DCHECK_GT(frame_repeat_count, 0);
-  }
-
-  VideoFrameData NextFrame() override {
-    if (current_display_count_ == 0)
-      GenerateNewFrame();
-    if (++current_display_count_ >= frame_display_count_)
-      current_display_count_ = 0;
-
-    return VideoFrameData(buffer_, absl::nullopt);
-  }
-
-  // Generates some randomly sized and colored squares scattered
-  // over the frame.
-  void GenerateNewFrame() {
-    // The squares should have a varying order of magnitude in order
-    // to simulate variation in the slides' complexity.
-    const int kSquareNum = 1 << (4 + (random_generator_.Rand(0, 3) * 2));
-
-    buffer_ = I420Buffer::Create(width_, height_);
-    memset(buffer_->MutableDataY(), 127, height_ * buffer_->StrideY());
-    memset(buffer_->MutableDataU(), 127,
-           buffer_->ChromaHeight() * buffer_->StrideU());
-    memset(buffer_->MutableDataV(), 127,
-           buffer_->ChromaHeight() * buffer_->StrideV());
-
-    for (int i = 0; i < kSquareNum; ++i) {
-      int length = random_generator_.Rand(1, width_ > 4 ? width_ / 4 : 1);
-      // Limit the length of later squares so that they don't overwrite the
-      // previous ones too much.
-      length = (length * (kSquareNum - i)) / kSquareNum;
-
-      int x = random_generator_.Rand(0, width_ - length);
-      int y = random_generator_.Rand(0, height_ - length);
-      uint8_t yuv_y = random_generator_.Rand(0, 255);
-      uint8_t yuv_u = random_generator_.Rand(0, 255);
-      uint8_t yuv_v = random_generator_.Rand(0, 255);
-
-      for (int yy = y; yy < y + length; ++yy) {
-        uint8_t* pos_y =
-            (buffer_->MutableDataY() + x + yy * buffer_->StrideY());
-        memset(pos_y, yuv_y, length);
-      }
-      for (int yy = y; yy < y + length; yy += 2) {
-        uint8_t* pos_u =
-            (buffer_->MutableDataU() + x / 2 + yy / 2 * buffer_->StrideU());
-        memset(pos_u, yuv_u, length / 2);
-        uint8_t* pos_v =
-            (buffer_->MutableDataV() + x / 2 + yy / 2 * buffer_->StrideV());
-        memset(pos_v, yuv_v, length / 2);
-      }
+    for (int yy = y; yy < y + length; yy += 2) {
+      uint8_t* pos_u =
+          (buffer_->MutableDataU() + x / 2 + yy / 2 * buffer_->StrideU());
+      memset(pos_u, yuv_u, length / 2);
+      uint8_t* pos_v =
+          (buffer_->MutableDataV() + x / 2 + yy / 2 * buffer_->StrideV());
+      memset(pos_v, yuv_v, length / 2);
     }
   }
-
- private:
-  const int width_;
-  const int height_;
-  const int frame_display_count_;
-  int current_display_count_;
-  Random random_generator_;
-  rtc::scoped_refptr<I420Buffer> buffer_;
-};
-
-class ScrollingImageFrameGenerator : public FrameGenerator {
- public:
-  ScrollingImageFrameGenerator(Clock* clock,
-                               const std::vector<FILE*>& files,
-                               size_t source_width,
-                               size_t source_height,
-                               size_t target_width,
-                               size_t target_height,
-                               int64_t scroll_time_ms,
-                               int64_t pause_time_ms)
-      : clock_(clock),
-        start_time_(clock->TimeInMilliseconds()),
-        scroll_time_(scroll_time_ms),
-        pause_time_(pause_time_ms),
-        num_frames_(files.size()),
-        target_width_(static_cast<int>(target_width)),
-        target_height_(static_cast<int>(target_height)),
-        current_frame_num_(num_frames_ - 1),
-        prev_frame_not_scrolled_(false),
-        current_source_frame_(nullptr, absl::nullopt),
-        current_frame_(nullptr, absl::nullopt),
-        file_generator_(files, source_width, source_height, 1) {
-    RTC_DCHECK(clock_ != nullptr);
-    RTC_DCHECK_GT(num_frames_, 0);
-    RTC_DCHECK_GE(source_height, target_height);
-    RTC_DCHECK_GE(source_width, target_width);
-    RTC_DCHECK_GE(scroll_time_ms, 0);
-    RTC_DCHECK_GE(pause_time_ms, 0);
-    RTC_DCHECK_GT(scroll_time_ms + pause_time_ms, 0);
-  }
-
-  ~ScrollingImageFrameGenerator() override {}
-
-  VideoFrameData NextFrame() override {
-    const int64_t kFrameDisplayTime = scroll_time_ + pause_time_;
-    const int64_t now = clock_->TimeInMilliseconds();
-    int64_t ms_since_start = now - start_time_;
-
-    size_t frame_num = (ms_since_start / kFrameDisplayTime) % num_frames_;
-    UpdateSourceFrame(frame_num);
-
-    bool cur_frame_not_scrolled;
-
-    double scroll_factor;
-    int64_t time_into_frame = ms_since_start % kFrameDisplayTime;
-    if (time_into_frame < scroll_time_) {
-      scroll_factor = static_cast<double>(time_into_frame) / scroll_time_;
-      cur_frame_not_scrolled = false;
-    } else {
-      scroll_factor = 1.0;
-      cur_frame_not_scrolled = true;
-    }
-    CropSourceToScrolledImage(scroll_factor);
-
-    bool same_scroll_position =
-        prev_frame_not_scrolled_ && cur_frame_not_scrolled;
-    if (!same_scroll_position) {
-      // If scrolling is not finished yet, force full frame update.
-      current_frame_.update_rect =
-          VideoFrame::UpdateRect{0, 0, target_width_, target_height_};
-    }
-    prev_frame_not_scrolled_ = cur_frame_not_scrolled;
-
-    return current_frame_;
-  }
-
-  void UpdateSourceFrame(size_t frame_num) {
-    VideoFrame::UpdateRect acc_update{0, 0, 0, 0};
-    while (current_frame_num_ != frame_num) {
-      current_source_frame_ = file_generator_.NextFrame();
-      if (current_source_frame_.update_rect) {
-        acc_update.Union(*current_source_frame_.update_rect);
-      }
-      current_frame_num_ = (current_frame_num_ + 1) % num_frames_;
-    }
-    current_source_frame_.update_rect = acc_update;
-  }
-
-  void CropSourceToScrolledImage(double scroll_factor) {
-    int scroll_margin_x = current_source_frame_.buffer->width() - target_width_;
-    int pixels_scrolled_x =
-        static_cast<int>(scroll_margin_x * scroll_factor + 0.5);
-    int scroll_margin_y =
-        current_source_frame_.buffer->height() - target_height_;
-    int pixels_scrolled_y =
-        static_cast<int>(scroll_margin_y * scroll_factor + 0.5);
-
-    rtc::scoped_refptr<I420BufferInterface> i420_buffer =
-        current_source_frame_.buffer->ToI420();
-    int offset_y =
-        (i420_buffer->StrideY() * pixels_scrolled_y) + pixels_scrolled_x;
-    int offset_u = (i420_buffer->StrideU() * (pixels_scrolled_y / 2)) +
-                   (pixels_scrolled_x / 2);
-    int offset_v = (i420_buffer->StrideV() * (pixels_scrolled_y / 2)) +
-                   (pixels_scrolled_x / 2);
-
-    VideoFrame::UpdateRect update_rect =
-        current_source_frame_.update_rect->IsEmpty()
-            ? VideoFrame::UpdateRect{0, 0, 0, 0}
-            : VideoFrame::UpdateRect{0, 0, target_width_, target_height_};
-    current_frame_ = VideoFrameData(
-        WrapI420Buffer(target_width_, target_height_,
-                       &i420_buffer->DataY()[offset_y], i420_buffer->StrideY(),
-                       &i420_buffer->DataU()[offset_u], i420_buffer->StrideU(),
-                       &i420_buffer->DataV()[offset_v], i420_buffer->StrideV(),
-                       KeepRefUntilDone(i420_buffer)),
-        update_rect);
-  }
-
-  Clock* const clock_;
-  const int64_t start_time_;
-  const int64_t scroll_time_;
-  const int64_t pause_time_;
-  const size_t num_frames_;
-  const int target_width_;
-  const int target_height_;
-
-  size_t current_frame_num_;
-  bool prev_frame_not_scrolled_;
-  VideoFrameData current_source_frame_;
-  VideoFrameData current_frame_;
-  YuvFileGenerator file_generator_;
-};
-
-}  // namespace
-
-FrameForwarder::FrameForwarder() : sink_(nullptr) {}
-FrameForwarder::~FrameForwarder() {}
-
-void FrameForwarder::IncomingCapturedFrame(const VideoFrame& video_frame) {
-  rtc::CritScope lock(&crit_);
-  if (sink_)
-    sink_->OnFrame(video_frame);
 }
 
-void FrameForwarder::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
-                                     const rtc::VideoSinkWants& wants) {
-  rtc::CritScope lock(&crit_);
-  RTC_DCHECK(!sink_ || sink_ == sink);
-  sink_ = sink;
-  sink_wants_ = wants;
-}
-
-void FrameForwarder::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) {
-  rtc::CritScope lock(&crit_);
-  RTC_DCHECK_EQ(sink, sink_);
-  sink_ = nullptr;
-}
-
-rtc::VideoSinkWants FrameForwarder::sink_wants() const {
-  rtc::CritScope lock(&crit_);
-  return sink_wants_;
-}
-
-bool FrameForwarder::has_sinks() const {
-  rtc::CritScope lock(&crit_);
-  return sink_ != nullptr;
-}
-
-void FrameGenerator::ChangeResolution(size_t width, size_t height) {
-  RTC_NOTREACHED();
-}
-
-std::unique_ptr<FrameGenerator> FrameGenerator::CreateSquareGenerator(
-    int width,
-    int height,
-    absl::optional<OutputType> type,
-    absl::optional<int> num_squares) {
-  return std::unique_ptr<FrameGenerator>(
-      new SquareGenerator(width, height, type.value_or(OutputType::kI420),
-                          num_squares.value_or(10)));
-}
-
-std::unique_ptr<FrameGenerator> FrameGenerator::CreateSlideGenerator(
-    int width,
-    int height,
-    int frame_repeat_count) {
-  return std::unique_ptr<FrameGenerator>(
-      new SlideGenerator(width, height, frame_repeat_count));
-}
-
-std::unique_ptr<FrameGenerator> FrameGenerator::CreateFromYuvFile(
-    std::vector<std::string> filenames,
-    size_t width,
-    size_t height,
-    int frame_repeat_count) {
-  RTC_DCHECK(!filenames.empty());
-  std::vector<FILE*> files;
-  for (const std::string& filename : filenames) {
-    FILE* file = fopen(filename.c_str(), "rb");
-    RTC_DCHECK(file != nullptr) << "Failed to open: '" << filename << "'\n";
-    files.push_back(file);
-  }
-
-  return std::unique_ptr<FrameGenerator>(
-      new YuvFileGenerator(files, width, height, frame_repeat_count));
-}
-
-std::unique_ptr<FrameGenerator>
-FrameGenerator::CreateScrollingInputFromYuvFiles(
+ScrollingImageFrameGenerator::ScrollingImageFrameGenerator(
     Clock* clock,
-    std::vector<std::string> filenames,
+    const std::vector<FILE*>& files,
     size_t source_width,
     size_t source_height,
     size_t target_width,
     size_t target_height,
     int64_t scroll_time_ms,
-    int64_t pause_time_ms) {
-  RTC_DCHECK(!filenames.empty());
-  std::vector<FILE*> files;
-  for (const std::string& filename : filenames) {
-    FILE* file = fopen(filename.c_str(), "rb");
-    RTC_DCHECK(file != nullptr);
-    files.push_back(file);
-  }
+    int64_t pause_time_ms)
+    : clock_(clock),
+      start_time_(clock->TimeInMilliseconds()),
+      scroll_time_(scroll_time_ms),
+      pause_time_(pause_time_ms),
+      num_frames_(files.size()),
+      target_width_(static_cast<int>(target_width)),
+      target_height_(static_cast<int>(target_height)),
+      current_frame_num_(num_frames_ - 1),
+      prev_frame_not_scrolled_(false),
+      current_source_frame_(nullptr, absl::nullopt),
+      current_frame_(nullptr, absl::nullopt),
+      file_generator_(files, source_width, source_height, 1) {
+  RTC_DCHECK(clock_ != nullptr);
+  RTC_DCHECK_GT(num_frames_, 0);
+  RTC_DCHECK_GE(source_height, target_height);
+  RTC_DCHECK_GE(source_width, target_width);
+  RTC_DCHECK_GE(scroll_time_ms, 0);
+  RTC_DCHECK_GE(pause_time_ms, 0);
+  RTC_DCHECK_GT(scroll_time_ms + pause_time_ms, 0);
+}
 
-  return std::unique_ptr<FrameGenerator>(new ScrollingImageFrameGenerator(
-      clock, files, source_width, source_height, target_width, target_height,
-      scroll_time_ms, pause_time_ms));
+FrameGeneratorInterface::VideoFrameData
+ScrollingImageFrameGenerator::NextFrame() {
+  const int64_t kFrameDisplayTime = scroll_time_ + pause_time_;
+  const int64_t now = clock_->TimeInMilliseconds();
+  int64_t ms_since_start = now - start_time_;
+
+  size_t frame_num = (ms_since_start / kFrameDisplayTime) % num_frames_;
+  UpdateSourceFrame(frame_num);
+
+  bool cur_frame_not_scrolled;
+
+  double scroll_factor;
+  int64_t time_into_frame = ms_since_start % kFrameDisplayTime;
+  if (time_into_frame < scroll_time_) {
+    scroll_factor = static_cast<double>(time_into_frame) / scroll_time_;
+    cur_frame_not_scrolled = false;
+  } else {
+    scroll_factor = 1.0;
+    cur_frame_not_scrolled = true;
+  }
+  CropSourceToScrolledImage(scroll_factor);
+
+  bool same_scroll_position =
+      prev_frame_not_scrolled_ && cur_frame_not_scrolled;
+  if (!same_scroll_position) {
+    // If scrolling is not finished yet, force full frame update.
+    current_frame_.update_rect =
+        VideoFrame::UpdateRect{0, 0, target_width_, target_height_};
+  }
+  prev_frame_not_scrolled_ = cur_frame_not_scrolled;
+
+  return current_frame_;
+}
+
+void ScrollingImageFrameGenerator::UpdateSourceFrame(size_t frame_num) {
+  VideoFrame::UpdateRect acc_update{0, 0, 0, 0};
+  while (current_frame_num_ != frame_num) {
+    current_source_frame_ = file_generator_.NextFrame();
+    if (current_source_frame_.update_rect) {
+      acc_update.Union(*current_source_frame_.update_rect);
+    }
+    current_frame_num_ = (current_frame_num_ + 1) % num_frames_;
+  }
+  current_source_frame_.update_rect = acc_update;
+}
+
+void ScrollingImageFrameGenerator::CropSourceToScrolledImage(
+    double scroll_factor) {
+  int scroll_margin_x = current_source_frame_.buffer->width() - target_width_;
+  int pixels_scrolled_x =
+      static_cast<int>(scroll_margin_x * scroll_factor + 0.5);
+  int scroll_margin_y = current_source_frame_.buffer->height() - target_height_;
+  int pixels_scrolled_y =
+      static_cast<int>(scroll_margin_y * scroll_factor + 0.5);
+
+  rtc::scoped_refptr<I420BufferInterface> i420_buffer =
+      current_source_frame_.buffer->ToI420();
+  int offset_y =
+      (i420_buffer->StrideY() * pixels_scrolled_y) + pixels_scrolled_x;
+  int offset_u = (i420_buffer->StrideU() * (pixels_scrolled_y / 2)) +
+                 (pixels_scrolled_x / 2);
+  int offset_v = (i420_buffer->StrideV() * (pixels_scrolled_y / 2)) +
+                 (pixels_scrolled_x / 2);
+
+  VideoFrame::UpdateRect update_rect =
+      current_source_frame_.update_rect->IsEmpty()
+          ? VideoFrame::UpdateRect{0, 0, 0, 0}
+          : VideoFrame::UpdateRect{0, 0, target_width_, target_height_};
+  current_frame_ = VideoFrameData(
+      WrapI420Buffer(target_width_, target_height_,
+                     &i420_buffer->DataY()[offset_y], i420_buffer->StrideY(),
+                     &i420_buffer->DataU()[offset_u], i420_buffer->StrideU(),
+                     &i420_buffer->DataV()[offset_v], i420_buffer->StrideV(),
+                     KeepRefUntilDone(i420_buffer)),
+      update_rect);
 }
 
 }  // namespace test
diff --git a/test/frame_generator.h b/test/frame_generator.h
index 47251b3..6f59c1e 100644
--- a/test/frame_generator.h
+++ b/test/frame_generator.h
@@ -14,87 +14,148 @@
 #include <string>
 #include <vector>
 
+#include "api/scoped_refptr.h"
 #include "api/test/frame_generator_interface.h"
+#include "api/video/i420_buffer.h"
 #include "api/video/video_frame.h"
+#include "api/video/video_frame_buffer.h"
 #include "api/video/video_source_interface.h"
 #include "rtc_base/critical_section.h"
+#include "rtc_base/random.h"
+#include "system_wrappers/include/clock.h"
 
 namespace webrtc {
-class Clock;
 namespace test {
 
-// FrameForwarder can be used as an implementation
-// of rtc::VideoSourceInterface<VideoFrame> where the caller controls when
-// a frame should be forwarded to its sink.
-// Currently this implementation only support one sink.
-class FrameForwarder : public rtc::VideoSourceInterface<VideoFrame> {
+// SquareGenerator is a FrameGenerator that draws a given amount of randomly
+// sized and colored squares. Between each new generated frame, the squares
+// are moved slightly towards the lower right corner.
+class SquareGenerator : public FrameGeneratorInterface {
  public:
-  FrameForwarder();
-  ~FrameForwarder() override;
-  // Forwards |video_frame| to the registered |sink_|.
-  virtual void IncomingCapturedFrame(const VideoFrame& video_frame);
-  rtc::VideoSinkWants sink_wants() const;
-  bool has_sinks() const;
+  SquareGenerator(int width, int height, OutputType type, int num_squares);
 
- protected:
-  void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
-                       const rtc::VideoSinkWants& wants) override;
-  void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override;
+  void ChangeResolution(size_t width, size_t height) override;
+  VideoFrameData NextFrame() override;
+
+ private:
+  rtc::scoped_refptr<I420Buffer> CreateI420Buffer(int width, int height);
+
+  class Square {
+   public:
+    Square(int width, int height, int seed);
+
+    void Draw(const rtc::scoped_refptr<VideoFrameBuffer>& frame_buffer);
+
+   private:
+    Random random_generator_;
+    int x_;
+    int y_;
+    const int length_;
+    const uint8_t yuv_y_;
+    const uint8_t yuv_u_;
+    const uint8_t yuv_v_;
+    const uint8_t yuv_a_;
+  };
 
   rtc::CriticalSection crit_;
-  rtc::VideoSinkInterface<VideoFrame>* sink_ RTC_GUARDED_BY(crit_);
-  rtc::VideoSinkWants sink_wants_ RTC_GUARDED_BY(crit_);
+  const OutputType type_;
+  int width_ RTC_GUARDED_BY(&crit_);
+  int height_ RTC_GUARDED_BY(&crit_);
+  std::vector<std::unique_ptr<Square>> squares_ RTC_GUARDED_BY(&crit_);
 };
 
-class FrameGenerator : public FrameGeneratorInterface {
+class YuvFileGenerator : public FrameGeneratorInterface {
  public:
-  virtual ~FrameGenerator() = default;
+  YuvFileGenerator(std::vector<FILE*> files,
+                   size_t width,
+                   size_t height,
+                   int frame_repeat_count);
 
-  // Change the capture resolution.
-  void ChangeResolution(size_t width, size_t height) override;
+  ~YuvFileGenerator();
 
-  // Creates a frame generator that produces frames with small squares that
-  // move randomly towards the lower right corner.
-  // |type| has the default value OutputType::I420. |num_squares| has the
-  // default value 10.
-  static std::unique_ptr<FrameGenerator> CreateSquareGenerator(
-      int width,
-      int height,
-      absl::optional<OutputType> type,
-      absl::optional<int> num_squares);
+  VideoFrameData NextFrame() override;
+  void ChangeResolution(size_t width, size_t height) override {
+    RTC_NOTREACHED();
+  }
 
-  // Creates a frame generator that repeatedly plays a set of yuv files.
-  // The frame_repeat_count determines how many times each frame is shown,
-  // with 1 = show each frame once, etc.
-  static std::unique_ptr<FrameGenerator> CreateFromYuvFile(
-      std::vector<std::string> files,
-      size_t width,
-      size_t height,
-      int frame_repeat_count);
+ private:
+  // Returns true if the new frame was loaded.
+  // False only in case of a single file with a single frame in it.
+  bool ReadNextFrame();
 
-  // Creates a frame generator which takes a set of yuv files (wrapping a
-  // frame generator created by CreateFromYuvFile() above), but outputs frames
-  // that have been cropped to specified resolution: source_width/source_height
-  // is the size of the source images, target_width/target_height is the size of
-  // the cropped output. For each source image read, the cropped viewport will
-  // be scrolled top to bottom/left to right for scroll_tim_ms milliseconds.
-  // After that the image will stay in place for pause_time_ms milliseconds,
-  // and then this will be repeated with the next file from the input set.
-  static std::unique_ptr<FrameGenerator> CreateScrollingInputFromYuvFiles(
-      Clock* clock,
-      std::vector<std::string> filenames,
-      size_t source_width,
-      size_t source_height,
-      size_t target_width,
-      size_t target_height,
-      int64_t scroll_time_ms,
-      int64_t pause_time_ms);
-
-  // Creates a frame generator that produces randomly generated slides.
-  // frame_repeat_count determines how many times each slide is shown.
-  static std::unique_ptr<FrameGenerator>
-  CreateSlideGenerator(int width, int height, int frame_repeat_count);
+  size_t file_index_;
+  size_t frame_index_;
+  const std::vector<FILE*> files_;
+  const size_t width_;
+  const size_t height_;
+  const size_t frame_size_;
+  const std::unique_ptr<uint8_t[]> frame_buffer_;
+  const int frame_display_count_;
+  int current_display_count_;
+  rtc::scoped_refptr<I420Buffer> last_read_buffer_;
 };
+
+// SlideGenerator works similarly to YuvFileGenerator but it fills the frames
+// with randomly sized and colored squares instead of reading their content
+// from files.
+class SlideGenerator : public FrameGeneratorInterface {
+ public:
+  SlideGenerator(int width, int height, int frame_repeat_count);
+
+  VideoFrameData NextFrame() override;
+  void ChangeResolution(size_t width, size_t height) override {
+    RTC_NOTREACHED();
+  }
+
+ private:
+  // Generates some randomly sized and colored squares scattered
+  // over the frame.
+  void GenerateNewFrame();
+
+  const int width_;
+  const int height_;
+  const int frame_display_count_;
+  int current_display_count_;
+  Random random_generator_;
+  rtc::scoped_refptr<I420Buffer> buffer_;
+};
+
+class ScrollingImageFrameGenerator : public FrameGeneratorInterface {
+ public:
+  ScrollingImageFrameGenerator(Clock* clock,
+                               const std::vector<FILE*>& files,
+                               size_t source_width,
+                               size_t source_height,
+                               size_t target_width,
+                               size_t target_height,
+                               int64_t scroll_time_ms,
+                               int64_t pause_time_ms);
+  ~ScrollingImageFrameGenerator() override = default;
+
+  VideoFrameData NextFrame() override;
+  void ChangeResolution(size_t width, size_t height) override {
+    RTC_NOTREACHED();
+  }
+
+ private:
+  void UpdateSourceFrame(size_t frame_num);
+  void CropSourceToScrolledImage(double scroll_factor);
+
+  Clock* const clock_;
+  const int64_t start_time_;
+  const int64_t scroll_time_;
+  const int64_t pause_time_;
+  const size_t num_frames_;
+  const int target_width_;
+  const int target_height_;
+
+  size_t current_frame_num_;
+  bool prev_frame_not_scrolled_;
+  VideoFrameData current_source_frame_;
+  VideoFrameData current_frame_;
+  YuvFileGenerator file_generator_;
+};
+
 }  // namespace test
 }  // namespace webrtc
 
diff --git a/test/frame_generator_capturer.cc b/test/frame_generator_capturer.cc
index e817db9..36249d6 100644
--- a/test/frame_generator_capturer.cc
+++ b/test/frame_generator_capturer.cc
@@ -17,6 +17,7 @@
 #include <utility>
 #include <vector>
 
+#include "api/test/create_frame_generator.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/critical_section.h"
 #include "rtc_base/logging.h"
@@ -71,8 +72,8 @@
     FrameGeneratorCapturerConfig::SquaresVideo config) {
   return std::make_unique<FrameGeneratorCapturer>(
       clock,
-      FrameGenerator::CreateSquareGenerator(
-          config.width, config.height, config.pixel_format, config.num_squares),
+      CreateSquareFrameGenerator(config.width, config.height,
+                                 config.pixel_format, config.num_squares),
       config.framerate, task_queue_factory);
 }
 std::unique_ptr<FrameGeneratorCapturer> FrameGeneratorCapturer::Create(
@@ -81,7 +82,7 @@
     FrameGeneratorCapturerConfig::SquareSlides config) {
   return std::make_unique<FrameGeneratorCapturer>(
       clock,
-      FrameGenerator::CreateSlideGenerator(
+      CreateSlideFrameGenerator(
           config.width, config.height,
           /*frame_repeat_count*/ config.change_interval.seconds<double>() *
               config.framerate),
@@ -94,9 +95,9 @@
   RTC_CHECK(config.width && config.height);
   return std::make_unique<FrameGeneratorCapturer>(
       clock,
-      FrameGenerator::CreateFromYuvFile({TransformFilePath(config.name)},
-                                        config.width, config.height,
-                                        /*frame_repeat_count*/ 1),
+      CreateFromYuvFileFrameGenerator({TransformFilePath(config.name)},
+                                      config.width, config.height,
+                                      /*frame_repeat_count*/ 1),
       config.framerate, task_queue_factory);
 }
 
@@ -104,7 +105,7 @@
     Clock* clock,
     TaskQueueFactory& task_queue_factory,
     FrameGeneratorCapturerConfig::ImageSlides config) {
-  std::unique_ptr<FrameGenerator> slides_generator;
+  std::unique_ptr<FrameGeneratorInterface> slides_generator;
   std::vector<std::string> paths = config.paths;
   for (std::string& path : paths)
     path = TransformFilePath(path);
@@ -117,11 +118,11 @@
     int crop_height = config.crop.height.value_or(config.height);
     RTC_CHECK_LE(crop_width, config.width);
     RTC_CHECK_LE(crop_height, config.height);
-    slides_generator = FrameGenerator::CreateScrollingInputFromYuvFiles(
+    slides_generator = CreateScrollingInputFromYuvFilesFrameGenerator(
         clock, paths, config.width, config.height, crop_width, crop_height,
         config.crop.scroll_duration.ms(), pause_duration.ms());
   } else {
-    slides_generator = FrameGenerator::CreateFromYuvFile(
+    slides_generator = CreateFromYuvFileFrameGenerator(
         paths, config.width, config.height,
         /*frame_repeat_count*/ config.change_interval.seconds<double>() *
             config.framerate);
@@ -176,7 +177,8 @@
 void FrameGeneratorCapturer::InsertFrame() {
   rtc::CritScope cs(&lock_);
   if (sending_) {
-    FrameGenerator::VideoFrameData frame_data = frame_generator_->NextFrame();
+    FrameGeneratorInterface::VideoFrameData frame_data =
+        frame_generator_->NextFrame();
     // TODO(srte): Use more advanced frame rate control to allow arbritrary
     // fractions.
     int decimation =
diff --git a/test/frame_generator_capturer.h b/test/frame_generator_capturer.h
index 6220870..aaed205 100644
--- a/test/frame_generator_capturer.h
+++ b/test/frame_generator_capturer.h
@@ -14,11 +14,12 @@
 #include <string>
 
 #include "api/task_queue/task_queue_factory.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/video/video_frame.h"
 #include "rtc_base/critical_section.h"
 #include "rtc_base/task_queue.h"
 #include "rtc_base/task_utils/repeating_task.h"
-#include "test/frame_generator.h"
+#include "system_wrappers/include/clock.h"
 #include "test/test_video_capturer.h"
 
 namespace webrtc {
@@ -38,7 +39,8 @@
 struct FrameGeneratorCapturerConfig {
   struct SquaresVideo {
     int framerate = 30;
-    FrameGenerator::OutputType pixel_format = FrameGenerator::OutputType::kI420;
+    FrameGeneratorInterface::OutputType pixel_format =
+        FrameGeneratorInterface::OutputType::kI420;
     int width = 320;
     int height = 180;
     int num_squares = 10;
diff --git a/test/frame_generator_unittest.cc b/test/frame_generator_unittest.cc
index 26cb319..12d5111 100644
--- a/test/frame_generator_unittest.cc
+++ b/test/frame_generator_unittest.cc
@@ -19,6 +19,8 @@
 #include <string>
 
 #include "api/scoped_refptr.h"
+#include "api/test/create_frame_generator.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/video/video_frame_buffer.h"
 #include "test/gtest.h"
 #include "test/testsupport/file_utils.h"
@@ -62,7 +64,7 @@
     fwrite(plane_buffer.get(), 1, uv_size, file);
   }
 
-  void CheckFrameAndMutate(const FrameGenerator::VideoFrameData& frame,
+  void CheckFrameAndMutate(const FrameGeneratorInterface::VideoFrameData& frame,
                            uint8_t y,
                            uint8_t u,
                            uint8_t v) {
@@ -81,7 +83,7 @@
       ASSERT_EQ(v, buffer[i]);
   }
 
-  uint64_t Hash(const FrameGenerator::VideoFrameData& frame) {
+  uint64_t Hash(const FrameGeneratorInterface::VideoFrameData& frame) {
     // Generate a 64-bit hash from the frame's buffer.
     uint64_t hash = 19;
     rtc::scoped_refptr<I420BufferInterface> i420_buffer =
@@ -108,17 +110,19 @@
 };
 
 TEST_F(FrameGeneratorTest, SingleFrameFile) {
-  std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile(
-      std::vector<std::string>(1, one_frame_filename_), kFrameWidth,
-      kFrameHeight, 1));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateFromYuvFileFrameGenerator(
+          std::vector<std::string>(1, one_frame_filename_), kFrameWidth,
+          kFrameHeight, 1));
   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
 }
 
 TEST_F(FrameGeneratorTest, TwoFrameFile) {
-  std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile(
-      std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
-      kFrameHeight, 1));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateFromYuvFileFrameGenerator(
+          std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
+          kFrameHeight, 1));
   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
   CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
@@ -129,8 +133,8 @@
   files.push_back(two_frame_filename_);
   files.push_back(one_frame_filename_);
 
-  std::unique_ptr<FrameGenerator> generator(
-      FrameGenerator::CreateFromYuvFile(files, kFrameWidth, kFrameHeight, 1));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight, 1));
   CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
   CheckFrameAndMutate(generator->NextFrame(), 127, 127, 127);
   CheckFrameAndMutate(generator->NextFrame(), 255, 255, 255);
@@ -139,9 +143,10 @@
 
 TEST_F(FrameGeneratorTest, TwoFrameFileWithRepeat) {
   const int kRepeatCount = 3;
-  std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile(
-      std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
-      kFrameHeight, kRepeatCount));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateFromYuvFileFrameGenerator(
+          std::vector<std::string>(1, two_frame_filename_), kFrameWidth,
+          kFrameHeight, kRepeatCount));
   for (int i = 0; i < kRepeatCount; ++i)
     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
   for (int i = 0; i < kRepeatCount; ++i)
@@ -154,8 +159,9 @@
   std::vector<std::string> files;
   files.push_back(two_frame_filename_);
   files.push_back(one_frame_filename_);
-  std::unique_ptr<FrameGenerator> generator(FrameGenerator::CreateFromYuvFile(
-      files, kFrameWidth, kFrameHeight, kRepeatCount));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateFromYuvFileFrameGenerator(files, kFrameWidth, kFrameHeight,
+                                      kRepeatCount));
   for (int i = 0; i < kRepeatCount; ++i)
     CheckFrameAndMutate(generator->NextFrame(), 0, 0, 0);
   for (int i = 0; i < kRepeatCount; ++i)
@@ -168,9 +174,8 @@
 TEST_F(FrameGeneratorTest, SlideGenerator) {
   const int kGenCount = 9;
   const int kRepeatCount = 3;
-  std::unique_ptr<FrameGenerator> generator(
-      FrameGenerator::CreateSlideGenerator(kFrameWidth, kFrameHeight,
-                                           kRepeatCount));
+  std::unique_ptr<FrameGeneratorInterface> generator(
+      CreateSlideFrameGenerator(kFrameWidth, kFrameHeight, kRepeatCount));
   uint64_t hashes[kGenCount];
   for (int i = 0; i < kGenCount; ++i) {
     hashes[i] = Hash(generator->NextFrame());
diff --git a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h
index 4918768..ccda57b 100644
--- a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h
+++ b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h
@@ -22,7 +22,6 @@
 #include "api/video/video_sink_interface.h"
 #include "api/video_codecs/video_decoder_factory.h"
 #include "api/video_codecs/video_encoder_factory.h"
-#include "test/frame_generator.h"
 #include "test/pc/e2e/analyzer/video/encoded_image_data_injector.h"
 #include "test/pc/e2e/analyzer/video/id_generator.h"
 #include "test/test_video_capturer.h"
diff --git a/test/scenario/BUILD.gn b/test/scenario/BUILD.gn
index 5614c0b..765fbf5 100644
--- a/test/scenario/BUILD.gn
+++ b/test/scenario/BUILD.gn
@@ -80,7 +80,9 @@
       "../:test_common",
       "../:test_support",
       "../:video_test_common",
+      "../../api:create_frame_generator",
       "../../api:fec_controller_api",
+      "../../api:frame_generator_api",
       "../../api:libjingle_peerconnection_api",
       "../../api:rtc_event_log_output_file",
       "../../api:rtp_parameters",
diff --git a/test/scenario/scenario_config.h b/test/scenario/scenario_config.h
index 301fc71..7b9c633 100644
--- a/test/scenario/scenario_config.h
+++ b/test/scenario/scenario_config.h
@@ -17,12 +17,12 @@
 #include "absl/types/optional.h"
 #include "api/fec_controller.h"
 #include "api/rtp_parameters.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/transport/network_control.h"
 #include "api/units/data_rate.h"
 #include "api/units/data_size.h"
 #include "api/units/time_delta.h"
 #include "api/video/video_codec_type.h"
-#include "test/frame_generator.h"
 #include "test/scenario/performance_stats.h"
 
 namespace webrtc {
@@ -103,7 +103,7 @@
       } images;
     } slides;
     struct Generator {
-      using PixelFormat = FrameGenerator::OutputType;
+      using PixelFormat = FrameGeneratorInterface::OutputType;
       PixelFormat pixel_format = PixelFormat::kI420;
       int width = 320;
       int height = 180;
diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc
index 56e97ef..7fd9d15 100644
--- a/test/scenario/video_stream.cc
+++ b/test/scenario/video_stream.cc
@@ -13,6 +13,8 @@
 #include <memory>
 #include <utility>
 
+#include "api/test/create_frame_generator.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/test/video/function_video_encoder_factory.h"
 #include "api/video/builtin_video_bitrate_allocator_factory.h"
 #include "media/base/media_constants.h"
@@ -261,7 +263,7 @@
   return encoder_config;
 }
 
-std::unique_ptr<FrameGenerator> CreateImageSlideGenerator(
+std::unique_ptr<FrameGeneratorInterface> CreateImageSlideGenerator(
     Clock* clock,
     VideoStreamConfig::Source::Slides slides,
     int framerate) {
@@ -276,33 +278,33 @@
     int crop_height = slides.images.crop.height.value_or(slides.images.height);
     RTC_CHECK_LE(crop_width, slides.images.width);
     RTC_CHECK_LE(crop_height, slides.images.height);
-    return FrameGenerator::CreateScrollingInputFromYuvFiles(
+    return CreateScrollingInputFromYuvFilesFrameGenerator(
         clock, paths, slides.images.width, slides.images.height, crop_width,
         crop_height, slides.images.crop.scroll_duration.ms(),
         pause_duration.ms());
   } else {
-    return FrameGenerator::CreateFromYuvFile(
+    return CreateFromYuvFileFrameGenerator(
         paths, slides.images.width, slides.images.height,
         slides.change_interval.seconds<double>() * framerate);
   }
 }
 
-std::unique_ptr<FrameGenerator> CreateFrameGenerator(
+std::unique_ptr<FrameGeneratorInterface> CreateFrameGenerator(
     Clock* clock,
     VideoStreamConfig::Source source) {
   using Capture = VideoStreamConfig::Source::Capture;
   switch (source.capture) {
     case Capture::kGenerator:
-      return FrameGenerator::CreateSquareGenerator(
+      return CreateSquareFrameGenerator(
           source.generator.width, source.generator.height,
           source.generator.pixel_format, /*num_squares*/ absl::nullopt);
     case Capture::kVideoFile:
       RTC_CHECK(source.video_file.width && source.video_file.height);
-      return FrameGenerator::CreateFromYuvFile(
+      return CreateFromYuvFileFrameGenerator(
           {TransformFilePath(source.video_file.name)}, source.video_file.width,
           source.video_file.height, /*frame_repeat_count*/ 1);
     case Capture::kGenerateSlides:
-      return FrameGenerator::CreateSlideGenerator(
+      return CreateSlideFrameGenerator(
           source.slides.generator.width, source.slides.generator.height,
           source.slides.change_interval.seconds<double>() * source.framerate);
     case Capture::kImageSlides:
diff --git a/test/testsupport/ivf_video_frame_generator.cc b/test/testsupport/ivf_video_frame_generator.cc
index 976af68..47edfaa 100644
--- a/test/testsupport/ivf_video_frame_generator.cc
+++ b/test/testsupport/ivf_video_frame_generator.cc
@@ -64,7 +64,7 @@
   }
 }
 
-FrameGenerator::VideoFrameData IvfVideoFrameGenerator::NextFrame() {
+FrameGeneratorInterface::VideoFrameData IvfVideoFrameGenerator::NextFrame() {
   RTC_DCHECK_RUN_ON(&sequence_checker_);
   next_frame_decoded_.Reset();
   RTC_CHECK(file_reader_);
diff --git a/test/testsupport/ivf_video_frame_generator.h b/test/testsupport/ivf_video_frame_generator.h
index b0985fc..e193a03 100644
--- a/test/testsupport/ivf_video_frame_generator.h
+++ b/test/testsupport/ivf_video_frame_generator.h
@@ -15,6 +15,7 @@
 #include <string>
 
 #include "absl/types/optional.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/video/video_codec_type.h"
 #include "api/video/video_frame.h"
 #include "api/video_codecs/video_decoder.h"
@@ -22,13 +23,12 @@
 #include "rtc_base/critical_section.h"
 #include "rtc_base/event.h"
 #include "rtc_base/synchronization/sequence_checker.h"
-#include "test/frame_generator.h"
 
 namespace webrtc {
 namespace test {
 
 // All methods except constructor must be used from the same thread.
-class IvfVideoFrameGenerator : public FrameGenerator {
+class IvfVideoFrameGenerator : public FrameGeneratorInterface {
  public:
   explicit IvfVideoFrameGenerator(const std::string& file_name);
   ~IvfVideoFrameGenerator() override;
diff --git a/test/testsupport/ivf_video_frame_generator_unittest.cc b/test/testsupport/ivf_video_frame_generator_unittest.cc
index 01ae778..a5e99d1 100644
--- a/test/testsupport/ivf_video_frame_generator_unittest.cc
+++ b/test/testsupport/ivf_video_frame_generator_unittest.cc
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "absl/types/optional.h"
+#include "api/test/create_frame_generator.h"
 #include "api/video/encoded_image.h"
 #include "api/video/video_codec_type.h"
 #include "api/video_codecs/video_codec.h"
@@ -26,7 +27,6 @@
 #include "modules/video_coding/utility/ivf_file_writer.h"
 #include "rtc_base/critical_section.h"
 #include "rtc_base/event.h"
-#include "test/frame_generator.h"
 #include "test/gtest.h"
 #include "test/testsupport/file_utils.h"
 #include "test/testsupport/ivf_video_frame_generator.h"
@@ -102,7 +102,7 @@
   }
   void TearDown() override { webrtc::test::RemoveFile(file_name_); }
 
-  VideoFrame BuildFrame(FrameGenerator::VideoFrameData frame_data) {
+  VideoFrame BuildFrame(FrameGeneratorInterface::VideoFrameData frame_data) {
     return VideoFrame::Builder()
         .set_video_frame_buffer(frame_data.buffer)
         .set_update_rect(frame_data.update_rect)
@@ -111,9 +111,9 @@
 
   void CreateTestVideoFile(VideoCodecType video_codec_type,
                            std::unique_ptr<VideoEncoder> video_encoder) {
-    std::unique_ptr<test::FrameGenerator> frame_generator =
-        test::FrameGenerator::CreateSquareGenerator(
-            kWidth, kHeight, test::FrameGenerator::OutputType::kI420,
+    std::unique_ptr<test::FrameGeneratorInterface> frame_generator =
+        test::CreateSquareFrameGenerator(
+            kWidth, kHeight, test::FrameGeneratorInterface::OutputType::kI420,
             absl::nullopt);
 
     VideoCodec codec_settings;
diff --git a/video/BUILD.gn b/video/BUILD.gn
index 6c8565b..cf9ce46 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -259,7 +259,9 @@
     ]
     deps = [
       ":frame_dumping_decoder",
+      "../api:create_frame_generator",
       "../api:fec_controller_api",
+      "../api:frame_generator_api",
       "../api:libjingle_peerconnection_api",
       "../api:rtc_event_log_output_file",
       "../api:test_dependency_factory",
@@ -563,8 +565,10 @@
       ":video",
       ":video_mocks",
       ":video_stream_encoder_impl",
+      "../api:create_frame_generator",
       "../api:fake_frame_decryptor",
       "../api:fake_frame_encryptor",
+      "../api:frame_generator_api",
       "../api:libjingle_peerconnection_api",
       "../api:mock_fec_controller_override",
       "../api:mock_frame_decryptor",
@@ -641,6 +645,7 @@
       "../test:fake_video_codecs",
       "../test:field_trial",
       "../test:fileutils",
+      "../test:frame_utils",
       "../test:null_transport",
       "../test:perf_test",
       "../test:rtp_test_utils",
diff --git a/video/end_to_end_tests/call_operation_tests.cc b/video/end_to_end_tests/call_operation_tests.cc
index b38062b..fcf7660 100644
--- a/video/end_to_end_tests/call_operation_tests.cc
+++ b/video/end_to_end_tests/call_operation_tests.cc
@@ -9,6 +9,9 @@
  */
 
 #include <memory>
+
+#include "api/test/create_frame_generator.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/test/simulated_network.h"
 #include "call/fake_network_pipe.h"
 #include "call/simulated_network.h"
@@ -16,7 +19,7 @@
 #include "system_wrappers/include/sleep.h"
 #include "test/call_test.h"
 #include "test/field_trial.h"
-#include "test/frame_generator.h"
+#include "test/frame_forwarder.h"
 #include "test/gtest.h"
 #include "test/null_transport.h"
 
@@ -125,13 +128,13 @@
 
         // Create frames that are smaller than the send width/height, this is
         // done to check that the callbacks are done after processing video.
-        std::unique_ptr<test::FrameGenerator> frame_generator(
-            test::FrameGenerator::CreateSquareGenerator(
-                kWidth, kHeight, absl::nullopt, absl::nullopt));
+        std::unique_ptr<test::FrameGeneratorInterface> frame_generator(
+            test::CreateSquareFrameGenerator(kWidth, kHeight, absl::nullopt,
+                                             absl::nullopt));
         GetVideoSendStream()->SetSource(
             &frame_forwarder, DegradationPreference::MAINTAIN_FRAMERATE);
 
-        test::FrameGenerator::VideoFrameData frame_data =
+        test::FrameGeneratorInterface::VideoFrameData frame_data =
             frame_generator->NextFrame();
         VideoFrame frame = VideoFrame::Builder()
                                .set_video_frame_buffer(frame_data.buffer)
@@ -163,7 +166,7 @@
     rtc::Event event_;
   } renderer;
 
-  std::unique_ptr<test::FrameGenerator> frame_generator;
+  std::unique_ptr<test::FrameGeneratorInterface> frame_generator;
   test::FrameForwarder frame_forwarder;
 
   std::unique_ptr<test::DirectTransport> sender_transport;
@@ -197,11 +200,11 @@
         CreateVideoStreams();
         Start();
 
-        frame_generator = test::FrameGenerator::CreateSquareGenerator(
+        frame_generator = test::CreateSquareFrameGenerator(
             kDefaultWidth, kDefaultHeight, absl::nullopt, absl::nullopt);
         GetVideoSendStream()->SetSource(
             &frame_forwarder, DegradationPreference::MAINTAIN_FRAMERATE);
-        test::FrameGenerator::VideoFrameData frame_data =
+        test::FrameGeneratorInterface::VideoFrameData frame_data =
             frame_generator->NextFrame();
         VideoFrame frame = VideoFrame::Builder()
                                .set_video_frame_buffer(frame_data.buffer)
diff --git a/video/end_to_end_tests/multi_stream_tester.cc b/video/end_to_end_tests/multi_stream_tester.cc
index c8e63e1..c3d41c3 100644
--- a/video/end_to_end_tests/multi_stream_tester.cc
+++ b/video/end_to_end_tests/multi_stream_tester.cc
@@ -18,6 +18,7 @@
 #include "api/rtc_event_log/rtc_event_log.h"
 #include "api/task_queue/default_task_queue_factory.h"
 #include "api/task_queue/task_queue_base.h"
+#include "api/test/create_frame_generator.h"
 #include "api/test/simulated_network.h"
 #include "api/test/video/function_video_encoder_factory.h"
 #include "api/video/builtin_video_bitrate_allocator_factory.h"
@@ -114,8 +115,8 @@
 
       auto* frame_generator = new test::FrameGeneratorCapturer(
           Clock::GetRealTimeClock(),
-          test::FrameGenerator::CreateSquareGenerator(
-              width, height, absl::nullopt, absl::nullopt),
+          test::CreateSquareFrameGenerator(width, height, absl::nullopt,
+                                           absl::nullopt),
           30, *task_queue_factory);
       frame_generators[i] = frame_generator;
       send_streams[i]->SetSource(frame_generator,
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index ad8c808..77dff46 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -22,6 +22,7 @@
 #include "api/rtc_event_log_output_file.h"
 #include "api/task_queue/default_task_queue_factory.h"
 #include "api/task_queue/task_queue_base.h"
+#include "api/test/create_frame_generator.h"
 #include "api/video/builtin_video_bitrate_allocator_factory.h"
 #include "api/video_codecs/video_encoder.h"
 #include "call/fake_network_pipe.h"
@@ -1049,24 +1050,23 @@
     auto frame_generator_capturer =
         std::make_unique<test::FrameGeneratorCapturer>(
             clock_,
-            test::FrameGenerator::CreateSquareGenerator(
-                static_cast<int>(thumbnail.width),
-                static_cast<int>(thumbnail.height), absl::nullopt,
-                absl::nullopt),
+            test::CreateSquareFrameGenerator(static_cast<int>(thumbnail.width),
+                                             static_cast<int>(thumbnail.height),
+                                             absl::nullopt, absl::nullopt),
             thumbnail.max_framerate, *task_queue_factory_);
     EXPECT_TRUE(frame_generator_capturer->Init());
     thumbnail_capturers_.push_back(std::move(frame_generator_capturer));
   }
 }
 
-std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator(
-    size_t video_idx) {
+std::unique_ptr<test::FrameGeneratorInterface>
+VideoQualityTest::CreateFrameGenerator(size_t video_idx) {
   // Setup frame generator.
   const size_t kWidth = 1850;
   const size_t kHeight = 1110;
-  std::unique_ptr<test::FrameGenerator> frame_generator;
+  std::unique_ptr<test::FrameGeneratorInterface> frame_generator;
   if (params_.screenshare[video_idx].generate_slides) {
-    frame_generator = test::FrameGenerator::CreateSlideGenerator(
+    frame_generator = test::CreateSlideFrameGenerator(
         kWidth, kHeight,
         params_.screenshare[video_idx].slide_change_interval *
             params_.video[video_idx].fps);
@@ -1080,7 +1080,7 @@
     }
     if (params_.screenshare[video_idx].scroll_duration == 0) {
       // Cycle image every slide_change_interval seconds.
-      frame_generator = test::FrameGenerator::CreateFromYuvFile(
+      frame_generator = test::CreateFromYuvFileFrameGenerator(
           slides, kWidth, kHeight,
           params_.screenshare[video_idx].slide_change_interval *
               params_.video[video_idx].fps);
@@ -1095,7 +1095,7 @@
       RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration,
                    params_.screenshare[video_idx].slide_change_interval);
 
-      frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles(
+      frame_generator = test::CreateScrollingInputFromYuvFilesFrameGenerator(
           clock_, slides, kWidth, kHeight, params_.video[video_idx].width,
           params_.video[video_idx].height,
           params_.screenshare[video_idx].scroll_duration * 1000,
@@ -1109,24 +1109,24 @@
   RTC_DCHECK(video_sources_.empty());
   video_sources_.resize(num_video_streams_);
   for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) {
-    std::unique_ptr<test::FrameGenerator> frame_generator;
+    std::unique_ptr<test::FrameGeneratorInterface> frame_generator;
     if (params_.screenshare[video_idx].enabled) {
       frame_generator = CreateFrameGenerator(video_idx);
     } else if (params_.video[video_idx].clip_path == "Generator") {
-      frame_generator = test::FrameGenerator::CreateSquareGenerator(
+      frame_generator = test::CreateSquareFrameGenerator(
           static_cast<int>(params_.video[video_idx].width),
           static_cast<int>(params_.video[video_idx].height), absl::nullopt,
           absl::nullopt);
     } else if (params_.video[video_idx].clip_path == "GeneratorI420A") {
-      frame_generator = test::FrameGenerator::CreateSquareGenerator(
+      frame_generator = test::CreateSquareFrameGenerator(
           static_cast<int>(params_.video[video_idx].width),
           static_cast<int>(params_.video[video_idx].height),
-          test::FrameGenerator::OutputType::kI420A, absl::nullopt);
+          test::FrameGeneratorInterface::OutputType::kI420A, absl::nullopt);
     } else if (params_.video[video_idx].clip_path == "GeneratorI010") {
-      frame_generator = test::FrameGenerator::CreateSquareGenerator(
+      frame_generator = test::CreateSquareFrameGenerator(
           static_cast<int>(params_.video[video_idx].width),
           static_cast<int>(params_.video[video_idx].height),
-          test::FrameGenerator::OutputType::kI010, absl::nullopt);
+          test::FrameGeneratorInterface::OutputType::kI010, absl::nullopt);
     } else if (params_.video[video_idx].clip_path.empty()) {
       video_sources_[video_idx] = test::CreateVideoCapturer(
           params_.video[video_idx].width, params_.video[video_idx].height,
@@ -1136,13 +1136,13 @@
         continue;
       } else {
         // Failed to get actual camera, use chroma generator as backup.
-        frame_generator = test::FrameGenerator::CreateSquareGenerator(
+        frame_generator = test::CreateSquareFrameGenerator(
             static_cast<int>(params_.video[video_idx].width),
             static_cast<int>(params_.video[video_idx].height), absl::nullopt,
             absl::nullopt);
       }
     } else {
-      frame_generator = test::FrameGenerator::CreateFromYuvFile(
+      frame_generator = test::CreateFromYuvFileFrameGenerator(
           {params_.video[video_idx].clip_path}, params_.video[video_idx].width,
           params_.video[video_idx].height, 1);
       ASSERT_TRUE(frame_generator) << "Could not create capturer for "
diff --git a/video/video_quality_test.h b/video/video_quality_test.h
index c287692..2177830 100644
--- a/video/video_quality_test.h
+++ b/video/video_quality_test.h
@@ -19,13 +19,13 @@
 #include "api/rtc_event_log/rtc_event_log_factory.h"
 #include "api/task_queue/task_queue_base.h"
 #include "api/task_queue/task_queue_factory.h"
+#include "api/test/frame_generator_interface.h"
 #include "api/test/video_quality_test_fixture.h"
 #include "api/video/video_bitrate_allocator_factory.h"
 #include "call/fake_network_pipe.h"
 #include "media/engine/internal_decoder_factory.h"
 #include "media/engine/internal_encoder_factory.h"
 #include "test/call_test.h"
-#include "test/frame_generator.h"
 #include "test/layer_filtering_transport.h"
 #include "video/video_analyzer.h"
 #ifdef WEBRTC_WIN
@@ -76,7 +76,8 @@
 
   // Helper methods for setting up the call.
   void CreateCapturers();
-  std::unique_ptr<test::FrameGenerator> CreateFrameGenerator(size_t video_idx);
+  std::unique_ptr<test::FrameGeneratorInterface> CreateFrameGenerator(
+      size_t video_idx);
   void SetupThumbnailCapturers(size_t num_thumbnail_streams);
   std::unique_ptr<VideoDecoder> CreateVideoDecoder(
       const SdpVideoFormat& format);
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index c3f2de9..eb6a723 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -50,7 +50,7 @@
 #include "test/fake_encoder.h"
 #include "test/fake_texture_frame.h"
 #include "test/field_trial.h"
-#include "test/frame_generator.h"
+#include "test/frame_forwarder.h"
 #include "test/frame_generator_capturer.h"
 #include "test/frame_utils.h"
 #include "test/gmock.h"
diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc
index f2e023d..71d975a 100644
--- a/video/video_stream_encoder_unittest.cc
+++ b/video/video_stream_encoder_unittest.cc
@@ -39,7 +39,7 @@
 #include "test/encoder_settings.h"
 #include "test/fake_encoder.h"
 #include "test/field_trial.h"
-#include "test/frame_generator.h"
+#include "test/frame_forwarder.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 #include "test/video_encoder_proxy_factory.h"