/* * 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 #include #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" namespace webrtc { bool EqualFrames(const I420VideoFrame& frame1, const I420VideoFrame& frame2); bool EqualFramesExceptSize(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()); } 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()); frame.set_ntp_time_ms(456); EXPECT_EQ(456, frame.ntp_time_ms()); frame.set_render_time_ms(789); EXPECT_EQ(789, frame.render_time_ms()); } TEST(TestI420VideoFrame, SizeAllocation) { I420VideoFrame frame; EXPECT_EQ(0, frame. CreateEmptyFrame(10, 10, 12, 14, 220)); int height = frame.height(); int stride_y = frame.stride(kYPlane); int stride_u = frame.stride(kUPlane); int stride_v = frame.stride(kVPlane); // Verify that allocated size was computed correctly. EXPECT_EQ(ExpectedSize(stride_y, height, kYPlane), frame.allocated_size(kYPlane)); EXPECT_EQ(ExpectedSize(stride_u, height, kUPlane), frame.allocated_size(kUPlane)); EXPECT_EQ(ExpectedSize(stride_v, height, kVPlane), 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; int stride_y = 15; int stride_u = 10; int stride_v = 10; 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; 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)); } TEST(TestI420VideoFrame, CloneFrame) { I420VideoFrame frame1; scoped_ptr frame2; const int kSizeY = 225; const int kSizeU = 80; const int kSizeV = 80; 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)); } TEST(TestI420VideoFrame, CopyBuffer) { I420VideoFrame frame1, frame2; int width = 15; int height = 15; int stride_y = 15; int stride_uv = 10; const int kSizeY = 225; const int kSizeUv = 80; EXPECT_EQ(0, frame2.CreateEmptyFrame(width, height, stride_y, stride_uv, stride_uv)); uint8_t buffer_y[kSizeY]; uint8_t buffer_u[kSizeUv]; uint8_t buffer_v[kSizeUv]; 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, 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_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, RefCountedInstantiation) { // Refcounted instantiation - ref_count should correspond to the number of // instances. scoped_refptr ref_count_frame( new RefCountImpl()); EXPECT_EQ(2, ref_count_frame->AddRef()); EXPECT_EQ(3, ref_count_frame->AddRef()); EXPECT_EQ(2, ref_count_frame->Release()); EXPECT_EQ(1, ref_count_frame->Release()); } bool 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))); } bool EqualFramesExceptSize(const I420VideoFrame& frame1, const I420VideoFrame& frame2) { if ((frame1.width() != frame2.width()) || (frame1.height() != frame2.height()) || (frame1.stride(kYPlane) != frame2.stride(kYPlane)) || (frame1.stride(kUPlane) != frame2.stride(kUPlane)) || (frame1.stride(kVPlane) != frame2.stride(kVPlane)) || (frame1.timestamp() != frame2.timestamp()) || (frame1.ntp_time_ms() != frame2.ntp_time_ms()) || (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); } int ExpectedSize(int plane_stride, int image_height, PlaneType type) { if (type == kYPlane) { return (plane_stride * image_height); } else { int half_height = (image_height + 1) / 2; return (plane_stride * half_height); } } } // namespace webrtc