Home | History | Annotate | Download | only in filters
      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 "media/base/video_frame.h"
      6 #include "media/base/video_util.h"
      7 #include "testing/gtest/include/gtest/gtest.h"
      8 #include "third_party/skia/include/core/SkCanvas.h"
      9 #include "third_party/skia/include/core/SkDevice.h"
     10 #include "media/filters/skcanvas_video_renderer.h"
     11 
     12 using media::VideoFrame;
     13 
     14 namespace media {
     15 
     16 static const int kWidth = 320;
     17 static const int kHeight = 240;
     18 static const gfx::Rect kNaturalRect(0, 0, kWidth, kHeight);
     19 
     20 // Helper for filling a |canvas| with a solid |color|.
     21 void FillCanvas(SkCanvas* canvas, SkColor color) {
     22   const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true);
     23   bitmap.lockPixels();
     24   bitmap.eraseColor(color);
     25   bitmap.unlockPixels();
     26 }
     27 
     28 // Helper for returning the color of a solid |canvas|.
     29 SkColor GetColorAt(SkCanvas* canvas, int x, int y) {
     30   const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
     31   bitmap.lockPixels();
     32   SkColor c = bitmap.getColor(x, y);
     33   bitmap.unlockPixels();
     34   return c;
     35 }
     36 
     37 SkColor GetColor(SkCanvas* canvas) {
     38   return GetColorAt(canvas, 0, 0);
     39 }
     40 
     41 class SkCanvasVideoRendererTest : public testing::Test {
     42  public:
     43   enum Color {
     44     kNone,
     45     kRed,
     46     kGreen,
     47     kBlue,
     48   };
     49 
     50   SkCanvasVideoRendererTest();
     51   virtual ~SkCanvasVideoRendererTest();
     52 
     53   // Paints to |canvas| using |renderer_| without any frame data.
     54   void PaintWithoutFrame(SkCanvas* canvas);
     55 
     56   // Paints the |video_frame| to the |canvas| using |renderer_|, setting the
     57   // color of |video_frame| to |color| first.
     58   void Paint(VideoFrame* video_frame, SkCanvas* canvas, Color color);
     59 
     60   // Getters for various frame sizes.
     61   VideoFrame* natural_frame() { return natural_frame_.get(); }
     62   VideoFrame* larger_frame() { return larger_frame_.get(); }
     63   VideoFrame* smaller_frame() { return smaller_frame_.get(); }
     64   VideoFrame* cropped_frame() { return cropped_frame_.get(); }
     65 
     66   // Getters for canvases that trigger the various painting paths.
     67   SkCanvas* fast_path_canvas() { return &fast_path_canvas_; }
     68   SkCanvas* slow_path_canvas() { return &slow_path_canvas_; }
     69 
     70  private:
     71   SkCanvasVideoRenderer renderer_;
     72 
     73   scoped_refptr<VideoFrame> natural_frame_;
     74   scoped_refptr<VideoFrame> larger_frame_;
     75   scoped_refptr<VideoFrame> smaller_frame_;
     76   scoped_refptr<VideoFrame> cropped_frame_;
     77 
     78   SkDevice fast_path_device_;
     79   SkCanvas fast_path_canvas_;
     80   SkDevice slow_path_device_;
     81   SkCanvas slow_path_canvas_;
     82 
     83   DISALLOW_COPY_AND_ASSIGN(SkCanvasVideoRendererTest);
     84 };
     85 
     86 SkCanvasVideoRendererTest::SkCanvasVideoRendererTest()
     87     : natural_frame_(VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight))),
     88       larger_frame_(VideoFrame::CreateBlackFrame(
     89           gfx::Size(kWidth * 2, kHeight * 2))),
     90       smaller_frame_(VideoFrame::CreateBlackFrame(
     91           gfx::Size(kWidth / 2, kHeight / 2))),
     92       cropped_frame_(VideoFrame::CreateFrame(
     93           VideoFrame::YV12,
     94           gfx::Size(16, 16),
     95           gfx::Rect(6, 6, 8, 6),
     96           gfx::Size(8, 6),
     97           base::TimeDelta::FromMilliseconds(4))),
     98       fast_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, true),
     99       fast_path_canvas_(&fast_path_device_),
    100       slow_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, false),
    101       slow_path_canvas_(&slow_path_device_) {
    102   // Give each frame a unique timestamp.
    103   natural_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(1));
    104   larger_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(2));
    105   smaller_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(3));
    106 
    107   // Make sure the cropped video frame's aspect ratio matches the output device.
    108   // Update cropped_frame_'s crop dimensions if this is not the case.
    109   EXPECT_EQ(cropped_frame()->natural_size().width() * kHeight,
    110       cropped_frame()->natural_size().height() * kWidth);
    111 
    112   // Fill in the cropped frame's entire data with colors:
    113   //
    114   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    115   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    116   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    117   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    118   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    119   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    120   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    121   //   Bl Bl Bl Bl Bl Bl Bl Bl R  R  R  R  R  R  R  R
    122   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    123   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    124   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    125   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    126   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    127   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    128   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    129   //   G  G  G  G  G  G  G  G  B  B  B  B  B  B  B  B
    130   //
    131   // The visible crop of the frame (as set by its visible_rect_) has contents:
    132   //
    133   //   Bl Bl R  R  R  R  R  R
    134   //   Bl Bl R  R  R  R  R  R
    135   //   G  G  B  B  B  B  B  B
    136   //   G  G  B  B  B  B  B  B
    137   //   G  G  B  B  B  B  B  B
    138   //   G  G  B  B  B  B  B  B
    139   //
    140   // Each color region in the cropped frame is on a 2x2 block granularity, to
    141   // avoid sharing UV samples between regions.
    142 
    143   static const uint8 cropped_y_plane[] = {
    144       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    145       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    146       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    147       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    148       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    149       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    150       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    151       0,   0,   0,   0,   0,   0,   0,   0, 76, 76, 76, 76, 76, 76, 76, 76,
    152     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    153     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    154     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    155     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    156     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    157     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    158     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    159     149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
    160   };
    161 
    162   static const uint8 cropped_u_plane[] = {
    163     128, 128, 128, 128,  84,  84,  84,  84,
    164     128, 128, 128, 128,  84,  84,  84,  84,
    165     128, 128, 128, 128,  84,  84,  84,  84,
    166     128, 128, 128, 128,  84,  84,  84,  84,
    167      43,  43,  43,  43, 255, 255, 255, 255,
    168      43,  43,  43,  43, 255, 255, 255, 255,
    169      43,  43,  43,  43, 255, 255, 255, 255,
    170      43,  43,  43,  43, 255, 255, 255, 255,
    171   };
    172   static const uint8 cropped_v_plane[] = {
    173     128, 128, 128, 128, 255, 255, 255, 255,
    174     128, 128, 128, 128, 255, 255, 255, 255,
    175     128, 128, 128, 128, 255, 255, 255, 255,
    176     128, 128, 128, 128, 255, 255, 255, 255,
    177      21,  21,  21,  21, 107, 107, 107, 107,
    178      21,  21,  21,  21, 107, 107, 107, 107,
    179      21,  21,  21,  21, 107, 107, 107, 107,
    180      21,  21,  21,  21, 107, 107, 107, 107,
    181   };
    182 
    183   media::CopyYPlane(cropped_y_plane, 16, 16, cropped_frame());
    184   media::CopyUPlane(cropped_u_plane, 8, 8, cropped_frame());
    185   media::CopyVPlane(cropped_v_plane, 8, 8, cropped_frame());
    186 }
    187 
    188 SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {}
    189 
    190 void SkCanvasVideoRendererTest::PaintWithoutFrame(SkCanvas* canvas) {
    191   renderer_.Paint(NULL, canvas, kNaturalRect, 0xFF);
    192 }
    193 
    194 void SkCanvasVideoRendererTest::Paint(VideoFrame* video_frame,
    195                                       SkCanvas* canvas,
    196                                       Color color) {
    197   switch (color) {
    198     case kNone:
    199       break;
    200     case kRed:
    201       media::FillYUV(video_frame, 76, 84, 255);
    202       break;
    203     case kGreen:
    204       media::FillYUV(video_frame, 149, 43, 21);
    205       break;
    206     case kBlue:
    207       media::FillYUV(video_frame, 29, 255, 107);
    208       break;
    209   }
    210   renderer_.Paint(video_frame, canvas, kNaturalRect, 0xFF);
    211 }
    212 
    213 TEST_F(SkCanvasVideoRendererTest, FastPaint_NoFrame) {
    214   // Test that black gets painted over canvas.
    215   FillCanvas(fast_path_canvas(), SK_ColorRED);
    216   PaintWithoutFrame(fast_path_canvas());
    217   EXPECT_EQ(SK_ColorBLACK, GetColor(fast_path_canvas()));
    218 }
    219 
    220 TEST_F(SkCanvasVideoRendererTest, SlowPaint_NoFrame) {
    221   // Test that black gets painted over canvas.
    222   FillCanvas(slow_path_canvas(), SK_ColorRED);
    223   PaintWithoutFrame(slow_path_canvas());
    224   EXPECT_EQ(SK_ColorBLACK, GetColor(slow_path_canvas()));
    225 }
    226 
    227 TEST_F(SkCanvasVideoRendererTest, FastPaint_Natural) {
    228   Paint(natural_frame(), fast_path_canvas(), kRed);
    229   EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
    230 }
    231 
    232 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Natural) {
    233   Paint(natural_frame(), slow_path_canvas(), kRed);
    234   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    235 }
    236 
    237 TEST_F(SkCanvasVideoRendererTest, FastPaint_Larger) {
    238   Paint(natural_frame(), fast_path_canvas(), kRed);
    239   EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
    240 
    241   Paint(larger_frame(), fast_path_canvas(), kBlue);
    242   EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
    243 }
    244 
    245 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Larger) {
    246   Paint(natural_frame(), slow_path_canvas(), kRed);
    247   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    248 
    249   Paint(larger_frame(), slow_path_canvas(), kBlue);
    250   EXPECT_EQ(SK_ColorBLUE, GetColor(slow_path_canvas()));
    251 }
    252 
    253 TEST_F(SkCanvasVideoRendererTest, FastPaint_Smaller) {
    254   Paint(natural_frame(), fast_path_canvas(), kRed);
    255   EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
    256 
    257   Paint(smaller_frame(), fast_path_canvas(), kBlue);
    258   EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
    259 }
    260 
    261 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Smaller) {
    262   Paint(natural_frame(), slow_path_canvas(), kRed);
    263   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    264 
    265   Paint(smaller_frame(), slow_path_canvas(), kBlue);
    266   EXPECT_EQ(SK_ColorBLUE, GetColor(slow_path_canvas()));
    267 }
    268 
    269 TEST_F(SkCanvasVideoRendererTest, FastPaint_NoTimestamp) {
    270   VideoFrame* video_frame = natural_frame();
    271   video_frame->SetTimestamp(media::kNoTimestamp());
    272   Paint(video_frame, fast_path_canvas(), kRed);
    273   EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
    274 }
    275 
    276 TEST_F(SkCanvasVideoRendererTest, SlowPaint_NoTimestamp) {
    277   VideoFrame* video_frame = natural_frame();
    278   video_frame->SetTimestamp(media::kNoTimestamp());
    279   Paint(video_frame, slow_path_canvas(), kRed);
    280   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    281 }
    282 
    283 TEST_F(SkCanvasVideoRendererTest, FastPaint_SameVideoFrame) {
    284   Paint(natural_frame(), fast_path_canvas(), kRed);
    285   EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
    286 
    287   // Fast paints always get painted to the canvas.
    288   Paint(natural_frame(), fast_path_canvas(), kBlue);
    289   EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
    290 }
    291 
    292 TEST_F(SkCanvasVideoRendererTest, SlowPaint_SameVideoFrame) {
    293   Paint(natural_frame(), slow_path_canvas(), kRed);
    294   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    295 
    296   // Slow paints can get cached, expect the old color value.
    297   Paint(natural_frame(), slow_path_canvas(), kBlue);
    298   EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
    299 }
    300 
    301 TEST_F(SkCanvasVideoRendererTest, FastPaint_CroppedFrame) {
    302   Paint(cropped_frame(), fast_path_canvas(), kNone);
    303   // Check the corners.
    304   EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), 0, 0));
    305   EXPECT_EQ(SK_ColorRED,   GetColorAt(fast_path_canvas(), kWidth - 1, 0));
    306   EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), 0, kHeight - 1));
    307   EXPECT_EQ(SK_ColorBLUE,  GetColorAt(fast_path_canvas(), kWidth - 1,
    308                                                           kHeight - 1));
    309   // Check the interior along the border between color regions.  Note that we're
    310   // bilinearly upscaling, so we'll need to take care to pick sample points that
    311   // are just outside the "zone of resampling".
    312   // TODO(sheu): commenting out two checks due to http://crbug.com/158462.
    313 #if 0
    314   EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), kWidth  * 1 / 8 - 1,
    315                                                           kHeight * 1 / 6 - 1));
    316 #endif
    317   EXPECT_EQ(SK_ColorRED,   GetColorAt(fast_path_canvas(), kWidth  * 3 / 8,
    318                                                           kHeight * 1 / 6 - 1));
    319 #if 0
    320   EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), kWidth  * 1 / 8 - 1,
    321                                                           kHeight * 3 / 6));
    322 #endif
    323   EXPECT_EQ(SK_ColorBLUE,  GetColorAt(fast_path_canvas(), kWidth  * 3 / 8,
    324                                                           kHeight * 3 / 6));
    325 }
    326 
    327 TEST_F(SkCanvasVideoRendererTest, SlowPaint_CroppedFrame) {
    328   Paint(cropped_frame(), slow_path_canvas(), kNone);
    329   // Check the corners.
    330   EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), 0, 0));
    331   EXPECT_EQ(SK_ColorRED,   GetColorAt(slow_path_canvas(), kWidth - 1, 0));
    332   EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), 0, kHeight - 1));
    333   EXPECT_EQ(SK_ColorBLUE,  GetColorAt(slow_path_canvas(), kWidth - 1,
    334                                                           kHeight - 1));
    335   // Check the interior along the border between color regions.  Note that we're
    336   // bilinearly upscaling, so we'll need to take care to pick sample points that
    337   // are just outside the "zone of resampling".
    338   EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), kWidth  * 1 / 8 - 1,
    339                                                           kHeight * 1 / 6 - 1));
    340   EXPECT_EQ(SK_ColorRED,   GetColorAt(slow_path_canvas(), kWidth  * 3 / 8,
    341                                                           kHeight * 1 / 6 - 1));
    342   EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), kWidth  * 1 / 8 - 1,
    343                                                           kHeight * 3 / 6));
    344   EXPECT_EQ(SK_ColorBLUE,  GetColorAt(slow_path_canvas(), kWidth  * 3 / 8,
    345                                                           kHeight * 3 / 6));
    346 }
    347 
    348 }  // namespace media
    349