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