Add scaling interface to VideoFrameBuffer

This can be overriden for kNative frame types to perform scaling efficiently.

Default implementations for existing buffer types require actual
buffer implementation, thus this CL also merges "video_frame"
with "video_frame_I420" build targets.

Bug: webrtc:11976, chromium:1132299
Change-Id: I3bf5f6bf179db5e7ab165b1c2301980043a08765
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186303
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#32352}
diff --git a/api/video/BUILD.gn b/api/video/BUILD.gn
index fd8363a..f4069d2 100644
--- a/api/video/BUILD.gn
+++ b/api/video/BUILD.gn
@@ -42,6 +42,8 @@
 rtc_library("video_frame") {
   visibility = [ "*" ]
   sources = [
+    "i420_buffer.cc",
+    "i420_buffer.h",
     "video_codec_type.h",
     "video_frame.cc",
     "video_frame.h",
@@ -59,7 +61,9 @@
     "..:scoped_refptr",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
+    "../../rtc_base/memory:aligned_malloc",
     "../../rtc_base/system:rtc_export",
+    "//third_party/libyuv",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
 }
@@ -70,6 +74,47 @@
   }
 }
 
+# Deprecated empty target. Use "video_frame" instead.
+rtc_source_set("video_frame_i420") {
+  visibility = [ "*" ]
+  sources = []
+  deps = [ ":video_frame" ]
+}
+
+rtc_library("video_frame_i010") {
+  visibility = [ "*" ]
+  sources = [
+    "i010_buffer.cc",
+    "i010_buffer.h",
+  ]
+  deps = [
+    ":video_frame",
+    ":video_rtp_headers",
+    "..:scoped_refptr",
+    "../../rtc_base",
+    "../../rtc_base:checks",
+    "../../rtc_base/memory:aligned_malloc",
+    "//third_party/libyuv",
+  ]
+}
+
+rtc_library("video_frame_nv12") {
+  visibility = [ "*" ]
+  sources = [
+    "nv12_buffer.cc",
+    "nv12_buffer.h",
+  ]
+  deps = [
+    ":video_frame",
+    "..:scoped_refptr",
+    "../../rtc_base",
+    "../../rtc_base:checks",
+    "../../rtc_base/memory:aligned_malloc",
+    "../../rtc_base/system:rtc_export",
+    "//third_party/libyuv",
+  ]
+}
+
 rtc_source_set("recordable_encoded_frame") {
   visibility = [ "*" ]
   sources = [ "recordable_encoded_frame.h" ]
@@ -90,60 +135,6 @@
   sources = [ "video_frame_type.h" ]
 }
 
-rtc_library("video_frame_i420") {
-  visibility = [ "*" ]
-  sources = [
-    "i420_buffer.cc",
-    "i420_buffer.h",
-  ]
-  deps = [
-    ":video_frame",
-    ":video_rtp_headers",
-    "..:scoped_refptr",
-    "../../rtc_base",
-    "../../rtc_base:checks",
-    "../../rtc_base/memory:aligned_malloc",
-    "../../rtc_base/system:rtc_export",
-    "//third_party/libyuv",
-  ]
-}
-
-rtc_library("video_frame_i010") {
-  visibility = [ "*" ]
-  sources = [
-    "i010_buffer.cc",
-    "i010_buffer.h",
-  ]
-  deps = [
-    ":video_frame",
-    ":video_frame_i420",
-    ":video_rtp_headers",
-    "..:scoped_refptr",
-    "../../rtc_base",
-    "../../rtc_base:checks",
-    "../../rtc_base/memory:aligned_malloc",
-    "//third_party/libyuv",
-  ]
-}
-
-rtc_library("video_frame_nv12") {
-  visibility = [ "*" ]
-  sources = [
-    "nv12_buffer.cc",
-    "nv12_buffer.h",
-  ]
-  deps = [
-    ":video_frame",
-    ":video_frame_i420",
-    "..:scoped_refptr",
-    "../../rtc_base",
-    "../../rtc_base:checks",
-    "../../rtc_base/memory:aligned_malloc",
-    "../../rtc_base/system:rtc_export",
-    "//third_party/libyuv",
-  ]
-}
-
 rtc_library("encoded_image") {
   visibility = [ "*" ]
   sources = [
diff --git a/api/video/nv12_buffer.cc b/api/video/nv12_buffer.cc
index d6f0183..cfa85ac 100644
--- a/api/video/nv12_buffer.cc
+++ b/api/video/nv12_buffer.cc
@@ -14,6 +14,7 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/ref_counted_object.h"
 #include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/scale.h"
 
 namespace webrtc {
 
@@ -122,4 +123,35 @@
   memset(data_.get(), 0, NV12DataSize(height_, stride_y_, stride_uv_));
 }
 
+void NV12Buffer::CropAndScaleFrom(const NV12BufferInterface& src,
+                                  int offset_x,
+                                  int offset_y,
+                                  int crop_width,
+                                  int crop_height) {
+  RTC_CHECK_LE(crop_width, src.width());
+  RTC_CHECK_LE(crop_height, src.height());
+  RTC_CHECK_LE(crop_width + offset_x, src.width());
+  RTC_CHECK_LE(crop_height + offset_y, src.height());
+  RTC_CHECK_GE(offset_x, 0);
+  RTC_CHECK_GE(offset_y, 0);
+
+  // Make sure offset is even so that u/v plane becomes aligned.
+  const int uv_offset_x = offset_x / 2;
+  const int uv_offset_y = offset_y / 2;
+  offset_x = uv_offset_x * 2;
+  offset_y = uv_offset_y * 2;
+
+  const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
+  const uint8_t* uv_plane =
+      src.DataUV() + src.StrideUV() * uv_offset_y + uv_offset_x * 2;
+
+  // kFilterBox is unsupported in libyuv, so using kFilterBilinear instead.
+  int res = libyuv::NV12Scale(y_plane, src.StrideY(), uv_plane, src.StrideUV(),
+                              crop_width, crop_height, MutableDataY(),
+                              StrideY(), MutableDataUV(), StrideUV(), width(),
+                              height(), libyuv::kFilterBilinear);
+
+  RTC_DCHECK_EQ(res, 0);
+}
+
 }  // namespace webrtc
diff --git a/api/video/nv12_buffer.h b/api/video/nv12_buffer.h
index 039f767..cb989e8 100644
--- a/api/video/nv12_buffer.h
+++ b/api/video/nv12_buffer.h
@@ -56,6 +56,14 @@
   // are resolved in a better way. Or in the mean time, use SetBlack.
   void InitializeData();
 
+  // Scale the cropped area of |src| to the size of |this| buffer, and
+  // write the result into |this|.
+  void CropAndScaleFrom(const NV12BufferInterface& src,
+                        int offset_x,
+                        int offset_y,
+                        int crop_width,
+                        int crop_height);
+
  protected:
   NV12Buffer(int width, int height);
   NV12Buffer(int width, int height, int stride_y, int stride_uv);
diff --git a/api/video/test/BUILD.gn b/api/video/test/BUILD.gn
index d46b48e..72f5049 100644
--- a/api/video/test/BUILD.gn
+++ b/api/video/test/BUILD.gn
@@ -20,7 +20,6 @@
     "..:video_adaptation",
     "..:video_bitrate_allocation",
     "..:video_frame",
-    "..:video_frame_i420",
     "..:video_frame_nv12",
     "..:video_rtp_headers",
     "../../../test:frame_utils",
diff --git a/api/video/video_frame_buffer.cc b/api/video/video_frame_buffer.cc
index aa4e69f..44cc546 100644
--- a/api/video/video_frame_buffer.cc
+++ b/api/video/video_frame_buffer.cc
@@ -10,10 +10,25 @@
 
 #include "api/video/video_frame_buffer.h"
 
+#include "api/video/i420_buffer.h"
 #include "rtc_base/checks.h"
 
 namespace webrtc {
 
+rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBuffer::CropAndScale(
+    int offset_x,
+    int offset_y,
+    int crop_width,
+    int crop_height,
+    int scaled_width,
+    int scaled_height) {
+  rtc::scoped_refptr<I420Buffer> result =
+      I420Buffer::Create(scaled_width, scaled_height);
+  result->CropAndScaleFrom(*this->ToI420(), offset_x, offset_y, crop_width,
+                           crop_height);
+  return result;
+}
+
 const I420BufferInterface* VideoFrameBuffer::GetI420() const {
   // Overridden by subclasses that can return an I420 buffer without any
   // conversion, in particular, I420BufferInterface.
@@ -99,5 +114,4 @@
 int NV12BufferInterface::ChromaHeight() const {
   return (height() + 1) / 2;
 }
-
 }  // namespace webrtc
diff --git a/api/video/video_frame_buffer.h b/api/video/video_frame_buffer.h
index abe9c08..457abfd 100644
--- a/api/video/video_frame_buffer.h
+++ b/api/video/video_frame_buffer.h
@@ -76,6 +76,24 @@
   // doesn't affect binary data at all. Another example is any I420A buffer.
   virtual const I420BufferInterface* GetI420() const;
 
+  // A format specific scale function. Default implementation works by
+  // converting to I420. But more efficient implementations may override it,
+  // especially for kNative.
+  // First, the image is cropped to |crop_width| and |crop_height| and then
+  // scaled to |scaled_width| and |scaled_height|.
+  virtual rtc::scoped_refptr<VideoFrameBuffer> CropAndScale(int offset_x,
+                                                            int offset_y,
+                                                            int crop_width,
+                                                            int crop_height,
+                                                            int scaled_width,
+                                                            int scaled_height);
+
+  // Alias for common use case.
+  rtc::scoped_refptr<VideoFrameBuffer> Scale(int scaled_width,
+                                             int scaled_height) {
+    return CropAndScale(0, 0, width(), height(), scaled_width, scaled_height);
+  }
+
   // These functions should only be called if type() is of the correct type.
   // Calling with a different type will result in a crash.
   const I420ABufferInterface* GetI420A() const;
diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn
index 1569125..a990276 100644
--- a/api/video_codecs/BUILD.gn
+++ b/api/video_codecs/BUILD.gn
@@ -137,7 +137,7 @@
   deps = [
     ":video_codecs_api",
     "..:fec_controller_api",
-    "../../api/video:video_frame_i420",
+    "../../api/video:video_frame",
     "../../media:rtc_h264_profile_id",
     "../../media:rtc_media_base",
     "../../modules/video_coding:video_codec_interface",
diff --git a/api/video_codecs/test/BUILD.gn b/api/video_codecs/test/BUILD.gn
index 10b18b6..c47e5b9 100644
--- a/api/video_codecs/test/BUILD.gn
+++ b/api/video_codecs/test/BUILD.gn
@@ -36,7 +36,6 @@
       "../../video:encoded_image",
       "../../video:video_bitrate_allocation",
       "../../video:video_frame",
-      "../../video:video_frame_i420",
       "../../video:video_rtp_headers",
       "//testing/gtest",
     ]
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index 9cb6f45..bea8530 100644
--- a/common_video/BUILD.gn
+++ b/common_video/BUILD.gn
@@ -49,7 +49,6 @@
     "../api/video:video_bitrate_allocation",
     "../api/video:video_bitrate_allocator",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_frame_nv12",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:bitstream_parser_api",
@@ -105,7 +104,7 @@
       "../api/units:time_delta",
       "../api/video:video_frame",
       "../api/video:video_frame_i010",
-      "../api/video:video_frame_i420",
+      "../api/video:video_frame_nv12",
       "../api/video:video_rtp_headers",
       "../media:rtc_h264_profile_id",
       "../rtc_base",
diff --git a/common_video/video_frame_unittest.cc b/common_video/video_frame_unittest.cc
index 225a7d3..9a7a5e2 100644
--- a/common_video/video_frame_unittest.cc
+++ b/common_video/video_frame_unittest.cc
@@ -15,6 +15,7 @@
 
 #include "api/video/i010_buffer.h"
 #include "api/video/i420_buffer.h"
+#include "api/video/nv12_buffer.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/time_utils.h"
 #include "test/fake_texture_frame.h"
@@ -157,6 +158,29 @@
   return I010Buffer::Copy(*buffer);
 }
 
+rtc::scoped_refptr<NV12BufferInterface> CreateNV12Gradient(int width,
+                                                           int height) {
+  rtc::scoped_refptr<NV12Buffer> buffer(NV12Buffer::Create(width, height));
+  // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h
+  for (int x = 0; x < width; x++) {
+    for (int y = 0; y < height; y++) {
+      buffer->MutableDataY()[x + y * width] =
+          128 * (x * height + y * width) / (width * height);
+    }
+  }
+  int chroma_width = buffer->ChromaWidth();
+  int chroma_height = buffer->ChromaHeight();
+  for (int x = 0; x < chroma_width; x++) {
+    for (int y = 0; y < chroma_height; y++) {
+      buffer->MutableDataUV()[x * 2 + y * buffer->StrideUV()] =
+          255 * x / (chroma_width - 1);
+      buffer->MutableDataUV()[x * 2 + 1 + y * buffer->StrideUV()] =
+          255 * y / (chroma_height - 1);
+    }
+  }
+  return buffer;
+}
+
 // The offsets and sizes describe the rectangle extracted from the
 // original (gradient) frame, in relative coordinates where the
 // original frame correspond to the unit square, 0.0 <= x, y < 1.0.
@@ -495,6 +519,35 @@
                          ::testing::Values(VideoFrameBuffer::Type::kI420,
                                            VideoFrameBuffer::Type::kI010));
 
+TEST(TestNV12Buffer, CropAndScale) {
+  const int kSourceWidth = 640;
+  const int kSourceHeight = 480;
+  const int kScaledWidth = 320;
+  const int kScaledHeight = 240;
+  const int kCropLeft = 40;
+  const int kCropTop = 30;
+  const int kCropRight = 0;
+  const int kCropBottom = 30;
+
+  rtc::scoped_refptr<VideoFrameBuffer> buf =
+      CreateNV12Gradient(kSourceWidth, kSourceHeight);
+
+  rtc::scoped_refptr<VideoFrameBuffer> scaled_buffer = buf->CropAndScale(
+      kCropLeft, kCropTop, kSourceWidth - kCropLeft - kCropRight,
+      kSourceHeight - kCropTop - kCropBottom, kScaledWidth, kScaledHeight);
+
+  // Parameters to CheckCrop indicate what part of the source frame is in the
+  // scaled frame.
+  const float kOffsetX = (kCropLeft + 0.0) / kSourceWidth;
+  const float kOffsetY = (kCropTop + 0.0) / kSourceHeight;
+  const float kRelativeWidth =
+      (kSourceWidth - kCropLeft - kCropRight + 0.0) / kSourceWidth;
+  const float kRelativeHeight =
+      (kSourceHeight - kCropTop - kCropBottom + 0.0) / kSourceHeight;
+  CheckCrop(*scaled_buffer->ToI420(), kOffsetX, kOffsetY, kRelativeWidth,
+            kRelativeHeight);
+}
+
 class TestPlanarYuvBufferRotate
     : public ::testing::TestWithParam<
           std::tuple<webrtc::VideoRotation, VideoFrameBuffer::Type>> {};
diff --git a/examples/BUILD.gn b/examples/BUILD.gn
index c7b113a..4315e0c 100644
--- a/examples/BUILD.gn
+++ b/examples/BUILD.gn
@@ -667,7 +667,7 @@
       "../api:scoped_refptr",
       "../api/audio:audio_mixer_api",
       "../api/audio_codecs:audio_codecs_api",
-      "../api/video:video_frame_i420",
+      "../api/video:video_frame",
       "../api/video:video_rtp_headers",
       "../api/video_codecs:video_codecs_api",
       "../media:rtc_media_base",
diff --git a/media/BUILD.gn b/media/BUILD.gn
index b736612..212ccf9 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -99,7 +99,6 @@
     "../api/video:video_bitrate_allocation",
     "../api/video:video_bitrate_allocator_factory",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:video_codecs_api",
     "../call:call_interfaces",
@@ -185,7 +184,6 @@
     "../api:scoped_refptr",
     "../api/video:video_codec_constants",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:rtc_software_fallback_wrappers",
     "../api/video_codecs:video_codecs_api",
@@ -299,7 +297,6 @@
     "../api/video:video_bitrate_allocator_factory",
     "../api/video:video_codec_constants",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:rtc_software_fallback_wrappers",
     "../api/video_codecs:video_codecs_api",
@@ -466,7 +463,6 @@
       "../api/video:encoded_image",
       "../api/video:video_bitrate_allocation",
       "../api/video:video_frame",
-      "../api/video:video_frame_i420",
       "../api/video:video_rtp_headers",
       "../api/video_codecs:video_codecs_api",
       "../call:call_interfaces",
@@ -568,7 +564,6 @@
       "../api/video:builtin_video_bitrate_allocator_factory",
       "../api/video:video_bitrate_allocation",
       "../api/video:video_frame",
-      "../api/video:video_frame_i420",
       "../api/video:video_rtp_headers",
       "../api/video_codecs:builtin_video_decoder_factory",
       "../api/video_codecs:builtin_video_encoder_factory",
diff --git a/modules/video_capture/BUILD.gn b/modules/video_capture/BUILD.gn
index 9822981..b63a78a 100644
--- a/modules/video_capture/BUILD.gn
+++ b/modules/video_capture/BUILD.gn
@@ -30,7 +30,6 @@
     "..:module_api",
     "../../api:scoped_refptr",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_rtp_headers",
     "../../common_video",
     "../../media:rtc_media_base",
@@ -132,7 +131,6 @@
         ":video_capture_module",
         "../../api:scoped_refptr",
         "../../api/video:video_frame",
-        "../../api/video:video_frame_i420",
         "../../api/video:video_rtp_headers",
         "../../common_video",
         "../../rtc_base:rtc_base_approved",
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index 7cbd1fc..86bd166 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -20,7 +20,6 @@
     ":video_codec_interface",
     "../../api/video:encoded_image",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_rtp_headers",
     "../../modules:module_api_public",
     "../../modules/rtp_rtcp:rtp_video_header",
@@ -186,7 +185,6 @@
     "../../api/video:video_adaptation",
     "../../api/video:video_bitrate_allocator",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_frame_type",
     "../../api/video:video_rtp_headers",
     "../../api/video_codecs:video_codecs_api",
@@ -380,7 +378,6 @@
     ":video_coding_utility",
     "../../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",
@@ -428,7 +425,6 @@
     "../../api:scoped_refptr",
     "../../api/video:encoded_image",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_rtp_headers",
     "../../api/video_codecs:video_codecs_api",
     "../../common_video",
@@ -463,7 +459,6 @@
     "../../api:scoped_refptr",
     "../../api/video:encoded_image",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_rtp_headers",
     "../../api/video_codecs:video_codecs_api",
     "../../api/video_codecs:vp8_temporal_layers_factory",
@@ -660,7 +655,6 @@
       "../../api:simulcast_test_fixture_api",
       "../../api/video:encoded_image",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_rtp_headers",
       "../../api/video_codecs:video_codecs_api",
       "../../common_video",
@@ -698,7 +692,6 @@
       "../../api/video:video_bitrate_allocator",
       "../../api/video:video_bitrate_allocator_factory",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_rtp_headers",
       "../../api/video_codecs:video_codecs_api",
       "../../common_video",
@@ -850,7 +843,6 @@
       "../../api/test/video:function_video_factory",
       "../../api/video:encoded_image",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_rtp_headers",
       "../../api/video_codecs:rtc_software_fallback_wrappers",
       "../../api/video_codecs:video_codecs_api",
@@ -982,7 +974,6 @@
       "../../api/video:video_bitrate_allocator",
       "../../api/video:video_bitrate_allocator_factory",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_frame_type",
       "../../api/video:video_rtp_headers",
       "../../api/video_codecs:video_codecs_api",
diff --git a/modules/video_coding/codecs/av1/BUILD.gn b/modules/video_coding/codecs/av1/BUILD.gn
index a1d2f6e..6c64953 100644
--- a/modules/video_coding/codecs/av1/BUILD.gn
+++ b/modules/video_coding/codecs/av1/BUILD.gn
@@ -22,7 +22,7 @@
       "../..:video_codec_interface",
       "../../../../api:scoped_refptr",
       "../../../../api/video:encoded_image",
-      "../../../../api/video:video_frame_i420",
+      "../../../../api/video:video_frame",
       "../../../../common_video",
       "../../../../rtc_base:logging",
       "//third_party/libaom",
@@ -116,7 +116,6 @@
       "../../../../api:scoped_refptr",
       "../../../../api/video:encoded_image",
       "../../../../api/video:video_frame",
-      "../../../../api/video:video_frame_i420",
       "../../../../common_video",
       "../../../../rtc_base:checks",
       "../../../../rtc_base:logging",
@@ -161,7 +160,7 @@
         "../../../../api:mock_video_encoder",
         "../../../../api/units:data_size",
         "../../../../api/units:time_delta",
-        "../../../../api/video:video_frame_i420",
+        "../../../../api/video:video_frame",
         "../../../../api/video_codecs:video_codecs_api",
         "../../../../test:test_support",
       ]
diff --git a/modules/video_processing/BUILD.gn b/modules/video_processing/BUILD.gn
index abc9f03..871012a 100644
--- a/modules/video_processing/BUILD.gn
+++ b/modules/video_processing/BUILD.gn
@@ -29,7 +29,6 @@
     "..:module_api",
     "../../api:scoped_refptr",
     "../../api/video:video_frame",
-    "../../api/video:video_frame_i420",
     "../../api/video:video_rtp_headers",
     "../../common_audio",
     "../../common_video",
@@ -100,7 +99,6 @@
       ":video_processing",
       "../../api:scoped_refptr",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_rtp_headers",
       "../../common_video",
       "../../test:fileutils",
diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn
index ae1c930..8a10d14 100644
--- a/rtc_tools/BUILD.gn
+++ b/rtc_tools/BUILD.gn
@@ -56,7 +56,6 @@
   deps = [
     "../api:scoped_refptr",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../rtc_base:checks",
     "../rtc_base:rtc_base_approved",
@@ -76,7 +75,6 @@
     ":video_file_reader",
     "../api:scoped_refptr",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../rtc_base:rtc_base_approved",
   ]
@@ -105,7 +103,6 @@
     "../api:array_view",
     "../api:scoped_refptr",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../common_video",
     "../rtc_base:checks",
@@ -487,7 +484,6 @@
       ":video_quality_analysis",
       "../api:scoped_refptr",
       "../api/video:video_frame",
-      "../api/video:video_frame_i420",
       "../api/video:video_rtp_headers",
       "../common_video",
       "../rtc_base",
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 14b2bca..2a80c65 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -383,7 +383,6 @@
         "../api:libjingle_peerconnection_api",
         "../api:media_stream_interface",
         "../api/video:video_frame",
-        "../api/video:video_frame_i420",
         "../api/video:video_rtp_headers",
         "../common_video",
         "../media:rtc_media_base",
@@ -412,7 +411,6 @@
       deps = [
         ":base_objc",
         "//api/video:video_frame",
-        "//api/video:video_frame_i420",
         "//api/video:video_rtp_headers",
         "//common_video",
         "//rtc_base:checks",
@@ -1130,7 +1128,7 @@
             ":videotoolbox_objc",
             "../api:scoped_refptr",
             "../api/task_queue:default_task_queue_factory",
-            "../api/video:video_frame_i420",
+            "../api/video:video_frame",
             "../common_video",
             "../media:rtc_media_base",
             "../media:rtc_media_tests_utils",
@@ -1656,7 +1654,6 @@
         ":vpx_codec_constants",
         ":wrapped_native_codec_objc",
         "../api/video:video_frame",
-        "../api/video:video_frame_i420",
         "../api/video:video_rtp_headers",
         "../api/video_codecs:video_codecs_api",
         "../common_video",
diff --git a/sdk/android/api/org/webrtc/VideoFrame.java b/sdk/android/api/org/webrtc/VideoFrame.java
index a0a0d4e..49c75fa 100644
--- a/sdk/android/api/org/webrtc/VideoFrame.java
+++ b/sdk/android/api/org/webrtc/VideoFrame.java
@@ -54,7 +54,6 @@
      * Crops a region defined by |cropx|, |cropY|, |cropWidth| and |cropHeight|. Scales it to size
      * |scaleWidth| x |scaleHeight|.
      */
-    @CalledByNative("Buffer")
     Buffer cropAndScale(
         int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight);
   }
diff --git a/sdk/android/src/jni/video_frame.cc b/sdk/android/src/jni/video_frame.cc
index d57fe8f..ca33c5c 100644
--- a/sdk/android/src/jni/video_frame.cc
+++ b/sdk/android/src/jni/video_frame.cc
@@ -152,19 +152,6 @@
   return j_video_frame_buffer_;
 }
 
-rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBuffer::CropAndScale(
-    JNIEnv* jni,
-    int crop_x,
-    int crop_y,
-    int crop_width,
-    int crop_height,
-    int scale_width,
-    int scale_height) {
-  return Adopt(jni, Java_Buffer_cropAndScale(jni, j_video_frame_buffer_, crop_x,
-                                             crop_y, crop_width, crop_height,
-                                             scale_width, scale_height));
-}
-
 VideoFrameBuffer::Type AndroidVideoBuffer::type() const {
   return Type::kNative;
 }
diff --git a/sdk/android/src/jni/video_frame.h b/sdk/android/src/jni/video_frame.h
index f6b569a..cb0ff0e 100644
--- a/sdk/android/src/jni/video_frame.h
+++ b/sdk/android/src/jni/video_frame.h
@@ -40,16 +40,6 @@
 
   const ScopedJavaGlobalRef<jobject>& video_frame_buffer() const;
 
-  // Crops a region defined by |crop_x|, |crop_y|, |crop_width| and
-  // |crop_height|. Scales it to size |scale_width| x |scale_height|.
-  rtc::scoped_refptr<AndroidVideoBuffer> CropAndScale(JNIEnv* jni,
-                                                      int crop_x,
-                                                      int crop_y,
-                                                      int crop_width,
-                                                      int crop_height,
-                                                      int scale_width,
-                                                      int scale_height);
-
  protected:
   // Should not be called directly. Adopts the Java VideoFrame.Buffer. Use
   // Create() or Adopt() instead for clarity.
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 58d3dab..9fa0e00 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -52,7 +52,6 @@
     "../api/video:encoded_image",
     "../api/video:video_frame",
     "../api/video:video_frame_i010",
-    "../api/video:video_frame_i420",
     "../api/video:video_frame_nv12",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:video_codecs_api",
@@ -86,7 +85,6 @@
   deps = [
     "../api:scoped_refptr",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
   ]
 }
 
@@ -113,8 +111,6 @@
     "../api:scoped_refptr",
     "../api/task_queue",
     "../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",
@@ -361,7 +357,6 @@
     "../api:scoped_refptr",
     "../api/video:encoded_image",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video_codecs:video_codecs_api",
     "../common_video",
     "../media:rtc_media_base",
@@ -517,7 +512,6 @@
       "../api/test/video:function_video_factory",
       "../api/video:encoded_image",
       "../api/video:video_frame",
-      "../api/video:video_frame_i420",
       "../api/video_codecs:video_codecs_api",
       "../call:video_stream_api",
       "../common_video",
@@ -763,7 +757,6 @@
     "../api/video:encoded_image",
     "../api/video:video_bitrate_allocation",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video_codecs:video_codecs_api",
     "../api/video_codecs:vp8_temporal_layers_factory",
diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn
index 5c9e259..3901297 100644
--- a/test/pc/e2e/BUILD.gn
+++ b/test/pc/e2e/BUILD.gn
@@ -124,10 +124,7 @@
       "analyzer/video/simulcast_dummy_buffer_helper.cc",
       "analyzer/video/simulcast_dummy_buffer_helper.h",
     ]
-    deps = [
-      "../../../api/video:video_frame",
-      "../../../api/video:video_frame_i420",
-    ]
+    deps = [ "../../../api/video:video_frame" ]
   }
 
   rtc_library("quality_analyzing_video_decoder") {
@@ -144,7 +141,6 @@
       "../../../api:video_quality_analyzer_api",
       "../../../api/video:encoded_image",
       "../../../api/video:video_frame",
-      "../../../api/video:video_frame_i420",
       "../../../api/video:video_rtp_headers",
       "../../../api/video_codecs:video_codecs_api",
       "../../../modules/video_coding:video_codec_interface",
@@ -522,7 +518,6 @@
         "../../../api:rtp_packet_info",
         "../../../api/video:encoded_image",
         "../../../api/video:video_frame",
-        "../../../api/video:video_frame_i420",
         "../../../common_video",
         "../../../modules/rtp_rtcp:rtp_rtcp_format",
         "../../../rtc_base:stringutils",
@@ -645,7 +640,6 @@
       "../../../api/units:timestamp",
       "../../../api/video:encoded_image",
       "../../../api/video:video_frame",
-      "../../../api/video:video_frame_i420",
       "../../../api/video:video_rtp_headers",
       "../../../common_video",
       "../../../rtc_base:criticalsection",
diff --git a/test/scenario/BUILD.gn b/test/scenario/BUILD.gn
index 2ec9d63..f5c22fc 100644
--- a/test/scenario/BUILD.gn
+++ b/test/scenario/BUILD.gn
@@ -97,7 +97,6 @@
       "../../api/units:timestamp",
       "../../api/video:builtin_video_bitrate_allocator_factory",
       "../../api/video:video_frame",
-      "../../api/video:video_frame_i420",
       "../../api/video:video_rtp_headers",
       "../../api/video_codecs:video_codecs_api",
       "../../audio",
diff --git a/video/BUILD.gn b/video/BUILD.gn
index f195883..115c71a 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -86,7 +86,6 @@
     "../api/video:video_bitrate_allocator",
     "../api/video:video_codec_constants",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video:video_stream_encoder",
     "../api/video:video_stream_encoder_create",
@@ -227,7 +226,6 @@
     "../api/video:video_bitrate_allocator_factory",
     "../api/video:video_codec_constants",
     "../api/video:video_frame",
-    "../api/video:video_frame_i420",
     "../api/video:video_rtp_headers",
     "../api/video:video_stream_encoder",
     "../api/video_codecs:video_codecs_api",
@@ -597,7 +595,6 @@
       "../api/video:video_adaptation",
       "../api/video:video_bitrate_allocation",
       "../api/video:video_frame",
-      "../api/video:video_frame_i420",
       "../api/video:video_frame_nv12",
       "../api/video:video_frame_type",
       "../api/video:video_rtp_headers",
diff --git a/video/adaptation/BUILD.gn b/video/adaptation/BUILD.gn
index 2a60ead..a96f4cf 100644
--- a/video/adaptation/BUILD.gn
+++ b/video/adaptation/BUILD.gn
@@ -80,7 +80,7 @@
       "../../api/task_queue:task_queue",
       "../../api/video:encoded_image",
       "../../api/video:video_adaptation",
-      "../../api/video:video_frame_i420",
+      "../../api/video:video_frame",
       "../../api/video_codecs:video_codecs_api",
       "../../call/adaptation:resource_adaptation",
       "../../call/adaptation:resource_adaptation_test_utilities",