Home | History | Annotate | Download | only in base
      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:
     14   VideoUtilTest()
     15       : height_(0),
     16         y_stride_(0),
     17         u_stride_(0),
     18         v_stride_(0) {
     19   }
     20 
     21   virtual ~VideoUtilTest() {}
     22 
     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 
     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 
     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 
     69 TEST_F(VideoUtilTest, CopyPlane_Exact) {
     70   CreateSourceFrame(16, 16, 16, 8, 8);
     71   CreateDestinationFrame(16, 16);
     72   CopyPlanes();
     73 }
     74 
     75 TEST_F(VideoUtilTest, CopyPlane_SmallerSource) {
     76   CreateSourceFrame(8, 8, 8, 4, 4);
     77   CreateDestinationFrame(16, 16);
     78   CopyPlanes();
     79 }
     80 
     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:
    299   VideoUtilRotationTest() {
    300     dest_.reset(new uint8[GetParam().width * GetParam().height]);
    301   }
    302 
    303   virtual ~VideoUtilRotationTest() {}
    304 
    305   uint8* dest_plane() { return dest_.get(); }
    306 
    307  private:
    308   scoped_ptr<uint8[]> dest_;
    309 
    310   DISALLOW_COPY_AND_ASSIGN(VideoUtilRotationTest);
    311 };
    312 
    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 
    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 
    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