diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-18 14:10:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-06-18 13:53:24 +0000 |
commit | 813fbf95af77a531c57a8c497345ad2c61d475b3 (patch) | |
tree | 821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/third_party/webrtc/common_video | |
parent | af6588f8d723931a298c995fa97259bb7f7deb55 (diff) | |
download | qtwebengine-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')
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_ |