summaryrefslogtreecommitdiff
path: root/chromium/third_party/webrtc/common_video
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/third_party/webrtc/common_video
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/third_party/webrtc/common_video')
-rw-r--r--chromium/third_party/webrtc/common_video/BUILD.gn24
-rw-r--r--chromium/third_party/webrtc/common_video/common_video.gyp24
-rw-r--r--chromium/third_party/webrtc/common_video/common_video_unittests.gyp5
-rw-r--r--chromium/third_party/webrtc/common_video/common_video_unittests.isolate6
-rw-r--r--chromium/third_party/webrtc/common_video/i420_buffer_pool.cc85
-rw-r--r--chromium/third_party/webrtc/common_video/i420_buffer_pool_unittest.cc74
-rw-r--r--chromium/third_party/webrtc/common_video/i420_video_frame.cc281
-rw-r--r--chromium/third_party/webrtc/common_video/i420_video_frame_unittest.cc376
-rw-r--r--chromium/third_party/webrtc/common_video/incoming_video_stream.cc257
-rw-r--r--chromium/third_party/webrtc/common_video/interface/i420_buffer_pool.h43
-rw-r--r--chromium/third_party/webrtc/common_video/interface/i420_video_frame.h17
-rw-r--r--chromium/third_party/webrtc/common_video/interface/incoming_video_stream.h101
-rw-r--r--chromium/third_party/webrtc/common_video/interface/native_handle.h36
-rw-r--r--chromium/third_party/webrtc/common_video/interface/texture_video_frame.h73
-rw-r--r--chromium/third_party/webrtc/common_video/interface/video_frame_buffer.h150
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/include/scaler.h7
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h41
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/libyuv_unittest.cc150
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/scaler.cc37
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/scaler_unittest.cc143
-rw-r--r--chromium/third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc81
-rw-r--r--chromium/third_party/webrtc/common_video/plane.cc4
-rw-r--r--chromium/third_party/webrtc/common_video/plane.h4
-rw-r--r--chromium/third_party/webrtc/common_video/plane_unittest.cc97
-rw-r--r--chromium/third_party/webrtc/common_video/rotation.h26
-rw-r--r--chromium/third_party/webrtc/common_video/texture_video_frame.cc105
-rw-r--r--chromium/third_party/webrtc/common_video/texture_video_frame_unittest.cc79
-rw-r--r--chromium/third_party/webrtc/common_video/video_frame_buffer.cc223
-rw-r--r--chromium/third_party/webrtc/common_video/video_render_frames.cc95
-rw-r--r--chromium/third_party/webrtc/common_video/video_render_frames.h59
30 files changed, 1636 insertions, 1067 deletions
diff --git a/chromium/third_party/webrtc/common_video/BUILD.gn b/chromium/third_party/webrtc/common_video/BUILD.gn
index d7f6dc23c26..e5cac4d447c 100644
--- a/chromium/third_party/webrtc/common_video/BUILD.gn
+++ b/chromium/third_party/webrtc/common_video/BUILD.gn
@@ -17,17 +17,19 @@ config("common_video_config") {
source_set("common_video") {
sources = [
+ "i420_buffer_pool.cc",
"i420_video_frame.cc",
- "interface/i420_video_frame.h",
- "interface/native_handle.h",
- "interface/texture_video_frame.h",
+ "incoming_video_stream.cc",
+ "interface/i420_buffer_pool.h",
+ "interface/incoming_video_stream.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"
+ "video_frame_buffer.cc",
+ "video_render_frames.cc",
+ "video_render_frames.h",
]
include_dirs = [ "../modules/interface" ]
@@ -44,12 +46,16 @@ source_set("common_video") {
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
- deps = [ "../system_wrappers" ]
+ deps = [
+ "..:webrtc_common",
+ "../system_wrappers",
+ ]
if (rtc_build_libyuv) {
- deps += [ "//third_party/libyuv" ]
+ deps += [ "$rtc_libyuv_dir" ]
+ public_deps = [ "$rtc_libyuv_dir" ]
} else {
# Need to add a directory normally exported by libyuv.
- include_dirs += [ "//third_party/libyuv/include" ]
+ include_dirs += [ "$rtc_libyuv_dir/include" ]
}
}
diff --git a/chromium/third_party/webrtc/common_video/common_video.gyp b/chromium/third_party/webrtc/common_video/common_video.gyp
index 97cb94197e2..daac9ce9e57 100644
--- a/chromium/third_party/webrtc/common_video/common_video.gyp
+++ b/chromium/third_party/webrtc/common_video/common_video.gyp
@@ -18,7 +18,8 @@
'libyuv/include',
],
'dependencies': [
- '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+ '<(webrtc_root)/common.gyp:webrtc_common',
+ '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
],
'direct_dependent_settings': {
'include_dirs': [
@@ -29,23 +30,28 @@
'conditions': [
['build_libyuv==1', {
'dependencies': ['<(DEPTH)/third_party/libyuv/libyuv.gyp:libyuv',],
+ 'export_dependent_settings': [
+ '<(DEPTH)/third_party/libyuv/libyuv.gyp:libyuv',
+ ],
}, {
# Need to add a directory normally exported by libyuv.gyp.
'include_dirs': ['<(libyuv_dir)/include',],
}],
],
'sources': [
- 'interface/i420_video_frame.h',
- 'interface/native_handle.h',
- 'interface/texture_video_frame.h',
+ 'i420_buffer_pool.cc',
'i420_video_frame.cc',
- 'libyuv/include/webrtc_libyuv.h',
+ 'incoming_video_stream.cc',
+ 'interface/i420_buffer_pool.h',
+ 'interface/incoming_video_stream.h',
+ 'interface/video_frame_buffer.h',
'libyuv/include/scaler.h',
- 'libyuv/webrtc_libyuv.cc',
+ 'libyuv/include/webrtc_libyuv.h',
'libyuv/scaler.cc',
- 'plane.h',
- 'plane.cc',
- 'texture_video_frame.cc'
+ 'libyuv/webrtc_libyuv.cc',
+ 'video_frame_buffer.cc',
+ 'video_render_frames.cc',
+ 'video_render_frames.h',
],
},
], # targets
diff --git a/chromium/third_party/webrtc/common_video/common_video_unittests.gyp b/chromium/third_party/webrtc/common_video/common_video_unittests.gyp
index 9189991ee4e..beeab5ddcad 100644
--- a/chromium/third_party/webrtc/common_video/common_video_unittests.gyp
+++ b/chromium/third_party/webrtc/common_video/common_video_unittests.gyp
@@ -15,15 +15,14 @@
'dependencies': [
'<(webrtc_root)/common_video/common_video.gyp:common_video',
'<(DEPTH)/testing/gtest.gyp:gtest',
- '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+ '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
'<(webrtc_root)/test/test.gyp:test_support_main',
],
'sources': [
+ 'i420_buffer_pool_unittest.cc',
'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.
'msvs_disabled_warnings': [
diff --git a/chromium/third_party/webrtc/common_video/common_video_unittests.isolate b/chromium/third_party/webrtc/common_video/common_video_unittests.isolate
index 70823654751..72018835008 100644
--- a/chromium/third_party/webrtc/common_video/common_video_unittests.isolate
+++ b/chromium/third_party/webrtc/common_video/common_video_unittests.isolate
@@ -7,11 +7,10 @@
# be found in the AUTHORS file in the root of the source tree.
{
'conditions': [
- ['OS=="android"', {
+ ['OS=="linux" or OS=="mac" or OS=="win" or OS=="android"', {
'variables': {
'files': [
- '<(DEPTH)/data/',
- '<(DEPTH)/resources/',
+ '<(DEPTH)/resources/foreman_cif.yuv',
],
},
}],
@@ -23,7 +22,6 @@
],
'files': [
'<(DEPTH)/DEPS',
- '<(DEPTH)/resources/foreman_cif.yuv',
'<(DEPTH)/testing/test_env.py',
'<(PRODUCT_DIR)/common_video_unittests<(EXECUTABLE_SUFFIX)',
],
diff --git a/chromium/third_party/webrtc/common_video/i420_buffer_pool.cc b/chromium/third_party/webrtc/common_video/i420_buffer_pool.cc
new file mode 100644
index 00000000000..35a6c109539
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/i420_buffer_pool.cc
@@ -0,0 +1,85 @@
+/*
+ * 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/i420_buffer_pool.h"
+
+#include "webrtc/base/checks.h"
+
+namespace {
+
+// One extra indirection is needed to make |HasOneRef| work.
+class PooledI420Buffer : public webrtc::VideoFrameBuffer {
+ public:
+ explicit PooledI420Buffer(
+ const rtc::scoped_refptr<webrtc::I420Buffer>& buffer)
+ : buffer_(buffer) {}
+
+ private:
+ ~PooledI420Buffer() override {}
+
+ int width() const override { return buffer_->width(); }
+ int height() const override { return buffer_->height(); }
+ const uint8_t* data(webrtc::PlaneType type) const override {
+ const webrtc::I420Buffer* cbuffer = buffer_.get();
+ return cbuffer->data(type);
+ }
+ uint8_t* data(webrtc::PlaneType type) {
+ DCHECK(HasOneRef());
+ const webrtc::I420Buffer* cbuffer = buffer_.get();
+ return const_cast<uint8_t*>(cbuffer->data(type));
+ }
+ int stride(webrtc::PlaneType type) const override {
+ return buffer_->stride(type);
+ }
+ void* native_handle() const override { return nullptr; }
+
+ friend class rtc::RefCountedObject<PooledI420Buffer>;
+ rtc::scoped_refptr<webrtc::I420Buffer> buffer_;
+};
+
+} // namespace
+
+namespace webrtc {
+
+I420BufferPool::I420BufferPool() {
+ Release();
+}
+
+void I420BufferPool::Release() {
+ thread_checker_.DetachFromThread();
+ buffers_.clear();
+}
+
+rtc::scoped_refptr<VideoFrameBuffer> I420BufferPool::CreateBuffer(int width,
+ int height) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Release buffers with wrong resolution.
+ for (auto it = buffers_.begin(); it != buffers_.end();) {
+ if ((*it)->width() != width || (*it)->height() != height)
+ it = buffers_.erase(it);
+ else
+ ++it;
+ }
+ // Look for a free buffer.
+ for (const rtc::scoped_refptr<I420Buffer>& buffer : buffers_) {
+ // If the buffer is in use, the ref count will be 2, one from the list we
+ // are looping over and one from a PooledI420Buffer returned from
+ // CreateBuffer that has not been released yet. If the ref count is 1
+ // (HasOneRef), then the list we are looping over holds the only reference
+ // and it's safe to reuse.
+ if (buffer->HasOneRef())
+ return new rtc::RefCountedObject<PooledI420Buffer>(buffer);
+ }
+ // Allocate new buffer.
+ buffers_.push_back(new rtc::RefCountedObject<I420Buffer>(width, height));
+ return new rtc::RefCountedObject<PooledI420Buffer>(buffers_.back());
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/i420_buffer_pool_unittest.cc b/chromium/third_party/webrtc/common_video/i420_buffer_pool_unittest.cc
new file mode 100644
index 00000000000..625160be119
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/i420_buffer_pool_unittest.cc
@@ -0,0 +1,74 @@
+/*
+ * 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 <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_video/interface/i420_buffer_pool.h"
+
+namespace webrtc {
+
+TEST(TestI420BufferPool, SimpleFrameReuse) {
+ I420BufferPool pool;
+ rtc::scoped_refptr<VideoFrameBuffer> buffer = pool.CreateBuffer(16, 16);
+ EXPECT_EQ(16, buffer->width());
+ EXPECT_EQ(16, buffer->height());
+ // Extract non-refcounted pointers for testing.
+ const uint8_t* y_ptr = buffer->data(kYPlane);
+ const uint8_t* u_ptr = buffer->data(kUPlane);
+ const uint8_t* v_ptr = buffer->data(kVPlane);
+ // Release buffer so that it is returned to the pool.
+ buffer = nullptr;
+ // Check that the memory is resued.
+ buffer = pool.CreateBuffer(16, 16);
+ EXPECT_EQ(y_ptr, buffer->data(kYPlane));
+ EXPECT_EQ(u_ptr, buffer->data(kUPlane));
+ EXPECT_EQ(v_ptr, buffer->data(kVPlane));
+ EXPECT_EQ(16, buffer->width());
+ EXPECT_EQ(16, buffer->height());
+}
+
+TEST(TestI420BufferPool, FailToReuse) {
+ I420BufferPool pool;
+ rtc::scoped_refptr<VideoFrameBuffer> buffer = pool.CreateBuffer(16, 16);
+ // Extract non-refcounted pointers for testing.
+ const uint8_t* u_ptr = buffer->data(kUPlane);
+ const uint8_t* v_ptr = buffer->data(kVPlane);
+ // Release buffer so that it is returned to the pool.
+ buffer = nullptr;
+ // Check that the pool doesn't try to reuse buffers of incorrect size.
+ buffer = pool.CreateBuffer(32, 16);
+ EXPECT_EQ(32, buffer->width());
+ EXPECT_EQ(16, buffer->height());
+ EXPECT_NE(u_ptr, buffer->data(kUPlane));
+ EXPECT_NE(v_ptr, buffer->data(kVPlane));
+}
+
+TEST(TestI420BufferPool, ExclusiveOwner) {
+ // Check that created buffers are exclusive so that they can be written to.
+ I420BufferPool pool;
+ rtc::scoped_refptr<VideoFrameBuffer> buffer = pool.CreateBuffer(16, 16);
+ EXPECT_TRUE(buffer->HasOneRef());
+}
+
+TEST(TestI420BufferPool, FrameValidAfterPoolDestruction) {
+ rtc::scoped_refptr<VideoFrameBuffer> buffer;
+ {
+ I420BufferPool pool;
+ buffer = pool.CreateBuffer(16, 16);
+ }
+ EXPECT_TRUE(buffer->HasOneRef());
+ EXPECT_EQ(16, buffer->width());
+ EXPECT_EQ(16, buffer->height());
+ // Try to trigger use-after-free errors by writing to y-plane.
+ memset(buffer->data(kYPlane), 0xA5, 16 * buffer->stride(kYPlane));
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/i420_video_frame.cc b/chromium/third_party/webrtc/common_video/i420_video_frame.cc
index fdc2bbc2305..3b062072cc2 100644
--- a/chromium/third_party/webrtc/common_video/i420_video_frame.cc
+++ b/chromium/third_party/webrtc/common_video/i420_video_frame.cc
@@ -8,192 +8,209 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_video/interface/i420_video_frame.h"
+#include "webrtc/video_frame.h"
#include <string.h>
#include <algorithm> // swap
+#include "webrtc/base/bind.h"
+#include "webrtc/base/checks.h"
+
namespace webrtc {
-I420VideoFrame::I420VideoFrame()
- : width_(0),
- height_(0),
- timestamp_(0),
- ntp_time_ms_(0),
- render_time_ms_(0) {}
+I420VideoFrame::I420VideoFrame() {
+ // Intentionally using Reset instead of initializer list so that any missed
+ // fields in Reset will be caught by memory checkers.
+ Reset();
+}
-I420VideoFrame::~I420VideoFrame() {}
+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(void* native_handle,
+ int width,
+ int height,
+ uint32_t timestamp,
+ int64_t render_time_ms,
+ VideoRotation rotation,
+ const rtc::Callback0<void>& no_longer_used)
+ : I420VideoFrame(new rtc::RefCountedObject<TextureBuffer>(native_handle,
+ width,
+ height,
+ no_longer_used),
+ timestamp,
+ render_time_ms,
+ rotation) {
+}
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)
- 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);
+ const int half_width = (width + 1) / 2;
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ DCHECK_GE(stride_y, width);
+ DCHECK_GE(stride_u, half_width);
+ DCHECK_GE(stride_v, half_width);
+
// 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;
}
-int I420VideoFrame::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 I420VideoFrame::CreateFrame(const uint8_t* buffer_y,
+ const uint8_t* buffer_u,
+ const uint8_t* buffer_v,
int width, int height,
- int stride_y, int stride_u, int stride_v) {
- if (size_y < 1 || size_u < 1 || size_v < 1)
- 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;
+ int stride_y,
+ int stride_u,
+ int stride_v) {
+ return CreateFrame(buffer_y, buffer_u, buffer_v,
+ width, height, stride_y, stride_u, stride_v,
+ kVideoRotation_0);
+}
+
+int I420VideoFrame::CreateFrame(const uint8_t* buffer_y,
+ const uint8_t* buffer_u,
+ const uint8_t* buffer_v,
+ int width,
+ int height,
+ int stride_y,
+ 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;
+ CreateEmptyFrame(width, height, stride_y, stride_u, stride_v);
+ 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::CreateFrame(const uint8_t* buffer,
+ int width,
+ int height,
+ VideoRotation rotation) {
+ const int stride_y = width;
+ const int stride_uv = (width + 1) / 2;
+
+ const uint8_t* buffer_y = buffer;
+ const uint8_t* buffer_u = buffer_y + stride_y * height;
+ const uint8_t* buffer_v = buffer_u + stride_uv * ((height + 1) / 2);
+ return CreateFrame(buffer_y, buffer_u, buffer_v, width, height, stride_y,
+ stride_uv, stride_uv, rotation);
+}
+
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.IsZeroSize()) {
+ video_frame_buffer_ = nullptr;
+ } else if (videoFrame.native_handle()) {
+ video_frame_buffer_ = videoFrame.video_frame_buffer();
+ } else {
+ CreateFrame(videoFrame.buffer(kYPlane), videoFrame.buffer(kUPlane),
+ videoFrame.buffer(kVPlane), videoFrame.width(),
+ videoFrame.height(), videoFrame.stride(kYPlane),
+ videoFrame.stride(kUPlane), videoFrame.stride(kVPlane));
+ }
+
timestamp_ = videoFrame.timestamp_;
ntp_time_ms_ = videoFrame.ntp_time_ms_;
render_time_ms_ = videoFrame.render_time_ms_;
+ rotation_ = videoFrame.rotation_;
return 0;
}
-I420VideoFrame* I420VideoFrame::CloneFrame() const {
- scoped_ptr<I420VideoFrame> new_frame(new I420VideoFrame());
- if (new_frame->CopyFrame(*this) == -1) {
- // CopyFrame failed.
- return NULL;
- }
- return new_frame.release();
+void I420VideoFrame::ShallowCopy(const I420VideoFrame& videoFrame) {
+ video_frame_buffer_ = videoFrame.video_frame_buffer();
+ timestamp_ = videoFrame.timestamp_;
+ ntp_time_ms_ = videoFrame.ntp_time_ms_;
+ render_time_ms_ = videoFrame.render_time_ms_;
+ rotation_ = videoFrame.rotation_;
}
-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_);
- std::swap(timestamp_, videoFrame->timestamp_);
- std::swap(ntp_time_ms_, videoFrame->ntp_time_ms_);
- std::swap(render_time_ms_, videoFrame->render_time_ms_);
+void I420VideoFrame::Reset() {
+ video_frame_buffer_ = nullptr;
+ timestamp_ = 0;
+ ntp_time_ms_ = 0;
+ render_time_ms_ = 0;
+ rotation_ = kVideoRotation_0;
}
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;
-}
-
-int I420VideoFrame::set_width(int width) {
- if (CheckDimensions(width, height_,
- y_plane_.stride(), u_plane_.stride(),
- v_plane_.stride()) < 0)
- return -1;
- width_ = width;
- return 0;
+ return video_frame_buffer_ ? video_frame_buffer_->stride(type) : 0;
}
-int I420VideoFrame::set_height(int height) {
- if (CheckDimensions(width_, height,
- y_plane_.stride(), u_plane_.stride(),
- v_plane_.stride()) < 0)
- return -1;
- height_ = height;
- return 0;
+int I420VideoFrame::width() const {
+ return video_frame_buffer_ ? video_frame_buffer_->width() : 0;
}
-bool I420VideoFrame::IsZeroSize() const {
- return (y_plane_.IsZeroSize() && u_plane_.IsZeroSize() &&
- v_plane_.IsZeroSize());
+int I420VideoFrame::height() const {
+ return video_frame_buffer_ ? video_frame_buffer_->height() : 0;
}
-void I420VideoFrame::ResetSize() {
- y_plane_.ResetSize();
- u_plane_.ResetSize();
- v_plane_.ResetSize();
+bool I420VideoFrame::IsZeroSize() const {
+ return !video_frame_buffer_;
}
-void* I420VideoFrame::native_handle() const { return NULL; }
+void* I420VideoFrame::native_handle() const {
+ return video_frame_buffer_ ? video_frame_buffer_->native_handle() : nullptr;
+}
-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;
+void I420VideoFrame::set_video_frame_buffer(
+ const rtc::scoped_refptr<webrtc::VideoFrameBuffer>& buffer) {
+ video_frame_buffer_ = buffer;
}
} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/i420_video_frame_unittest.cc b/chromium/third_party/webrtc/common_video/i420_video_frame_unittest.cc
index ca01fd0cd52..1cb1e7d9f73 100644
--- a/chromium/third_party/webrtc/common_video/i420_video_frame_unittest.cc
+++ b/chromium/third_party/webrtc/common_video/i420_video_frame_unittest.cc
@@ -8,46 +8,55 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include "webrtc/video_frame.h"
+
#include <math.h>
#include <string.h>
#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/common_video/interface/i420_video_frame.h"
-#include "webrtc/system_wrappers/interface/ref_count.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
-#include "webrtc/system_wrappers/interface/scoped_refptr.h"
+#include "webrtc/base/bind.h"
+#include "webrtc/base/scoped_ptr.h"
namespace webrtc {
-bool EqualFrames(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2);
-bool EqualFramesExceptSize(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2);
+class NativeHandleImpl {
+ public:
+ NativeHandleImpl() : no_longer_needed_(false) {}
+ virtual ~NativeHandleImpl() {}
+ bool no_longer_needed() const { return no_longer_needed_; }
+ void SetNoLongerNeeded() { no_longer_needed_ = true; }
+
+ private:
+ bool no_longer_needed_;
+};
+
+bool EqualPlane(const uint8_t* data1,
+ const uint8_t* data2,
+ int stride,
+ int width,
+ int height);
+bool EqualFrames(const I420VideoFrame& frame1, const I420VideoFrame& frame2);
+bool EqualTextureFrames(const I420VideoFrame& frame1,
+ const I420VideoFrame& frame2);
int ExpectedSize(int plane_stride, int image_height, PlaneType type);
TEST(TestI420VideoFrame, InitialValues) {
I420VideoFrame frame;
- // Invalid arguments - one call for each variable.
EXPECT_TRUE(frame.IsZeroSize());
- EXPECT_EQ(-1, frame.CreateEmptyFrame(0, 10, 10, 14, 14));
- EXPECT_EQ(-1, frame.CreateEmptyFrame(10, -1, 10, 90, 14));
- EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 0, 14, 18));
- EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 10, -2, 13));
- EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 10, 14, 0));
- EXPECT_EQ(0, frame.CreateEmptyFrame(10, 10, 10, 14, 90));
- EXPECT_FALSE(frame.IsZeroSize());
+ EXPECT_EQ(kVideoRotation_0, frame.rotation());
+}
+
+TEST(TestI420VideoFrame, CopiesInitialFrameWithoutCrashing) {
+ I420VideoFrame frame;
+ I420VideoFrame frame2;
+ frame2.CopyFrame(frame);
}
TEST(TestI420VideoFrame, WidthHeightValues) {
I420VideoFrame frame;
const int valid_value = 10;
- const int invalid_value = -1;
EXPECT_EQ(0, frame.CreateEmptyFrame(10, 10, 10, 14, 90));
EXPECT_EQ(valid_value, frame.width());
- EXPECT_EQ(invalid_value, frame.set_width(invalid_value));
- EXPECT_EQ(valid_value, frame.height());
- EXPECT_EQ(valid_value, frame.height());
- EXPECT_EQ(invalid_value, frame.set_height(0));
EXPECT_EQ(valid_value, frame.height());
frame.set_timestamp(123u);
EXPECT_EQ(123u, frame.timestamp());
@@ -73,16 +82,7 @@ TEST(TestI420VideoFrame, SizeAllocation) {
frame.allocated_size(kVPlane));
}
-TEST(TestI420VideoFrame, ResetSize) {
- I420VideoFrame frame;
- EXPECT_EQ(0, frame. CreateEmptyFrame(10, 10, 12, 14, 220));
- EXPECT_FALSE(frame.IsZeroSize());
- frame.ResetSize();
- EXPECT_TRUE(frame.IsZeroSize());
-}
-
TEST(TestI420VideoFrame, CopyFrame) {
- I420VideoFrame frame1, frame2;
uint32_t timestamp = 1;
int64_t ntp_time_ms = 2;
int64_t render_time_ms = 3;
@@ -92,57 +92,111 @@ TEST(TestI420VideoFrame, CopyFrame) {
int width = 15;
int height = 15;
// Copy frame.
- EXPECT_EQ(0, frame1.CreateEmptyFrame(width, height,
- stride_y, stride_u, stride_v));
- frame1.set_timestamp(timestamp);
- frame1.set_ntp_time_ms(ntp_time_ms);
- frame1.set_render_time_ms(render_time_ms);
- const int kSizeY = 225;
- const int kSizeU = 80;
- const int kSizeV = 80;
+ I420VideoFrame small_frame;
+ EXPECT_EQ(0, small_frame.CreateEmptyFrame(width, height,
+ stride_y, stride_u, stride_v));
+ small_frame.set_timestamp(timestamp);
+ small_frame.set_ntp_time_ms(ntp_time_ms);
+ small_frame.set_render_time_ms(render_time_ms);
+ const int kSizeY = 400;
+ const int kSizeU = 100;
+ const int kSizeV = 100;
+ const VideoRotation kRotation = kVideoRotation_270;
uint8_t buffer_y[kSizeY];
uint8_t buffer_u[kSizeU];
uint8_t buffer_v[kSizeV];
memset(buffer_y, 16, kSizeY);
memset(buffer_u, 8, kSizeU);
memset(buffer_v, 4, kSizeV);
- frame2.CreateFrame(kSizeY, buffer_y,
- kSizeU, buffer_u,
- kSizeV, buffer_v,
- width + 5, height + 5, stride_y + 5, stride_u, stride_v);
- // Frame of smaller dimensions - allocated sizes should not vary.
- EXPECT_EQ(0, frame1.CopyFrame(frame2));
- EXPECT_TRUE(EqualFramesExceptSize(frame1, frame2));
- EXPECT_EQ(kSizeY, frame1.allocated_size(kYPlane));
- EXPECT_EQ(kSizeU, frame1.allocated_size(kUPlane));
- EXPECT_EQ(kSizeV, frame1.allocated_size(kVPlane));
- // Verify copy of all parameters.
- // Frame of larger dimensions - update allocated sizes.
- EXPECT_EQ(0, frame2.CopyFrame(frame1));
- EXPECT_TRUE(EqualFrames(frame1, frame2));
+ I420VideoFrame big_frame;
+ EXPECT_EQ(0,
+ big_frame.CreateFrame(buffer_y, buffer_u, buffer_v,
+ width + 5, height + 5, stride_y + 5,
+ stride_u, stride_v, kRotation));
+ // Frame of smaller dimensions.
+ EXPECT_EQ(0, small_frame.CopyFrame(big_frame));
+ EXPECT_TRUE(EqualFrames(small_frame, big_frame));
+ EXPECT_EQ(kRotation, small_frame.rotation());
+
+ // Frame of larger dimensions.
+ EXPECT_EQ(0, small_frame.CreateEmptyFrame(width, height,
+ stride_y, stride_u, stride_v));
+ memset(small_frame.buffer(kYPlane), 1, small_frame.allocated_size(kYPlane));
+ memset(small_frame.buffer(kUPlane), 2, small_frame.allocated_size(kUPlane));
+ memset(small_frame.buffer(kVPlane), 3, small_frame.allocated_size(kVPlane));
+ EXPECT_EQ(0, big_frame.CopyFrame(small_frame));
+ EXPECT_TRUE(EqualFrames(small_frame, big_frame));
}
-TEST(TestI420VideoFrame, CloneFrame) {
- I420VideoFrame frame1;
- scoped_ptr<I420VideoFrame> frame2;
- const int kSizeY = 225;
- const int kSizeU = 80;
- const int kSizeV = 80;
+TEST(TestI420VideoFrame, ShallowCopy) {
+ uint32_t timestamp = 1;
+ int64_t ntp_time_ms = 2;
+ int64_t render_time_ms = 3;
+ int stride_y = 15;
+ int stride_u = 10;
+ int stride_v = 10;
+ int width = 15;
+ int height = 15;
+
+ const int kSizeY = 400;
+ const int kSizeU = 100;
+ const int kSizeV = 100;
+ const VideoRotation kRotation = kVideoRotation_270;
uint8_t buffer_y[kSizeY];
uint8_t buffer_u[kSizeU];
uint8_t buffer_v[kSizeV];
memset(buffer_y, 16, kSizeY);
memset(buffer_u, 8, kSizeU);
memset(buffer_v, 4, kSizeV);
- frame1.CreateFrame(
- kSizeY, buffer_y, kSizeU, buffer_u, kSizeV, buffer_v, 20, 20, 20, 10, 10);
- frame1.set_timestamp(1);
- frame1.set_ntp_time_ms(2);
- frame1.set_render_time_ms(3);
-
- frame2.reset(frame1.CloneFrame());
- EXPECT_TRUE(frame2.get() != NULL);
- EXPECT_TRUE(EqualFrames(frame1, *frame2));
+ I420VideoFrame frame1;
+ EXPECT_EQ(0, frame1.CreateFrame(buffer_y, buffer_u, buffer_v, width, height,
+ stride_y, stride_u, stride_v, kRotation));
+ frame1.set_timestamp(timestamp);
+ frame1.set_ntp_time_ms(ntp_time_ms);
+ frame1.set_render_time_ms(render_time_ms);
+ I420VideoFrame frame2;
+ frame2.ShallowCopy(frame1);
+
+ // To be able to access the buffers, we need const pointers to the frames.
+ const I420VideoFrame* const_frame1_ptr = &frame1;
+ const I420VideoFrame* const_frame2_ptr = &frame2;
+
+ EXPECT_TRUE(const_frame1_ptr->buffer(kYPlane) ==
+ const_frame2_ptr->buffer(kYPlane));
+ EXPECT_TRUE(const_frame1_ptr->buffer(kUPlane) ==
+ const_frame2_ptr->buffer(kUPlane));
+ EXPECT_TRUE(const_frame1_ptr->buffer(kVPlane) ==
+ const_frame2_ptr->buffer(kVPlane));
+
+ EXPECT_EQ(frame2.timestamp(), frame1.timestamp());
+ EXPECT_EQ(frame2.ntp_time_ms(), frame1.ntp_time_ms());
+ EXPECT_EQ(frame2.render_time_ms(), frame1.render_time_ms());
+ EXPECT_EQ(frame2.rotation(), frame1.rotation());
+
+ frame2.set_timestamp(timestamp + 1);
+ frame2.set_ntp_time_ms(ntp_time_ms + 1);
+ frame2.set_render_time_ms(render_time_ms + 1);
+ frame2.set_rotation(kVideoRotation_90);
+
+ EXPECT_NE(frame2.timestamp(), frame1.timestamp());
+ EXPECT_NE(frame2.ntp_time_ms(), frame1.ntp_time_ms());
+ EXPECT_NE(frame2.render_time_ms(), frame1.render_time_ms());
+ EXPECT_NE(frame2.rotation(), frame1.rotation());
+}
+
+TEST(TestI420VideoFrame, Reset) {
+ I420VideoFrame frame;
+ ASSERT_TRUE(frame.CreateEmptyFrame(5, 5, 5, 5, 5) == 0);
+ frame.set_ntp_time_ms(1);
+ frame.set_timestamp(2);
+ frame.set_render_time_ms(3);
+ ASSERT_TRUE(frame.video_frame_buffer() != NULL);
+
+ frame.Reset();
+ EXPECT_EQ(0u, frame.ntp_time_ms());
+ EXPECT_EQ(0u, frame.render_time_ms());
+ EXPECT_EQ(0u, frame.timestamp());
+ EXPECT_TRUE(frame.video_frame_buffer() == NULL);
}
TEST(TestI420VideoFrame, CopyBuffer) {
@@ -161,110 +215,87 @@ TEST(TestI420VideoFrame, CopyBuffer) {
memset(buffer_y, 16, kSizeY);
memset(buffer_u, 8, kSizeUv);
memset(buffer_v, 4, kSizeUv);
- frame2.CreateFrame(kSizeY, buffer_y,
- kSizeUv, buffer_u,
- kSizeUv, buffer_v,
+ frame2.CreateFrame(buffer_y, buffer_u, buffer_v,
width, height, stride_y, stride_uv, stride_uv);
- // Copy memory (at least allocated size).
- EXPECT_EQ(memcmp(buffer_y, frame2.buffer(kYPlane), kSizeY), 0);
- EXPECT_EQ(memcmp(buffer_u, frame2.buffer(kUPlane), kSizeUv), 0);
- EXPECT_EQ(memcmp(buffer_v, frame2.buffer(kVPlane), kSizeUv), 0);
- // Comapre size.
+ // Expect exactly the same pixel data.
+ EXPECT_TRUE(EqualPlane(buffer_y, frame2.buffer(kYPlane), stride_y, 15, 15));
+ EXPECT_TRUE(EqualPlane(buffer_u, frame2.buffer(kUPlane), stride_uv, 8, 8));
+ EXPECT_TRUE(EqualPlane(buffer_v, frame2.buffer(kVPlane), stride_uv, 8, 8));
+
+ // Compare size.
EXPECT_LE(kSizeY, frame2.allocated_size(kYPlane));
EXPECT_LE(kSizeUv, frame2.allocated_size(kUPlane));
EXPECT_LE(kSizeUv, frame2.allocated_size(kVPlane));
}
-TEST(TestI420VideoFrame, FrameSwap) {
- I420VideoFrame frame1, frame2;
- uint32_t timestamp1 = 1;
- int64_t ntp_time_ms1 = 2;
- int64_t render_time_ms1 = 3;
- int stride_y1 = 15;
- int stride_u1 = 10;
- int stride_v1 = 10;
- int width1 = 15;
- int height1 = 15;
- const int kSizeY1 = 225;
- const int kSizeU1 = 80;
- const int kSizeV1 = 80;
- uint32_t timestamp2 = 4;
- int64_t ntp_time_ms2 = 5;
- int64_t render_time_ms2 = 6;
- int stride_y2 = 30;
- int stride_u2 = 20;
- int stride_v2 = 20;
- int width2 = 30;
- int height2 = 30;
- const int kSizeY2 = 900;
- const int kSizeU2 = 300;
- const int kSizeV2 = 300;
- // Initialize frame1 values.
- EXPECT_EQ(0, frame1.CreateEmptyFrame(width1, height1,
- stride_y1, stride_u1, stride_v1));
- frame1.set_timestamp(timestamp1);
- frame1.set_ntp_time_ms(ntp_time_ms1);
- frame1.set_render_time_ms(render_time_ms1);
- // Set memory for frame1.
- uint8_t buffer_y1[kSizeY1];
- uint8_t buffer_u1[kSizeU1];
- uint8_t buffer_v1[kSizeV1];
- memset(buffer_y1, 2, kSizeY1);
- memset(buffer_u1, 4, kSizeU1);
- memset(buffer_v1, 8, kSizeV1);
- frame1.CreateFrame(kSizeY1, buffer_y1,
- kSizeU1, buffer_u1,
- kSizeV1, buffer_v1,
- width1, height1, stride_y1, stride_u1, stride_v1);
- // Initialize frame2 values.
- EXPECT_EQ(0, frame2.CreateEmptyFrame(width2, height2,
- stride_y2, stride_u2, stride_v2));
- frame2.set_timestamp(timestamp2);
- frame1.set_ntp_time_ms(ntp_time_ms2);
- frame2.set_render_time_ms(render_time_ms2);
- // Set memory for frame2.
- uint8_t buffer_y2[kSizeY2];
- uint8_t buffer_u2[kSizeU2];
- uint8_t buffer_v2[kSizeV2];
- memset(buffer_y2, 0, kSizeY2);
- memset(buffer_u2, 1, kSizeU2);
- memset(buffer_v2, 2, kSizeV2);
- frame2.CreateFrame(kSizeY2, buffer_y2,
- kSizeU2, buffer_u2,
- kSizeV2, buffer_v2,
- width2, height2, stride_y2, stride_u2, stride_v2);
- // Copy frames for subsequent comparison.
- I420VideoFrame frame1_copy, frame2_copy;
- frame1_copy.CopyFrame(frame1);
- frame2_copy.CopyFrame(frame2);
- // Swap frames.
- frame1.SwapFrame(&frame2);
- // Verify swap.
- EXPECT_TRUE(EqualFrames(frame1_copy, frame2));
- 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());
+TEST(TestI420VideoFrame, TextureInitialValues) {
+ NativeHandleImpl handle;
+ I420VideoFrame frame(&handle, 640, 480, 100, 10, webrtc::kVideoRotation_0,
+ rtc::Callback0<void>());
+ EXPECT_EQ(640, frame.width());
+ EXPECT_EQ(480, frame.height());
+ EXPECT_EQ(100u, frame.timestamp());
+ EXPECT_EQ(10, frame.render_time_ms());
+ EXPECT_EQ(&handle, frame.native_handle());
+
+ frame.set_timestamp(200);
+ EXPECT_EQ(200u, frame.timestamp());
+ frame.set_render_time_ms(20);
+ EXPECT_EQ(20, frame.render_time_ms());
}
-bool EqualFrames(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2) {
- return (EqualFramesExceptSize(frame1, frame2) &&
- (frame1.allocated_size(kYPlane) == frame2.allocated_size(kYPlane)) &&
- (frame1.allocated_size(kUPlane) == frame2.allocated_size(kUPlane)) &&
- (frame1.allocated_size(kVPlane) == frame2.allocated_size(kVPlane)));
+TEST(TestI420VideoFrame, NoLongerNeeded) {
+ NativeHandleImpl handle;
+ ASSERT_FALSE(handle.no_longer_needed());
+ I420VideoFrame* frame = new I420VideoFrame(
+ &handle, 640, 480, 100, 200, webrtc::kVideoRotation_0,
+ rtc::Bind(&NativeHandleImpl::SetNoLongerNeeded, &handle));
+ EXPECT_FALSE(handle.no_longer_needed());
+ delete frame;
+ EXPECT_TRUE(handle.no_longer_needed());
}
-bool EqualFramesExceptSize(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2) {
+bool EqualPlane(const uint8_t* data1,
+ const uint8_t* data2,
+ int stride,
+ int width,
+ int height) {
+ for (int y = 0; y < height; ++y) {
+ if (memcmp(data1, data2, width) != 0)
+ return false;
+ data1 += stride;
+ data2 += stride;
+ }
+ return true;
+}
+
+bool EqualFrames(const I420VideoFrame& frame1, const I420VideoFrame& frame2) {
if ((frame1.width() != frame2.width()) ||
(frame1.height() != frame2.height()) ||
(frame1.stride(kYPlane) != frame2.stride(kYPlane)) ||
@@ -275,16 +306,23 @@ bool EqualFramesExceptSize(const I420VideoFrame& frame1,
(frame1.render_time_ms() != frame2.render_time_ms())) {
return false;
}
- // Memory should be the equal for the minimum of the two sizes.
- int size_y = std::min(frame1.allocated_size(kYPlane),
- frame2.allocated_size(kYPlane));
- int size_u = std::min(frame1.allocated_size(kUPlane),
- frame2.allocated_size(kUPlane));
- int size_v = std::min(frame1.allocated_size(kVPlane),
- frame2.allocated_size(kVPlane));
- return (memcmp(frame1.buffer(kYPlane), frame2.buffer(kYPlane), size_y) == 0 &&
- memcmp(frame1.buffer(kUPlane), frame2.buffer(kUPlane), size_u) == 0 &&
- memcmp(frame1.buffer(kVPlane), frame2.buffer(kVPlane), size_v) == 0);
+ const int half_width = (frame1.width() + 1) / 2;
+ const int half_height = (frame1.height() + 1) / 2;
+ return EqualPlane(frame1.buffer(kYPlane), frame2.buffer(kYPlane),
+ frame1.stride(kYPlane), frame1.width(), frame1.height()) &&
+ EqualPlane(frame1.buffer(kUPlane), frame2.buffer(kUPlane),
+ frame1.stride(kUPlane), half_width, half_height) &&
+ EqualPlane(frame1.buffer(kVPlane), frame2.buffer(kVPlane),
+ frame1.stride(kVPlane), half_width, half_height);
+}
+
+bool EqualTextureFrames(const I420VideoFrame& frame1,
+ const I420VideoFrame& frame2) {
+ return ((frame1.native_handle() == frame2.native_handle()) &&
+ (frame1.width() == frame2.width()) &&
+ (frame1.height() == frame2.height()) &&
+ (frame1.timestamp() == frame2.timestamp()) &&
+ (frame1.render_time_ms() == frame2.render_time_ms()));
}
int ExpectedSize(int plane_stride, int image_height, PlaneType type) {
diff --git a/chromium/third_party/webrtc/common_video/incoming_video_stream.cc b/chromium/third_party/webrtc/common_video/incoming_video_stream.cc
new file mode 100644
index 00000000000..471e6dc9f46
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/incoming_video_stream.cc
@@ -0,0 +1,257 @@
+/*
+ * 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/interface/incoming_video_stream.h"
+
+#include <assert.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif defined(WEBRTC_LINUX)
+#include <sys/time.h>
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/common_video/video_render_frames.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/event_wrapper.h"
+#include "webrtc/system_wrappers/interface/thread_wrapper.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+#include "webrtc/system_wrappers/interface/trace.h"
+
+namespace webrtc {
+
+IncomingVideoStream::IncomingVideoStream(uint32_t stream_id)
+ : stream_id_(stream_id),
+ stream_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
+ thread_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
+ buffer_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
+ incoming_render_thread_(),
+ deliver_buffer_event_(EventTimerWrapper::Create()),
+ running_(false),
+ external_callback_(nullptr),
+ render_callback_(nullptr),
+ render_buffers_(new VideoRenderFrames()),
+ incoming_rate_(0),
+ last_rate_calculation_time_ms_(0),
+ num_frames_since_last_calculation_(0),
+ last_render_time_ms_(0),
+ temp_frame_(),
+ start_image_(),
+ timeout_image_(),
+ timeout_time_() {
+}
+
+IncomingVideoStream::~IncomingVideoStream() {
+ Stop();
+}
+
+VideoRenderCallback* IncomingVideoStream::ModuleCallback() {
+ CriticalSectionScoped cs(stream_critsect_.get());
+ return this;
+}
+
+int32_t IncomingVideoStream::RenderFrame(const uint32_t stream_id,
+ const I420VideoFrame& video_frame) {
+ CriticalSectionScoped csS(stream_critsect_.get());
+
+ if (!running_) {
+ return -1;
+ }
+
+ // Rate statistics.
+ num_frames_since_last_calculation_++;
+ int64_t now_ms = TickTime::MillisecondTimestamp();
+ if (now_ms >= last_rate_calculation_time_ms_ + kFrameRatePeriodMs) {
+ incoming_rate_ =
+ static_cast<uint32_t>(1000 * num_frames_since_last_calculation_ /
+ (now_ms - last_rate_calculation_time_ms_));
+ num_frames_since_last_calculation_ = 0;
+ last_rate_calculation_time_ms_ = now_ms;
+ }
+
+ // Insert frame.
+ CriticalSectionScoped csB(buffer_critsect_.get());
+ if (render_buffers_->AddFrame(video_frame) == 1)
+ deliver_buffer_event_->Set();
+
+ return 0;
+}
+
+int32_t IncomingVideoStream::SetStartImage(
+ const I420VideoFrame& video_frame) {
+ CriticalSectionScoped csS(thread_critsect_.get());
+ return start_image_.CopyFrame(video_frame);
+}
+
+int32_t IncomingVideoStream::SetTimeoutImage(
+ const I420VideoFrame& video_frame, const uint32_t timeout) {
+ CriticalSectionScoped csS(thread_critsect_.get());
+ timeout_time_ = timeout;
+ return timeout_image_.CopyFrame(video_frame);
+}
+
+void IncomingVideoStream::SetRenderCallback(
+ VideoRenderCallback* render_callback) {
+ CriticalSectionScoped cs(thread_critsect_.get());
+ render_callback_ = render_callback;
+}
+
+int32_t IncomingVideoStream::SetExpectedRenderDelay(
+ int32_t delay_ms) {
+ CriticalSectionScoped csS(stream_critsect_.get());
+ if (running_) {
+ return -1;
+ }
+ CriticalSectionScoped cs(buffer_critsect_.get());
+ return render_buffers_->SetRenderDelay(delay_ms);
+}
+
+void IncomingVideoStream::SetExternalCallback(
+ VideoRenderCallback* external_callback) {
+ CriticalSectionScoped cs(thread_critsect_.get());
+ external_callback_ = external_callback;
+}
+
+int32_t IncomingVideoStream::Start() {
+ CriticalSectionScoped csS(stream_critsect_.get());
+ if (running_) {
+ return 0;
+ }
+
+ CriticalSectionScoped csT(thread_critsect_.get());
+ assert(incoming_render_thread_ == NULL);
+
+ incoming_render_thread_ = ThreadWrapper::CreateThread(
+ IncomingVideoStreamThreadFun, this, "IncomingVideoStreamThread");
+ if (!incoming_render_thread_) {
+ return -1;
+ }
+
+ if (incoming_render_thread_->Start()) {
+ } else {
+ return -1;
+ }
+ incoming_render_thread_->SetPriority(kRealtimePriority);
+ deliver_buffer_event_->StartTimer(false, kEventStartupTimeMs);
+
+ running_ = true;
+ return 0;
+}
+
+int32_t IncomingVideoStream::Stop() {
+ CriticalSectionScoped cs_stream(stream_critsect_.get());
+
+ if (!running_) {
+ return 0;
+ }
+
+ ThreadWrapper* thread = NULL;
+ {
+ CriticalSectionScoped cs_thread(thread_critsect_.get());
+ if (incoming_render_thread_) {
+ // Setting the incoming render thread to NULL marks that we're performing
+ // a shutdown and will make IncomingVideoStreamProcess abort after wakeup.
+ thread = incoming_render_thread_.release();
+ deliver_buffer_event_->StopTimer();
+ // Set the event to allow the thread to wake up and shut down without
+ // waiting for a timeout.
+ deliver_buffer_event_->Set();
+ }
+ }
+ if (thread) {
+ if (thread->Stop()) {
+ delete thread;
+ } else {
+ assert(false);
+ }
+ }
+ running_ = false;
+ return 0;
+}
+
+int32_t IncomingVideoStream::Reset() {
+ CriticalSectionScoped cs_buffer(buffer_critsect_.get());
+ render_buffers_->ReleaseAllFrames();
+ return 0;
+}
+
+uint32_t IncomingVideoStream::StreamId() const {
+ return stream_id_;
+}
+
+uint32_t IncomingVideoStream::IncomingRate() const {
+ CriticalSectionScoped cs(stream_critsect_.get());
+ return incoming_rate_;
+}
+
+bool IncomingVideoStream::IncomingVideoStreamThreadFun(void* obj) {
+ return static_cast<IncomingVideoStream*>(obj)->IncomingVideoStreamProcess();
+}
+
+bool IncomingVideoStream::IncomingVideoStreamProcess() {
+ if (kEventError != deliver_buffer_event_->Wait(kEventMaxWaitTimeMs)) {
+ CriticalSectionScoped cs(thread_critsect_.get());
+ if (incoming_render_thread_ == NULL) {
+ // Terminating
+ return false;
+ }
+ // Get a new frame to render and the time for the frame after this one.
+ I420VideoFrame frame_to_render;
+ uint32_t wait_time;
+ {
+ CriticalSectionScoped cs(buffer_critsect_.get());
+ frame_to_render = render_buffers_->FrameToRender();
+ wait_time = render_buffers_->TimeToNextFrameRelease();
+ }
+
+ // Set timer for next frame to render.
+ if (wait_time > kEventMaxWaitTimeMs) {
+ wait_time = kEventMaxWaitTimeMs;
+ }
+ deliver_buffer_event_->StartTimer(false, wait_time);
+
+ if (frame_to_render.IsZeroSize()) {
+ if (render_callback_) {
+ if (last_render_time_ms_ == 0 && !start_image_.IsZeroSize()) {
+ // We have not rendered anything and have a start image.
+ temp_frame_.CopyFrame(start_image_);
+ render_callback_->RenderFrame(stream_id_, temp_frame_);
+ } else if (!timeout_image_.IsZeroSize() &&
+ last_render_time_ms_ + timeout_time_ <
+ TickTime::MillisecondTimestamp()) {
+ // Render a timeout image.
+ temp_frame_.CopyFrame(timeout_image_);
+ render_callback_->RenderFrame(stream_id_, temp_frame_);
+ }
+ }
+
+ // No frame.
+ return true;
+ }
+
+ // Send frame for rendering.
+ if (external_callback_) {
+ external_callback_->RenderFrame(stream_id_, frame_to_render);
+ } else if (render_callback_) {
+ render_callback_->RenderFrame(stream_id_, frame_to_render);
+ }
+
+ // We're done with this frame.
+ if (!frame_to_render.IsZeroSize())
+ last_render_time_ms_ = frame_to_render.render_time_ms();
+ }
+ return true;
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/interface/i420_buffer_pool.h b/chromium/third_party/webrtc/common_video/interface/i420_buffer_pool.h
new file mode 100644
index 00000000000..df862cdba51
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/interface/i420_buffer_pool.h
@@ -0,0 +1,43 @@
+/*
+ * 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_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_
+#define WEBRTC_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_
+
+#include <list>
+
+#include "webrtc/base/thread_checker.h"
+#include "webrtc/common_video/interface/video_frame_buffer.h"
+
+namespace webrtc {
+
+// Simple buffer pool to avoid unnecessary allocations of I420Buffer objects.
+// The pool manages the memory of the I420Buffer returned from CreateBuffer.
+// When the I420Buffer is destructed, the memory is returned to the pool for use
+// by subsequent calls to CreateBuffer. If the resolution passed to CreateBuffer
+// changes, old buffers will be purged from the pool.
+class I420BufferPool {
+ public:
+ I420BufferPool();
+ // Returns a buffer from the pool, or creates a new buffer if no suitable
+ // buffer exists in the pool.
+ rtc::scoped_refptr<VideoFrameBuffer> CreateBuffer(int width, int height);
+ // Clears buffers_ and detaches the thread checker so that it can be reused
+ // later from another thread.
+ void Release();
+
+ private:
+ rtc::ThreadChecker thread_checker_;
+ std::list<rtc::scoped_refptr<I420Buffer>> buffers_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_VIDEO_INTERFACE_I420_BUFFER_POOL_H_
diff --git a/chromium/third_party/webrtc/common_video/interface/i420_video_frame.h b/chromium/third_party/webrtc/common_video/interface/i420_video_frame.h
deleted file mode 100644
index ba23c87a8f0..00000000000
--- a/chromium/third_party/webrtc/common_video/interface/i420_video_frame.h
+++ /dev/null
@@ -1,17 +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.
- */
-
-#ifndef COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
-#define COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
-
-// TODO(pbos): Remove this file and include webrtc/video_frame.h instead.
-#include "webrtc/video_frame.h"
-
-#endif // COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
diff --git a/chromium/third_party/webrtc/common_video/interface/incoming_video_stream.h b/chromium/third_party/webrtc/common_video/interface/incoming_video_stream.h
new file mode 100644
index 00000000000..f5383b543c4
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/interface/incoming_video_stream.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_
+#define WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/common_video/video_render_frames.h"
+
+namespace webrtc {
+class CriticalSectionWrapper;
+class EventTimerWrapper;
+class ThreadWrapper;
+
+class VideoRenderCallback {
+ public:
+ virtual int32_t RenderFrame(const uint32_t streamId,
+ const I420VideoFrame& videoFrame) = 0;
+ protected:
+ virtual ~VideoRenderCallback() {}
+};
+
+class IncomingVideoStream : public VideoRenderCallback {
+ public:
+ explicit IncomingVideoStream(uint32_t stream_id);
+ ~IncomingVideoStream();
+
+ // Get callback to deliver frames to the module.
+ VideoRenderCallback* ModuleCallback();
+ virtual int32_t RenderFrame(const uint32_t stream_id,
+ const I420VideoFrame& video_frame);
+
+ // Set callback to the platform dependent code.
+ void SetRenderCallback(VideoRenderCallback* render_callback);
+
+ // Callback for file recording, snapshot, ...
+ void SetExternalCallback(VideoRenderCallback* render_object);
+
+ // Start/Stop.
+ int32_t Start();
+ int32_t Stop();
+
+ // Clear all buffers.
+ int32_t Reset();
+
+ // Properties.
+ uint32_t StreamId() const;
+ uint32_t IncomingRate() const;
+
+ int32_t SetStartImage(const I420VideoFrame& video_frame);
+
+ int32_t SetTimeoutImage(const I420VideoFrame& video_frame,
+ const uint32_t timeout);
+
+ int32_t SetExpectedRenderDelay(int32_t delay_ms);
+
+ protected:
+ static bool IncomingVideoStreamThreadFun(void* obj);
+ bool IncomingVideoStreamProcess();
+
+ private:
+ enum { kEventStartupTimeMs = 10 };
+ enum { kEventMaxWaitTimeMs = 100 };
+ enum { kFrameRatePeriodMs = 1000 };
+
+ uint32_t const stream_id_;
+ // Critsects in allowed to enter order.
+ const rtc::scoped_ptr<CriticalSectionWrapper> stream_critsect_;
+ const rtc::scoped_ptr<CriticalSectionWrapper> thread_critsect_;
+ const rtc::scoped_ptr<CriticalSectionWrapper> buffer_critsect_;
+ rtc::scoped_ptr<ThreadWrapper> incoming_render_thread_
+ GUARDED_BY(thread_critsect_);
+ rtc::scoped_ptr<EventTimerWrapper> deliver_buffer_event_;
+
+ bool running_ GUARDED_BY(stream_critsect_);
+ VideoRenderCallback* external_callback_ GUARDED_BY(thread_critsect_);
+ VideoRenderCallback* render_callback_ GUARDED_BY(thread_critsect_);
+ const rtc::scoped_ptr<VideoRenderFrames> render_buffers_
+ GUARDED_BY(buffer_critsect_);
+
+ uint32_t incoming_rate_ GUARDED_BY(stream_critsect_);
+ int64_t last_rate_calculation_time_ms_ GUARDED_BY(stream_critsect_);
+ uint16_t num_frames_since_last_calculation_ GUARDED_BY(stream_critsect_);
+ int64_t last_render_time_ms_ GUARDED_BY(thread_critsect_);
+ I420VideoFrame temp_frame_ GUARDED_BY(thread_critsect_);
+ I420VideoFrame start_image_ GUARDED_BY(thread_critsect_);
+ I420VideoFrame timeout_image_ GUARDED_BY(thread_critsect_);
+ uint32_t timeout_time_ GUARDED_BY(thread_critsect_);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_VIDEO_INTERFACE_INCOMING_VIDEO_STREAM_H_
diff --git a/chromium/third_party/webrtc/common_video/interface/native_handle.h b/chromium/third_party/webrtc/common_video/interface/native_handle.h
deleted file mode 100644
index d078d4ca2e9..00000000000
--- a/chromium/third_party/webrtc/common_video/interface/native_handle.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2013 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 COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
-#define COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
-
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-// A class to store an opaque handle of the underlying video frame. This is used
-// when the frame is backed by a texture. WebRTC carries the handle in
-// TextureVideoFrame. This object keeps a reference to the handle. The reference
-// is cleared when the object is destroyed. It is important to destroy the
-// object as soon as possible so the texture can be recycled.
-class NativeHandle {
- public:
- virtual ~NativeHandle() {}
- // For scoped_refptr
- virtual int32_t AddRef() = 0;
- virtual int32_t Release() = 0;
-
- // Gets the handle.
- virtual void* GetHandle() = 0;
-};
-
-} // namespace webrtc
-
-#endif // COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
diff --git a/chromium/third_party/webrtc/common_video/interface/texture_video_frame.h b/chromium/third_party/webrtc/common_video/interface/texture_video_frame.h
deleted file mode 100644
index 2c625ab57d7..00000000000
--- a/chromium/third_party/webrtc/common_video/interface/texture_video_frame.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013 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 COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
-#define COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
-
-// TextureVideoFrame class
-//
-// Storing and handling of video frames backed by textures.
-
-#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 {
-
-class TextureVideoFrame : public I420VideoFrame {
- public:
- TextureVideoFrame(NativeHandle* handle,
- int width,
- 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 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 ResetSize() 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
-
-#endif // COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
diff --git a/chromium/third_party/webrtc/common_video/interface/video_frame_buffer.h b/chromium/third_party/webrtc/common_video/interface/video_frame_buffer.h
new file mode 100644
index 00000000000..1aefa6c6114
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/interface/video_frame_buffer.h
@@ -0,0 +1,150 @@
+/*
+ * 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/callback.h"
+#include "webrtc/base/refcount.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/scoped_ref_ptr.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 void* 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;
+ void* native_handle() const override;
+
+ protected:
+ ~I420Buffer() override;
+
+ private:
+ 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 is a VideoFrameBuffer wrapper around a |native_handle|.
+// |native_handle| must be valid for the lifetime of an instance of this object.
+// |no_longer_used| can be used to manage the lifetime of |native_handle|.
+class TextureBuffer : public VideoFrameBuffer {
+ public:
+ TextureBuffer(void* native_handle,
+ int width,
+ int height,
+ const rtc::Callback0<void>& no_longer_used);
+ 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;
+ void* native_handle() const override;
+
+ private:
+ friend class rtc::RefCountedObject<TextureBuffer>;
+ ~TextureBuffer() override;
+
+ // |native_handle_| is a raw pointer and not owned by TextureBuffer.
+ void* native_handle_;
+ const int width_;
+ const int height_;
+ rtc::Callback0<void> no_longer_used_cb_;
+};
+
+class WrappedI420Buffer : public webrtc::VideoFrameBuffer {
+ public:
+ WrappedI420Buffer(int desired_width,
+ int desired_height,
+ int width,
+ int height,
+ const uint8_t* y_plane,
+ int y_stride,
+ const uint8_t* u_plane,
+ int u_stride,
+ const uint8_t* v_plane,
+ int v_stride,
+ const rtc::Callback0<void>& no_longer_used);
+ 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;
+ void* native_handle() const override;
+
+ private:
+ friend class rtc::RefCountedObject<WrappedI420Buffer>;
+ ~WrappedI420Buffer() override;
+
+ int width_;
+ int height_;
+ const uint8_t* y_plane_;
+ const uint8_t* u_plane_;
+ const uint8_t* v_plane_;
+ const int y_stride_;
+ const int u_stride_;
+ const int v_stride_;
+ rtc::Callback0<void> no_longer_used_cb_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_VIDEO_FRAME_BUFFER_H_
diff --git a/chromium/third_party/webrtc/common_video/libyuv/include/scaler.h b/chromium/third_party/webrtc/common_video/libyuv/include/scaler.h
index ce7462c121b..48f2b7a0261 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/include/scaler.h
+++ b/chromium/third_party/webrtc/common_video/libyuv/include/scaler.h
@@ -15,9 +15,10 @@
#ifndef WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_
#define WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_SCALER_H_
-#include "webrtc/common_video/interface/i420_video_frame.h"
+#include "webrtc/common_video/interface/i420_buffer_pool.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/typedefs.h"
+#include "webrtc/video_frame.h"
namespace webrtc {
@@ -43,8 +44,7 @@ class Scaler {
ScaleMethod method);
// Scale frame
- // Memory is allocated by user. If dst_frame is not of sufficient size,
- // the frame will be reallocated to the appropriate size.
+ // Memory is allocated by this object and recycled using |buffer_pool_|.
// Return value: 0 - OK,
// -1 - parameter error
// -2 - scaler not set
@@ -62,6 +62,7 @@ class Scaler {
int dst_width_;
int dst_height_;
bool set_;
+ I420BufferPool buffer_pool_;
};
} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/chromium/third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h
index 70d8e2ae5fa..176585b7fea 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h
+++ b/chromium/third_party/webrtc/common_video/libyuv/include/webrtc_libyuv.h
@@ -18,8 +18,9 @@
#include <stdio.h>
#include "webrtc/common_types.h" // RawVideoTypes.
-#include "webrtc/common_video/interface/i420_video_frame.h"
+#include "webrtc/common_video/rotation.h"
#include "webrtc/typedefs.h"
+#include "webrtc/video_frame.h"
namespace webrtc {
@@ -50,15 +51,6 @@ const double kPerfectPSNR = 48.0f;
// TODO(wu): Consolidate types into one type throughout WebRtc.
VideoType RawVideoTypeToCommonVideoVideoType(RawVideoType type);
-// Supported rotation
-// Direction of rotation - clockwise.
-enum VideoRotationMode {
- kRotateNone = 0,
- kRotate90 = 90,
- kRotate180 = 180,
- kRotate270 = 270,
-};
-
// Align integer values.
// Input:
// - value : Input value to be aligned.
@@ -81,8 +73,8 @@ void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv);
// - width :frame width in pixels.
// - height :frame height in pixels.
// Return value: :The required size in bytes to accommodate the specified
-// video frame or -1 in case of an error .
-int CalcBufferSize(VideoType type, int width, int height);
+// video frame.
+size_t CalcBufferSize(VideoType type, int width, int height);
// TODO(mikhal): Add unit test for these two functions and determine location.
// Print I420VideoFrame to file
@@ -101,7 +93,7 @@ int PrintI420VideoFrame(const I420VideoFrame& frame, FILE* file);
// - buffer : Pointer to buffer
// Return value: length of buffer if OK, < 0 otherwise.
int ExtractBuffer(const I420VideoFrame& input_frame,
- int size, uint8_t* buffer);
+ size_t size, uint8_t* buffer);
// Convert To I420
// Input:
// - src_video_type : Type of input video.
@@ -117,10 +109,12 @@ int ExtractBuffer(const I420VideoFrame& input_frame,
int ConvertToI420(VideoType src_video_type,
const uint8_t* src_frame,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int sample_size,
- VideoRotationMode rotation,
+ int crop_x,
+ int crop_y,
+ int src_width,
+ int src_height,
+ size_t sample_size,
+ VideoRotation rotation,
I420VideoFrame* dst_frame);
// Convert From I420
@@ -152,19 +146,6 @@ int ConvertNV12ToRGB565(const uint8_t* src_frame,
uint8_t* dst_frame,
int width, int height);
-// Mirror functions
-// The following 2 functions perform mirroring on a given image
-// (LeftRight/UpDown).
-// Input:
-// - src_frame : Pointer to a source frame.
-// - dst_frame : Pointer to a destination frame.
-// Return value: 0 if OK, < 0 otherwise.
-// It is assumed that src and dst frames have equal dimensions.
-int MirrorI420LeftRight(const I420VideoFrame* src_frame,
- I420VideoFrame* dst_frame);
-int MirrorI420UpDown(const I420VideoFrame* src_frame,
- I420VideoFrame* dst_frame);
-
// Compute PSNR for an I420 frame (all planes).
// Returns the PSNR in decibel, to a maximum of kInfinitePSNR.
double I420PSNR(const I420VideoFrame* ref_frame,
diff --git a/chromium/third_party/webrtc/common_video/libyuv/libyuv_unittest.cc b/chromium/third_party/webrtc/common_video/libyuv/libyuv_unittest.cc
index 0abe7f3cc0e..bf31cbacd47 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/libyuv_unittest.cc
+++ b/chromium/third_party/webrtc/common_video/libyuv/libyuv_unittest.cc
@@ -12,11 +12,11 @@
#include <string.h>
#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/common_video/interface/i420_video_frame.h"
+#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/test/testsupport/fileutils.h"
+#include "webrtc/video_frame.h"
namespace webrtc {
@@ -84,12 +84,12 @@ class TestLibYuv : public ::testing::Test {
FILE* source_file_;
I420VideoFrame orig_frame_;
- scoped_ptr<uint8_t[]> orig_buffer_;
+ rtc::scoped_ptr<uint8_t[]> orig_buffer_;
const int width_;
const int height_;
const int size_y_;
const int size_uv_;
- const int frame_length_;
+ const size_t frame_length_;
};
TestLibYuv::TestLibYuv()
@@ -110,11 +110,11 @@ void TestLibYuv::SetUp() {
ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<<
input_file_name << "\n";
- EXPECT_EQ(fread(orig_buffer_.get(), 1, frame_length_, source_file_),
- static_cast<unsigned int>(frame_length_));
- EXPECT_EQ(0, orig_frame_.CreateFrame(size_y_, orig_buffer_.get(),
- size_uv_, orig_buffer_.get() + size_y_,
- size_uv_, orig_buffer_.get() +
+ EXPECT_EQ(frame_length_,
+ fread(orig_buffer_.get(), 1, frame_length_, source_file_));
+ EXPECT_EQ(0, orig_frame_.CreateFrame(orig_buffer_.get(),
+ orig_buffer_.get() + size_y_,
+ orig_buffer_.get() +
size_y_ + size_uv_,
width_, height_,
width_, (width_ + 1) / 2,
@@ -147,12 +147,11 @@ TEST_F(TestLibYuv, ConvertTest) {
(width_ + 1) / 2,
(width_ + 1) / 2));
printf("\nConvert #%d I420 <-> I420 \n", j);
- scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]);
+ rtc::scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0,
out_i420_buffer.get()));
- EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0,
- width_, height_,
- 0, kRotateNone, &res_i420_frame));
+ EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0, width_,
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -162,7 +161,7 @@ TEST_F(TestLibYuv, ConvertTest) {
j++;
printf("\nConvert #%d I420 <-> RGB24\n", j);
- scoped_ptr<uint8_t[]> res_rgb_buffer2(new uint8_t[width_ * height_ * 3]);
+ rtc::scoped_ptr<uint8_t[]> res_rgb_buffer2(new uint8_t[width_ * height_ * 3]);
// Align the stride values for the output frame.
int stride_y = 0;
int stride_uv = 0;
@@ -172,7 +171,7 @@ TEST_F(TestLibYuv, ConvertTest) {
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kRGB24, 0, res_rgb_buffer2.get()));
EXPECT_EQ(0, ConvertToI420(kRGB24, res_rgb_buffer2.get(), 0, 0, width_,
- height_, 0, kRotateNone, &res_i420_frame));
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -184,10 +183,10 @@ TEST_F(TestLibYuv, ConvertTest) {
j++;
printf("\nConvert #%d I420 <-> UYVY\n", j);
- scoped_ptr<uint8_t[]> out_uyvy_buffer(new uint8_t[width_ * height_ * 2]);
+ rtc::scoped_ptr<uint8_t[]> out_uyvy_buffer(new uint8_t[width_ * height_ * 2]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kUYVY, 0, out_uyvy_buffer.get()));
EXPECT_EQ(0, ConvertToI420(kUYVY, out_uyvy_buffer.get(), 0, 0, width_,
- height_, 0, kRotateNone, &res_i420_frame));
+ height_, 0, kVideoRotation_0, &res_i420_frame));
psnr = I420PSNR(&orig_frame_, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
@@ -196,33 +195,33 @@ TEST_F(TestLibYuv, ConvertTest) {
j++;
printf("\nConvert #%d I420 <-> YV12\n", j);
- scoped_ptr<uint8_t[]> outYV120Buffer(new uint8_t[frame_length_]);
- scoped_ptr<uint8_t[]> res_i420_buffer(new uint8_t[frame_length_]);
+ rtc::scoped_ptr<uint8_t[]> outYV120Buffer(new uint8_t[frame_length_]);
+ rtc::scoped_ptr<uint8_t[]> res_i420_buffer(new uint8_t[frame_length_]);
I420VideoFrame yv12_frame;
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kYV12, 0, outYV120Buffer.get()));
- yv12_frame.CreateFrame(size_y_, outYV120Buffer.get(),
- size_uv_, outYV120Buffer.get() + size_y_,
- size_uv_, outYV120Buffer.get() + size_y_ + size_uv_,
+ yv12_frame.CreateFrame(outYV120Buffer.get(),
+ outYV120Buffer.get() + size_y_,
+ outYV120Buffer.get() + size_y_ + size_uv_,
width_, height_,
width_, (width_ + 1) / 2, (width_ + 1) / 2);
EXPECT_EQ(0, ConvertFromYV12(yv12_frame, kI420, 0, res_i420_buffer.get()));
- if (fwrite(res_i420_buffer.get(), 1, frame_length_,
- output_file) != static_cast<unsigned int>(frame_length_)) {
+ if (fwrite(res_i420_buffer.get(), 1, frame_length_, output_file) !=
+ frame_length_) {
return;
}
- ConvertToI420(kI420, res_i420_buffer.get(), 0, 0,
- width_, height_, 0, kRotateNone, &res_i420_frame);
+ ConvertToI420(kI420, res_i420_buffer.get(), 0, 0, width_, height_, 0,
+ kVideoRotation_0, &res_i420_frame);
psnr = I420PSNR(&orig_frame_, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
j++;
printf("\nConvert #%d I420 <-> YUY2\n", j);
- scoped_ptr<uint8_t[]> out_yuy2_buffer(new uint8_t[width_ * height_ * 2]);
+ rtc::scoped_ptr<uint8_t[]> out_yuy2_buffer(new uint8_t[width_ * height_ * 2]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kYUY2, 0, out_yuy2_buffer.get()));
EXPECT_EQ(0, ConvertToI420(kYUY2, out_yuy2_buffer.get(), 0, 0, width_,
- height_, 0, kRotateNone, &res_i420_frame));
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -231,12 +230,13 @@ TEST_F(TestLibYuv, ConvertTest) {
psnr = I420PSNR(&orig_frame_, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
printf("\nConvert #%d I420 <-> RGB565\n", j);
- scoped_ptr<uint8_t[]> out_rgb565_buffer(new uint8_t[width_ * height_ * 2]);
+ rtc::scoped_ptr<uint8_t[]> out_rgb565_buffer(
+ new uint8_t[width_ * height_ * 2]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kRGB565, 0,
out_rgb565_buffer.get()));
EXPECT_EQ(0, ConvertToI420(kRGB565, out_rgb565_buffer.get(), 0, 0, width_,
- height_, 0, kRotateNone, &res_i420_frame));
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -250,12 +250,13 @@ TEST_F(TestLibYuv, ConvertTest) {
EXPECT_GT(ceil(psnr), 40);
printf("\nConvert #%d I420 <-> ARGB8888\n", j);
- scoped_ptr<uint8_t[]> out_argb8888_buffer(new uint8_t[width_ * height_ * 4]);
+ rtc::scoped_ptr<uint8_t[]> out_argb8888_buffer(
+ new uint8_t[width_ * height_ * 4]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kARGB, 0,
out_argb8888_buffer.get()));
EXPECT_EQ(0, ConvertToI420(kARGB, out_argb8888_buffer.get(), 0, 0, width_,
- height_, 0, kRotateNone, &res_i420_frame));
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -283,12 +284,11 @@ TEST_F(TestLibYuv, ConvertAlignedFrame) {
Calc16ByteAlignedStride(width_, &stride_y, &stride_uv);
EXPECT_EQ(0,res_i420_frame.CreateEmptyFrame(width_, height_,
stride_y, stride_uv, stride_uv));
- scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]);
+ rtc::scoped_ptr<uint8_t[]> out_i420_buffer(new uint8_t[frame_length_]);
EXPECT_EQ(0, ConvertFromI420(orig_frame_, kI420, 0,
out_i420_buffer.get()));
- EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0,
- width_, height_,
- 0, kRotateNone, &res_i420_frame));
+ EXPECT_EQ(0, ConvertToI420(kI420, out_i420_buffer.get(), 0, 0, width_,
+ height_, 0, kVideoRotation_0, &res_i420_frame));
if (PrintI420VideoFrame(res_i420_frame, output_file) < 0) {
return;
@@ -312,81 +312,15 @@ TEST_F(TestLibYuv, RotateTest) {
stride_y,
stride_uv,
stride_uv));
- EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0,
- width_, height_,
- 0, kRotate90, &rotated_res_i420_frame));
- EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0,
- width_, height_,
- 0, kRotate270, &rotated_res_i420_frame));
+ EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_,
+ 0, kVideoRotation_90, &rotated_res_i420_frame));
+ EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_,
+ 0, kVideoRotation_270, &rotated_res_i420_frame));
EXPECT_EQ(0,rotated_res_i420_frame.CreateEmptyFrame(width_, height_,
width_, (width_ + 1) / 2,
(width_ + 1) / 2));
- EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0,
- width_, height_,
- 0, kRotate180, &rotated_res_i420_frame));
-}
-
-TEST_F(TestLibYuv, MirrorTest) {
- // TODO(mikhal): Add an automated test to confirm output.
- std::string str;
- int width = 16;
- int half_width = (width + 1) / 2;
- int height = 8;
- int half_height = (height + 1) / 2;
-
- I420VideoFrame test_frame;
- test_frame.CreateEmptyFrame(width, height, width,
- half_width, half_width);
- memset(test_frame.buffer(kYPlane), 255, width * height);
- memset(test_frame.buffer(kUPlane), 255, half_width * half_height);
- memset(test_frame.buffer(kVPlane), 255, half_width * half_height);
-
- // Create input frame.
- I420VideoFrame in_frame, test_in_frame;
- in_frame.CreateEmptyFrame(width, height, width,
- half_width ,half_width);
- int plane_offset[kNumOfPlanes];
- plane_offset[kYPlane] = 10;
- plane_offset[kUPlane] = 100;
- plane_offset[kVPlane] = 200;
- CreateImage(&in_frame, plane_offset);
- EXPECT_EQ(0, PrintFrame(&in_frame, "InputFrame"));
- test_in_frame.CopyFrame(in_frame);
-
- I420VideoFrame out_frame, test_out_frame;
- out_frame.CreateEmptyFrame(width, height, width,
- half_width ,half_width);
- CreateImage(&out_frame, plane_offset);
- test_out_frame.CopyFrame(out_frame);
-
- // Left-Right.
- std::cout << "Test Mirror function: LeftRight" << std::endl;
- EXPECT_EQ(0, MirrorI420LeftRight(&in_frame, &out_frame));
- EXPECT_EQ(0, PrintFrame(&out_frame, "OutputFrame"));
- EXPECT_EQ(0, MirrorI420LeftRight(&out_frame, &in_frame));
-
- EXPECT_EQ(0, memcmp(in_frame.buffer(kYPlane),
- test_in_frame.buffer(kYPlane), width * height));
- EXPECT_EQ(0, memcmp(in_frame.buffer(kUPlane),
- test_in_frame.buffer(kUPlane), half_width * half_height));
- EXPECT_EQ(0, memcmp(in_frame.buffer(kVPlane),
- test_in_frame.buffer(kVPlane), half_width * half_height));
-
- // UpDown
- std::cout << "Test Mirror function: UpDown" << std::endl;
- EXPECT_EQ(0, MirrorI420UpDown(&in_frame, &out_frame));
- EXPECT_EQ(0, PrintFrame(&out_frame, "OutputFrame"));
- EXPECT_EQ(0, MirrorI420UpDown(&out_frame, &test_frame));
- EXPECT_EQ(0, memcmp(in_frame.buffer(kYPlane),
- test_in_frame.buffer(kYPlane), width * height));
- EXPECT_EQ(0, memcmp(in_frame.buffer(kUPlane),
- test_in_frame.buffer(kUPlane), half_width * half_height));
- EXPECT_EQ(0, memcmp(in_frame.buffer(kVPlane),
- test_in_frame.buffer(kVPlane), half_width * half_height));
-
- // TODO(mikhal): Write to a file, and ask to look at the file.
-
- std::cout << "Do the mirrored frames look correct?" << std::endl;
+ EXPECT_EQ(0, ConvertToI420(kI420, orig_buffer_.get(), 0, 0, width_, height_,
+ 0, kVideoRotation_180, &rotated_res_i420_frame));
}
TEST_F(TestLibYuv, alignment) {
diff --git a/chromium/third_party/webrtc/common_video/libyuv/scaler.cc b/chromium/third_party/webrtc/common_video/libyuv/scaler.cc
index c9c4f5ad2a2..598c1d018f4 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/scaler.cc
+++ b/chromium/third_party/webrtc/common_video/libyuv/scaler.cc
@@ -10,6 +10,8 @@
#include "webrtc/common_video/libyuv/include/scaler.h"
+#include <algorithm>
+
// NOTE(ajm): Path provided by gyp.
#include "libyuv.h" // NOLINT
@@ -54,18 +56,37 @@ int Scaler::Scale(const I420VideoFrame& src_frame,
return -2;
// Making sure that destination frame is of sufficient size.
- // Aligning stride values based on width.
- dst_frame->CreateEmptyFrame(dst_width_, dst_height_,
- dst_width_, (dst_width_ + 1) / 2,
- (dst_width_ + 1) / 2);
+ dst_frame->set_video_frame_buffer(
+ buffer_pool_.CreateBuffer(dst_width_, dst_height_));
+
+ // We want to preserve aspect ratio instead of stretching the frame.
+ // Therefore, we need to crop the source frame. Calculate the largest center
+ // aligned region of the source frame that can be used.
+ const int cropped_src_width =
+ std::min(src_width_, dst_width_ * src_height_ / dst_height_);
+ const int cropped_src_height =
+ std::min(src_height_, dst_height_ * src_width_ / dst_width_);
+ // Make sure the offsets are even to avoid rounding errors for the U/V planes.
+ const int src_offset_x = ((src_width_ - cropped_src_width) / 2) & ~1;
+ const int src_offset_y = ((src_height_ - cropped_src_height) / 2) & ~1;
+
+ const uint8_t* y_ptr = src_frame.buffer(kYPlane) +
+ src_offset_y * src_frame.stride(kYPlane) +
+ src_offset_x;
+ const uint8_t* u_ptr = src_frame.buffer(kUPlane) +
+ src_offset_y / 2 * src_frame.stride(kUPlane) +
+ src_offset_x / 2;
+ const uint8_t* v_ptr = src_frame.buffer(kVPlane) +
+ src_offset_y / 2 * src_frame.stride(kVPlane) +
+ src_offset_x / 2;
- return libyuv::I420Scale(src_frame.buffer(kYPlane),
+ return libyuv::I420Scale(y_ptr,
src_frame.stride(kYPlane),
- src_frame.buffer(kUPlane),
+ u_ptr,
src_frame.stride(kUPlane),
- src_frame.buffer(kVPlane),
+ v_ptr,
src_frame.stride(kVPlane),
- src_width_, src_height_,
+ cropped_src_width, cropped_src_height,
dst_frame->buffer(kYPlane),
dst_frame->stride(kYPlane),
dst_frame->buffer(kUPlane),
diff --git a/chromium/third_party/webrtc/common_video/libyuv/scaler_unittest.cc b/chromium/third_party/webrtc/common_video/libyuv/scaler_unittest.cc
index f186d82d89d..19bcff652a2 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/scaler_unittest.cc
+++ b/chromium/third_party/webrtc/common_video/libyuv/scaler_unittest.cc
@@ -44,7 +44,7 @@ class TestScaler : public ::testing::Test {
const int half_height_;
const int size_y_;
const int size_uv_;
- const int frame_length_;
+ const size_t frame_length_;
};
TestScaler::TestScaler()
@@ -99,11 +99,11 @@ TEST_F(TestScaler, ScaleSendingBufferTooSmall) {
kI420, kI420,
kScalePoint));
I420VideoFrame test_frame2;
- scoped_ptr<uint8_t[]> orig_buffer(new uint8_t[frame_length_]);
+ rtc::scoped_ptr<uint8_t[]> orig_buffer(new uint8_t[frame_length_]);
EXPECT_GT(fread(orig_buffer.get(), 1, frame_length_, source_file_), 0U);
- test_frame_.CreateFrame(size_y_, orig_buffer.get(),
- size_uv_, orig_buffer.get() + size_y_,
- size_uv_, orig_buffer.get() + size_y_ + size_uv_,
+ test_frame_.CreateFrame(orig_buffer.get(),
+ orig_buffer.get() + size_y_,
+ orig_buffer.get() + size_y_ + size_uv_,
width_, height_,
width_, half_width_, half_width_);
EXPECT_EQ(0, test_scaler_.Scale(test_frame_, &test_frame2));
@@ -180,26 +180,6 @@ TEST_F(TestScaler, DISABLED_ON_ANDROID(PointScaleTest)) {
// average PSNR under same conditions.
ASSERT_GT(avg_psnr, 25.8);
ASSERT_EQ(0, fclose(source_file2));
- // Up-sample to odd size frame and scale back down.
- out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_699_531.yuv";
- ScaleSequence(method,
- source_file_, out_name,
- width_, height_,
- 699, 531);
- source_file2 = fopen(out_name.c_str(), "rb");
- out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_352_288_"
- "downfrom_699_531.yuv";
- ScaleSequence(method,
- source_file2, out_name,
- 699, 531,
- 352, 288);
- avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_);
- printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to "
- "original size: %f \n", width_, height_, 699, 531, avg_psnr);
- // Average PSNR for lower bound in assert is ~0.1dB lower than the actual
- // average PSNR under same conditions.
- ASSERT_GT(avg_psnr, 37.8);
- ASSERT_EQ(0, fclose(source_file2));
}
TEST_F(TestScaler, DISABLED_ON_ANDROID(BiLinearScaleTest)) {
@@ -252,48 +232,6 @@ TEST_F(TestScaler, DISABLED_ON_ANDROID(BiLinearScaleTest)) {
source_file_, out_name,
width_, height_,
400, 300);
- // Down-sample to odd size frame and scale back up.
- out_name = webrtc::test::OutputPath() +
- "LibYuvTest_BilinearScale_282_231.yuv";
- ScaleSequence(method,
- source_file_, out_name,
- width_, height_,
- 282, 231);
- source_file2 = fopen(out_name.c_str(), "rb");
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BilinearScale_352_288_"
- "upfrom_282_231.yuv";
- ScaleSequence(method,
- source_file2, out_name,
- 282, 231,
- width_, height_);
- avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_);
- printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to "
- "original size: %f \n", width_, height_, 282, 231, avg_psnr);
- // Average PSNR for lower bound in assert is ~0.1dB lower than the actual
- // average PSNR under same conditions.
- ASSERT_GT(avg_psnr, 29.7);
- ASSERT_EQ(0, fclose(source_file2));
- // Upsample to odd size frame and scale back down.
- out_name = webrtc::test::OutputPath() +
- "LibYuvTest_BilinearScale_699_531.yuv";
- ScaleSequence(method,
- source_file_, out_name,
- width_, height_,
- 699, 531);
- source_file2 = fopen(out_name.c_str(), "rb");
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BilinearScale_352_288_"
- "downfrom_699_531.yuv";
- ScaleSequence(method,
- source_file2, out_name,
- 699, 531,
- width_, height_);
- avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_);
- printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to "
- "original size: %f \n", width_, height_, 699, 531, avg_psnr);
- // Average PSNR for lower bound in assert is ~0.1dB lower than the actual
- // average PSNR under same conditions.
- ASSERT_GT(avg_psnr, 31.4);
- ASSERT_EQ(0, fclose(source_file2));
}
TEST_F(TestScaler, DISABLED_ON_ANDROID(BoxScaleTest)) {
@@ -341,46 +279,6 @@ TEST_F(TestScaler, DISABLED_ON_ANDROID(BoxScaleTest)) {
source_file_, out_name,
width_, height_,
400, 300);
- // Down-sample to odd size frame and scale back up.
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_282_231.yuv";
- ScaleSequence(method,
- source_file_, out_name,
- width_, height_,
- 282, 231);
- source_file2 = fopen(out_name.c_str(), "rb");
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_352_288_"
- "upfrom_282_231.yuv";
- ScaleSequence(method,
- source_file2, out_name,
- 282, 231,
- width_, height_);
- avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_);
- printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to "
- "original size: %f \n", width_, height_, 282, 231, avg_psnr);
- // Average PSNR for lower bound in assert is ~0.1dB lower than the actual
- // average PSNR under same conditions.
- ASSERT_GT(avg_psnr, 29.7);
- ASSERT_EQ(0, fclose(source_file2));
- // Up-sample to odd size frame and scale back down.
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_699_531.yuv";
- ScaleSequence(method,
- source_file_, out_name,
- width_, height_,
- 699, 531);
- source_file2 = fopen(out_name.c_str(), "rb");
- out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_352_288_"
- "downfrom_699_531.yuv";
- ScaleSequence(method,
- source_file2, out_name,
- 699, 531,
- width_, height_);
- avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_);
- printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to "
- "original size: %f \n", width_, height_, 699, 531, avg_psnr);
- // Average PSNR for lower bound in assert is ~0.1dB lower than the actual
- // average PSNR under same conditions.
- ASSERT_GT(avg_psnr, 31.4);
- ASSERT_EQ(0, fclose(source_file2));
}
double TestScaler::ComputeAvgSequencePSNR(FILE* input_file,
@@ -392,25 +290,28 @@ double TestScaler::ComputeAvgSequencePSNR(FILE* input_file,
rewind(input_file);
rewind(output_file);
- int required_size = CalcBufferSize(kI420, width, height);
+ size_t required_size = CalcBufferSize(kI420, width, height);
uint8_t* input_buffer = new uint8_t[required_size];
uint8_t* output_buffer = new uint8_t[required_size];
int frame_count = 0;
double avg_psnr = 0;
I420VideoFrame in_frame, out_frame;
+ const int half_width = (width + 1) / 2;
+ in_frame.CreateEmptyFrame(width, height, width, half_width, half_width);
+ out_frame.CreateEmptyFrame(width, height, width, half_width, half_width);
while (feof(input_file) == 0) {
- if ((size_t)required_size !=
- fread(input_buffer, 1, required_size, input_file)) {
+ if (fread(input_buffer, 1, required_size, input_file) != required_size) {
break;
}
- if ((size_t)required_size !=
- fread(output_buffer, 1, required_size, output_file)) {
+ if (fread(output_buffer, 1, required_size, output_file) != required_size) {
break;
}
frame_count++;
- ConvertFromI420(in_frame, kI420, 0, input_buffer);
- ConvertFromI420(out_frame, kI420, 0, output_buffer);
+ EXPECT_EQ(0, ConvertToI420(kI420, input_buffer, 0, 0, width, height,
+ required_size, kVideoRotation_0, &in_frame));
+ EXPECT_EQ(0, ConvertToI420(kI420, output_buffer, 0, 0, width, height,
+ required_size, kVideoRotation_0, &out_frame));
double psnr = I420PSNR(&in_frame, &out_frame);
avg_psnr += psnr;
}
@@ -441,20 +342,20 @@ void TestScaler::ScaleSequence(ScaleMethod method,
int64_t start_clock, total_clock;
total_clock = 0;
int frame_count = 0;
- int src_required_size = CalcBufferSize(kI420, src_width, src_height);
- scoped_ptr<uint8_t[]> frame_buffer(new uint8_t[src_required_size]);
+ size_t src_required_size = CalcBufferSize(kI420, src_width, src_height);
+ rtc::scoped_ptr<uint8_t[]> frame_buffer(new uint8_t[src_required_size]);
int size_y = src_width * src_height;
int size_uv = ((src_width + 1) / 2) * ((src_height + 1) / 2);
// Running through entire sequence.
while (feof(source_file) == 0) {
- if ((size_t)src_required_size !=
- fread(frame_buffer.get(), 1, src_required_size, source_file))
+ if (fread(frame_buffer.get(), 1, src_required_size, source_file) !=
+ src_required_size)
break;
- input_frame.CreateFrame(size_y, frame_buffer.get(),
- size_uv, frame_buffer.get() + size_y,
- size_uv, frame_buffer.get() + size_y + size_uv,
+ input_frame.CreateFrame(frame_buffer.get(),
+ frame_buffer.get() + size_y,
+ frame_buffer.get() + size_y + size_uv,
src_width, src_height,
src_width, (src_width + 1) / 2,
(src_width + 1) / 2);
diff --git a/chromium/third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc b/chromium/third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc
index 0094525b5c0..65b4d0c5cd8 100644
--- a/chromium/third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc
+++ b/chromium/third_party/webrtc/common_video/libyuv/webrtc_libyuv.cc
@@ -66,8 +66,10 @@ void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) {
*stride_uv = AlignInt((width + 1) / 2, k16ByteAlignment);
}
-int CalcBufferSize(VideoType type, int width, int height) {
- int buffer_size = 0;
+size_t CalcBufferSize(VideoType type, int width, int height) {
+ assert(width >= 0);
+ assert(height >= 0);
+ size_t buffer_size = 0;
switch (type) {
case kI420:
case kNV12:
@@ -95,7 +97,7 @@ int CalcBufferSize(VideoType type, int width, int height) {
break;
default:
assert(false);
- return -1;
+ break;
}
return buffer_size;
}
@@ -122,11 +124,12 @@ int PrintI420VideoFrame(const I420VideoFrame& frame, FILE* file) {
}
int ExtractBuffer(const I420VideoFrame& input_frame,
- int size, uint8_t* buffer) {
+ size_t size, uint8_t* buffer) {
assert(buffer);
if (input_frame.IsZeroSize())
return -1;
- int length = CalcBufferSize(kI420, input_frame.width(), input_frame.height());
+ size_t length =
+ CalcBufferSize(kI420, input_frame.width(), input_frame.height());
if (size < length) {
return -1;
}
@@ -147,7 +150,7 @@ int ExtractBuffer(const I420VideoFrame& input_frame,
plane_ptr += input_frame.stride(static_cast<PlaneType>(plane));
}
}
- return length;
+ return static_cast<int>(length);
}
@@ -173,15 +176,15 @@ int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame,
width, height);
}
-libyuv::RotationMode ConvertRotationMode(VideoRotationMode rotation) {
+libyuv::RotationMode ConvertRotationMode(VideoRotation rotation) {
switch(rotation) {
- case kRotateNone:
+ case kVideoRotation_0:
return libyuv::kRotate0;
- case kRotate90:
+ case kVideoRotation_90:
return libyuv::kRotate90;
- case kRotate180:
+ case kVideoRotation_180:
return libyuv::kRotate180;
- case kRotate270:
+ case kVideoRotation_270:
return libyuv::kRotate270;
}
assert(false);
@@ -228,16 +231,18 @@ int ConvertVideoType(VideoType video_type) {
int ConvertToI420(VideoType src_video_type,
const uint8_t* src_frame,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int sample_size,
- VideoRotationMode rotation,
+ int crop_x,
+ int crop_y,
+ int src_width,
+ int src_height,
+ size_t sample_size,
+ VideoRotation rotation,
I420VideoFrame* dst_frame) {
int dst_width = dst_frame->width();
int dst_height = dst_frame->height();
// LibYuv expects pre-rotation values for dst.
// Stride values should correspond to the destination values.
- if (rotation == kRotate90 || rotation == kRotate270) {
+ if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) {
dst_width = dst_frame->height();
dst_height =dst_frame->width();
}
@@ -285,50 +290,6 @@ int ConvertFromYV12(const I420VideoFrame& src_frame,
ConvertVideoType(dst_video_type));
}
-int MirrorI420LeftRight(const I420VideoFrame* src_frame,
- I420VideoFrame* dst_frame) {
- // Source and destination frames should have equal resolution.
- if (src_frame->width() != dst_frame->width() ||
- src_frame->height() != dst_frame->height())
- return -1;
- return libyuv::I420Mirror(src_frame->buffer(kYPlane),
- src_frame->stride(kYPlane),
- src_frame->buffer(kUPlane),
- src_frame->stride(kUPlane),
- src_frame->buffer(kVPlane),
- src_frame->stride(kVPlane),
- dst_frame->buffer(kYPlane),
- dst_frame->stride(kYPlane),
- dst_frame->buffer(kUPlane),
- dst_frame->stride(kUPlane),
- dst_frame->buffer(kVPlane),
- dst_frame->stride(kVPlane),
- src_frame->width(), src_frame->height());
-}
-
-int MirrorI420UpDown(const I420VideoFrame* src_frame,
- I420VideoFrame* dst_frame) {
- // Source and destination frames should have equal resolution
- if (src_frame->width() != dst_frame->width() ||
- src_frame->height() != dst_frame->height())
- return -1;
-
- // Inserting negative height flips the frame.
- return libyuv::I420Copy(src_frame->buffer(kYPlane),
- src_frame->stride(kYPlane),
- src_frame->buffer(kUPlane),
- src_frame->stride(kUPlane),
- src_frame->buffer(kVPlane),
- src_frame->stride(kVPlane),
- dst_frame->buffer(kYPlane),
- dst_frame->stride(kYPlane),
- dst_frame->buffer(kUPlane),
- dst_frame->stride(kUPlane),
- dst_frame->buffer(kVPlane),
- dst_frame->stride(kVPlane),
- src_frame->width(), -(src_frame->height()));
-}
-
// Compute PSNR for an I420 frame (all planes)
double I420PSNR(const I420VideoFrame* ref_frame,
const I420VideoFrame* test_frame) {
diff --git a/chromium/third_party/webrtc/common_video/plane.cc b/chromium/third_party/webrtc/common_video/plane.cc
index 3776de1323e..e0bbba10bac 100644
--- a/chromium/third_party/webrtc/common_video/plane.cc
+++ b/chromium/third_party/webrtc/common_video/plane.cc
@@ -41,8 +41,8 @@ int Plane::MaybeResize(int new_size) {
return -1;
if (new_size <= allocated_size_)
return 0;
- scoped_ptr<uint8_t, AlignedFreeDeleter> new_buffer(static_cast<uint8_t*>(
- AlignedMalloc(new_size, kBufferAlignment)));
+ rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> new_buffer(
+ static_cast<uint8_t*>(AlignedMalloc(new_size, kBufferAlignment)));
if (buffer_.get()) {
memcpy(new_buffer.get(), buffer_.get(), plane_size_);
}
diff --git a/chromium/third_party/webrtc/common_video/plane.h b/chromium/third_party/webrtc/common_video/plane.h
index 4031e03b4ce..66b8a5a0822 100644
--- a/chromium/third_party/webrtc/common_video/plane.h
+++ b/chromium/third_party/webrtc/common_video/plane.h
@@ -11,8 +11,8 @@
#ifndef COMMON_VIDEO_PLANE_H
#define COMMON_VIDEO_PLANE_H
+#include "webrtc/base/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/aligned_malloc.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
namespace webrtc {
@@ -64,7 +64,7 @@ class Plane {
// Return value: 0 on success ,-1 on error.
int MaybeResize(int new_size);
- scoped_ptr<uint8_t, AlignedFreeDeleter> buffer_;
+ rtc::scoped_ptr<uint8_t, AlignedFreeDeleter> buffer_;
int allocated_size_;
int plane_size_;
int stride_;
diff --git a/chromium/third_party/webrtc/common_video/plane_unittest.cc b/chromium/third_party/webrtc/common_video/plane_unittest.cc
deleted file mode 100644
index d1655982870..00000000000
--- a/chromium/third_party/webrtc/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/chromium/third_party/webrtc/common_video/rotation.h b/chromium/third_party/webrtc/common_video/rotation.h
new file mode 100644
index 00000000000..46a9ecc5eab
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/rotation.h
@@ -0,0 +1,26 @@
+/*
+ * 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_COMMON_VIDEO_ROTATION_H_
+#define WEBRTC_COMMON_VIDEO_ROTATION_H_
+
+namespace webrtc {
+
+// enum for clockwise rotation.
+enum VideoRotation {
+ kVideoRotation_0 = 0,
+ kVideoRotation_90 = 90,
+ kVideoRotation_180 = 180,
+ kVideoRotation_270 = 270
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_VIDEO_ROTATION_H_
diff --git a/chromium/third_party/webrtc/common_video/texture_video_frame.cc b/chromium/third_party/webrtc/common_video/texture_video_frame.cc
deleted file mode 100644
index f301d19c8e8..00000000000
--- a/chromium/third_party/webrtc/common_video/texture_video_frame.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2013 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/texture_video_frame.h"
-
-#include <assert.h>
-
-namespace webrtc {
-
-TextureVideoFrame::TextureVideoFrame(NativeHandle* handle,
- int width,
- int height,
- uint32_t timestamp,
- int64_t render_time_ms)
- : handle_(handle) {
- set_width(width);
- set_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::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::ResetSize() {
- assert(false); // Should not be called.
-}
-
-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/chromium/third_party/webrtc/common_video/texture_video_frame_unittest.cc b/chromium/third_party/webrtc/common_video/texture_video_frame_unittest.cc
deleted file mode 100644
index 408f5f6120d..00000000000
--- a/chromium/third_party/webrtc/common_video/texture_video_frame_unittest.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2013 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/texture_video_frame.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/common_video/interface/native_handle.h"
-
-namespace webrtc {
-
-class NativeHandleImpl : public NativeHandle {
- public:
- NativeHandleImpl() : ref_count_(0) {}
- virtual ~NativeHandleImpl() {}
- virtual int32_t AddRef() { return ++ref_count_; }
- virtual int32_t Release() { return --ref_count_; }
- virtual void* GetHandle() { return NULL; }
-
- int32_t ref_count() { return ref_count_; }
- private:
- int32_t ref_count_;
-};
-
-bool EqualTextureFrames(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2);
-
-TEST(TestTextureVideoFrame, InitialValues) {
- NativeHandleImpl handle;
- TextureVideoFrame frame(&handle, 640, 480, 100, 10);
- EXPECT_EQ(640, frame.width());
- EXPECT_EQ(480, frame.height());
- EXPECT_EQ(100u, frame.timestamp());
- EXPECT_EQ(10, frame.render_time_ms());
- EXPECT_EQ(&handle, frame.native_handle());
-
- EXPECT_EQ(0, frame.set_width(320));
- EXPECT_EQ(320, frame.width());
- EXPECT_EQ(0, frame.set_height(240));
- EXPECT_EQ(240, frame.height());
- frame.set_timestamp(200);
- EXPECT_EQ(200u, frame.timestamp());
- frame.set_render_time_ms(20);
- EXPECT_EQ(20, frame.render_time_ms());
-}
-
-TEST(TestTextureVideoFrame, RefCount) {
- NativeHandleImpl handle;
- EXPECT_EQ(0, handle.ref_count());
- TextureVideoFrame *frame = new TextureVideoFrame(&handle, 640, 480, 100, 200);
- EXPECT_EQ(1, handle.ref_count());
- delete frame;
- EXPECT_EQ(0, handle.ref_count());
-}
-
-TEST(TestTextureVideoFrame, CloneFrame) {
- NativeHandleImpl handle;
- TextureVideoFrame frame1(&handle, 640, 480, 100, 200);
- scoped_ptr<I420VideoFrame> frame2(frame1.CloneFrame());
- EXPECT_TRUE(frame2.get() != NULL);
- EXPECT_TRUE(EqualTextureFrames(frame1, *frame2));
-}
-
-bool EqualTextureFrames(const I420VideoFrame& frame1,
- const I420VideoFrame& frame2) {
- return ((frame1.native_handle() == frame2.native_handle()) &&
- (frame1.width() == frame2.width()) &&
- (frame1.height() == frame2.height()) &&
- (frame1.timestamp() == frame2.timestamp()) &&
- (frame1.render_time_ms() == frame2.render_time_ms()));
-}
-
-} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/video_frame_buffer.cc b/chromium/third_party/webrtc/common_video/video_frame_buffer.cc
new file mode 100644
index 00000000000..908c97272d8
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/video_frame_buffer.cc
@@ -0,0 +1,223 @@
+/*
+ * 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/bind.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;
+ }
+}
+
+void* I420Buffer::native_handle() const {
+ return nullptr;
+}
+
+TextureBuffer::TextureBuffer(void* native_handle,
+ int width,
+ int height,
+ const rtc::Callback0<void>& no_longer_used)
+ : native_handle_(native_handle),
+ width_(width),
+ height_(height),
+ no_longer_used_cb_(no_longer_used) {
+ DCHECK(native_handle != nullptr);
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+}
+
+TextureBuffer::~TextureBuffer() {
+ no_longer_used_cb_();
+}
+
+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;
+}
+
+void* TextureBuffer::native_handle() const {
+ return native_handle_;
+}
+
+
+WrappedI420Buffer::WrappedI420Buffer(int desired_width,
+ int desired_height,
+ int width,
+ int height,
+ const uint8_t* y_plane,
+ int y_stride,
+ const uint8_t* u_plane,
+ int u_stride,
+ const uint8_t* v_plane,
+ int v_stride,
+ const rtc::Callback0<void>& no_longer_used)
+ : width_(desired_width),
+ height_(desired_height),
+ y_plane_(y_plane),
+ u_plane_(u_plane),
+ v_plane_(v_plane),
+ y_stride_(y_stride),
+ u_stride_(u_stride),
+ v_stride_(v_stride),
+ no_longer_used_cb_(no_longer_used) {
+ CHECK(width >= desired_width && height >= desired_height);
+
+ // Center crop to |desired_width| x |desired_height|.
+ // Make sure offset is even so that u/v plane becomes aligned.
+ const int offset_x = ((width - desired_width) / 2) & ~1;
+ const int offset_y = ((height - desired_height) / 2) & ~1;
+ y_plane_ += y_stride_ * offset_y + offset_x;
+ u_plane_ += u_stride_ * (offset_y / 2) + (offset_x / 2);
+ v_plane_ += v_stride_ * (offset_y / 2) + (offset_x / 2);
+}
+
+WrappedI420Buffer::~WrappedI420Buffer() {
+ no_longer_used_cb_();
+}
+
+
+int WrappedI420Buffer::width() const {
+ return width_;
+}
+
+int WrappedI420Buffer::height() const {
+ return height_;
+}
+
+const uint8_t* WrappedI420Buffer::data(PlaneType type) const {
+ switch (type) {
+ case kYPlane:
+ return y_plane_;
+ case kUPlane:
+ return u_plane_;
+ case kVPlane:
+ return v_plane_;
+ default:
+ RTC_NOTREACHED();
+ return nullptr;
+ }
+}
+
+uint8_t* WrappedI420Buffer::data(PlaneType type) {
+ RTC_NOTREACHED();
+ return nullptr;
+}
+
+int WrappedI420Buffer::stride(PlaneType type) const {
+ switch (type) {
+ case kYPlane:
+ return y_stride_;
+ case kUPlane:
+ return u_stride_;
+ case kVPlane:
+ return v_stride_;
+ default:
+ RTC_NOTREACHED();
+ return 0;
+ }
+}
+
+void* WrappedI420Buffer::native_handle() const {
+ return nullptr;
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/video_render_frames.cc b/chromium/third_party/webrtc/common_video/video_render_frames.cc
new file mode 100644
index 00000000000..abd1e43dfe6
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/video_render_frames.cc
@@ -0,0 +1,95 @@
+/*
+ * 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/video_render_frames.h"
+
+#include <assert.h>
+
+#include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+#include "webrtc/system_wrappers/interface/trace.h"
+
+namespace webrtc {
+
+const uint32_t KEventMaxWaitTimeMs = 200;
+const uint32_t kMinRenderDelayMs = 10;
+const uint32_t kMaxRenderDelayMs= 500;
+
+VideoRenderFrames::VideoRenderFrames()
+ : render_delay_ms_(10) {
+}
+
+int32_t VideoRenderFrames::AddFrame(const I420VideoFrame& new_frame) {
+ const int64_t time_now = TickTime::MillisecondTimestamp();
+
+ // Drop old frames only when there are other frames in the queue, otherwise, a
+ // really slow system never renders any frames.
+ if (!incoming_frames_.empty() &&
+ new_frame.render_time_ms() + KOldRenderTimestampMS < time_now) {
+ WEBRTC_TRACE(kTraceWarning,
+ kTraceVideoRenderer,
+ -1,
+ "%s: too old frame, timestamp=%u.",
+ __FUNCTION__,
+ new_frame.timestamp());
+ return -1;
+ }
+
+ if (new_frame.render_time_ms() > time_now + KFutureRenderTimestampMS) {
+ WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, -1,
+ "%s: frame too long into the future, timestamp=%u.",
+ __FUNCTION__, new_frame.timestamp());
+ return -1;
+ }
+
+ incoming_frames_.push_back(new_frame);
+ return static_cast<int32_t>(incoming_frames_.size());
+}
+
+I420VideoFrame VideoRenderFrames::FrameToRender() {
+ I420VideoFrame render_frame;
+ // Get the newest frame that can be released for rendering.
+ while (!incoming_frames_.empty() && TimeToNextFrameRelease() <= 0) {
+ render_frame = incoming_frames_.front();
+ incoming_frames_.pop_front();
+ }
+ return render_frame;
+}
+
+int32_t VideoRenderFrames::ReleaseAllFrames() {
+ incoming_frames_.clear();
+ return 0;
+}
+
+uint32_t VideoRenderFrames::TimeToNextFrameRelease() {
+ if (incoming_frames_.empty()) {
+ return KEventMaxWaitTimeMs;
+ }
+ const int64_t time_to_release = incoming_frames_.front().render_time_ms() -
+ render_delay_ms_ -
+ TickTime::MillisecondTimestamp();
+ return time_to_release < 0 ? 0u : static_cast<uint32_t>(time_to_release);
+}
+
+int32_t VideoRenderFrames::SetRenderDelay(
+ const uint32_t render_delay) {
+ if (render_delay < kMinRenderDelayMs ||
+ render_delay > kMaxRenderDelayMs) {
+ WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer,
+ -1, "%s(%d): Invalid argument.", __FUNCTION__,
+ render_delay);
+ return -1;
+ }
+
+ render_delay_ms_ = render_delay;
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/chromium/third_party/webrtc/common_video/video_render_frames.h b/chromium/third_party/webrtc/common_video/video_render_frames.h
new file mode 100644
index 00000000000..31d15970bc6
--- /dev/null
+++ b/chromium/third_party/webrtc/common_video/video_render_frames.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef WEBRTC_COMMON_VIDEO_VIDEO_RENDER_FRAMES_H_
+#define WEBRTC_COMMON_VIDEO_VIDEO_RENDER_FRAMES_H_
+
+#include <stdint.h>
+
+#include <list>
+
+#include "webrtc/video_frame.h"
+
+namespace webrtc {
+
+// Class definitions
+class VideoRenderFrames {
+ public:
+ VideoRenderFrames();
+
+ // Add a frame to the render queue
+ int32_t AddFrame(const I420VideoFrame& new_frame);
+
+ // Get a frame for rendering, or a zero-size frame if it's not time to render.
+ I420VideoFrame FrameToRender();
+
+ // Releases all frames
+ int32_t ReleaseAllFrames();
+
+ // Returns the number of ms to next frame to render
+ uint32_t TimeToNextFrameRelease();
+
+ // Sets estimates delay in renderer
+ int32_t SetRenderDelay(const uint32_t render_delay);
+
+ private:
+ // 10 seconds for 30 fps.
+ enum { KMaxNumberOfFrames = 300 };
+ // Don't render frames with timestamp older than 500ms from now.
+ enum { KOldRenderTimestampMS = 500 };
+ // Don't render frames with timestamp more than 10s into the future.
+ enum { KFutureRenderTimestampMS = 10000 };
+
+ // Sorted list with framed to be rendered, oldest first.
+ std::list<I420VideoFrame> incoming_frames_;
+
+ // Estimated delay from a frame is released until it's rendered.
+ uint32_t render_delay_ms_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_VIDEO_VIDEO_RENDER_FRAMES_H_