OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/video_frame_impl.h" | |
6 | |
7 #include "base/format_macros.h" | |
8 #include "base/string_util.h" | |
9 #include "media/base/buffers.h" | |
10 #include "media/base/mock_filters.h" | |
11 #include "media/base/yuv_convert.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 namespace media { | |
15 | |
16 // Helper function that initializes a YV12 frame with white and black scan | |
17 // lines based on the |white_to_black| parameter. If 0, then the entire | |
18 // frame will be black, if 1 then the entire frame will be white. | |
19 void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { | |
20 VideoSurface surface; | |
21 if (!frame->Lock(&surface)) { | |
22 ADD_FAILURE(); | |
23 return; | |
24 } | |
25 EXPECT_EQ(VideoSurface::YV12, surface.format); | |
26 size_t first_black_row = static_cast<size_t>(surface.height * white_to_black); | |
27 uint8* y_plane = surface.data[VideoSurface::kYPlane]; | |
28 for (size_t row = 0; row < surface.height; ++row) { | |
29 int color = (row < first_black_row) ? 0xFF : 0x00; | |
30 memset(y_plane, color, surface.width); | |
31 y_plane += surface.strides[VideoSurface::kYPlane]; | |
32 } | |
33 uint8* u_plane = surface.data[VideoSurface::kUPlane]; | |
34 uint8* v_plane = surface.data[VideoSurface::kVPlane]; | |
35 for (size_t row = 0; row < surface.height; row += 2) { | |
36 memset(u_plane, 0x80, surface.width / 2); | |
37 memset(v_plane, 0x80, surface.width / 2); | |
38 u_plane += surface.strides[VideoSurface::kUPlane]; | |
39 v_plane += surface.strides[VideoSurface::kVPlane]; | |
40 } | |
41 frame->Unlock(); | |
42 } | |
43 | |
44 // Given a |yv12_frame| this method converts the YV12 frame to RGBA and | |
45 // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|. | |
46 void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { | |
47 // On linux and mac builds if you directly compare using EXPECT_EQ and use | |
48 // the VideoSurface::kNumxxxPlanes constants, it generates an error when | |
49 // linking. These are declared so that we can compare against locals. | |
50 const size_t expect_yuv_planes = VideoSurface::kNumYUVPlanes; | |
51 const size_t expect_rgb_planes = VideoSurface::kNumRGBPlanes; | |
52 | |
53 VideoSurface yuv_surface; | |
54 ASSERT_TRUE(yv12_frame->Lock(&yuv_surface)); | |
55 ASSERT_EQ(VideoSurface::YV12, yuv_surface.format); | |
56 ASSERT_EQ(expect_yuv_planes, yuv_surface.planes); | |
57 ASSERT_EQ(yuv_surface.strides[VideoSurface::kUPlane], | |
58 yuv_surface.strides[VideoSurface::kVPlane]); | |
59 | |
60 scoped_refptr<media::VideoFrame> rgb_frame; | |
61 media::VideoFrameImpl::CreateFrame(VideoSurface::RGBA, | |
62 yuv_surface.width, | |
63 yuv_surface.height, | |
64 yv12_frame->GetTimestamp(), | |
65 yv12_frame->GetDuration(), | |
66 &rgb_frame); | |
67 media::VideoSurface rgb_surface; | |
68 ASSERT_TRUE(rgb_frame->Lock(&rgb_surface)); | |
69 ASSERT_EQ(yuv_surface.width, rgb_surface.width); | |
70 ASSERT_EQ(yuv_surface.height, rgb_surface.height); | |
71 ASSERT_EQ(expect_rgb_planes, rgb_surface.planes); | |
72 | |
73 media::ConvertYUVToRGB32(yuv_surface.data[VideoSurface::kYPlane], | |
74 yuv_surface.data[VideoSurface::kUPlane], | |
75 yuv_surface.data[VideoSurface::kVPlane], | |
76 rgb_surface.data[VideoSurface::kRGBPlane], | |
77 rgb_surface.width, | |
78 rgb_surface.height, | |
79 yuv_surface.strides[VideoSurface::kYPlane], | |
80 yuv_surface.strides[VideoSurface::kUPlane], | |
81 rgb_surface.strides[VideoSurface::kRGBPlane], | |
82 media::YV12); | |
83 | |
84 for (size_t row = 0; row < rgb_surface.height; ++row) { | |
85 uint32* rgb_row_data = reinterpret_cast<uint32*>( | |
86 rgb_surface.data[VideoSurface::kRGBPlane] + | |
87 (rgb_surface.strides[VideoSurface::kRGBPlane] * row)); | |
88 for (size_t col = 0; col < rgb_surface.width; ++col) { | |
89 SCOPED_TRACE(StringPrintf("Checking (%" PRIuS ", %" PRIuS ")", row, col)); | |
90 EXPECT_EQ(expect_rgb_color, rgb_row_data[col]); | |
91 } | |
92 } | |
93 rgb_frame->Unlock(); | |
94 yv12_frame->Unlock(); | |
95 } | |
96 | |
97 TEST(VideoFrameImpl, CreateFrame) { | |
98 const size_t kWidth = 64; | |
99 const size_t kHeight = 48; | |
100 const base::TimeDelta kTimestampA = base::TimeDelta::FromMicroseconds(1337); | |
101 const base::TimeDelta kDurationA = base::TimeDelta::FromMicroseconds(1667); | |
102 const base::TimeDelta kTimestampB = base::TimeDelta::FromMicroseconds(1234); | |
103 const base::TimeDelta kDurationB = base::TimeDelta::FromMicroseconds(5678); | |
104 | |
105 // Create a YV12 Video Frame. | |
106 scoped_refptr<media::VideoFrame> frame; | |
107 VideoFrameImpl::CreateFrame(media::VideoSurface::YV12, kWidth, kHeight, | |
108 kTimestampA, kDurationA, &frame); | |
109 ASSERT_TRUE(frame); | |
110 | |
111 // Test StreamSample implementation. | |
112 EXPECT_EQ(kTimestampA.InMicroseconds(), | |
113 frame->GetTimestamp().InMicroseconds()); | |
114 EXPECT_EQ(kDurationA.InMicroseconds(), frame->GetDuration().InMicroseconds()); | |
115 EXPECT_FALSE(frame->IsEndOfStream()); | |
116 EXPECT_FALSE(frame->IsDiscontinuous()); | |
117 frame->SetTimestamp(kTimestampB); | |
118 frame->SetDuration(kDurationB); | |
119 EXPECT_EQ(kTimestampB.InMicroseconds(), | |
120 frame->GetTimestamp().InMicroseconds()); | |
121 EXPECT_EQ(kDurationB.InMicroseconds(), frame->GetDuration().InMicroseconds()); | |
122 EXPECT_FALSE(frame->IsEndOfStream()); | |
123 frame->SetDiscontinuous(true); | |
124 EXPECT_TRUE(frame->IsDiscontinuous()); | |
125 frame->SetDiscontinuous(false); | |
126 EXPECT_FALSE(frame->IsDiscontinuous()); | |
127 | |
128 // Test VideoFrame implementation. | |
129 { | |
130 SCOPED_TRACE(""); | |
131 InitializeYV12Frame(frame, 0.0f); | |
132 ExpectFrameColor(frame, 0xFF000000); | |
133 } | |
134 { | |
135 SCOPED_TRACE(""); | |
136 InitializeYV12Frame(frame, 1.0f); | |
137 ExpectFrameColor(frame, 0xFFFFFFFF); | |
138 } | |
139 | |
140 // Test an empty frame. | |
141 VideoFrameImpl::CreateEmptyFrame(&frame); | |
142 EXPECT_TRUE(frame->IsEndOfStream()); | |
143 } | |
144 | |
145 TEST(VideoFrameImpl, CreateBlackFrame) { | |
146 const size_t kWidth = 2; | |
147 const size_t kHeight = 2; | |
148 const uint8 kExpectedYRow[] = { 0, 0 }; | |
149 const uint8 kExpectedUVRow[] = { 128 }; | |
150 | |
151 scoped_refptr<media::VideoFrame> frame; | |
152 VideoFrameImpl::CreateBlackFrame(kWidth, kHeight, &frame); | |
153 ASSERT_TRUE(frame); | |
154 | |
155 // Test basic properties. | |
156 EXPECT_EQ(0, frame->GetTimestamp().InMicroseconds()); | |
157 EXPECT_EQ(0, frame->GetDuration().InMicroseconds()); | |
158 EXPECT_FALSE(frame->IsEndOfStream()); | |
159 | |
160 // Test surface properties. | |
161 VideoSurface surface; | |
162 EXPECT_TRUE(frame->Lock(&surface)); | |
163 EXPECT_EQ(VideoSurface::YV12, surface.format); | |
164 EXPECT_EQ(kWidth, surface.width); | |
165 EXPECT_EQ(kHeight, surface.height); | |
166 EXPECT_EQ(3u, surface.planes); | |
167 | |
168 // Test surfaces themselves. | |
169 for (size_t y = 0; y < surface.height; ++y) { | |
170 EXPECT_EQ(0, memcmp(kExpectedYRow, surface.data[VideoSurface::kYPlane], | |
171 arraysize(kExpectedYRow))); | |
172 surface.data[VideoSurface::kYPlane] += | |
173 surface.strides[VideoSurface::kYPlane]; | |
174 } | |
175 for (size_t y = 0; y < surface.height / 2; ++y) { | |
176 EXPECT_EQ(0, memcmp(kExpectedUVRow, surface.data[VideoSurface::kUPlane], | |
177 arraysize(kExpectedUVRow))); | |
178 EXPECT_EQ(0, memcmp(kExpectedUVRow, surface.data[VideoSurface::kVPlane], | |
179 arraysize(kExpectedUVRow))); | |
180 surface.data[VideoSurface::kUPlane] += | |
181 surface.strides[VideoSurface::kUPlane]; | |
182 surface.data[VideoSurface::kVPlane] += | |
183 surface.strides[VideoSurface::kVPlane]; | |
184 } | |
185 } | |
186 | |
187 } // namespace media | |
OLD | NEW |