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.
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"
12 class VideoUtilTest
: public testing::Test
{
21 ~VideoUtilTest() override
{}
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);
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]);
39 void CreateDestinationFrame(int width
, int height
) {
40 gfx::Size
size(width
, height
);
41 destination_frame_
= VideoFrame::CreateFrame(
42 PIXEL_FORMAT_YV12
, size
, gfx::Rect(size
), size
, base::TimeDelta());
46 CopyYPlane(y_plane_
.get(), y_stride_
, height_
, destination_frame_
.get());
48 u_plane_
.get(), u_stride_
, height_
/ 2, destination_frame_
.get());
50 v_plane_
.get(), v_stride_
, height_
/ 2, destination_frame_
.get());
54 scoped_ptr
<uint8
[]> y_plane_
;
55 scoped_ptr
<uint8
[]> u_plane_
;
56 scoped_ptr
<uint8
[]> v_plane_
;
63 scoped_refptr
<VideoFrame
> destination_frame_
;
65 DISALLOW_COPY_AND_ASSIGN(VideoUtilTest
);
68 TEST_F(VideoUtilTest
, GetNaturalSize
) {
69 gfx::Size
visible_size(320, 240);
72 EXPECT_EQ(gfx::Size(0, 0), GetNaturalSize(gfx::Size(0, 0), 1, 1));
73 EXPECT_EQ(gfx::Size(0, 1), GetNaturalSize(gfx::Size(0, 1), 1, 1));
74 EXPECT_EQ(gfx::Size(1, 0), GetNaturalSize(gfx::Size(1, 0), 1, 1));
76 // Test abnormal ratios.
77 EXPECT_EQ(gfx::Size(0, 0), GetNaturalSize(visible_size
, 0, 0));
78 EXPECT_EQ(gfx::Size(0, 0), GetNaturalSize(visible_size
, 1, 0));
79 EXPECT_EQ(gfx::Size(0, 0), GetNaturalSize(visible_size
, 1, -1));
80 EXPECT_EQ(gfx::Size(0, 0), GetNaturalSize(visible_size
, -1, 1));
82 // Test normal sizes and ratios.
83 EXPECT_EQ(gfx::Size(0, 240), GetNaturalSize(visible_size
, 0, 1));
84 EXPECT_EQ(gfx::Size(320, 240), GetNaturalSize(visible_size
, 1, 1));
85 EXPECT_EQ(gfx::Size(640, 240), GetNaturalSize(visible_size
, 2, 1));
86 EXPECT_EQ(gfx::Size(160, 240), GetNaturalSize(visible_size
, 1, 2));
87 EXPECT_EQ(gfx::Size(427, 240), GetNaturalSize(visible_size
, 4, 3));
88 EXPECT_EQ(gfx::Size(240, 240), GetNaturalSize(visible_size
, 3, 4));
89 EXPECT_EQ(gfx::Size(569, 240), GetNaturalSize(visible_size
, 16, 9));
90 EXPECT_EQ(gfx::Size(180, 240), GetNaturalSize(visible_size
, 9, 16));
92 // Test some random ratios.
93 EXPECT_EQ(gfx::Size(495, 240), GetNaturalSize(visible_size
, 17, 11));
94 EXPECT_EQ(gfx::Size(207, 240), GetNaturalSize(visible_size
, 11, 17));
97 TEST_F(VideoUtilTest
, CopyPlane_Exact
) {
98 CreateSourceFrame(16, 16, 16, 8, 8);
99 CreateDestinationFrame(16, 16);
103 TEST_F(VideoUtilTest
, CopyPlane_SmallerSource
) {
104 CreateSourceFrame(8, 8, 8, 4, 4);
105 CreateDestinationFrame(16, 16);
109 TEST_F(VideoUtilTest
, CopyPlane_SmallerDestination
) {
110 CreateSourceFrame(16, 16, 16, 8, 8);
111 CreateDestinationFrame(8, 8);
120 12, 13, 14, 15, 16, 17,
121 18, 19, 20, 21, 22, 23
124 // Target images, name pattern target_rotation_flipV_flipH.
125 uint8
* target6x4_0_n_n
= src6x4
;
127 uint8 target6x4_0_n_y
[] = {
130 17, 16, 15, 14, 13, 12,
131 23, 22, 21, 20, 19, 18
134 uint8 target6x4_0_y_n
[] = {
135 18, 19, 20, 21, 22, 23,
136 12, 13, 14, 15, 16, 17,
141 uint8 target6x4_0_y_y
[] = {
142 23, 22, 21, 20, 19, 18,
143 17, 16, 15, 14, 13, 12,
148 uint8 target6x4_90_n_n
[] = {
149 255, 19, 13, 7, 1, 255,
150 255, 20, 14, 8, 2, 255,
151 255, 21, 15, 9, 3, 255,
152 255, 22, 16, 10, 4, 255
155 uint8 target6x4_90_n_y
[] = {
156 255, 1, 7, 13, 19, 255,
157 255, 2, 8, 14, 20, 255,
158 255, 3, 9, 15, 21, 255,
159 255, 4, 10, 16, 22, 255
162 uint8 target6x4_90_y_n
[] = {
163 255, 22, 16, 10, 4, 255,
164 255, 21, 15, 9, 3, 255,
165 255, 20, 14, 8, 2, 255,
166 255, 19, 13, 7, 1, 255
169 uint8 target6x4_90_y_y
[] = {
170 255, 4, 10, 16, 22, 255,
171 255, 3, 9, 15, 21, 255,
172 255, 2, 8, 14, 20, 255,
173 255, 1, 7, 13, 19, 255
176 uint8
* target6x4_180_n_n
= target6x4_0_y_y
;
177 uint8
* target6x4_180_n_y
= target6x4_0_y_n
;
178 uint8
* target6x4_180_y_n
= target6x4_0_n_y
;
179 uint8
* target6x4_180_y_y
= target6x4_0_n_n
;
181 uint8
* target6x4_270_n_n
= target6x4_90_y_y
;
182 uint8
* target6x4_270_n_y
= target6x4_90_y_n
;
183 uint8
* target6x4_270_y_n
= target6x4_90_n_y
;
184 uint8
* target6x4_270_y_y
= target6x4_90_n_n
;
195 uint8
* target4x6_0_n_n
= src4x6
;
197 uint8 target4x6_0_n_y
[] = {
206 uint8 target4x6_0_y_n
[] = {
215 uint8 target4x6_0_y_y
[] = {
224 uint8 target4x6_90_n_n
[] = {
233 uint8 target4x6_90_n_y
[] = {
242 uint8 target4x6_90_y_n
[] = {
251 uint8 target4x6_90_y_y
[] = {
260 uint8
* target4x6_180_n_n
= target4x6_0_y_y
;
261 uint8
* target4x6_180_n_y
= target4x6_0_y_n
;
262 uint8
* target4x6_180_y_n
= target4x6_0_n_y
;
263 uint8
* target4x6_180_y_y
= target4x6_0_n_n
;
265 uint8
* target4x6_270_n_n
= target4x6_90_y_y
;
266 uint8
* target4x6_270_n_y
= target4x6_90_y_n
;
267 uint8
* target4x6_270_y_n
= target4x6_90_n_y
;
268 uint8
* target4x6_270_y_y
= target4x6_90_n_n
;
270 struct VideoRotationTestData
{
280 const VideoRotationTestData kVideoRotationTestData
[] = {
281 { src6x4
, target6x4_0_n_n
, 6, 4, 0, false, false },
282 { src6x4
, target6x4_0_n_y
, 6, 4, 0, false, true },
283 { src6x4
, target6x4_0_y_n
, 6, 4, 0, true, false },
284 { src6x4
, target6x4_0_y_y
, 6, 4, 0, true, true },
286 { src6x4
, target6x4_90_n_n
, 6, 4, 90, false, false },
287 { src6x4
, target6x4_90_n_y
, 6, 4, 90, false, true },
288 { src6x4
, target6x4_90_y_n
, 6, 4, 90, true, false },
289 { src6x4
, target6x4_90_y_y
, 6, 4, 90, true, true },
291 { src6x4
, target6x4_180_n_n
, 6, 4, 180, false, false },
292 { src6x4
, target6x4_180_n_y
, 6, 4, 180, false, true },
293 { src6x4
, target6x4_180_y_n
, 6, 4, 180, true, false },
294 { src6x4
, target6x4_180_y_y
, 6, 4, 180, true, true },
296 { src6x4
, target6x4_270_n_n
, 6, 4, 270, false, false },
297 { src6x4
, target6x4_270_n_y
, 6, 4, 270, false, true },
298 { src6x4
, target6x4_270_y_n
, 6, 4, 270, true, false },
299 { src6x4
, target6x4_270_y_y
, 6, 4, 270, true, true },
301 { src4x6
, target4x6_0_n_n
, 4, 6, 0, false, false },
302 { src4x6
, target4x6_0_n_y
, 4, 6, 0, false, true },
303 { src4x6
, target4x6_0_y_n
, 4, 6, 0, true, false },
304 { src4x6
, target4x6_0_y_y
, 4, 6, 0, true, true },
306 { src4x6
, target4x6_90_n_n
, 4, 6, 90, false, false },
307 { src4x6
, target4x6_90_n_y
, 4, 6, 90, false, true },
308 { src4x6
, target4x6_90_y_n
, 4, 6, 90, true, false },
309 { src4x6
, target4x6_90_y_y
, 4, 6, 90, true, true },
311 { src4x6
, target4x6_180_n_n
, 4, 6, 180, false, false },
312 { src4x6
, target4x6_180_n_y
, 4, 6, 180, false, true },
313 { src4x6
, target4x6_180_y_n
, 4, 6, 180, true, false },
314 { src4x6
, target4x6_180_y_y
, 4, 6, 180, true, true },
316 { src4x6
, target4x6_270_n_n
, 4, 6, 270, false, false },
317 { src4x6
, target4x6_270_n_y
, 4, 6, 270, false, true },
318 { src4x6
, target4x6_270_y_n
, 4, 6, 270, true, false },
319 { src4x6
, target4x6_270_y_y
, 4, 6, 270, true, true }
324 class VideoUtilRotationTest
325 : public testing::TestWithParam
<VideoRotationTestData
> {
327 VideoUtilRotationTest() {
328 dest_
.reset(new uint8
[GetParam().width
* GetParam().height
]);
331 virtual ~VideoUtilRotationTest() {}
333 uint8
* dest_plane() { return dest_
.get(); }
336 scoped_ptr
<uint8
[]> dest_
;
338 DISALLOW_COPY_AND_ASSIGN(VideoUtilRotationTest
);
341 TEST_P(VideoUtilRotationTest
, Rotate
) {
342 int rotation
= GetParam().rotation
;
343 EXPECT_TRUE((rotation
>= 0) && (rotation
< 360) && (rotation
% 90 == 0));
345 int size
= GetParam().width
* GetParam().height
;
346 uint8
* dest
= dest_plane();
347 memset(dest
, 255, size
);
349 RotatePlaneByPixels(GetParam().src
, dest
, GetParam().width
,
350 GetParam().height
, rotation
,
351 GetParam().flip_vert
, GetParam().flip_horiz
);
353 EXPECT_EQ(memcmp(dest
, GetParam().target
, size
), 0);
356 INSTANTIATE_TEST_CASE_P(, VideoUtilRotationTest
,
357 testing::ValuesIn(kVideoRotationTestData
));
359 // Tests the ComputeLetterboxRegion function. Also, because of shared code
360 // internally, this also tests ScaleSizeToFitWithinTarget().
361 TEST_F(VideoUtilTest
, ComputeLetterboxRegion
) {
362 EXPECT_EQ(gfx::Rect(166, 0, 667, 500),
363 ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
364 gfx::Size(640, 480)));
365 EXPECT_EQ(gfx::Rect(0, 312, 500, 375),
366 ComputeLetterboxRegion(gfx::Rect(0, 0, 500, 1000),
367 gfx::Size(640, 480)));
368 EXPECT_EQ(gfx::Rect(55, 0, 889, 500),
369 ComputeLetterboxRegion(gfx::Rect(0, 0, 1000, 500),
370 gfx::Size(1920, 1080)));
371 EXPECT_EQ(gfx::Rect(0, 12, 100, 75),
372 ComputeLetterboxRegion(gfx::Rect(0, 0, 100, 100),
373 gfx::Size(400, 300)));
374 EXPECT_EQ(gfx::Rect(0, 250000000, 2000000000, 1500000000),
375 ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
376 gfx::Size(40000, 30000)));
377 EXPECT_TRUE(ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
378 gfx::Size(0, 0)).IsEmpty());
381 TEST_F(VideoUtilTest
, ScaleSizeToEncompassTarget
) {
382 EXPECT_EQ(gfx::Size(1000, 750),
383 ScaleSizeToEncompassTarget(gfx::Size(640, 480),
384 gfx::Size(1000, 500)));
385 EXPECT_EQ(gfx::Size(1333, 1000),
386 ScaleSizeToEncompassTarget(gfx::Size(640, 480),
387 gfx::Size(500, 1000)));
388 EXPECT_EQ(gfx::Size(1000, 563),
389 ScaleSizeToEncompassTarget(gfx::Size(1920, 1080),
390 gfx::Size(1000, 500)));
391 EXPECT_EQ(gfx::Size(133, 100),
392 ScaleSizeToEncompassTarget(gfx::Size(400, 300),
393 gfx::Size(100, 100)));
394 EXPECT_EQ(gfx::Size(266666667, 200000000),
395 ScaleSizeToEncompassTarget(gfx::Size(40000, 30000),
396 gfx::Size(200000000, 200000000)));
397 EXPECT_TRUE(ScaleSizeToEncompassTarget(
398 gfx::Size(0, 0), gfx::Size(2000000000, 2000000000)).IsEmpty());
401 TEST_F(VideoUtilTest
, PadToMatchAspectRatio
) {
402 EXPECT_EQ(gfx::Size(640, 480),
403 PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(640, 480)));
404 EXPECT_EQ(gfx::Size(640, 480),
405 PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(4, 3)));
406 EXPECT_EQ(gfx::Size(960, 480),
407 PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(1000, 500)));
408 EXPECT_EQ(gfx::Size(640, 1280),
409 PadToMatchAspectRatio(gfx::Size(640, 480), gfx::Size(500, 1000)));
410 EXPECT_EQ(gfx::Size(2160, 1080),
411 PadToMatchAspectRatio(gfx::Size(1920, 1080), gfx::Size(1000, 500)));
412 EXPECT_EQ(gfx::Size(400, 400),
413 PadToMatchAspectRatio(gfx::Size(400, 300), gfx::Size(100, 100)));
414 EXPECT_EQ(gfx::Size(400, 400),
415 PadToMatchAspectRatio(gfx::Size(300, 400), gfx::Size(100, 100)));
416 EXPECT_EQ(gfx::Size(40000, 40000),
417 PadToMatchAspectRatio(gfx::Size(40000, 30000),
418 gfx::Size(2000000000, 2000000000)));
419 EXPECT_TRUE(PadToMatchAspectRatio(
420 gfx::Size(40000, 30000), gfx::Size(0, 0)).IsEmpty());
423 TEST_F(VideoUtilTest
, LetterboxYUV
) {
426 gfx::Size
size(width
, height
);
427 scoped_refptr
<VideoFrame
> frame(VideoFrame::CreateFrame(
428 PIXEL_FORMAT_YV12
, size
, gfx::Rect(size
), size
, base::TimeDelta()));
430 for (int left_margin
= 0; left_margin
<= 10; left_margin
+= 10) {
431 for (int right_margin
= 0; right_margin
<= 10; right_margin
+= 10) {
432 for (int top_margin
= 0; top_margin
<= 10; top_margin
+= 10) {
433 for (int bottom_margin
= 0; bottom_margin
<= 10; bottom_margin
+= 10) {
434 gfx::Rect
view_area(left_margin
, top_margin
,
435 width
- left_margin
- right_margin
,
436 height
- top_margin
- bottom_margin
);
437 FillYUV(frame
.get(), 0x1, 0x2, 0x3);
438 LetterboxYUV(frame
.get(), view_area
);
439 for (int x
= 0; x
< width
; x
++) {
440 for (int y
= 0; y
< height
; y
++) {
441 bool inside
= x
>= view_area
.x() &&
442 x
< view_area
.x() + view_area
.width() &&
443 y
>= view_area
.y() &&
444 y
< view_area
.y() + view_area
.height();
445 EXPECT_EQ(frame
->data(VideoFrame::kYPlane
)[
446 y
* frame
->stride(VideoFrame::kYPlane
) + x
],
447 inside
? 0x01 : 0x00);
448 EXPECT_EQ(frame
->data(VideoFrame::kUPlane
)[
449 (y
/ 2) * frame
->stride(VideoFrame::kUPlane
) + (x
/ 2)],
450 inside
? 0x02 : 0x80);
451 EXPECT_EQ(frame
->data(VideoFrame::kVPlane
)[
452 (y
/ 2) * frame
->stride(VideoFrame::kVPlane
) + (x
/ 2)],
453 inside
? 0x03 : 0x80);