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.
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 "media/filters/skcanvas_video_renderer.h"
11 using media::VideoFrame;
15 static const int kWidth = 320;
16 static const int kHeight = 240;
17 static const gfx::Rect kNaturalRect(0, 0, kWidth, kHeight);
19 // Helper for filling a |canvas| with a solid |color|.
20 void FillCanvas(SkCanvas* canvas, SkColor color) {
24 // Helper for returning the color of a solid |canvas|.
25 SkColor GetColorAt(SkCanvas* canvas, int x, int y) {
27 if (!bitmap.tryAllocN32Pixels(1, 1))
29 if (!canvas->readPixels(&bitmap, x, y))
31 return bitmap.getColor(0, 0);
34 SkColor GetColor(SkCanvas* canvas) {
35 return GetColorAt(canvas, 0, 0);
38 class SkCanvasVideoRendererTest : public testing::Test {
47 SkCanvasVideoRendererTest();
48 virtual ~SkCanvasVideoRendererTest();
50 // Paints to |canvas| using |renderer_| without any frame data.
51 void PaintWithoutFrame(SkCanvas* canvas);
53 // Paints the |video_frame| to the |canvas| using |renderer_|, setting the
54 // color of |video_frame| to |color| first.
55 void Paint(const scoped_refptr<VideoFrame>& video_frame,
58 void PaintRotated(const scoped_refptr<VideoFrame>& video_frame,
61 SkXfermode::Mode mode,
62 VideoRotation video_rotation);
64 void Copy(const scoped_refptr<VideoFrame>& video_frame, SkCanvas* canvas);
66 // Getters for various frame sizes.
67 scoped_refptr<VideoFrame> natural_frame() { return natural_frame_; }
68 scoped_refptr<VideoFrame> larger_frame() { return larger_frame_; }
69 scoped_refptr<VideoFrame> smaller_frame() { return smaller_frame_; }
70 scoped_refptr<VideoFrame> cropped_frame() { return cropped_frame_; }
73 SkCanvas* target_canvas() { return &target_canvas_; }
76 SkCanvasVideoRenderer renderer_;
78 scoped_refptr<VideoFrame> natural_frame_;
79 scoped_refptr<VideoFrame> larger_frame_;
80 scoped_refptr<VideoFrame> smaller_frame_;
81 scoped_refptr<VideoFrame> cropped_frame_;
83 SkCanvas target_canvas_;
85 DISALLOW_COPY_AND_ASSIGN(SkCanvasVideoRendererTest);
88 static SkBitmap AllocBitmap(int width, int height) {
90 bitmap.allocPixels(SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
95 SkCanvasVideoRendererTest::SkCanvasVideoRendererTest()
96 : natural_frame_(VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight))),
97 larger_frame_(VideoFrame::CreateBlackFrame(
98 gfx::Size(kWidth * 2, kHeight * 2))),
99 smaller_frame_(VideoFrame::CreateBlackFrame(
100 gfx::Size(kWidth / 2, kHeight / 2))),
101 cropped_frame_(VideoFrame::CreateFrame(
104 gfx::Rect(6, 6, 8, 6),
106 base::TimeDelta::FromMilliseconds(4))),
107 target_canvas_(AllocBitmap(kWidth, kHeight)) {
108 // Give each frame a unique timestamp.
109 natural_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(1));
110 larger_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(2));
111 smaller_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(3));
113 // Make sure the cropped video frame's aspect ratio matches the output device.
114 // Update cropped_frame_'s crop dimensions if this is not the case.
115 EXPECT_EQ(cropped_frame()->visible_rect().width() * kHeight,
116 cropped_frame()->visible_rect().height() * kWidth);
118 // Fill in the cropped frame's entire data with colors:
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 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
123 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
124 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
125 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
126 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
127 // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R
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 // G G G G G G G G B B B B B B B B
131 // G G G G G G G G B B B B B B B B
132 // G G G G G G G G B B B B B B B B
133 // G G G G G G G G B B B B B B B B
134 // G G G G G G G G B B B B B B B B
135 // G G G G G G G G B B B B B B B B
137 // The visible crop of the frame (as set by its visible_rect_) has contents:
146 // Each color region in the cropped frame is on a 2x2 block granularity, to
147 // avoid sharing UV samples between regions.
149 static const uint8 cropped_y_plane[] = {
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 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
153 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
154 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
155 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
156 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
157 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76,
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 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
161 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
162 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
163 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
164 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
165 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29,
168 static const uint8 cropped_u_plane[] = {
169 128, 128, 128, 128, 84, 84, 84, 84,
170 128, 128, 128, 128, 84, 84, 84, 84,
171 128, 128, 128, 128, 84, 84, 84, 84,
172 128, 128, 128, 128, 84, 84, 84, 84,
173 43, 43, 43, 43, 255, 255, 255, 255,
174 43, 43, 43, 43, 255, 255, 255, 255,
175 43, 43, 43, 43, 255, 255, 255, 255,
176 43, 43, 43, 43, 255, 255, 255, 255,
178 static const uint8 cropped_v_plane[] = {
179 128, 128, 128, 128, 255, 255, 255, 255,
180 128, 128, 128, 128, 255, 255, 255, 255,
181 128, 128, 128, 128, 255, 255, 255, 255,
182 128, 128, 128, 128, 255, 255, 255, 255,
183 21, 21, 21, 21, 107, 107, 107, 107,
184 21, 21, 21, 21, 107, 107, 107, 107,
185 21, 21, 21, 21, 107, 107, 107, 107,
186 21, 21, 21, 21, 107, 107, 107, 107,
189 media::CopyYPlane(cropped_y_plane, 16, 16, cropped_frame().get());
190 media::CopyUPlane(cropped_u_plane, 8, 8, cropped_frame().get());
191 media::CopyVPlane(cropped_v_plane, 8, 8, cropped_frame().get());
194 SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {}
196 void SkCanvasVideoRendererTest::PaintWithoutFrame(SkCanvas* canvas) {
197 renderer_.Paint(NULL,
201 SkXfermode::kSrcOver_Mode,
205 void SkCanvasVideoRendererTest::Paint(
206 const scoped_refptr<VideoFrame>& video_frame,
210 video_frame, canvas, color, SkXfermode::kSrcOver_Mode, VIDEO_ROTATION_0);
213 void SkCanvasVideoRendererTest::PaintRotated(
214 const scoped_refptr<VideoFrame>& video_frame,
217 SkXfermode::Mode mode,
218 VideoRotation video_rotation) {
223 media::FillYUV(video_frame.get(), 76, 84, 255);
226 media::FillYUV(video_frame.get(), 149, 43, 21);
229 media::FillYUV(video_frame.get(), 29, 255, 107);
233 video_frame, canvas, kNaturalRect, 0xFF, mode, video_rotation);
236 void SkCanvasVideoRendererTest::Copy(
237 const scoped_refptr<VideoFrame>& video_frame,
239 renderer_.Copy(video_frame, canvas);
242 TEST_F(SkCanvasVideoRendererTest, NoFrame) {
243 // Test that black gets painted over canvas.
244 FillCanvas(target_canvas(), SK_ColorRED);
245 PaintWithoutFrame(target_canvas());
246 EXPECT_EQ(SK_ColorBLACK, GetColor(target_canvas()));
249 TEST_F(SkCanvasVideoRendererTest, TransparentFrame) {
250 FillCanvas(target_canvas(), SK_ColorRED);
252 VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
255 SkXfermode::kSrcOver_Mode,
257 EXPECT_EQ(static_cast<SkColor>(SK_ColorRED), GetColor(target_canvas()));
260 TEST_F(SkCanvasVideoRendererTest, TransparentFrameSrcMode) {
261 FillCanvas(target_canvas(), SK_ColorRED);
262 // SRC mode completely overwrites the buffer.
264 VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
267 SkXfermode::kSrc_Mode,
269 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
270 GetColor(target_canvas()));
273 TEST_F(SkCanvasVideoRendererTest, CopyTransparentFrame) {
274 FillCanvas(target_canvas(), SK_ColorRED);
275 Copy(VideoFrame::CreateTransparentFrame(gfx::Size(kWidth, kHeight)).get(),
277 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT),
278 GetColor(target_canvas()));
281 TEST_F(SkCanvasVideoRendererTest, Natural) {
282 Paint(natural_frame(), target_canvas(), kRed);
283 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
286 TEST_F(SkCanvasVideoRendererTest, Larger) {
287 Paint(natural_frame(), target_canvas(), kRed);
288 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
290 Paint(larger_frame(), target_canvas(), kBlue);
291 EXPECT_EQ(SK_ColorBLUE, GetColor(target_canvas()));
294 TEST_F(SkCanvasVideoRendererTest, Smaller) {
295 Paint(natural_frame(), target_canvas(), kRed);
296 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
298 Paint(smaller_frame(), target_canvas(), kBlue);
299 EXPECT_EQ(SK_ColorBLUE, GetColor(target_canvas()));
302 TEST_F(SkCanvasVideoRendererTest, NoTimestamp) {
303 VideoFrame* video_frame = natural_frame().get();
304 video_frame->set_timestamp(media::kNoTimestamp());
305 Paint(video_frame, target_canvas(), kRed);
306 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
309 TEST_F(SkCanvasVideoRendererTest, SameVideoFrame) {
310 Paint(natural_frame(), target_canvas(), kRed);
311 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
313 // Slow paints can get cached, expect the old color value.
314 Paint(natural_frame(), target_canvas(), kBlue);
315 EXPECT_EQ(SK_ColorRED, GetColor(target_canvas()));
318 TEST_F(SkCanvasVideoRendererTest, CroppedFrame) {
319 Paint(cropped_frame(), target_canvas(), kNone);
320 // Check the corners.
321 EXPECT_EQ(SK_ColorBLACK, GetColorAt(target_canvas(), 0, 0));
322 EXPECT_EQ(SK_ColorRED, GetColorAt(target_canvas(), kWidth - 1, 0));
323 EXPECT_EQ(SK_ColorGREEN, GetColorAt(target_canvas(), 0, kHeight - 1));
324 EXPECT_EQ(SK_ColorBLUE, GetColorAt(target_canvas(), kWidth - 1,
326 // Check the interior along the border between color regions. Note that we're
327 // bilinearly upscaling, so we'll need to take care to pick sample points that
328 // are just outside the "zone of resampling".
329 EXPECT_EQ(SK_ColorBLACK, GetColorAt(target_canvas(), kWidth * 1 / 8 - 1,
330 kHeight * 1 / 6 - 1));
331 EXPECT_EQ(SK_ColorRED, GetColorAt(target_canvas(), kWidth * 3 / 8,
332 kHeight * 1 / 6 - 1));
333 EXPECT_EQ(SK_ColorGREEN, GetColorAt(target_canvas(), kWidth * 1 / 8 - 1,
335 EXPECT_EQ(SK_ColorBLUE, GetColorAt(target_canvas(), kWidth * 3 / 8,
339 TEST_F(SkCanvasVideoRendererTest, CroppedFrame_NoScaling) {
340 SkCanvas canvas(AllocBitmap(kWidth, kHeight));
341 const gfx::Rect crop_rect = cropped_frame()->visible_rect();
343 // Force painting to a non-zero position on the destination bitmap, to check
344 // if the coordinates are calculated properly.
345 const int offset_x = 10;
346 const int offset_y = 15;
347 canvas.translate(offset_x, offset_y);
349 // Create a destination canvas with dimensions and scale which would not
351 canvas.scale(static_cast<SkScalar>(crop_rect.width()) / kWidth,
352 static_cast<SkScalar>(crop_rect.height()) / kHeight);
354 Paint(cropped_frame(), &canvas, kNone);
356 // Check the corners.
357 EXPECT_EQ(SK_ColorBLACK, GetColorAt(&canvas, offset_x, offset_y));
358 EXPECT_EQ(SK_ColorRED,
359 GetColorAt(&canvas, offset_x + crop_rect.width() - 1, offset_y));
360 EXPECT_EQ(SK_ColorGREEN,
361 GetColorAt(&canvas, offset_x, offset_y + crop_rect.height() - 1));
362 EXPECT_EQ(SK_ColorBLUE,
364 offset_x + crop_rect.width() - 1,
365 offset_y + crop_rect.height() - 1));
368 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_90) {
369 SkCanvas canvas(AllocBitmap(kWidth, kHeight));
370 const gfx::Rect crop_rect = cropped_frame()->visible_rect();
371 PaintRotated(cropped_frame(),
374 SkXfermode::kSrcOver_Mode,
376 // Check the corners.
377 EXPECT_EQ(SK_ColorGREEN, GetColorAt(&canvas, 0, 0));
378 EXPECT_EQ(SK_ColorBLACK, GetColorAt(&canvas, kWidth - 1, 0));
379 EXPECT_EQ(SK_ColorRED, GetColorAt(&canvas, kWidth - 1, kHeight - 1));
380 EXPECT_EQ(SK_ColorBLUE, GetColorAt(&canvas, 0, kHeight - 1));
383 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_180) {
384 SkCanvas canvas(AllocBitmap(kWidth, kHeight));
385 const gfx::Rect crop_rect = cropped_frame()->visible_rect();
386 PaintRotated(cropped_frame(),
389 SkXfermode::kSrcOver_Mode,
391 // Check the corners.
392 EXPECT_EQ(SK_ColorBLUE, GetColorAt(&canvas, 0, 0));
393 EXPECT_EQ(SK_ColorGREEN, GetColorAt(&canvas, kWidth - 1, 0));
394 EXPECT_EQ(SK_ColorBLACK, GetColorAt(&canvas, kWidth - 1, kHeight - 1));
395 EXPECT_EQ(SK_ColorRED, GetColorAt(&canvas, 0, kHeight - 1));
398 TEST_F(SkCanvasVideoRendererTest, Video_Rotation_270) {
399 SkCanvas canvas(AllocBitmap(kWidth, kHeight));
400 const gfx::Rect crop_rect = cropped_frame()->visible_rect();
401 PaintRotated(cropped_frame(),
404 SkXfermode::kSrcOver_Mode,
406 // Check the corners.
407 EXPECT_EQ(SK_ColorRED, GetColorAt(&canvas, 0, 0));
408 EXPECT_EQ(SK_ColorBLUE, GetColorAt(&canvas, kWidth - 1, 0));
409 EXPECT_EQ(SK_ColorGREEN, GetColorAt(&canvas, kWidth - 1, kHeight - 1));
410 EXPECT_EQ(SK_ColorBLACK, GetColorAt(&canvas, 0, kHeight - 1));