1 // Copyright (c) 2012 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 "base/memory/scoped_ptr.h"
6 #include "media/base/video_frame.h"
7 #include "media/base/video_util.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace media {
11
12 class VideoUtilTest : public testing::Test {
13 public:
VideoUtilTest()14 VideoUtilTest()
15 : height_(0),
16 y_stride_(0),
17 u_stride_(0),
18 v_stride_(0) {
19 }
20
~VideoUtilTest()21 virtual ~VideoUtilTest() {}
22
CreateSourceFrame(int width,int height,int y_stride,int u_stride,int v_stride)23 void CreateSourceFrame(int width, int height,
24 int y_stride, int u_stride, int v_stride) {
25 EXPECT_GE(y_stride, width);
26 EXPECT_GE(u_stride, width / 2);
27 EXPECT_GE(v_stride, width / 2);
28
29 height_ = height;
30 y_stride_ = y_stride;
31 u_stride_ = u_stride;
32 v_stride_ = v_stride;
33
34 y_plane_.reset(new uint8[y_stride * height]);
35 u_plane_.reset(new uint8[u_stride * height / 2]);
36 v_plane_.reset(new uint8[v_stride * height / 2]);
37 }
38
CreateDestinationFrame(int width,int height)39 void CreateDestinationFrame(int width, int height) {
40 gfx::Size size(width, height);
41 destination_frame_ =
42 VideoFrame::CreateFrame(VideoFrame::YV12, size, gfx::Rect(size), size,
43 base::TimeDelta());
44 }
45
CopyPlanes()46 void CopyPlanes() {
47 CopyYPlane(y_plane_.get(), y_stride_, height_, destination_frame_.get());
48 CopyUPlane(
49 u_plane_.get(), u_stride_, height_ / 2, destination_frame_.get());
50 CopyVPlane(
51 v_plane_.get(), v_stride_, height_ / 2, destination_frame_.get());
52 }
53
54 private:
55 scoped_ptr<uint8[]> y_plane_;
56 scoped_ptr<uint8[]> u_plane_;
57 scoped_ptr<uint8[]> v_plane_;
58
59 int height_;
60 int y_stride_;
61 int u_stride_;
62 int v_stride_;
63
64 scoped_refptr<VideoFrame> destination_frame_;
65
66 DISALLOW_COPY_AND_ASSIGN(VideoUtilTest);
67 };
68
TEST_F(VideoUtilTest,CopyPlane_Exact)69 TEST_F(VideoUtilTest, CopyPlane_Exact) {
70 CreateSourceFrame(16, 16, 16, 8, 8);
71 CreateDestinationFrame(16, 16);
72 CopyPlanes();
73 }
74
TEST_F(VideoUtilTest,CopyPlane_SmallerSource)75 TEST_F(VideoUtilTest, CopyPlane_SmallerSource) {
76 CreateSourceFrame(8, 8, 8, 4, 4);
77 CreateDestinationFrame(16, 16);
78 CopyPlanes();
79 }
80
TEST_F(VideoUtilTest,CopyPlane_SmallerDestination)81 TEST_F(VideoUtilTest, CopyPlane_SmallerDestination) {
82 CreateSourceFrame(16, 16, 16, 8, 8);
83 CreateDestinationFrame(8, 8);
84 CopyPlanes();
85 }
86
87 namespace {
88
89 uint8 src6x4[] = {
90 0, 1, 2, 3, 4, 5,
91 6, 7, 8, 9, 10, 11,
92 12, 13, 14, 15, 16, 17,
93 18, 19, 20, 21, 22, 23
94 };
95
96 // Target images, name pattern target_rotation_flipV_flipH.
97 uint8* target6x4_0_n_n = src6x4;
98
99 uint8 target6x4_0_n_y[] = {
100 5, 4, 3, 2, 1, 0,
101 11, 10, 9, 8, 7, 6,
102 17, 16, 15, 14, 13, 12,
103 23, 22, 21, 20, 19, 18
104 };
105
106 uint8 target6x4_0_y_n[] = {
107 18, 19, 20, 21, 22, 23,
108 12, 13, 14, 15, 16, 17,
109 6, 7, 8, 9, 10, 11,
110 0, 1, 2, 3, 4, 5
111 };
112
113 uint8 target6x4_0_y_y[] = {
114 23, 22, 21, 20, 19, 18,
115 17, 16, 15, 14, 13, 12,
116 11, 10, 9, 8, 7, 6,
117 5, 4, 3, 2, 1, 0
118 };
119
120 uint8 target6x4_90_n_n[] = {
121 255, 19, 13, 7, 1, 255,
122 255, 20, 14, 8, 2, 255,
123 255, 21, 15, 9, 3, 255,
124 255, 22, 16, 10, 4, 255
125 };
126
127 uint8 target6x4_90_n_y[] = {
128 255, 1, 7, 13, 19, 255,
129 255, 2, 8, 14, 20, 255,
130 255, 3, 9, 15, 21, 255,
131 255, 4, 10, 16, 22, 255
132 };
133
134 uint8 target6x4_90_y_n[] = {
135 255, 22, 16, 10, 4, 255,
136 255, 21, 15, 9, 3, 255,
137 255, 20, 14, 8, 2, 255,
138 255, 19, 13, 7, 1, 255
139 };
140
141 uint8 target6x4_90_y_y[] = {
142 255, 4, 10, 16, 22, 255,
143 255, 3, 9, 15, 21, 255,
144 255, 2, 8, 14, 20, 255,
145 255, 1, 7, 13, 19, 255
146 };
147
148 uint8* target6x4_180_n_n = target6x4_0_y_y;
149 uint8* target6x4_180_n_y = target6x4_0_y_n;
150 uint8* target6x4_180_y_n = target6x4_0_n_y;
151 uint8* target6x4_180_y_y = target6x4_0_n_n;
152
153 uint8* target6x4_270_n_n = target6x4_90_y_y;
154 uint8* target6x4_270_n_y = target6x4_90_y_n;
155 uint8* target6x4_270_y_n = target6x4_90_n_y;
156 uint8* target6x4_270_y_y = target6x4_90_n_n;
157
158 uint8 src4x6[] = {
159 0, 1, 2, 3,
160 4, 5, 6, 7,
161 8, 9, 10, 11,
162 12, 13, 14, 15,
163 16, 17, 18, 19,
164 20, 21, 22, 23
165 };
166
167 uint8* target4x6_0_n_n = src4x6;
168
169 uint8 target4x6_0_n_y[] = {
170 3, 2, 1, 0,
171 7, 6, 5, 4,
172 11, 10, 9, 8,
173 15, 14, 13, 12,
174 19, 18, 17, 16,
175 23, 22, 21, 20
176 };
177
178 uint8 target4x6_0_y_n[] = {
179 20, 21, 22, 23,
180 16, 17, 18, 19,
181 12, 13, 14, 15,
182 8, 9, 10, 11,
183 4, 5, 6, 7,
184 0, 1, 2, 3
185 };
186
187 uint8 target4x6_0_y_y[] = {
188 23, 22, 21, 20,
189 19, 18, 17, 16,
190 15, 14, 13, 12,
191 11, 10, 9, 8,
192 7, 6, 5, 4,
193 3, 2, 1, 0
194 };
195
196 uint8 target4x6_90_n_n[] = {
197 255, 255, 255, 255,
198 16, 12, 8, 4,
199 17, 13, 9, 5,
200 18, 14, 10, 6,
201 19, 15, 11, 7,
202 255, 255, 255, 255
203 };
204
205 uint8 target4x6_90_n_y[] = {
206 255, 255, 255, 255,
207 4, 8, 12, 16,
208 5, 9, 13, 17,
209 6, 10, 14, 18,
210 7, 11, 15, 19,
211 255, 255, 255, 255
212 };
213
214 uint8 target4x6_90_y_n[] = {
215 255, 255, 255, 255,
216 19, 15, 11, 7,
217 18, 14, 10, 6,
218 17, 13, 9, 5,
219 16, 12, 8, 4,
220 255, 255, 255, 255
221 };
222
223 uint8 target4x6_90_y_y[] = {
224 255, 255, 255, 255,
225 7, 11, 15, 19,
226 6, 10, 14, 18,
227 5, 9, 13, 17,
228 4, 8, 12, 16,
229 255, 255, 255, 255
230 };
231
232 uint8* target4x6_180_n_n = target4x6_0_y_y;
233 uint8* target4x6_180_n_y = target4x6_0_y_n;
234 uint8* target4x6_180_y_n = target4x6_0_n_y;
235 uint8* target4x6_180_y_y = target4x6_0_n_n;
236
237 uint8* target4x6_270_n_n = target4x6_90_y_y;
238 uint8* target4x6_270_n_y = target4x6_90_y_n;
239 uint8* target4x6_270_y_n = target4x6_90_n_y;
240 uint8* target4x6_270_y_y = target4x6_90_n_n;
241
242 struct VideoRotationTestData {
243 uint8* src;
244 uint8* target;
245 int width;
246 int height;
247 int rotation;
248 bool flip_vert;
249 bool flip_horiz;
250 };
251
252 const VideoRotationTestData kVideoRotationTestData[] = {
253 { src6x4, target6x4_0_n_n, 6, 4, 0, false, false },
254 { src6x4, target6x4_0_n_y, 6, 4, 0, false, true },
255 { src6x4, target6x4_0_y_n, 6, 4, 0, true, false },
256 { src6x4, target6x4_0_y_y, 6, 4, 0, true, true },
257
258 { src6x4, target6x4_90_n_n, 6, 4, 90, false, false },
259 { src6x4, target6x4_90_n_y, 6, 4, 90, false, true },
260 { src6x4, target6x4_90_y_n, 6, 4, 90, true, false },
261 { src6x4, target6x4_90_y_y, 6, 4, 90, true, true },
262
263 { src6x4, target6x4_180_n_n, 6, 4, 180, false, false },
264 { src6x4, target6x4_180_n_y, 6, 4, 180, false, true },
265 { src6x4, target6x4_180_y_n, 6, 4, 180, true, false },
266 { src6x4, target6x4_180_y_y, 6, 4, 180, true, true },
267
268 { src6x4, target6x4_270_n_n, 6, 4, 270, false, false },
269 { src6x4, target6x4_270_n_y, 6, 4, 270, false, true },
270 { src6x4, target6x4_270_y_n, 6, 4, 270, true, false },
271 { src6x4, target6x4_270_y_y, 6, 4, 270, true, true },
272
273 { src4x6, target4x6_0_n_n, 4, 6, 0, false, false },
274 { src4x6, target4x6_0_n_y, 4, 6, 0, false, true },
275 { src4x6, target4x6_0_y_n, 4, 6, 0, true, false },
276 { src4x6, target4x6_0_y_y, 4, 6, 0, true, true },
277
278 { src4x6, target4x6_90_n_n, 4, 6, 90, false, false },
279 { src4x6, target4x6_90_n_y, 4, 6, 90, false, true },
280 { src4x6, target4x6_90_y_n, 4, 6, 90, true, false },
281 { src4x6, target4x6_90_y_y, 4, 6, 90, true, true },
282
283 { src4x6, target4x6_180_n_n, 4, 6, 180, false, false },
284 { src4x6, target4x6_180_n_y, 4, 6, 180, false, true },
285 { src4x6, target4x6_180_y_n, 4, 6, 180, true, false },
286 { src4x6, target4x6_180_y_y, 4, 6, 180, true, true },
287
288 { src4x6, target4x6_270_n_n, 4, 6, 270, false, false },
289 { src4x6, target4x6_270_n_y, 4, 6, 270, false, true },
290 { src4x6, target4x6_270_y_n, 4, 6, 270, true, false },
291 { src4x6, target4x6_270_y_y, 4, 6, 270, true, true }
292 };
293
294 } // namespace
295
296 class VideoUtilRotationTest
297 : public testing::TestWithParam<VideoRotationTestData> {
298 public:
VideoUtilRotationTest()299 VideoUtilRotationTest() {
300 dest_.reset(new uint8[GetParam().width * GetParam().height]);
301 }
302
~VideoUtilRotationTest()303 virtual ~VideoUtilRotationTest() {}
304
dest_plane()305 uint8* dest_plane() { return dest_.get(); }
306
307 private:
308 scoped_ptr<uint8[]> dest_;
309
310 DISALLOW_COPY_AND_ASSIGN(VideoUtilRotationTest);
311 };
312
TEST_P(VideoUtilRotationTest,Rotate)313 TEST_P(VideoUtilRotationTest, Rotate) {
314 int rotation = GetParam().rotation;
315 EXPECT_TRUE((rotation >= 0) && (rotation < 360) && (rotation % 90 == 0));
316
317 int size = GetParam().width * GetParam().height;
318 uint8* dest = dest_plane();
319 memset(dest, 255, size);
320
321 RotatePlaneByPixels(GetParam().src, dest, GetParam().width,
322 GetParam().height, rotation,
323 GetParam().flip_vert, GetParam().flip_horiz);
324
325 EXPECT_EQ(memcmp(dest, GetParam().target, size), 0);
326 }
327
328 INSTANTIATE_TEST_CASE_P(, VideoUtilRotationTest,
329 testing::ValuesIn(kVideoRotationTestData));
330
TEST_F(VideoUtilTest,ComputeLetterboxRegion)331 TEST_F(VideoUtilTest, ComputeLetterboxRegion) {
332 EXPECT_EQ(gfx::Rect(167, 0, 666, 500),
333 ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
334 gfx::Size(640, 480)));
335 EXPECT_EQ(gfx::Rect(0, 312, 500, 375),
336 ComputeLetterboxRegion(gfx::Rect(0, 0, 500, 1000),
337 gfx::Size(640, 480)));
338 EXPECT_EQ(gfx::Rect(56, 0, 888, 500),
339 ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
340 gfx::Size(1920, 1080)));
341 EXPECT_EQ(gfx::Rect(0, 12, 100, 75),
342 ComputeLetterboxRegion(gfx::Rect(0, 0, 100, 100),
343 gfx::Size(400, 300)));
344 EXPECT_EQ(gfx::Rect(0, 250000000, 2000000000, 1500000000),
345 ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
346 gfx::Size(40000, 30000)));
347 EXPECT_TRUE(ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
348 gfx::Size(0, 0)).IsEmpty());
349 }
350
TEST_F(VideoUtilTest,LetterboxYUV)351 TEST_F(VideoUtilTest, LetterboxYUV) {
352 int width = 40;
353 int height = 30;
354 gfx::Size size(width, height);
355 scoped_refptr<VideoFrame> frame(
356 VideoFrame::CreateFrame(VideoFrame::YV12, size, gfx::Rect(size), size,
357 base::TimeDelta()));
358
359 for (int left_margin = 0; left_margin <= 10; left_margin += 10) {
360 for (int right_margin = 0; right_margin <= 10; right_margin += 10) {
361 for (int top_margin = 0; top_margin <= 10; top_margin += 10) {
362 for (int bottom_margin = 0; bottom_margin <= 10; bottom_margin += 10) {
363 gfx::Rect view_area(left_margin, top_margin,
364 width - left_margin - right_margin,
365 height - top_margin - bottom_margin);
366 FillYUV(frame.get(), 0x1, 0x2, 0x3);
367 LetterboxYUV(frame.get(), view_area);
368 for (int x = 0; x < width; x++) {
369 for (int y = 0; y < height; y++) {
370 bool inside = x >= view_area.x() &&
371 x < view_area.x() + view_area.width() &&
372 y >= view_area.y() &&
373 y < view_area.y() + view_area.height();
374 EXPECT_EQ(frame->data(VideoFrame::kYPlane)[
375 y * frame->stride(VideoFrame::kYPlane) + x],
376 inside ? 0x01 : 0x00);
377 EXPECT_EQ(frame->data(VideoFrame::kUPlane)[
378 (y / 2) * frame->stride(VideoFrame::kUPlane) + (x / 2)],
379 inside ? 0x02 : 0x80);
380 EXPECT_EQ(frame->data(VideoFrame::kVPlane)[
381 (y / 2) * frame->stride(VideoFrame::kVPlane) + (x / 2)],
382 inside ? 0x03 : 0x80);
383 }
384 }
385 }
386 }
387 }
388 }
389 }
390
391 } // namespace media
392