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 12using media::VideoFrame; 13 14namespace media { 15 16static const int kWidth = 320; 17static const int kHeight = 240; 18static const gfx::Rect kNaturalRect(0, 0, kWidth, kHeight); 19 20// Helper for filling a |canvas| with a solid |color|. 21void 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|. 29SkColor 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 37SkColor GetColor(SkCanvas* canvas) { 38 return GetColorAt(canvas, 0, 0); 39} 40 41class 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 86SkCanvasVideoRendererTest::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 188SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {} 189 190void SkCanvasVideoRendererTest::PaintWithoutFrame(SkCanvas* canvas) { 191 renderer_.Paint(NULL, canvas, kNaturalRect, 0xFF); 192} 193 194void 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 213TEST_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 220TEST_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 227TEST_F(SkCanvasVideoRendererTest, FastPaint_Natural) { 228 Paint(natural_frame(), fast_path_canvas(), kRed); 229 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas())); 230} 231 232TEST_F(SkCanvasVideoRendererTest, SlowPaint_Natural) { 233 Paint(natural_frame(), slow_path_canvas(), kRed); 234 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas())); 235} 236 237TEST_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 245TEST_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 253TEST_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 261TEST_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 269TEST_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 276TEST_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 283TEST_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 292TEST_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 301TEST_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 327TEST_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