Unify underlying frame buffer in I420VideoFrame and WebRtcVideoFrame

Currently, I420VideoFrame uses three webrtc::Plane to store pixel data, and WebRtcVideoFrame uses WebRtcVideoFrame::FrameBuffer/webrtc::VideoFrame. The two subclasses WebRtcTextureVideoFrame and TextureVideoFrame use a NativeHandle to store pixel data, and there is also a class WebRtcVideoRenderFrame that wraps an I420VideoFrame.

This CL replaces these classes with a new interface VideoFrameBuffer that provides the common functionality. This makes it possible to remove deep frame copies between cricket::VideoFrame and I420VideoFrame.

Some additional minor changes are:
* Disallow creation of 0x0 texture frames.
* Remove the half-implemented ref count functions in I420VideoFrame.
* Remove the Alias functionality in WebRtcVideoFrame

The final goal is to eliminate all frame copies, but to limit the scope of this CL, some planned changes are postponed to follow-up CL:s (see planned changes in https://webrtc-codereview.appspot.com/38879004, or https://docs.google.com/document/d/1bxoJZNmlo-Z9GnQwIaWpEG6hDlL_W-bzka8Zb_K2NbA/preview). Specifically, this CL:
* Keeps empty subclasses WebRtcTextureVideoFrame and TextureVideoFrame, and just delegates the construction to the superclass.
* Keeps the deep copies from cricket::VideoFrame to I420VideoFrame.

BUG=1128
R=mflodman@webrtc.org, pbos@webrtc.org, perkj@webrtc.org, tommi@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/42469004

Cr-Original-Commit-Position: refs/heads/master@{#8580}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: c8895aa2f31e05d3bd4d29507af3bbfcaa638499
diff --git a/base/checks.h b/base/checks.h
index f64d273..82d6533 100644
--- a/base/checks.h
+++ b/base/checks.h
@@ -185,6 +185,9 @@
 #define DCHECK_GT(v1, v2) EAT_STREAM_PARAMETERS((v1) > (v2))
 #endif
 
+#define RTC_UNREACHABLE_CODE_HIT false
+#define NOTREACHED() DCHECK(RTC_UNREACHABLE_CODE_HIT)
+
 // This is identical to LogMessageVoidify but in name.
 class FatalMessageVoidify {
  public:
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index 32a9f2c..06a4b7e 100644
--- a/common_video/BUILD.gn
+++ b/common_video/BUILD.gn
@@ -21,13 +21,13 @@
     "interface/i420_video_frame.h",
     "interface/native_handle.h",
     "interface/texture_video_frame.h",
+    "interface/video_frame_buffer.h",
     "libyuv/include/scaler.h",
     "libyuv/include/webrtc_libyuv.h",
     "libyuv/scaler.cc",
     "libyuv/webrtc_libyuv.cc",
-    "plane.cc",
-    "plane.h",
-    "texture_video_frame.cc"
+    "texture_video_frame.cc",
+    "video_frame_buffer.cc",
   ]
 
   include_dirs = [ "../modules/interface" ]
diff --git a/common_video/common_video.gyp b/common_video/common_video.gyp
index ee04fc7..5945ddb 100644
--- a/common_video/common_video.gyp
+++ b/common_video/common_video.gyp
@@ -42,14 +42,14 @@
         'interface/i420_video_frame.h',
         'interface/native_handle.h',
         'interface/texture_video_frame.h',
+        'interface/video_frame_buffer.h',
         'i420_video_frame.cc',
         'libyuv/include/webrtc_libyuv.h',
         'libyuv/include/scaler.h',
         'libyuv/webrtc_libyuv.cc',
         'libyuv/scaler.cc',
-        'plane.h',
-        'plane.cc',
-        'texture_video_frame.cc'
+        'texture_video_frame.cc',
+        'video_frame_buffer.cc',
       ],
     },
   ],  # targets
diff --git a/common_video/common_video_unittests.gyp b/common_video/common_video_unittests.gyp
index 2b896c6..a7e51ee 100644
--- a/common_video/common_video_unittests.gyp
+++ b/common_video/common_video_unittests.gyp
@@ -22,7 +22,6 @@
         'i420_video_frame_unittest.cc',
         'libyuv/libyuv_unittest.cc',
         'libyuv/scaler_unittest.cc',
-        'plane_unittest.cc',
         'texture_video_frame_unittest.cc'
       ],
       # Disable warnings to enable Win64 build, issue 1323.
diff --git a/common_video/i420_video_frame.cc b/common_video/i420_video_frame.cc
index d956970..b3943d5 100644
--- a/common_video/i420_video_frame.cc
+++ b/common_video/i420_video_frame.cc
@@ -14,37 +14,59 @@
 
 #include <algorithm>  // swap
 
+#include "webrtc/base/checks.h"
+
 namespace webrtc {
 
 I420VideoFrame::I420VideoFrame()
-    : width_(0),
-      height_(0),
-      timestamp_(0),
+    : timestamp_(0),
       ntp_time_ms_(0),
       render_time_ms_(0),
       rotation_(kVideoRotation_0) {
 }
 
+I420VideoFrame::I420VideoFrame(
+    const rtc::scoped_refptr<VideoFrameBuffer>& buffer,
+    uint32_t timestamp,
+    int64_t render_time_ms,
+    VideoRotation rotation)
+    : video_frame_buffer_(buffer),
+      timestamp_(timestamp),
+      ntp_time_ms_(0),
+      render_time_ms_(render_time_ms),
+      rotation_(rotation) {
+}
+
 I420VideoFrame::~I420VideoFrame() {}
 
 int I420VideoFrame::CreateEmptyFrame(int width, int height,
                                      int stride_y, int stride_u, int stride_v) {
-  if (CheckDimensions(width, height, stride_y, stride_u, stride_v) < 0)
+  const int half_width = (width + 1) / 2;
+  if (width <= 0 || height <= 0 || stride_y < width || stride_u < half_width ||
+      stride_v < half_width) {
     return -1;
-  int size_y = stride_y * height;
-  int half_height = (height + 1) / 2;
-  int size_u = stride_u * half_height;
-  int size_v = stride_v * half_height;
-  width_ = width;
-  height_ = height;
-  y_plane_.CreateEmptyPlane(size_y, stride_y, size_y);
-  u_plane_.CreateEmptyPlane(size_u, stride_u, size_u);
-  v_plane_.CreateEmptyPlane(size_v, stride_v, size_v);
+  }
   // Creating empty frame - reset all values.
   timestamp_ = 0;
   ntp_time_ms_ = 0;
   render_time_ms_ = 0;
   rotation_ = kVideoRotation_0;
+
+  // Check if it's safe to reuse allocation.
+  if (video_frame_buffer_ &&
+      video_frame_buffer_->HasOneRef() &&
+      !video_frame_buffer_->native_handle() &&
+      width == video_frame_buffer_->width() &&
+      height == video_frame_buffer_->height() &&
+      stride_y == stride(kYPlane) &&
+      stride_u == stride(kUPlane) &&
+      stride_v == stride(kVPlane)) {
+    return 0;
+  }
+
+  // Need to allocate new buffer.
+  video_frame_buffer_ = new rtc::RefCountedObject<I420Buffer>(
+      width, height, stride_y, stride_u, stride_v);
   return 0;
 }
 
@@ -70,31 +92,35 @@
                                 int stride_u,
                                 int stride_v,
                                 VideoRotation rotation) {
-  if (size_y < 1 || size_u < 1 || size_v < 1)
+  const int half_height = (height + 1) / 2;
+  const int expected_size_y = height * stride_y;
+  const int expected_size_u = half_height * stride_u;
+  const int expected_size_v = half_height * stride_v;
+  CHECK_GE(size_y, expected_size_y);
+  CHECK_GE(size_u, expected_size_u);
+  CHECK_GE(size_v, expected_size_v);
+  if (CreateEmptyFrame(width, height, stride_y, stride_u, stride_v) < 0)
     return -1;
-  if (CheckDimensions(width, height, stride_y, stride_u, stride_v) < 0)
-    return -1;
-  y_plane_.Copy(size_y, stride_y, buffer_y);
-  u_plane_.Copy(size_u, stride_u, buffer_u);
-  v_plane_.Copy(size_v, stride_v, buffer_v);
-  width_ = width;
-  height_ = height;
+  memcpy(buffer(kYPlane), buffer_y, expected_size_y);
+  memcpy(buffer(kUPlane), buffer_u, expected_size_u);
+  memcpy(buffer(kVPlane), buffer_v, expected_size_v);
   rotation_ = rotation;
   return 0;
 }
 
 int I420VideoFrame::CopyFrame(const I420VideoFrame& videoFrame) {
-  int ret = CreateFrame(videoFrame.allocated_size(kYPlane),
-                        videoFrame.buffer(kYPlane),
-                        videoFrame.allocated_size(kUPlane),
-                        videoFrame.buffer(kUPlane),
-                        videoFrame.allocated_size(kVPlane),
-                        videoFrame.buffer(kVPlane),
-                        videoFrame.width_, videoFrame.height_,
-                        videoFrame.stride(kYPlane), videoFrame.stride(kUPlane),
-                        videoFrame.stride(kVPlane));
-  if (ret < 0)
-    return ret;
+  if (videoFrame.native_handle()) {
+    video_frame_buffer_ = videoFrame.video_frame_buffer();
+  } else {
+    int ret = CreateFrame(
+        videoFrame.allocated_size(kYPlane), videoFrame.buffer(kYPlane),
+        videoFrame.allocated_size(kUPlane), videoFrame.buffer(kUPlane),
+        videoFrame.allocated_size(kVPlane), videoFrame.buffer(kVPlane),
+        videoFrame.width(), videoFrame.height(), videoFrame.stride(kYPlane),
+        videoFrame.stride(kUPlane), videoFrame.stride(kVPlane));
+    if (ret < 0)
+      return ret;
+  }
   timestamp_ = videoFrame.timestamp_;
   ntp_time_ms_ = videoFrame.ntp_time_ms_;
   render_time_ms_ = videoFrame.render_time_ms_;
@@ -112,11 +138,7 @@
 }
 
 void I420VideoFrame::SwapFrame(I420VideoFrame* videoFrame) {
-  y_plane_.Swap(videoFrame->y_plane_);
-  u_plane_.Swap(videoFrame->u_plane_);
-  v_plane_.Swap(videoFrame->v_plane_);
-  std::swap(width_, videoFrame->width_);
-  std::swap(height_, videoFrame->height_);
+  video_frame_buffer_.swap(videoFrame->video_frame_buffer_);
   std::swap(timestamp_, videoFrame->timestamp_);
   std::swap(ntp_time_ms_, videoFrame->ntp_time_ms_);
   std::swap(render_time_ms_, videoFrame->render_time_ms_);
@@ -124,75 +146,43 @@
 }
 
 uint8_t* I420VideoFrame::buffer(PlaneType type) {
-  Plane* plane_ptr = GetPlane(type);
-  if (plane_ptr)
-    return plane_ptr->buffer();
-  return NULL;
+  return video_frame_buffer_ ? video_frame_buffer_->data(type) : nullptr;
 }
 
 const uint8_t* I420VideoFrame::buffer(PlaneType type) const {
-  const Plane* plane_ptr = GetPlane(type);
-  if (plane_ptr)
-    return plane_ptr->buffer();
-  return NULL;
+  // Const cast to call the correct const-version of data.
+  const VideoFrameBuffer* const_buffer = video_frame_buffer_.get();
+  return const_buffer ? const_buffer->data(type) : nullptr;
 }
 
 int I420VideoFrame::allocated_size(PlaneType type) const {
-  const Plane* plane_ptr = GetPlane(type);
-    if (plane_ptr)
-      return plane_ptr->allocated_size();
-  return -1;
+  const int plane_height = (type == kYPlane) ? height() : (height() + 1) / 2;
+  return plane_height * stride(type);
 }
 
 int I420VideoFrame::stride(PlaneType type) const {
-  const Plane* plane_ptr = GetPlane(type);
-  if (plane_ptr)
-    return plane_ptr->stride();
-  return -1;
+  return video_frame_buffer_ ? video_frame_buffer_->stride(type) : 0;
+}
+
+int I420VideoFrame::width() const {
+  return video_frame_buffer_ ? video_frame_buffer_->width() : 0;
+}
+
+int I420VideoFrame::height() const {
+  return video_frame_buffer_ ? video_frame_buffer_->height() : 0;
 }
 
 bool I420VideoFrame::IsZeroSize() const {
-  return (y_plane_.IsZeroSize() && u_plane_.IsZeroSize() &&
-    v_plane_.IsZeroSize());
+  return !video_frame_buffer_;
 }
 
-void* I420VideoFrame::native_handle() const { return NULL; }
-
-int I420VideoFrame::CheckDimensions(int width, int height,
-                                    int stride_y, int stride_u, int stride_v) {
-  int half_width = (width + 1) / 2;
-  if (width < 1 || height < 1 ||
-      stride_y < width || stride_u < half_width || stride_v < half_width)
-    return -1;
-  return 0;
+void* I420VideoFrame::native_handle() const {
+  return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr;
 }
 
-const Plane* I420VideoFrame::GetPlane(PlaneType type) const {
-  switch (type) {
-    case kYPlane :
-      return &y_plane_;
-    case kUPlane :
-      return &u_plane_;
-    case kVPlane :
-      return &v_plane_;
-    default:
-      assert(false);
-  }
-  return NULL;
-}
-
-Plane* I420VideoFrame::GetPlane(PlaneType type) {
-  switch (type) {
-    case kYPlane :
-      return &y_plane_;
-    case kUPlane :
-      return &u_plane_;
-    case kVPlane :
-      return &v_plane_;
-    default:
-      assert(false);
-  }
-  return NULL;
+rtc::scoped_refptr<VideoFrameBuffer> I420VideoFrame::video_frame_buffer()
+    const {
+  return video_frame_buffer_;
 }
 
 }  // namespace webrtc
diff --git a/common_video/i420_video_frame_unittest.cc b/common_video/i420_video_frame_unittest.cc
index 47017ef..45e9016 100644
--- a/common_video/i420_video_frame_unittest.cc
+++ b/common_video/i420_video_frame_unittest.cc
@@ -14,8 +14,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/common_video/interface/i420_video_frame.h"
-#include "webrtc/system_wrappers/interface/ref_count.h"
-#include "webrtc/system_wrappers/interface/scoped_refptr.h"
 
 namespace webrtc {
 
@@ -237,15 +235,30 @@
   EXPECT_TRUE(EqualFrames(frame2_copy, frame1));
 }
 
-TEST(TestI420VideoFrame, RefCountedInstantiation) {
-  // Refcounted instantiation - ref_count should correspond to the number of
-  // instances.
-  scoped_refptr<I420VideoFrame> ref_count_frame(
-      new RefCountImpl<I420VideoFrame>());
-  EXPECT_EQ(2, ref_count_frame->AddRef());
-  EXPECT_EQ(3, ref_count_frame->AddRef());
-  EXPECT_EQ(2, ref_count_frame->Release());
-  EXPECT_EQ(1, ref_count_frame->Release());
+TEST(TestI420VideoFrame, ReuseAllocation) {
+  I420VideoFrame frame;
+  frame.CreateEmptyFrame(640, 320, 640, 320, 320);
+  const uint8_t* y = frame.buffer(kYPlane);
+  const uint8_t* u = frame.buffer(kUPlane);
+  const uint8_t* v = frame.buffer(kVPlane);
+  frame.CreateEmptyFrame(640, 320, 640, 320, 320);
+  EXPECT_EQ(y, frame.buffer(kYPlane));
+  EXPECT_EQ(u, frame.buffer(kUPlane));
+  EXPECT_EQ(v, frame.buffer(kVPlane));
+}
+
+TEST(TestI420VideoFrame, FailToReuseAllocation) {
+  I420VideoFrame frame1;
+  frame1.CreateEmptyFrame(640, 320, 640, 320, 320);
+  const uint8_t* y = frame1.buffer(kYPlane);
+  const uint8_t* u = frame1.buffer(kUPlane);
+  const uint8_t* v = frame1.buffer(kVPlane);
+  // Make a shallow copy of |frame1|.
+  I420VideoFrame frame2(frame1.video_frame_buffer(), 0, 0, kVideoRotation_0);
+  frame1.CreateEmptyFrame(640, 320, 640, 320, 320);
+  EXPECT_NE(y, frame1.buffer(kYPlane));
+  EXPECT_NE(u, frame1.buffer(kUPlane));
+  EXPECT_NE(v, frame1.buffer(kVPlane));
 }
 
 bool EqualPlane(const uint8_t* data1,
diff --git a/common_video/interface/texture_video_frame.h b/common_video/interface/texture_video_frame.h
index 225a0ec..fbd722f 100644
--- a/common_video/interface/texture_video_frame.h
+++ b/common_video/interface/texture_video_frame.h
@@ -17,7 +17,6 @@
 
 #include "webrtc/common_video/interface/i420_video_frame.h"
 #include "webrtc/common_video/interface/native_handle.h"
-#include "webrtc/system_wrappers/interface/scoped_refptr.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
@@ -29,54 +28,6 @@
                     int height,
                     uint32_t timestamp,
                     int64_t render_time_ms);
-  virtual ~TextureVideoFrame();
-
-  // I420VideoFrame implementation
-  virtual int CreateEmptyFrame(int width,
-                               int height,
-                               int stride_y,
-                               int stride_u,
-                               int stride_v) OVERRIDE;
-  virtual int CreateFrame(int size_y,
-                          const uint8_t* buffer_y,
-                          int size_u,
-                          const uint8_t* buffer_u,
-                          int size_v,
-                          const uint8_t* buffer_v,
-                          int width,
-                          int height,
-                          int stride_y,
-                          int stride_u,
-                          int stride_v) OVERRIDE;
-  virtual int CreateFrame(int size_y,
-                          const uint8_t* buffer_y,
-                          int size_u,
-                          const uint8_t* buffer_u,
-                          int size_v,
-                          const uint8_t* buffer_v,
-                          int width,
-                          int height,
-                          int stride_y,
-                          int stride_u,
-                          int stride_v,
-                          webrtc::VideoRotation rotation) OVERRIDE;
-  virtual int CopyFrame(const I420VideoFrame& videoFrame) OVERRIDE;
-  virtual I420VideoFrame* CloneFrame() const OVERRIDE;
-  virtual void SwapFrame(I420VideoFrame* videoFrame) OVERRIDE;
-  virtual uint8_t* buffer(PlaneType type) OVERRIDE;
-  virtual const uint8_t* buffer(PlaneType type) const OVERRIDE;
-  virtual int allocated_size(PlaneType type) const OVERRIDE;
-  virtual int stride(PlaneType type) const OVERRIDE;
-  virtual bool IsZeroSize() const OVERRIDE;
-  virtual void* native_handle() const OVERRIDE;
-
- protected:
-  virtual int CheckDimensions(
-      int width, int height, int stride_y, int stride_u, int stride_v) OVERRIDE;
-
- private:
-  // An opaque handle that stores the underlying video frame.
-  scoped_refptr<NativeHandle> handle_;
 };
 
 }  // namespace webrtc
diff --git a/common_video/interface/video_frame_buffer.h b/common_video/interface/video_frame_buffer.h
new file mode 100644
index 0000000..9b6438a
--- /dev/null
+++ b/common_video/interface/video_frame_buffer.h
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (c) 2015 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 WEBRTC_VIDEO_FRAME_BUFFER_H_
+#define WEBRTC_VIDEO_FRAME_BUFFER_H_
+
+#include "webrtc/base/refcount.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/common_video/interface/native_handle.h"
+#include "webrtc/system_wrappers/interface/aligned_malloc.h"
+
+namespace webrtc {
+
+enum PlaneType {
+  kYPlane = 0,
+  kUPlane = 1,
+  kVPlane = 2,
+  kNumOfPlanes = 3,
+};
+
+// Interface of a simple frame buffer containing pixel data. This interface does
+// not contain any frame metadata such as rotation, timestamp, pixel_width, etc.
+class VideoFrameBuffer : public rtc::RefCountInterface {
+ public:
+  // Returns true if this buffer has a single exclusive owner.
+  virtual bool HasOneRef() const = 0;
+
+  // The resolution of the frame in pixels. For formats where some planes are
+  // subsampled, this is the highest-resolution plane.
+  virtual int width() const = 0;
+  virtual int height() const = 0;
+
+  // Returns pointer to the pixel data for a given plane. The memory is owned by
+  // the VideoFrameBuffer object and must not be freed by the caller.
+  virtual const uint8_t* data(PlaneType type) const = 0;
+
+  // Non-const data access is only allowed if |HasOneRef| is true.
+  virtual uint8_t* data(PlaneType type) = 0;
+
+  // Returns the number of bytes between successive rows for a given plane.
+  virtual int stride(PlaneType type) const = 0;
+
+  // Return the handle of the underlying video frame. This is used when the
+  // frame is backed by a texture.
+  virtual rtc::scoped_refptr<NativeHandle> native_handle() const = 0;
+
+ protected:
+  virtual ~VideoFrameBuffer();
+};
+
+// Plain I420 buffer in standard memory.
+class I420Buffer : public VideoFrameBuffer {
+ public:
+  I420Buffer(int width, int height);
+  I420Buffer(int width, int height, int stride_y, int stride_u, int stride_v);
+
+  int width() const override;
+  int height() const override;
+  const uint8_t* data(PlaneType type) const override;
+  uint8_t* data(PlaneType type) override;
+  int stride(PlaneType type) const override;
+  rtc::scoped_refptr<NativeHandle> native_handle() const override;
+
+ private:
+  friend class rtc::RefCountedObject<I420Buffer>;
+  ~I420Buffer() override;
+
+  const int width_;
+  const int height_;
+  const int stride_y_;
+  const int stride_u_;
+  const int stride_v_;
+  const rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> data_;
+};
+
+// Texture buffer around a NativeHandle.
+class TextureBuffer : public VideoFrameBuffer {
+ public:
+  TextureBuffer(const rtc::scoped_refptr<NativeHandle>& native_handle,
+                int width,
+                int height);
+
+  int width() const override;
+  int height() const override;
+  const uint8_t* data(PlaneType type) const override;
+  uint8_t* data(PlaneType type) override;
+  int stride(PlaneType type) const override;
+  rtc::scoped_refptr<NativeHandle> native_handle() const override;
+
+ private:
+  friend class rtc::RefCountedObject<TextureBuffer>;
+  ~TextureBuffer() override;
+
+  const rtc::scoped_refptr<NativeHandle> native_handle_;
+  const int width_;
+  const int height_;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_VIDEO_FRAME_BUFFER_H_
diff --git a/common_video/plane_unittest.cc b/common_video/plane_unittest.cc
deleted file mode 100644
index d165598..0000000
--- a/common_video/plane_unittest.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  Copyright (c) 2012 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 "webrtc/common_video/plane.h"
-
-#include <math.h>
-#include <string.h>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace webrtc {
-
-TEST(TestPlane, CreateEmptyPlaneValues) {
-  Plane plane;
-  int size, stride;
-  EXPECT_EQ(0, plane.allocated_size());
-  EXPECT_EQ(0, plane.stride());
-  EXPECT_TRUE(plane.IsZeroSize());
-  size = 0;
-  stride = 20;
-  EXPECT_EQ(-1, plane.CreateEmptyPlane(size, stride, 1));
-  EXPECT_EQ(-1, plane.CreateEmptyPlane(10, stride, size));
-  size  = 20;
-  stride = 0;
-  EXPECT_EQ(-1, plane.CreateEmptyPlane(size, stride, size));
-  stride = 20;
-  EXPECT_EQ(0, plane.CreateEmptyPlane(size, stride, size));
-  EXPECT_EQ(size, plane.allocated_size());
-  EXPECT_EQ(stride, plane.stride());
-  EXPECT_FALSE(plane.IsZeroSize());
-}
-
-TEST(TestPlane, ResetSize) {
-  Plane plane;
-  EXPECT_TRUE(plane.IsZeroSize());
-  int allocated_size, plane_size, stride;
-  EXPECT_EQ(0, plane.allocated_size());
-  allocated_size = 30;
-  plane_size = 20;
-  stride = 10;
-  EXPECT_EQ(0, plane.CreateEmptyPlane(allocated_size, stride, plane_size));
-  EXPECT_EQ(allocated_size, plane.allocated_size());
-  EXPECT_FALSE(plane.IsZeroSize());
-  plane.ResetSize();
-  EXPECT_TRUE(plane.IsZeroSize());
-}
-
-TEST(TestPlane, PlaneCopy) {
-  Plane plane1, plane2;
-  // Copy entire plane.
-  plane1.CreateEmptyPlane(100, 10, 100);
-  int size1 = plane1.allocated_size();
-  int size2 = 30;
-  plane2.CreateEmptyPlane(50, 15, size2);
-  int stride1 = plane1.stride();
-  int stride2 = plane2.stride();
-  plane1.Copy(plane2);
-  // Smaller size - keep buffer size as is.
-  EXPECT_EQ(size1, plane1.allocated_size());
-  EXPECT_EQ(stride2, plane1.stride());
-  plane2.Copy(plane1);
-  // Verify increment of allocated size.
-  EXPECT_EQ(plane1.allocated_size(), plane2.allocated_size());
-  EXPECT_EQ(stride2, plane2.stride());
-  // Copy buffer.
-  uint8_t buffer1[100];
-  size1 = 80;
-  memset(&buffer1, 0, size1);
-  plane2.Copy(size1, stride1, buffer1);
-  EXPECT_GE(plane2.allocated_size(), size1);
-  EXPECT_EQ(0, memcmp(buffer1, plane2.buffer(), size1));
-}
-
-TEST(TestPlane, PlaneSwap) {
-  Plane plane1, plane2;
-  int size1, size2, stride1, stride2;
-  plane1.CreateEmptyPlane(100, 10, 100);
-  plane2.CreateEmptyPlane(50, 15, 50);
-  size1 = plane1.allocated_size();
-  stride1 = plane1.stride();
-  stride2 = plane2.stride();
-  size2 = plane2.allocated_size();
-  plane1.Swap(plane2);
-  EXPECT_EQ(size1, plane2.allocated_size());
-  EXPECT_EQ(size2, plane1.allocated_size());
-  EXPECT_EQ(stride2, plane1.stride());
-  EXPECT_EQ(stride1, plane2.stride());
-}
-
-}  // namespace webrtc
diff --git a/common_video/texture_video_frame.cc b/common_video/texture_video_frame.cc
index 7772f12..4ae252d 100644
--- a/common_video/texture_video_frame.cc
+++ b/common_video/texture_video_frame.cc
@@ -10,7 +10,7 @@
 
 #include "webrtc/common_video/interface/texture_video_frame.h"
 
-#include <assert.h>
+#include "webrtc/base/refcount.h"
 
 namespace webrtc {
 
@@ -19,99 +19,11 @@
                                      int height,
                                      uint32_t timestamp,
                                      int64_t render_time_ms)
-    : handle_(handle) {
-  width_ = width;
-  height_ = height;
-  set_timestamp(timestamp);
-  set_render_time_ms(render_time_ms);
-}
-
-TextureVideoFrame::~TextureVideoFrame() {}
-
-int TextureVideoFrame::CreateEmptyFrame(int width,
-                                        int height,
-                                        int stride_y,
-                                        int stride_u,
-                                        int stride_v) {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-int TextureVideoFrame::CreateFrame(int size_y,
-                                   const uint8_t* buffer_y,
-                                   int size_u,
-                                   const uint8_t* buffer_u,
-                                   int size_v,
-                                   const uint8_t* buffer_v,
-                                   int width,
-                                   int height,
-                                   int stride_y,
-                                   int stride_u,
-                                   int stride_v) {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-int TextureVideoFrame::CreateFrame(int size_y,
-                                   const uint8_t* buffer_y,
-                                   int size_u,
-                                   const uint8_t* buffer_u,
-                                   int size_v,
-                                   const uint8_t* buffer_v,
-                                   int width,
-                                   int height,
-                                   int stride_y,
-                                   int stride_u,
-                                   int stride_v,
-                                   webrtc::VideoRotation rotation) {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-int TextureVideoFrame::CopyFrame(const I420VideoFrame& videoFrame) {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-I420VideoFrame* TextureVideoFrame::CloneFrame() const {
-  return new TextureVideoFrame(
-      handle_, width(), height(), timestamp(), render_time_ms());
-}
-
-void TextureVideoFrame::SwapFrame(I420VideoFrame* videoFrame) {
-  assert(false);  // Should not be called.
-}
-
-uint8_t* TextureVideoFrame::buffer(PlaneType type) {
-  assert(false);  // Should not be called.
-  return NULL;
-}
-
-const uint8_t* TextureVideoFrame::buffer(PlaneType type) const {
-  assert(false);  // Should not be called.
-  return NULL;
-}
-
-int TextureVideoFrame::allocated_size(PlaneType type) const {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-int TextureVideoFrame::stride(PlaneType type) const {
-  assert(false);  // Should not be called.
-  return -1;
-}
-
-bool TextureVideoFrame::IsZeroSize() const {
-  assert(false);  // Should not be called.
-  return true;
-}
-
-void* TextureVideoFrame::native_handle() const { return handle_.get(); }
-
-int TextureVideoFrame::CheckDimensions(
-    int width, int height, int stride_y, int stride_u, int stride_v) {
-  return 0;
+    : I420VideoFrame(
+          new rtc::RefCountedObject<TextureBuffer>(handle, width, height),
+          timestamp,
+          render_time_ms,
+          kVideoRotation_0) {
 }
 
 }  // namespace webrtc
diff --git a/common_video/video_frame_buffer.cc b/common_video/video_frame_buffer.cc
new file mode 100644
index 0000000..29048e9
--- /dev/null
+++ b/common_video/video_frame_buffer.cc
@@ -0,0 +1,136 @@
+/*
+ *  Copyright (c) 2015 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 "webrtc/common_video/interface/video_frame_buffer.h"
+
+#include "webrtc/base/checks.h"
+
+// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD.
+static const int kBufferAlignment = 64;
+
+namespace webrtc {
+
+VideoFrameBuffer::~VideoFrameBuffer() {}
+
+I420Buffer::I420Buffer(int width, int height)
+    : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {
+}
+
+I420Buffer::I420Buffer(int width,
+                       int height,
+                       int stride_y,
+                       int stride_u,
+                       int stride_v)
+    : width_(width),
+      height_(height),
+      stride_y_(stride_y),
+      stride_u_(stride_u),
+      stride_v_(stride_v),
+      data_(static_cast<uint8_t*>(AlignedMalloc(
+          stride_y * height + (stride_u + stride_v) * ((height + 1) / 2),
+          kBufferAlignment))) {
+  DCHECK_GT(width, 0);
+  DCHECK_GT(height, 0);
+  DCHECK_GE(stride_y, width);
+  DCHECK_GE(stride_u, (width + 1) / 2);
+  DCHECK_GE(stride_v, (width + 1) / 2);
+}
+
+I420Buffer::~I420Buffer() {
+}
+
+int I420Buffer::width() const {
+  return width_;
+}
+
+int I420Buffer::height() const {
+  return height_;
+}
+
+const uint8_t* I420Buffer::data(PlaneType type) const {
+  switch (type) {
+    case kYPlane:
+      return data_.get();
+    case kUPlane:
+      return data_.get() + stride_y_ * height_;
+    case kVPlane:
+      return data_.get() + stride_y_ * height_ +
+             stride_u_ * ((height_ + 1) / 2);
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+}
+
+uint8_t* I420Buffer::data(PlaneType type) {
+  DCHECK(HasOneRef());
+  return const_cast<uint8_t*>(
+      static_cast<const VideoFrameBuffer*>(this)->data(type));
+}
+
+int I420Buffer::stride(PlaneType type) const {
+  switch (type) {
+    case kYPlane:
+      return stride_y_;
+    case kUPlane:
+      return stride_u_;
+    case kVPlane:
+      return stride_v_;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+rtc::scoped_refptr<NativeHandle> I420Buffer::native_handle() const {
+  return nullptr;
+}
+
+TextureBuffer::TextureBuffer(
+    const rtc::scoped_refptr<NativeHandle>& native_handle,
+    int width,
+    int height)
+    : native_handle_(native_handle), width_(width), height_(height) {
+  DCHECK(native_handle.get());
+  DCHECK_GT(width, 0);
+  DCHECK_GT(height, 0);
+}
+
+TextureBuffer::~TextureBuffer() {
+}
+
+int TextureBuffer::width() const {
+  return width_;
+}
+
+int TextureBuffer::height() const {
+  return height_;
+}
+
+const uint8_t* TextureBuffer::data(PlaneType type) const {
+  NOTREACHED();  // Should not be called.
+  return nullptr;
+}
+
+uint8_t* TextureBuffer::data(PlaneType type) {
+  NOTREACHED();  // Should not be called.
+  return nullptr;
+}
+
+int TextureBuffer::stride(PlaneType type) const {
+  NOTREACHED();  // Should not be called.
+  return 0;
+}
+
+rtc::scoped_refptr<NativeHandle> TextureBuffer::native_handle() const {
+  return native_handle_;
+}
+
+}  // namespace webrtc
diff --git a/modules/interface/module_common_types.h b/modules/interface/module_common_types.h
index 5cb2c56..c36d8f1 100644
--- a/modules/interface/module_common_types.h
+++ b/modules/interface/module_common_types.h
@@ -394,232 +394,6 @@
   float spatial_pred_err_v;
 };
 
-/*************************************************
- *
- * VideoFrame class
- *
- * The VideoFrame class allows storing and
- * handling of video frames.
- *
- *
- *************************************************/
-class VideoFrame {
- public:
-  VideoFrame();
-  ~VideoFrame();
-  /**
-  * Verifies that current allocated buffer size is larger than or equal to the
-  * input size.
-  * If the current buffer size is smaller, a new allocation is made and the old
-  * buffer data
-  * is copied to the new buffer.
-  * Buffer size is updated to minimumSize.
-  */
-  int32_t VerifyAndAllocate(const size_t minimumSize);
-  /**
-  *    Update length of data buffer in frame. Function verifies that new length
-  * is less or
-  *    equal to allocated size.
-  */
-  int32_t SetLength(const size_t newLength);
-  /*
-  *    Swap buffer and size data
-  */
-  int32_t Swap(uint8_t*& newMemory, size_t& newLength, size_t& newSize);
-  /*
-  *    Swap buffer and size data
-  */
-  int32_t SwapFrame(VideoFrame& videoFrame);
-  /**
-  *    Copy buffer: If newLength is bigger than allocated size, a new buffer of
-  * size length
-  *    is allocated.
-  */
-  int32_t CopyFrame(const VideoFrame& videoFrame);
-  /**
-  *    Copy buffer: If newLength is bigger than allocated size, a new buffer of
-  * size length
-  *    is allocated.
-  */
-  int32_t CopyFrame(size_t length, const uint8_t* sourceBuffer);
-  /**
-  *    Delete VideoFrame and resets members to zero
-  */
-  void Free();
-  /**
-  *   Set frame timestamp (90kHz)
-  */
-  void SetTimeStamp(const uint32_t timeStamp) { _timeStamp = timeStamp; }
-  /**
-  *   Get pointer to frame buffer
-  */
-  uint8_t* Buffer() const { return _buffer; }
-
-  uint8_t*& Buffer() { return _buffer; }
-
-  /**
-  *   Get allocated buffer size
-  */
-  size_t Size() const { return _bufferSize; }
-  /**
-  *   Get frame length
-  */
-  size_t Length() const { return _bufferLength; }
-  /**
-  *   Get frame timestamp (90kHz)
-  */
-  uint32_t TimeStamp() const { return _timeStamp; }
-  /**
-  *   Get frame width
-  */
-  uint32_t Width() const { return _width; }
-  /**
-  *   Get frame height
-  */
-  uint32_t Height() const { return _height; }
-  /**
-  *   Set frame width
-  */
-  void SetWidth(const uint32_t width) { _width = width; }
-  /**
-  *   Set frame height
-  */
-  void SetHeight(const uint32_t height) { _height = height; }
-  /**
-  *   Set render time in miliseconds
-  */
-  void SetRenderTime(const int64_t renderTimeMs) {
-    _renderTimeMs = renderTimeMs;
-  }
-  /**
-  *  Get render time in miliseconds
-  */
-  int64_t RenderTimeMs() const { return _renderTimeMs; }
-
- private:
-  void Set(uint8_t* buffer, uint32_t size, uint32_t length, uint32_t timeStamp);
-
-  uint8_t* _buffer;      // Pointer to frame buffer
-  size_t _bufferSize;    // Allocated buffer size
-  size_t _bufferLength;  // Length (in bytes) of buffer
-  uint32_t _timeStamp;   // Timestamp of frame (90kHz)
-  uint32_t _width;
-  uint32_t _height;
-  int64_t _renderTimeMs;
-};  // end of VideoFrame class declaration
-
-// inline implementation of VideoFrame class:
-inline VideoFrame::VideoFrame()
-    : _buffer(0),
-      _bufferSize(0),
-      _bufferLength(0),
-      _timeStamp(0),
-      _width(0),
-      _height(0),
-      _renderTimeMs(0) {
-  //
-}
-inline VideoFrame::~VideoFrame() {
-  if (_buffer) {
-    delete[] _buffer;
-    _buffer = NULL;
-  }
-}
-
-inline int32_t VideoFrame::VerifyAndAllocate(const size_t minimumSize) {
-  if (minimumSize < 1) {
-    return -1;
-  }
-  if (minimumSize > _bufferSize) {
-    // create buffer of sufficient size
-    uint8_t* newBufferBuffer = new uint8_t[minimumSize];
-    if (_buffer) {
-      // copy old data
-      memcpy(newBufferBuffer, _buffer, _bufferSize);
-      delete[] _buffer;
-    } else {
-      memset(newBufferBuffer, 0, minimumSize * sizeof(uint8_t));
-    }
-    _buffer = newBufferBuffer;
-    _bufferSize = minimumSize;
-  }
-  return 0;
-}
-
-inline int32_t VideoFrame::SetLength(const size_t newLength) {
-  if (newLength > _bufferSize) {  // can't accomodate new value
-    return -1;
-  }
-  _bufferLength = newLength;
-  return 0;
-}
-
-inline int32_t VideoFrame::SwapFrame(VideoFrame& videoFrame) {
-  uint32_t tmpTimeStamp = _timeStamp;
-  uint32_t tmpWidth = _width;
-  uint32_t tmpHeight = _height;
-  int64_t tmpRenderTime = _renderTimeMs;
-
-  _timeStamp = videoFrame._timeStamp;
-  _width = videoFrame._width;
-  _height = videoFrame._height;
-  _renderTimeMs = videoFrame._renderTimeMs;
-
-  videoFrame._timeStamp = tmpTimeStamp;
-  videoFrame._width = tmpWidth;
-  videoFrame._height = tmpHeight;
-  videoFrame._renderTimeMs = tmpRenderTime;
-
-  return Swap(videoFrame._buffer, videoFrame._bufferLength,
-              videoFrame._bufferSize);
-}
-
-inline int32_t VideoFrame::Swap(uint8_t*& newMemory, size_t& newLength,
-                                size_t& newSize) {
-  std::swap(_buffer, newMemory);
-  std::swap(_bufferLength, newLength);
-  std::swap(_bufferSize, newSize);
-  return 0;
-}
-
-inline int32_t VideoFrame::CopyFrame(size_t length,
-                                     const uint8_t* sourceBuffer) {
-  if (length > _bufferSize) {
-    int32_t ret = VerifyAndAllocate(length);
-    if (ret < 0) {
-      return ret;
-    }
-  }
-  memcpy(_buffer, sourceBuffer, length);
-  _bufferLength = length;
-  return 0;
-}
-
-inline int32_t VideoFrame::CopyFrame(const VideoFrame& videoFrame) {
-  if (CopyFrame(videoFrame.Length(), videoFrame.Buffer()) != 0) {
-    return -1;
-  }
-  _timeStamp = videoFrame._timeStamp;
-  _width = videoFrame._width;
-  _height = videoFrame._height;
-  _renderTimeMs = videoFrame._renderTimeMs;
-  return 0;
-}
-
-inline void VideoFrame::Free() {
-  _timeStamp = 0;
-  _bufferLength = 0;
-  _bufferSize = 0;
-  _height = 0;
-  _width = 0;
-  _renderTimeMs = 0;
-
-  if (_buffer) {
-    delete[] _buffer;
-    _buffer = NULL;
-  }
-}
-
 /* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It
  * allows for adding and subtracting frames while keeping track of the resulting
  * states.
diff --git a/video_engine/vie_capturer_unittest.cc b/video_engine/vie_capturer_unittest.cc
index bb61c4c..6e5bdbd 100644
--- a/video_engine/vie_capturer_unittest.cc
+++ b/video_engine/vie_capturer_unittest.cc
@@ -135,7 +135,8 @@
   for (int i = 0 ; i < kNumFrame; ++i) {
     webrtc::RefCountImpl<FakeNativeHandle>* handle =
               new webrtc::RefCountImpl<FakeNativeHandle>();
-    input_frames_.push_back(new TextureVideoFrame(handle, i, i, i, i));
+    // Add one to |i| so that width/height > 0.
+    input_frames_.push_back(new TextureVideoFrame(handle, i + 1, i + 1, i, i));
     AddInputFrame(input_frames_[i]);
     WaitOutputFrame();
   }
diff --git a/video_frame.h b/video_frame.h
index 3f673cd..4193390 100644
--- a/video_frame.h
+++ b/video_frame.h
@@ -11,42 +11,21 @@
 #ifndef WEBRTC_VIDEO_FRAME_H_
 #define WEBRTC_VIDEO_FRAME_H_
 
-#include <assert.h>
-
-#include "webrtc/common_video/plane.h"
-// TODO(pbos): Remove scoped_refptr include (and AddRef/Release if they're not
-// used).
-#include "webrtc/system_wrappers/interface/scoped_refptr.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/common_video/interface/video_frame_buffer.h"
 #include "webrtc/typedefs.h"
 #include "webrtc/common_video/rotation.h"
 
 namespace webrtc {
 
-enum PlaneType {
-  kYPlane = 0,
-  kUPlane = 1,
-  kVPlane = 2,
-  kNumOfPlanes = 3
-};
-
 class I420VideoFrame {
  public:
   I420VideoFrame();
+  I420VideoFrame(const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer,
+                 uint32_t timestamp,
+                 int64_t render_time_ms,
+                 VideoRotation rotation);
   virtual ~I420VideoFrame();
-  // Infrastructure for refCount implementation.
-  // Implements dummy functions for reference counting so that non reference
-  // counted instantiation can be done. These functions should not be called
-  // when creating the frame with new I420VideoFrame().
-  // Note: do not pass a I420VideoFrame created with new I420VideoFrame() or
-  // equivalent to a scoped_refptr or memory leak will occur.
-  virtual int32_t AddRef() {
-    assert(false);
-    return -1;
-  }
-  virtual int32_t Release() {
-    assert(false);
-    return -1;
-  }
 
   // CreateEmptyFrame: Sets frame dimensions and allocates buffers based
   // on set dimensions - height and plane stride.
@@ -62,6 +41,7 @@
   // CreateFrame: Sets the frame's members and buffers. If required size is
   // bigger than allocated one, new buffers of adequate size will be allocated.
   // Return value: 0 on success, -1 on error.
+  // TODO(magjed): Remove unnecessary buffer size arguments.
   virtual int CreateFrame(int size_y,
                           const uint8_t* buffer_y,
                           int size_u,
@@ -112,10 +92,10 @@
   virtual int stride(PlaneType type) const;
 
   // Get frame width.
-  virtual int width() const { return width_; }
+  virtual int width() const;
 
   // Get frame height.
-  virtual int height() const { return height_; }
+  virtual int height() const;
 
   // Set frame timestamp (90kHz).
   virtual void set_timestamp(uint32_t timestamp) { timestamp_ = timestamp; }
@@ -162,27 +142,13 @@
   // longer in use, so the underlying resource can be freed.
   virtual void* native_handle() const;
 
- protected:
-  // Verifies legality of parameters.
-  // Return value: 0 on success, -1 on error.
-  virtual int CheckDimensions(int width,
-                              int height,
-                              int stride_y,
-                              int stride_u,
-                              int stride_v);
-  // TODO(magjed): Move these to an internal frame buffer instead.
-  int width_;
-  int height_;
+  // Return the underlying buffer.
+  virtual rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer()
+      const;
 
  private:
-  // Get the pointer to a specific plane.
-  const Plane* GetPlane(PlaneType type) const;
-  // Overloading with non-const.
-  Plane* GetPlane(PlaneType type);
-
-  Plane y_plane_;
-  Plane u_plane_;
-  Plane v_plane_;
+  // An opaque reference counted handle that stores the pixel data.
+  rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
   uint32_t timestamp_;
   int64_t ntp_time_ms_;
   int64_t render_time_ms_;