• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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