Update I420Buffer to new VideoFrameBuffer interface

This is a follow-up cleanup for CL https://codereview.webrtc.org/2847383002/.

BUG=webrtc:7632
TBR=stefan

Review-Url: https://codereview.webrtc.org/2906053002
Cr-Commit-Position: refs/heads/master@{#18388}
diff --git a/webrtc/api/video/i420_buffer.cc b/webrtc/api/video/i420_buffer.cc
index ae770c6..495009c 100644
--- a/webrtc/api/video/i420_buffer.cc
+++ b/webrtc/api/video/i420_buffer.cc
@@ -77,7 +77,7 @@
 
 // static
 rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(
-    const VideoFrameBuffer& source) {
+    const I420BufferInterface& source) {
   return Copy(source.width(), source.height(),
               source.DataY(), source.StrideY(),
               source.DataU(), source.StrideU(),
@@ -104,7 +104,8 @@
 
 // static
 rtc::scoped_refptr<I420Buffer> I420Buffer::Rotate(
-    const VideoFrameBuffer& src, VideoRotation rotation) {
+    const I420BufferInterface& src,
+    VideoRotation rotation) {
   RTC_CHECK(src.DataY());
   RTC_CHECK(src.DataU());
   RTC_CHECK(src.DataV());
@@ -183,12 +184,11 @@
                              0, 128, 128) == 0);
 }
 
-void I420Buffer::CropAndScaleFrom(
-    const VideoFrameBuffer& src,
-    int offset_x,
-    int offset_y,
-    int crop_width,
-    int crop_height) {
+void I420Buffer::CropAndScaleFrom(const I420BufferInterface& 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());
@@ -220,8 +220,7 @@
   RTC_DCHECK_EQ(res, 0);
 }
 
-void I420Buffer::CropAndScaleFrom(
-    const VideoFrameBuffer& src) {
+void I420Buffer::CropAndScaleFrom(const I420BufferInterface& src) {
   const int crop_width =
       std::min(src.width(), width() * src.height() / height());
   const int crop_height =
@@ -233,7 +232,7 @@
       crop_width, crop_height);
 }
 
-void I420Buffer::ScaleFrom(const VideoFrameBuffer& src) {
+void I420Buffer::ScaleFrom(const I420BufferInterface& src) {
   CropAndScaleFrom(src, 0, 0, src.width(), src.height());
 }
 
diff --git a/webrtc/api/video/i420_buffer.h b/webrtc/api/video/i420_buffer.h
index c849ab2..31014a3 100644
--- a/webrtc/api/video/i420_buffer.h
+++ b/webrtc/api/video/i420_buffer.h
@@ -30,7 +30,11 @@
                                                int stride_v);
 
   // Create a new buffer and copy the pixel data.
-  static rtc::scoped_refptr<I420Buffer> Copy(const VideoFrameBuffer& buffer);
+  static rtc::scoped_refptr<I420Buffer> Copy(const I420BufferInterface& buffer);
+  // Deprecated.
+  static rtc::scoped_refptr<I420Buffer> Copy(const VideoFrameBuffer& buffer) {
+    return Copy(*buffer.GetI420());
+  }
 
   static rtc::scoped_refptr<I420Buffer> Copy(
       int width, int height,
@@ -39,8 +43,13 @@
       const uint8_t* data_v, int stride_v);
 
   // Returns a rotated copy of |src|.
-  static rtc::scoped_refptr<I420Buffer> Rotate(const VideoFrameBuffer& src,
+  static rtc::scoped_refptr<I420Buffer> Rotate(const I420BufferInterface& src,
                                                VideoRotation rotation);
+  // Deprecated.
+  static rtc::scoped_refptr<I420Buffer> Rotate(const VideoFrameBuffer& src,
+                                               VideoRotation rotation) {
+    return Rotate(*src.GetI420(), rotation);
+  }
 
   // Sets the buffer to all black.
   static void SetBlack(I420Buffer* buffer);
@@ -69,7 +78,7 @@
 
   // Scale the cropped area of |src| to the size of |this| buffer, and
   // write the result into |this|.
-  void CropAndScaleFrom(const VideoFrameBuffer& src,
+  void CropAndScaleFrom(const I420BufferInterface& src,
                         int offset_x,
                         int offset_y,
                         int crop_width,
@@ -77,10 +86,10 @@
 
   // The common case of a center crop, when needed to adjust the
   // aspect ratio without distorting the image.
-  void CropAndScaleFrom(const VideoFrameBuffer& src);
+  void CropAndScaleFrom(const I420BufferInterface& src);
 
   // Scale all of |src| to the size of |this| buffer, with no cropping.
-  void ScaleFrom(const VideoFrameBuffer& src);
+  void ScaleFrom(const I420BufferInterface& src);
 
  protected:
   I420Buffer(int width, int height);
diff --git a/webrtc/api/video/video_frame.h b/webrtc/api/video/video_frame.h
index 82c348d..3ee381b 100644
--- a/webrtc/api/video/video_frame.h
+++ b/webrtc/api/video/video_frame.h
@@ -98,7 +98,7 @@
   // TODO(nisse): Deprecated.
   // Return true if the frame is stored in a texture.
   bool is_texture() const {
-    return video_frame_buffer()->native_handle() != nullptr;
+    return video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative;
   }
 
  private:
diff --git a/webrtc/api/video/video_frame_buffer.cc b/webrtc/api/video/video_frame_buffer.cc
index bb31717..3fc442b 100644
--- a/webrtc/api/video/video_frame_buffer.cc
+++ b/webrtc/api/video/video_frame_buffer.cc
@@ -26,7 +26,7 @@
 // VideoFrameBuffer) vs ToI420 (returns I420BufferInterface).
 class I420InterfaceAdapter : public I420BufferInterface {
  public:
-  explicit I420InterfaceAdapter(rtc::scoped_refptr<VideoFrameBuffer> buffer)
+  explicit I420InterfaceAdapter(const VideoFrameBuffer* buffer)
       : buffer_(buffer) {}
 
   int width() const override { return buffer_->width(); }
@@ -41,7 +41,7 @@
   int StrideV() const override { return buffer_->StrideV(); }
 
  private:
-  rtc::scoped_refptr<VideoFrameBuffer> buffer_;
+  rtc::scoped_refptr<const VideoFrameBuffer> buffer_;
 };
 
 }  // namespace
@@ -54,28 +54,28 @@
 }
 
 const uint8_t* VideoFrameBuffer::DataY() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->DataY();
+  return GetI420()->DataY();
 }
 
 const uint8_t* VideoFrameBuffer::DataU() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->DataU();
+  return GetI420()->DataU();
 }
 
 const uint8_t* VideoFrameBuffer::DataV() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->DataV();
+  return GetI420()->DataV();
 }
 
 // Returns the number of bytes between successive rows for a given plane.
 int VideoFrameBuffer::StrideY() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->StrideY();
+  return GetI420()->StrideY();
 }
 
 int VideoFrameBuffer::StrideU() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->StrideU();
+  return GetI420()->StrideU();
 }
 
 int VideoFrameBuffer::StrideV() const {
-  return const_cast<VideoFrameBuffer*>(this)->GetI420()->StrideV();
+  return GetI420()->StrideV();
 }
 
 void* VideoFrameBuffer::native_handle() const {
@@ -98,11 +98,24 @@
   return new rtc::RefCountedObject<I420InterfaceAdapter>(this);
 }
 
-rtc::scoped_refptr<I444BufferInterface> VideoFrameBuffer::GetI444() {
+rtc::scoped_refptr<const I420BufferInterface> VideoFrameBuffer::GetI420()
+    const {
+  RTC_CHECK(type() == Type::kI420);
+  // TODO(magjed): static_cast to I420BufferInterface instead once external
+  // clients are updated.
+  return new rtc::RefCountedObject<I420InterfaceAdapter>(this);
+}
+
+I444BufferInterface* VideoFrameBuffer::GetI444() {
   RTC_CHECK(type() == Type::kI444);
   return static_cast<I444BufferInterface*>(this);
 }
 
+const I444BufferInterface* VideoFrameBuffer::GetI444() const {
+  RTC_CHECK(type() == Type::kI444);
+  return static_cast<const I444BufferInterface*>(this);
+}
+
 VideoFrameBuffer::Type I420BufferInterface::type() const {
   return Type::kI420;
 }
diff --git a/webrtc/api/video/video_frame_buffer.h b/webrtc/api/video/video_frame_buffer.h
index 13005af..fa711d8 100644
--- a/webrtc/api/video/video_frame_buffer.h
+++ b/webrtc/api/video/video_frame_buffer.h
@@ -63,8 +63,12 @@
 
   // These functions should only be called if type() is of the correct type.
   // Calling with a different type will result in a crash.
+  // TODO(magjed): Return raw pointers for GetI420 once deprecated interface is
+  // removed.
   rtc::scoped_refptr<I420BufferInterface> GetI420();
-  rtc::scoped_refptr<I444BufferInterface> GetI444();
+  rtc::scoped_refptr<const I420BufferInterface> GetI420() const;
+  I444BufferInterface* GetI444();
+  const I444BufferInterface* GetI444() const;
 
   // Deprecated - use ToI420() first instead.
   // Returns pointer to the pixel data for a given plane. The memory is owned by
diff --git a/webrtc/common_video/i420_buffer_pool_unittest.cc b/webrtc/common_video/i420_buffer_pool_unittest.cc
index a4dda0c..77aa086 100644
--- a/webrtc/common_video/i420_buffer_pool_unittest.cc
+++ b/webrtc/common_video/i420_buffer_pool_unittest.cc
@@ -17,7 +17,7 @@
 
 TEST(TestI420BufferPool, SimpleFrameReuse) {
   I420BufferPool pool;
-  rtc::scoped_refptr<VideoFrameBuffer> buffer = pool.CreateBuffer(16, 16);
+  rtc::scoped_refptr<I420BufferInterface> buffer = pool.CreateBuffer(16, 16);
   EXPECT_EQ(16, buffer->width());
   EXPECT_EQ(16, buffer->height());
   // Extract non-refcounted pointers for testing.
@@ -37,7 +37,7 @@
 
 TEST(TestI420BufferPool, FailToReuse) {
   I420BufferPool pool;
-  rtc::scoped_refptr<VideoFrameBuffer> buffer = pool.CreateBuffer(16, 16);
+  rtc::scoped_refptr<I420BufferInterface> buffer = pool.CreateBuffer(16, 16);
   // Extract non-refcounted pointers for testing.
   const uint8_t* u_ptr = buffer->DataU();
   const uint8_t* v_ptr = buffer->DataV();
@@ -65,7 +65,7 @@
 
 TEST(TestI420BufferPool, MaxNumberOfBuffers) {
   I420BufferPool pool(false, 1);
-  rtc::scoped_refptr<VideoFrameBuffer> buffer1 = pool.CreateBuffer(16, 16);
+  rtc::scoped_refptr<I420BufferInterface> buffer1 = pool.CreateBuffer(16, 16);
   EXPECT_NE(nullptr, buffer1.get());
   EXPECT_EQ(nullptr, pool.CreateBuffer(16, 16).get());
 }
diff --git a/webrtc/common_video/i420_video_frame_unittest.cc b/webrtc/common_video/i420_video_frame_unittest.cc
index f3ee931..1e4f207 100644
--- a/webrtc/common_video/i420_video_frame_unittest.cc
+++ b/webrtc/common_video/i420_video_frame_unittest.cc
@@ -33,8 +33,8 @@
           128 * (x * height + y * width) / (width * height);
     }
   }
-  int chroma_width = (width + 1) / 2;
-  int chroma_height = (height + 1) / 2;
+  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->MutableDataU()[x + y * chroma_width] =
@@ -49,7 +49,7 @@
 // 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.
-void CheckCrop(const webrtc::VideoFrameBuffer& frame,
+void CheckCrop(const webrtc::I420BufferInterface& frame,
                double offset_x,
                double offset_y,
                double rel_width,
@@ -78,8 +78,10 @@
   }
 }
 
-void CheckRotate(int width, int height, webrtc::VideoRotation rotation,
-                 const webrtc::VideoFrameBuffer& rotated) {
+void CheckRotate(int width,
+                 int height,
+                 webrtc::VideoRotation rotation,
+                 const webrtc::I420BufferInterface& rotated) {
   int rotated_width = width;
   int rotated_height = height;
 
@@ -160,12 +162,13 @@
   VideoFrame frame2(frame1);
 
   EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer());
-  EXPECT_EQ(frame1.video_frame_buffer()->DataY(),
-            frame2.video_frame_buffer()->DataY());
-  EXPECT_EQ(frame1.video_frame_buffer()->DataU(),
-            frame2.video_frame_buffer()->DataU());
-  EXPECT_EQ(frame1.video_frame_buffer()->DataV(),
-            frame2.video_frame_buffer()->DataV());
+  rtc::scoped_refptr<I420BufferInterface> yuv1 =
+      frame1.video_frame_buffer()->GetI420();
+  rtc::scoped_refptr<I420BufferInterface> yuv2 =
+      frame2.video_frame_buffer()->GetI420();
+  EXPECT_EQ(yuv1->DataY(), yuv2->DataY());
+  EXPECT_EQ(yuv1->DataU(), yuv2->DataU());
+  EXPECT_EQ(yuv1->DataV(), yuv2->DataV());
 
   EXPECT_EQ(frame2.timestamp(), frame1.timestamp());
   EXPECT_EQ(frame2.ntp_time_ms(), frame1.ntp_time_ms());
@@ -280,8 +283,8 @@
     : public ::testing::TestWithParam<webrtc::VideoRotation> {};
 
 TEST_P(TestI420BufferRotate, Rotates) {
-  rtc::scoped_refptr<VideoFrameBuffer> buffer = CreateGradient(640, 480);
-  rtc::scoped_refptr<VideoFrameBuffer> rotated_buffer =
+  rtc::scoped_refptr<I420BufferInterface> buffer = CreateGradient(640, 480);
+  rtc::scoped_refptr<I420BufferInterface> rotated_buffer =
       I420Buffer::Rotate(*buffer, GetParam());
   CheckRotate(640, 480, GetParam(), *rotated_buffer);
 }
diff --git a/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/webrtc/common_video/libyuv/include/webrtc_libyuv.h
index 0924f68..b0c6ab6 100644
--- a/webrtc/common_video/libyuv/include/webrtc_libyuv.h
+++ b/webrtc/common_video/libyuv/include/webrtc_libyuv.h
@@ -50,9 +50,9 @@
 //                    already open for writing.
 // Return value: 0 if OK, < 0 otherwise.
 int PrintVideoFrame(const VideoFrame& frame, FILE* file);
-int PrintVideoFrame(const VideoFrameBuffer& frame, FILE* file);
+int PrintVideoFrame(const I420BufferInterface& frame, FILE* file);
 
-// Extract buffer from VideoFrame or VideoFrameBuffer (consecutive
+// Extract buffer from VideoFrame or I420BufferInterface (consecutive
 // planes, no stride)
 // Input:
 //   - frame       : Reference to video frame.
@@ -60,7 +60,7 @@
 //                   insufficient, an error will be returned.
 //   - buffer      : Pointer to buffer
 // Return value: length of buffer if OK, < 0 otherwise.
-int ExtractBuffer(const rtc::scoped_refptr<VideoFrameBuffer>& input_frame,
+int ExtractBuffer(const rtc::scoped_refptr<I420BufferInterface>& input_frame,
                   size_t size,
                   uint8_t* buffer);
 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer);
@@ -108,13 +108,13 @@
 // Compute PSNR for an I420 frame (all planes).
 // Returns the PSNR in decibel, to a maximum of kInfinitePSNR.
 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame);
-double I420PSNR(const VideoFrameBuffer& ref_buffer,
-                const VideoFrameBuffer& test_buffer);
+double I420PSNR(const I420BufferInterface& ref_buffer,
+                const I420BufferInterface& test_buffer);
 
 // Compute SSIM for an I420 frame (all planes).
 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame);
-double I420SSIM(const VideoFrameBuffer& ref_buffer,
-                const VideoFrameBuffer& test_buffer);
+double I420SSIM(const I420BufferInterface& ref_buffer,
+                const I420BufferInterface& test_buffer);
 
 // Helper function for scaling NV12 to NV12.
 void NV12Scale(std::vector<uint8_t>* tmp_buffer,
diff --git a/webrtc/common_video/libyuv/libyuv_unittest.cc b/webrtc/common_video/libyuv/libyuv_unittest.cc
index c60085c..ea90ec4 100644
--- a/webrtc/common_video/libyuv/libyuv_unittest.cc
+++ b/webrtc/common_video/libyuv/libyuv_unittest.cc
@@ -62,7 +62,7 @@
   ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<<
                                        input_file_name << "\n";
 
-  rtc::scoped_refptr<VideoFrameBuffer> buffer(
+  rtc::scoped_refptr<I420BufferInterface> buffer(
       test::ReadI420Buffer(width_, height_, source_file_));
 
   orig_frame_.reset(new VideoFrame(buffer, kVideoRotation_0, 0));
@@ -89,8 +89,8 @@
 
   double psnr = 0.0;
 
-  rtc::scoped_refptr<I420Buffer> res_i420_buffer = I420Buffer::Create(
-      width_, height_, width_, (width_ + 1) / 2, (width_ + 1) / 2);
+  rtc::scoped_refptr<I420Buffer> res_i420_buffer =
+      I420Buffer::Create(width_, height_);
 
   printf("\nConvert #%d I420 <-> I420 \n", j);
   std::unique_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]);
@@ -103,7 +103,8 @@
   if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) {
     return;
   }
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   EXPECT_EQ(48.0, psnr);
   j++;
 
@@ -125,7 +126,8 @@
   if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) {
     return;
   }
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
 
   // Optimization Speed- quality trade-off => 45 dB only (platform dependant).
   EXPECT_GT(ceil(psnr), 44);
@@ -138,7 +140,8 @@
   EXPECT_EQ(0,
             ConvertToI420(VideoType::kUYVY, out_uyvy_buffer.get(), 0, 0, width_,
                           height_, 0, kVideoRotation_0, res_i420_buffer.get()));
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   EXPECT_EQ(48.0, psnr);
   if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) {
     return;
@@ -158,7 +161,8 @@
     return;
   }
 
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   EXPECT_EQ(48.0, psnr);
 
   printf("\nConvert #%d I420 <-> RGB565\n", j);
@@ -175,7 +179,8 @@
   }
   j++;
 
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   // TODO(leozwang) Investigate the right psnr should be set for I420ToRGB565,
   // Another example is I420ToRGB24, the psnr is 44
   // TODO(mikhal): Add psnr for RGB565, 1555, 4444, convert to ARGB.
@@ -195,7 +200,8 @@
     return;
   }
 
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   // TODO(leozwang) Investigate the right psnr should be set for
   // I420ToARGB8888,
   EXPECT_GT(ceil(psnr), 42);
@@ -228,7 +234,8 @@
   if (PrintVideoFrame(*res_i420_buffer, output_file) < 0) {
     return;
   }
-  psnr = I420PSNR(*orig_frame_->video_frame_buffer(), *res_i420_buffer);
+  psnr =
+      I420PSNR(*orig_frame_->video_frame_buffer()->GetI420(), *res_i420_buffer);
   EXPECT_EQ(48.0, psnr);
 }
 
@@ -241,7 +248,8 @@
   int stride_uv;
 
   // Assume compact layout, no padding.
-  const uint8_t *orig_buffer = orig_frame_->video_frame_buffer()->DataY();
+  const uint8_t* orig_buffer =
+      orig_frame_->video_frame_buffer()->GetI420()->DataY();
 
   Calc16ByteAlignedStride(rotated_width, &stride_y, &stride_uv);
   rtc::scoped_refptr<I420Buffer> rotated_res_i420_buffer = I420Buffer::Create(
@@ -252,8 +260,7 @@
   EXPECT_EQ(
       0, ConvertToI420(VideoType::kI420, orig_buffer, 0, 0, width_, height_, 0,
                        kVideoRotation_270, rotated_res_i420_buffer.get()));
-  rotated_res_i420_buffer = I420Buffer::Create(
-      width_, height_, width_, (width_ + 1) / 2, (width_ + 1) / 2);
+  rotated_res_i420_buffer = I420Buffer::Create(width_, height_);
   EXPECT_EQ(
       0, ConvertToI420(VideoType::kI420, orig_buffer, 0, 0, width_, height_, 0,
                        kVideoRotation_180, rotated_res_i420_buffer.get()));
diff --git a/webrtc/common_video/libyuv/webrtc_libyuv.cc b/webrtc/common_video/libyuv/webrtc_libyuv.cc
index fd08029..2f60e09 100644
--- a/webrtc/common_video/libyuv/webrtc_libyuv.cc
+++ b/webrtc/common_video/libyuv/webrtc_libyuv.cc
@@ -70,11 +70,11 @@
 }
 
 // TODO(nisse): Belongs with the test code?
-int PrintVideoFrame(const VideoFrameBuffer& frame, FILE* file) {
+int PrintVideoFrame(const I420BufferInterface& frame, FILE* file) {
   int width = frame.width();
   int height = frame.height();
-  int chroma_width = (width + 1) / 2;
-  int chroma_height = (height + 1) / 2;
+  int chroma_width = frame.ChromaWidth();
+  int chroma_height = frame.ChromaHeight();
 
   if (PrintPlane(frame.DataY(), width, height,
                  frame.StrideY(), file) < 0) {
@@ -94,10 +94,10 @@
 }
 
 int PrintVideoFrame(const VideoFrame& frame, FILE* file) {
-  return PrintVideoFrame(*frame.video_frame_buffer(), file);
+  return PrintVideoFrame(*frame.video_frame_buffer()->ToI420(), file);
 }
 
-int ExtractBuffer(const rtc::scoped_refptr<VideoFrameBuffer>& input_frame,
+int ExtractBuffer(const rtc::scoped_refptr<I420BufferInterface>& input_frame,
                   size_t size,
                   uint8_t* buffer) {
   RTC_DCHECK(buffer);
@@ -110,8 +110,8 @@
      return -1;
   }
 
-  int chroma_width = (width + 1) / 2;
-  int chroma_height = (height + 1) / 2;
+  int chroma_width = input_frame->ChromaWidth();
+  int chroma_height = input_frame->ChromaHeight();
 
   libyuv::I420Copy(input_frame->DataY(),
                    input_frame->StrideY(),
@@ -129,7 +129,8 @@
 }
 
 int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) {
-  return ExtractBuffer(input_frame.video_frame_buffer(), size, buffer);
+  return ExtractBuffer(input_frame.video_frame_buffer()->ToI420(), size,
+                       buffer);
 }
 
 int ConvertNV12ToRGB565(const uint8_t* src_frame,
@@ -240,21 +241,18 @@
                     VideoType dst_video_type,
                     int dst_sample_size,
                     uint8_t* dst_frame) {
+  rtc::scoped_refptr<I420BufferInterface> i420_buffer =
+      src_frame.video_frame_buffer()->ToI420();
   return libyuv::ConvertFromI420(
-      src_frame.video_frame_buffer()->DataY(),
-      src_frame.video_frame_buffer()->StrideY(),
-      src_frame.video_frame_buffer()->DataU(),
-      src_frame.video_frame_buffer()->StrideU(),
-      src_frame.video_frame_buffer()->DataV(),
-      src_frame.video_frame_buffer()->StrideV(),
-      dst_frame, dst_sample_size,
-      src_frame.width(), src_frame.height(),
+      i420_buffer->DataY(), i420_buffer->StrideY(), i420_buffer->DataU(),
+      i420_buffer->StrideU(), i420_buffer->DataV(), i420_buffer->StrideV(),
+      dst_frame, dst_sample_size, src_frame.width(), src_frame.height(),
       ConvertVideoType(dst_video_type));
 }
 
 // Compute PSNR for an I420 frame (all planes). Can upscale test frame.
-double I420PSNR(const VideoFrameBuffer& ref_buffer,
-                const VideoFrameBuffer& test_buffer) {
+double I420PSNR(const I420BufferInterface& ref_buffer,
+                const I420BufferInterface& test_buffer) {
   RTC_DCHECK_GE(ref_buffer.width(), test_buffer.width());
   RTC_DCHECK_GE(ref_buffer.height(), test_buffer.height());
   if ((ref_buffer.width() != test_buffer.width()) ||
@@ -279,13 +277,13 @@
 double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
   if (!ref_frame || !test_frame)
     return -1;
-  return I420PSNR(*ref_frame->video_frame_buffer(),
-                  *test_frame->video_frame_buffer());
+  return I420PSNR(*ref_frame->video_frame_buffer()->ToI420(),
+                  *test_frame->video_frame_buffer()->ToI420());
 }
 
 // Compute SSIM for an I420 frame (all planes). Can upscale test_buffer.
-double I420SSIM(const VideoFrameBuffer& ref_buffer,
-                const VideoFrameBuffer& test_buffer) {
+double I420SSIM(const I420BufferInterface& ref_buffer,
+                const I420BufferInterface& test_buffer) {
   RTC_DCHECK_GE(ref_buffer.width(), test_buffer.width());
   RTC_DCHECK_GE(ref_buffer.height(), test_buffer.height());
   if ((ref_buffer.width() != test_buffer.width()) ||
@@ -305,8 +303,8 @@
 double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) {
   if (!ref_frame || !test_frame)
     return -1;
-  return I420SSIM(*ref_frame->video_frame_buffer(),
-                  *test_frame->video_frame_buffer());
+  return I420SSIM(*ref_frame->video_frame_buffer()->ToI420(),
+                  *test_frame->video_frame_buffer()->ToI420());
 }
 
 void NV12Scale(std::vector<uint8_t>* tmp_buffer,
diff --git a/webrtc/examples/peerconnection/client/linux/main_wnd.cc b/webrtc/examples/peerconnection/client/linux/main_wnd.cc
index 55a59ae..151faaa 100644
--- a/webrtc/examples/peerconnection/client/linux/main_wnd.cc
+++ b/webrtc/examples/peerconnection/client/linux/main_wnd.cc
@@ -523,8 +523,8 @@
     const webrtc::VideoFrame& video_frame) {
   gdk_threads_enter();
 
-  rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
-      video_frame.video_frame_buffer());
+  rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
+      video_frame.video_frame_buffer()->ToI420());
   if (video_frame.rotation() != webrtc::kVideoRotation_0) {
     buffer = webrtc::I420Buffer::Rotate(*buffer, video_frame.rotation());
   }
diff --git a/webrtc/examples/peerconnection/client/main_wnd.cc b/webrtc/examples/peerconnection/client/main_wnd.cc
index a869f5b..e7c4c6e 100644
--- a/webrtc/examples/peerconnection/client/main_wnd.cc
+++ b/webrtc/examples/peerconnection/client/main_wnd.cc
@@ -606,8 +606,8 @@
   {
     AutoLock<VideoRenderer> lock(this);
 
-    rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
-        video_frame.video_frame_buffer());
+    rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
+        video_frame.video_frame_buffer()->ToI420());
     if (video_frame.rotation() != webrtc::kVideoRotation_0) {
       buffer = webrtc::I420Buffer::Rotate(*buffer, video_frame.rotation());
     }
diff --git a/webrtc/media/base/adaptedvideotracksource.cc b/webrtc/media/base/adaptedvideotracksource.cc
index 7a3e9f2..9513be8 100644
--- a/webrtc/media/base/adaptedvideotracksource.cc
+++ b/webrtc/media/base/adaptedvideotracksource.cc
@@ -45,12 +45,11 @@
      true was just added. The VideoBroadcaster enforces
      synchronization for us in this case, by not passing the frame on
      to sinks which don't want it. */
-  if (apply_rotation() &&
-      frame.rotation() != webrtc::kVideoRotation_0 &&
-      !buffer->native_handle()) {
+  if (apply_rotation() && frame.rotation() != webrtc::kVideoRotation_0 &&
+      buffer->type() == webrtc::VideoFrameBuffer::Type::kI420) {
     /* Apply pending rotation. */
     broadcaster_.OnFrame(webrtc::VideoFrame(
-        webrtc::I420Buffer::Rotate(*buffer, frame.rotation()),
+        webrtc::I420Buffer::Rotate(*buffer->GetI420(), frame.rotation()),
         webrtc::kVideoRotation_0, frame.timestamp_us()));
   } else {
     broadcaster_.OnFrame(frame);
diff --git a/webrtc/media/base/videocapturer.cc b/webrtc/media/base/videocapturer.cc
index 704840b..df1eafc 100644
--- a/webrtc/media/base/videocapturer.cc
+++ b/webrtc/media/base/videocapturer.cc
@@ -205,17 +205,17 @@
   if (apply_rotation_ && frame.rotation() != webrtc::kVideoRotation_0) {
     rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer(
         frame.video_frame_buffer());
-    if (buffer->native_handle()) {
-      // Sources producing native frames must handle apply_rotation
+    if (buffer->type() != webrtc::VideoFrameBuffer::Type::kI420) {
+      // Sources producing non-I420 frames must handle apply_rotation
       // themselves. But even if they do, we may occasionally end up
       // in this case, for frames in flight at the time
       // applied_rotation is set to true. In that case, we just drop
       // the frame.
-      LOG(LS_WARNING) << "Native frame requiring rotation. Discarding.";
+      LOG(LS_WARNING) << "Non-I420 frame requiring rotation. Discarding.";
       return;
     }
     broadcaster_.OnFrame(webrtc::VideoFrame(
-        webrtc::I420Buffer::Rotate(*buffer, frame.rotation()),
+        webrtc::I420Buffer::Rotate(*buffer->GetI420(), frame.rotation()),
         webrtc::kVideoRotation_0, frame.timestamp_us()));
   } else {
     broadcaster_.OnFrame(frame);
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
index 8a310c1..f919ced 100644
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor.cc
@@ -256,7 +256,7 @@
       << "Must process frames without gaps.";
   RTC_DCHECK(initialized_) << "Attempting to use uninitialized VideoProcessor";
 
-  rtc::scoped_refptr<VideoFrameBuffer> buffer(
+  rtc::scoped_refptr<I420BufferInterface> buffer(
       analysis_frame_reader_->ReadFrame());
 
   if (!buffer) {
@@ -483,12 +483,7 @@
     rtc::scoped_refptr<I420Buffer> scaled_buffer(I420Buffer::Create(
         config_.codec_settings->width, config_.codec_settings->height));
     // Should be the same aspect ratio, no cropping needed.
-    if (image.video_frame_buffer()->native_handle()) {
-      scaled_buffer->ScaleFrom(
-          *image.video_frame_buffer()->NativeToI420Buffer());
-    } else {
-      scaled_buffer->ScaleFrom(*image.video_frame_buffer());
-    }
+    scaled_buffer->ScaleFrom(*image.video_frame_buffer()->ToI420());
 
     size_t length = CalcBufferSize(VideoType::kI420, scaled_buffer->width(),
                                    scaled_buffer->height());
@@ -500,14 +495,8 @@
     size_t length =
         CalcBufferSize(VideoType::kI420, image.width(), image.height());
     extracted_buffer.SetSize(length);
-    if (image.video_frame_buffer()->native_handle()) {
-      extracted_length =
-          ExtractBuffer(image.video_frame_buffer()->NativeToI420Buffer(),
-                        length, extracted_buffer.data());
-    } else {
-      extracted_length = ExtractBuffer(image.video_frame_buffer(), length,
-                                       extracted_buffer.data());
-    }
+    extracted_length = ExtractBuffer(image.video_frame_buffer()->ToI420(),
+                                     length, extracted_buffer.data());
   }
 
   RTC_DCHECK_EQ(extracted_length, analysis_frame_writer_->FrameLength());
diff --git a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
index c3453d8..a3db4fd 100644
--- a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
+++ b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
@@ -157,7 +157,7 @@
     // Processing only one frame.
     source_file_ = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb");
     ASSERT_TRUE(source_file_ != nullptr);
-    rtc::scoped_refptr<VideoFrameBuffer> compact_buffer(
+    rtc::scoped_refptr<I420BufferInterface> compact_buffer(
         test::ReadI420Buffer(kWidth, kHeight, source_file_));
     ASSERT_TRUE(compact_buffer);
     codec_settings_.width = kWidth;
diff --git a/webrtc/sdk/objc/Framework/Classes/Video/avfoundationvideocapturer.mm b/webrtc/sdk/objc/Framework/Classes/Video/avfoundationvideocapturer.mm
index 2b2ea2a..a060b51 100644
--- a/webrtc/sdk/objc/Framework/Classes/Video/avfoundationvideocapturer.mm
+++ b/webrtc/sdk/objc/Framework/Classes/Video/avfoundationvideocapturer.mm
@@ -160,8 +160,7 @@
   // Applying rotation is only supported for legacy reasons and performance is
   // not critical here.
   if (apply_rotation() && rotation != kVideoRotation_0) {
-    buffer = I420Buffer::Rotate(*buffer->NativeToI420Buffer(),
-                                rotation);
+    buffer = I420Buffer::Rotate(*buffer->ToI420(), rotation);
     if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
       std::swap(captured_width, captured_height);
     }
diff --git a/webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.mm b/webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.mm
index 1cc772f..387bb1b 100644
--- a/webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.mm
+++ b/webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.mm
@@ -53,7 +53,8 @@
     // Adapted I420 frame.
     // TODO(magjed): Optimize this I420 path.
     rtc::scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(adapted_width, adapted_height);
-    i420_buffer->CropAndScaleFrom(*frame.videoBuffer, crop_x, crop_y, crop_width, crop_height);
+    i420_buffer->CropAndScaleFrom(
+        *frame.videoBuffer->ToI420(), crop_x, crop_y, crop_width, crop_height);
     buffer = i420_buffer;
   }
 
@@ -61,7 +62,7 @@
   // not critical here.
   webrtc::VideoRotation rotation = static_cast<webrtc::VideoRotation>(frame.rotation);
   if (apply_rotation() && rotation != kVideoRotation_0) {
-    buffer = I420Buffer::Rotate(*buffer->NativeToI420Buffer(), rotation);
+    buffer = I420Buffer::Rotate(*buffer->ToI420(), rotation);
     rotation = kVideoRotation_0;
   }
 
diff --git a/webrtc/test/testsupport/metrics/video_metrics.cc b/webrtc/test/testsupport/metrics/video_metrics.cc
index 2895337..e150f36 100644
--- a/webrtc/test/testsupport/metrics/video_metrics.cc
+++ b/webrtc/test/testsupport/metrics/video_metrics.cc
@@ -38,8 +38,8 @@
 
 // Calculates metrics for a frame and adds statistics to the result for it.
 void CalculateFrame(VideoMetricsType video_metrics_type,
-                    const VideoFrameBuffer& ref,
-                    const VideoFrameBuffer& test,
+                    const I420BufferInterface& ref,
+                    const I420BufferInterface& test,
                     int frame_number,
                     QualityMetricsResult* result) {
   FrameResult frame_result = {0, 0};
diff --git a/webrtc/test/video_capturer.cc b/webrtc/test/video_capturer.cc
index c8b3826..d0b5c37 100644
--- a/webrtc/test/video_capturer.cc
+++ b/webrtc/test/video_capturer.cc
@@ -37,7 +37,7 @@
     // return scaled version.
     rtc::scoped_refptr<I420Buffer> scaled_buffer =
         I420Buffer::Create(out_width, out_height);
-    scaled_buffer->ScaleFrom(*frame.video_frame_buffer().get());
+    scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420());
     out_frame.emplace(
         VideoFrame(scaled_buffer, kVideoRotation_0, frame.timestamp_us()));
   } else {