diff --git a/webrtc/common_video/i420_video_frame_unittest.cc b/webrtc/common_video/i420_video_frame_unittest.cc index f9dcc66827..c10fefdbfe 100644 --- a/webrtc/common_video/i420_video_frame_unittest.cc +++ b/webrtc/common_video/i420_video_frame_unittest.cc @@ -84,6 +84,12 @@ TEST(TestVideoFrame, InitialValues) { EXPECT_EQ(kVideoRotation_0, frame.rotation()); } +TEST(TestVideoFrame, CopiesInitialFrameWithoutCrashing) { + VideoFrame frame; + VideoFrame frame2; + frame2.CopyFrame(frame); +} + TEST(TestVideoFrame, WidthHeightValues) { VideoFrame frame(I420Buffer::Create(10, 10, 10, 14, 90), webrtc::kVideoRotation_0, @@ -98,6 +104,44 @@ TEST(TestVideoFrame, WidthHeightValues) { EXPECT_EQ(789, frame.render_time_ms()); } +TEST(TestVideoFrame, CopyFrame) { + int stride_y = 15; + int stride_u = 10; + int stride_v = 10; + int width = 15; + int height = 15; + // Copy frame. + VideoFrame small_frame; + 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); + VideoFrame big_frame; + 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. + small_frame.CopyFrame(big_frame); + EXPECT_TRUE(test::FramesEqual(small_frame, big_frame)); + EXPECT_EQ(kRotation, small_frame.rotation()); + + // Frame of larger dimensions. + rtc::scoped_refptr buffer = + I420Buffer::Create(width, height, stride_y, stride_u, stride_v); + memset(buffer->MutableDataY(), 1, width * height); + memset(buffer->MutableDataU(), 2, ((height + 1) / 2) * stride_u); + memset(buffer->MutableDataV(), 3, ((height + 1) / 2) * stride_u); + VideoFrame other_frame(buffer, 0, 0, webrtc::kVideoRotation_0); + big_frame.CopyFrame(other_frame); + EXPECT_TRUE(test::FramesEqual(other_frame, big_frame)); +} + TEST(TestVideoFrame, ShallowCopy) { uint32_t timestamp = 1; int64_t ntp_time_ms = 2; diff --git a/webrtc/common_video/video_frame.cc b/webrtc/common_video/video_frame.cc index 7145a623e6..9a8f8ab318 100644 --- a/webrtc/common_video/video_frame.cc +++ b/webrtc/common_video/video_frame.cc @@ -93,6 +93,15 @@ void VideoFrame::CreateFrame(const uint8_t* buffer, stride_uv, stride_uv, rotation); } +void VideoFrame::CopyFrame(const VideoFrame& videoFrame) { + ShallowCopy(videoFrame); + + // If backed by a plain memory buffer, create a new, non-shared, copy. + if (video_frame_buffer_ && !video_frame_buffer_->native_handle()) { + video_frame_buffer_ = I420Buffer::Copy(video_frame_buffer_); + } +} + void VideoFrame::ShallowCopy(const VideoFrame& videoFrame) { video_frame_buffer_ = videoFrame.video_frame_buffer(); timestamp_rtp_ = videoFrame.timestamp_rtp_; diff --git a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 63be85afdc..5616c92c49 100644 --- a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -110,7 +110,7 @@ bool Vp8UnitTestDecodeCompleteCallback::DecodeComplete() { } int Vp8UnitTestDecodeCompleteCallback::Decoded(VideoFrame& image) { - decoded_frame_->ShallowCopy(image); + decoded_frame_->CopyFrame(image); decode_complete = true; return 0; } diff --git a/webrtc/modules/video_processing/test/video_processing_unittest.cc b/webrtc/modules/video_processing/test/video_processing_unittest.cc index 259829ad8f..43238bcd18 100644 --- a/webrtc/modules/video_processing/test/video_processing_unittest.cc +++ b/webrtc/modules/video_processing/test/video_processing_unittest.cc @@ -250,10 +250,9 @@ void TestSize(const VideoFrame& source_frame, // Scale |resampled_source_frame| back to the source scale. VideoFrame resampled_source_frame; - resampled_source_frame.ShallowCopy(*out_frame); + resampled_source_frame.CopyFrame(*out_frame); // Compute PSNR against the cropped source frame and check expectation. - PreprocessFrameAndVerify(resampled_source_frame, - cropped_source.width(), + PreprocessFrameAndVerify(resampled_source_frame, cropped_source.width(), cropped_source.height(), vpm, out_frame); WriteProcessedFrameForVisualInspection(resampled_source_frame, *out_frame); diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc index 1102bcb48d..9adcc16206 100644 --- a/webrtc/video/video_quality_test.cc +++ b/webrtc/video/video_quality_test.cc @@ -482,8 +482,8 @@ class VideoAnalyzer : public PacketReceiver, rtc::CritScope crit(&comparison_lock_); if (comparisons_.size() < kMaxComparisons) { - reference_copy.ShallowCopy(reference); - render_copy.ShallowCopy(render); + reference_copy.CopyFrame(reference); + render_copy.CopyFrame(render); } else { // Copy the time to ensure that delay calculations can still be made. reference_copy.set_ntp_time_ms(reference.ntp_time_ms()); diff --git a/webrtc/video_frame.h b/webrtc/video_frame.h index b01555e092..21654d95e4 100644 --- a/webrtc/video_frame.h +++ b/webrtc/video_frame.h @@ -70,6 +70,13 @@ class VideoFrame { int height, VideoRotation rotation); + // Deep copy frame: If required size is bigger than allocated one, new + // buffers of adequate size will be allocated. + // TODO(nisse): Should be deleted in the cricket::VideoFrame and + // webrtc::VideoFrame merge. Instead, use I420Buffer::Copy to make a copy of + // the pixel data, and use the constructor to wrap it into a VideoFrame. + void CopyFrame(const VideoFrame& videoFrame); + // Creates a shallow copy of |videoFrame|, i.e, the this object will retain a // reference to the video buffer also retained by |videoFrame|. // TODO(nisse): Deprecated. Should be deleted in the cricket::VideoFrame and