Implement `Y4mFrameGenerator::ChangeResolution()`

This CL implements `ChangeResolution()` to let `Y4mFrameGenerator`
generate I420 frame with resolution other than y4m input by scaling. The
code is mostly copied from `IvfVideoFrameGenerator`.

The test case is also added for this change.

Bug: webrtc:15210
Change-Id: I690e427a545a72d93ed39b77fd0f602054a30508
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311521
Commit-Queue: Jianhui J Dai <jianhui.j.dai@intel.com>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40426}
diff --git a/test/testsupport/y4m_frame_generator.cc b/test/testsupport/y4m_frame_generator.cc
index 39a5ad9..f1ecbf9 100644
--- a/test/testsupport/y4m_frame_generator.cc
+++ b/test/testsupport/y4m_frame_generator.cc
@@ -59,7 +59,26 @@
                                              static_cast<int>(height_)};
   rtc::scoped_refptr<webrtc::I420Buffer> next_frame_buffer =
       frame_reader_->PullFrame();
-  return VideoFrameData(next_frame_buffer, update_rect);
+
+  if (!next_frame_buffer ||
+      (static_cast<size_t>(next_frame_buffer->width()) == width_ &&
+       static_cast<size_t>(next_frame_buffer->height()) == height_)) {
+    return VideoFrameData(next_frame_buffer, update_rect);
+  }
+
+  // Allocate a new buffer and return scaled version.
+  rtc::scoped_refptr<webrtc::I420Buffer> scaled_buffer(
+      I420Buffer::Create(width_, height_));
+  webrtc::I420Buffer::SetBlack(scaled_buffer.get());
+  scaled_buffer->ScaleFrom(*next_frame_buffer->ToI420());
+  return VideoFrameData(scaled_buffer, update_rect);
+}
+
+void Y4mFrameGenerator::ChangeResolution(size_t width, size_t height) {
+  width_ = width;
+  height_ = height;
+  RTC_CHECK_GT(width_, 0);
+  RTC_CHECK_GT(height_, 0);
 }
 
 FrameGeneratorInterface::Resolution Y4mFrameGenerator::GetResolution() const {
diff --git a/test/testsupport/y4m_frame_generator.h b/test/testsupport/y4m_frame_generator.h
index bccd109..4ff64be 100644
--- a/test/testsupport/y4m_frame_generator.h
+++ b/test/testsupport/y4m_frame_generator.h
@@ -45,9 +45,7 @@
 
   VideoFrameData NextFrame() override;
 
-  void ChangeResolution(size_t width, size_t height) override {
-    RTC_CHECK_NOTREACHED();
-  }
+  void ChangeResolution(size_t width, size_t height) override;
 
   Resolution GetResolution() const override;
 
diff --git a/test/testsupport/y4m_frame_generator_test.cc b/test/testsupport/y4m_frame_generator_test.cc
index 4341c3e..24d10c8 100644
--- a/test/testsupport/y4m_frame_generator_test.cc
+++ b/test/testsupport/y4m_frame_generator_test.cc
@@ -82,6 +82,29 @@
   remove(input_filepath.c_str());
 }
 
+TEST_F(Y4mFrameGeneratorTest, CanChangeResolution) {
+  constexpr int kNewWidth = 4;
+  constexpr int kNewHeight = 6;
+  constexpr int kFrameCount = 10;
+
+  Y4mFrameGenerator generator(input_filepath_,
+                              Y4mFrameGenerator::RepeatMode::kLoop);
+  FrameGeneratorInterface::Resolution res = generator.GetResolution();
+  EXPECT_EQ(res.width, 2u);
+  EXPECT_EQ(res.height, 2u);
+
+  generator.ChangeResolution(kNewWidth, kNewHeight);
+  res = generator.GetResolution();
+  EXPECT_EQ(static_cast<int>(res.width), kNewWidth);
+  EXPECT_EQ(static_cast<int>(res.height), kNewHeight);
+
+  for (int i = 0; i < kFrameCount; ++i) {
+    FrameGeneratorInterface::VideoFrameData frame = generator.NextFrame();
+    EXPECT_EQ(frame.buffer->width(), kNewWidth);
+    EXPECT_EQ(frame.buffer->height(), kNewHeight);
+  }
+}
+
 TEST_F(Y4mFrameGeneratorTest, SingleRepeatMode) {
   Y4mFrameGenerator generator(input_filepath_,
                               Y4mFrameGenerator::RepeatMode::kSingle);