diff --git a/webrtc/common_video/i420_video_frame_unittest.cc b/webrtc/common_video/i420_video_frame_unittest.cc index 8273136dce..9b2bdd762d 100644 --- a/webrtc/common_video/i420_video_frame_unittest.cc +++ b/webrtc/common_video/i420_video_frame_unittest.cc @@ -254,4 +254,14 @@ TEST(TestVideoFrame, TextureInitialValues) { EXPECT_EQ(20, frame.render_time_ms()); } +TEST(TestI420FrameBuffer, Copy) { + rtc::scoped_refptr buf1( + new rtc::RefCountedObject(20, 10)); + memset(buf1->MutableData(kYPlane), 1, 200); + memset(buf1->MutableData(kUPlane), 2, 50); + memset(buf1->MutableData(kVPlane), 3, 50); + rtc::scoped_refptr buf2 = I420Buffer::Copy(buf1); + EXPECT_TRUE(test::FrameBufsEqual(buf1, buf2)); +} + } // namespace webrtc diff --git a/webrtc/common_video/include/video_frame_buffer.h b/webrtc/common_video/include/video_frame_buffer.h index 270f2d5a2d..9cf57a4359 100644 --- a/webrtc/common_video/include/video_frame_buffer.h +++ b/webrtc/common_video/include/video_frame_buffer.h @@ -81,6 +81,10 @@ class I420Buffer : public VideoFrameBuffer { void* native_handle() const override; rtc::scoped_refptr NativeToI420Buffer() override; + // Create a new buffer and copy the pixel data. + static rtc::scoped_refptr Copy( + const rtc::scoped_refptr& buffer); + protected: ~I420Buffer() override; diff --git a/webrtc/common_video/video_frame_buffer.cc b/webrtc/common_video/video_frame_buffer.cc index 19e44febaf..6f49e8aef9 100644 --- a/webrtc/common_video/video_frame_buffer.cc +++ b/webrtc/common_video/video_frame_buffer.cc @@ -12,6 +12,7 @@ #include "webrtc/base/checks.h" #include "webrtc/base/keep_ref_until_done.h" +#include "libyuv/convert.h" // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. static const int kBufferAlignment = 64; @@ -117,6 +118,23 @@ rtc::scoped_refptr I420Buffer::NativeToI420Buffer() { return nullptr; } +rtc::scoped_refptr I420Buffer::Copy( + const rtc::scoped_refptr& buffer) { + int width = buffer->width(); + int height = buffer->height(); + rtc::scoped_refptr copy = + new rtc::RefCountedObject(width, height); + RTC_CHECK(libyuv::I420Copy(buffer->data(kYPlane), buffer->stride(kYPlane), + buffer->data(kUPlane), buffer->stride(kUPlane), + buffer->data(kVPlane), buffer->stride(kVPlane), + copy->MutableData(kYPlane), copy->stride(kYPlane), + copy->MutableData(kUPlane), copy->stride(kUPlane), + copy->MutableData(kVPlane), copy->stride(kVPlane), + width, height) == 0); + + return copy; +} + NativeHandleBuffer::NativeHandleBuffer(void* native_handle, int width, int height) diff --git a/webrtc/test/frame_utils.cc b/webrtc/test/frame_utils.cc index 13f358a2a1..0f41144745 100644 --- a/webrtc/test/frame_utils.cc +++ b/webrtc/test/frame_utils.cc @@ -47,5 +47,23 @@ bool FramesEqual(const webrtc::VideoFrame& f1, const webrtc::VideoFrame& f2) { f1.stride(webrtc::kVPlane), half_width, half_height); } +bool FrameBufsEqual(const rtc::scoped_refptr& f1, + const rtc::scoped_refptr& f2) { + if (f1->width() != f2->width() || f1->height() != f2->height() || + f1->stride(webrtc::kYPlane) != f2->stride(webrtc::kYPlane) || + f1->stride(webrtc::kUPlane) != f2->stride(webrtc::kUPlane) || + f1->stride(webrtc::kVPlane) != f2->stride(webrtc::kVPlane)) { + return false; + } + const int half_width = (f1->width() + 1) / 2; + const int half_height = (f1->height() + 1) / 2; + return EqualPlane(f1->data(webrtc::kYPlane), f2->data(webrtc::kYPlane), + f1->stride(webrtc::kYPlane), f1->width(), f1->height()) && + EqualPlane(f1->data(webrtc::kUPlane), f2->data(webrtc::kUPlane), + f1->stride(webrtc::kUPlane), half_width, half_height) && + EqualPlane(f1->data(webrtc::kVPlane), f2->data(webrtc::kVPlane), + f1->stride(webrtc::kVPlane), half_width, half_height); +} + } // namespace test } // namespace webrtc diff --git a/webrtc/test/frame_utils.h b/webrtc/test/frame_utils.h index 42e2cba67e..668d9994ab 100644 --- a/webrtc/test/frame_utils.h +++ b/webrtc/test/frame_utils.h @@ -11,9 +11,11 @@ #define WEBRTC_TEST_FRAME_UTILS_H_ #include "webrtc/base/basictypes.h" +#include "webrtc/base/scoped_ref_ptr.h" namespace webrtc { class VideoFrame; +class VideoFrameBuffer; namespace test { bool EqualPlane(const uint8_t* data1, @@ -24,6 +26,9 @@ bool EqualPlane(const uint8_t* data1, bool FramesEqual(const webrtc::VideoFrame& f1, const webrtc::VideoFrame& f2); +bool FrameBufsEqual(const rtc::scoped_refptr& f1, + const rtc::scoped_refptr& f2); + } // namespace test } // namespace webrtc