Revert 8580 "Unify underlying frame buffer in I420VideoFrame and..."
This is unfortunately causing build problems in Chrome on Windows.
> 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
TBR=magjed@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/42199005
Cr-Original-Commit-Position: refs/heads/master@{#8599}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 1f94407319f85abc286c993774a4ea93807ec32e
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index 06a4b7e..32a9f2c 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",
- "texture_video_frame.cc",
- "video_frame_buffer.cc",
+ "plane.cc",
+ "plane.h",
+ "texture_video_frame.cc"
]
include_dirs = [ "../modules/interface" ]
diff --git a/common_video/common_video.gyp b/common_video/common_video.gyp
index 5945ddb..ee04fc7 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',
- 'texture_video_frame.cc',
- 'video_frame_buffer.cc',
+ 'plane.h',
+ 'plane.cc',
+ 'texture_video_frame.cc'
],
},
], # targets
diff --git a/common_video/common_video_unittests.gyp b/common_video/common_video_unittests.gyp
index a7e51ee..2b896c6 100644
--- a/common_video/common_video_unittests.gyp
+++ b/common_video/common_video_unittests.gyp
@@ -22,6 +22,7 @@
'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 b3943d5..d956970 100644
--- a/common_video/i420_video_frame.cc
+++ b/common_video/i420_video_frame.cc
@@ -14,59 +14,37 @@
#include <algorithm> // swap
-#include "webrtc/base/checks.h"
-
namespace webrtc {
I420VideoFrame::I420VideoFrame()
- : timestamp_(0),
+ : width_(0),
+ height_(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) {
- const int half_width = (width + 1) / 2;
- if (width <= 0 || height <= 0 || stride_y < width || stride_u < half_width ||
- stride_v < half_width) {
+ if (CheckDimensions(width, height, stride_y, stride_u, stride_v) < 0)
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;
}
@@ -92,35 +70,31 @@
int stride_u,
int stride_v,
VideoRotation rotation) {
- 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)
+ if (size_y < 1 || size_u < 1 || size_v < 1)
return -1;
- memcpy(buffer(kYPlane), buffer_y, expected_size_y);
- memcpy(buffer(kUPlane), buffer_u, expected_size_u);
- memcpy(buffer(kVPlane), buffer_v, expected_size_v);
+ 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;
rotation_ = rotation;
return 0;
}
int I420VideoFrame::CopyFrame(const I420VideoFrame& videoFrame) {
- 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;
- }
+ 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_;
@@ -138,7 +112,11 @@
}
void I420VideoFrame::SwapFrame(I420VideoFrame* videoFrame) {
- video_frame_buffer_.swap(videoFrame->video_frame_buffer_);
+ 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_);
std::swap(timestamp_, videoFrame->timestamp_);
std::swap(ntp_time_ms_, videoFrame->ntp_time_ms_);
std::swap(render_time_ms_, videoFrame->render_time_ms_);
@@ -146,43 +124,75 @@
}
uint8_t* I420VideoFrame::buffer(PlaneType type) {
- return video_frame_buffer_ ? video_frame_buffer_->data(type) : nullptr;
+ Plane* plane_ptr = GetPlane(type);
+ if (plane_ptr)
+ return plane_ptr->buffer();
+ return NULL;
}
const uint8_t* I420VideoFrame::buffer(PlaneType type) const {
- // 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;
+ const Plane* plane_ptr = GetPlane(type);
+ if (plane_ptr)
+ return plane_ptr->buffer();
+ return NULL;
}
int I420VideoFrame::allocated_size(PlaneType type) const {
- const int plane_height = (type == kYPlane) ? height() : (height() + 1) / 2;
- return plane_height * stride(type);
+ const Plane* plane_ptr = GetPlane(type);
+ if (plane_ptr)
+ return plane_ptr->allocated_size();
+ return -1;
}
int I420VideoFrame::stride(PlaneType type) const {
- 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;
+ const Plane* plane_ptr = GetPlane(type);
+ if (plane_ptr)
+ return plane_ptr->stride();
+ return -1;
}
bool I420VideoFrame::IsZeroSize() const {
- return !video_frame_buffer_;
+ return (y_plane_.IsZeroSize() && u_plane_.IsZeroSize() &&
+ v_plane_.IsZeroSize());
}
-void* I420VideoFrame::native_handle() const {
- return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr;
+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;
}
-rtc::scoped_refptr<VideoFrameBuffer> I420VideoFrame::video_frame_buffer()
- const {
- return video_frame_buffer_;
+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;
}
} // namespace webrtc
diff --git a/common_video/i420_video_frame_unittest.cc b/common_video/i420_video_frame_unittest.cc
index 9c0d700..3e97309 100644
--- a/common_video/i420_video_frame_unittest.cc
+++ b/common_video/i420_video_frame_unittest.cc
@@ -14,6 +14,8 @@
#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 {
@@ -238,30 +240,15 @@
EXPECT_TRUE(EqualFrames(frame2_copy, frame1));
}
-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));
+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());
}
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 fbd722f..225a0ec 100644
--- a/common_video/interface/texture_video_frame.h
+++ b/common_video/interface/texture_video_frame.h
@@ -17,6 +17,7 @@
#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 {
@@ -28,6 +29,54 @@
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
deleted file mode 100644
index 9b6438a..0000000
--- a/common_video/interface/video_frame_buffer.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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
new file mode 100644
index 0000000..d165598
--- /dev/null
+++ b/common_video/plane_unittest.cc
@@ -0,0 +1,97 @@
+/*
+ * 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 4ae252d..7772f12 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 "webrtc/base/refcount.h"
+#include <assert.h>
namespace webrtc {
@@ -19,11 +19,99 @@
int height,
uint32_t timestamp,
int64_t render_time_ms)
- : I420VideoFrame(
- new rtc::RefCountedObject<TextureBuffer>(handle, width, height),
- timestamp,
- render_time_ms,
- kVideoRotation_0) {
+ : 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;
}
} // namespace webrtc
diff --git a/common_video/video_frame_buffer.cc b/common_video/video_frame_buffer.cc
deleted file mode 100644
index 76e97b7..0000000
--- a/common_video/video_frame_buffer.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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:
- RTC_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:
- RTC_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 {
- RTC_NOTREACHED(); // Should not be called.
- return nullptr;
-}
-
-uint8_t* TextureBuffer::data(PlaneType type) {
- RTC_NOTREACHED(); // Should not be called.
- return nullptr;
-}
-
-int TextureBuffer::stride(PlaneType type) const {
- RTC_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 c36d8f1..5cb2c56 100644
--- a/modules/interface/module_common_types.h
+++ b/modules/interface/module_common_types.h
@@ -394,6 +394,232 @@
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 6e5bdbd..bb61c4c 100644
--- a/video_engine/vie_capturer_unittest.cc
+++ b/video_engine/vie_capturer_unittest.cc
@@ -135,8 +135,7 @@
for (int i = 0 ; i < kNumFrame; ++i) {
webrtc::RefCountImpl<FakeNativeHandle>* handle =
new webrtc::RefCountImpl<FakeNativeHandle>();
- // Add one to |i| so that width/height > 0.
- input_frames_.push_back(new TextureVideoFrame(handle, i + 1, i + 1, i, i));
+ input_frames_.push_back(new TextureVideoFrame(handle, i, i, i, i));
AddInputFrame(input_frames_[i]);
WaitOutputFrame();
}
diff --git a/video_frame.h b/video_frame.h
index 4193390..3f673cd 100644
--- a/video_frame.h
+++ b/video_frame.h
@@ -11,21 +11,42 @@
#ifndef WEBRTC_VIDEO_FRAME_H_
#define WEBRTC_VIDEO_FRAME_H_
-#include "webrtc/base/scoped_ref_ptr.h"
-#include "webrtc/common_video/interface/video_frame_buffer.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/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.
@@ -41,7 +62,6 @@
// 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,
@@ -92,10 +112,10 @@
virtual int stride(PlaneType type) const;
// Get frame width.
- virtual int width() const;
+ virtual int width() const { return width_; }
// Get frame height.
- virtual int height() const;
+ virtual int height() const { return height_; }
// Set frame timestamp (90kHz).
virtual void set_timestamp(uint32_t timestamp) { timestamp_ = timestamp; }
@@ -142,13 +162,27 @@
// longer in use, so the underlying resource can be freed.
virtual void* native_handle() const;
- // Return the underlying buffer.
- virtual rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer()
- 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_;
private:
- // An opaque reference counted handle that stores the pixel data.
- rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_;
+ // 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_;
uint32_t timestamp_;
int64_t ntp_time_ms_;
int64_t render_time_ms_;