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.allocN32Pixels(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(VideoFrame* video_frame, SkCanvas* canvas, Color color);
57 // Getters for various frame sizes.
58 VideoFrame* natural_frame() { return natural_frame_.get(); }
59 VideoFrame* larger_frame() { return larger_frame_.get(); }
60 VideoFrame* smaller_frame() { return smaller_frame_.get(); }
61 VideoFrame* cropped_frame() { return cropped_frame_.get(); }
63 // Getters for canvases that trigger the various painting paths.
64 SkCanvas* fast_path_canvas() { return &fast_path_canvas_; }
65 SkCanvas* slow_path_canvas() { return &slow_path_canvas_; }
68 SkCanvasVideoRenderer renderer_;
70 scoped_refptr<VideoFrame> natural_frame_;
71 scoped_refptr<VideoFrame> larger_frame_;
72 scoped_refptr<VideoFrame> smaller_frame_;
73 scoped_refptr<VideoFrame> cropped_frame_;
75 SkCanvas fast_path_canvas_;
76 SkCanvas slow_path_canvas_;
78 DISALLOW_COPY_AND_ASSIGN(SkCanvasVideoRendererTest);
81 static SkBitmap AllocBitmap(int width, int height, bool isOpaque) {
82 SkAlphaType alpha_type = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
85 bitmap.allocPixels(SkImageInfo::MakeN32(width, height, alpha_type));
91 SkCanvasVideoRendererTest::SkCanvasVideoRendererTest()
92 : natural_frame_(VideoFrame::CreateBlackFrame(gfx::Size(kWidth, kHeight))),
93 larger_frame_(VideoFrame::CreateBlackFrame(
94 gfx::Size(kWidth * 2, kHeight * 2))),
95 smaller_frame_(VideoFrame::CreateBlackFrame(
96 gfx::Size(kWidth / 2, kHeight / 2))),
97 cropped_frame_(VideoFrame::CreateFrame(
100 gfx::Rect(6, 6, 8, 6),
102 base::TimeDelta::FromMilliseconds(4))),
103 fast_path_canvas_(AllocBitmap(kWidth, kHeight, true)),
104 slow_path_canvas_(AllocBitmap(kWidth, kHeight, false)) {
105 // Give each frame a unique timestamp.
106 natural_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(1));
107 larger_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(2));
108 smaller_frame_->set_timestamp(base::TimeDelta::FromMilliseconds(3));
110 // Make sure the cropped video frame's aspect ratio matches the output device.
111 // Update cropped_frame_'s crop dimensions if this is not the case.
112 EXPECT_EQ(cropped_frame()->visible_rect().width() * kHeight,
113 cropped_frame()->visible_rect().height() * kWidth);
115 // Fill in the cropped frame's entire data with colors:
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 // 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 // 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 // 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
134 // The visible crop of the frame (as set by its visible_rect_) has contents:
143 // Each color region in the cropped frame is on a 2x2 block granularity, to
144 // avoid sharing UV samples between regions.
146 static const uint8 cropped_y_plane[] = {
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 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 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 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,
165 static const uint8 cropped_u_plane[] = {
166 128, 128, 128, 128, 84, 84, 84, 84,
167 128, 128, 128, 128, 84, 84, 84, 84,
168 128, 128, 128, 128, 84, 84, 84, 84,
169 128, 128, 128, 128, 84, 84, 84, 84,
170 43, 43, 43, 43, 255, 255, 255, 255,
171 43, 43, 43, 43, 255, 255, 255, 255,
172 43, 43, 43, 43, 255, 255, 255, 255,
173 43, 43, 43, 43, 255, 255, 255, 255,
175 static const uint8 cropped_v_plane[] = {
176 128, 128, 128, 128, 255, 255, 255, 255,
177 128, 128, 128, 128, 255, 255, 255, 255,
178 128, 128, 128, 128, 255, 255, 255, 255,
179 128, 128, 128, 128, 255, 255, 255, 255,
180 21, 21, 21, 21, 107, 107, 107, 107,
181 21, 21, 21, 21, 107, 107, 107, 107,
182 21, 21, 21, 21, 107, 107, 107, 107,
183 21, 21, 21, 21, 107, 107, 107, 107,
186 media::CopyYPlane(cropped_y_plane, 16, 16, cropped_frame());
187 media::CopyUPlane(cropped_u_plane, 8, 8, cropped_frame());
188 media::CopyVPlane(cropped_v_plane, 8, 8, cropped_frame());
191 SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {}
193 void SkCanvasVideoRendererTest::PaintWithoutFrame(SkCanvas* canvas) {
194 renderer_.Paint(NULL, canvas, kNaturalRect, 0xFF);
197 void SkCanvasVideoRendererTest::Paint(VideoFrame* video_frame,
204 media::FillYUV(video_frame, 76, 84, 255);
207 media::FillYUV(video_frame, 149, 43, 21);
210 media::FillYUV(video_frame, 29, 255, 107);
213 renderer_.Paint(video_frame, canvas, kNaturalRect, 0xFF);
216 TEST_F(SkCanvasVideoRendererTest, FastPaint_NoFrame) {
217 // Test that black gets painted over canvas.
218 FillCanvas(fast_path_canvas(), SK_ColorRED);
219 PaintWithoutFrame(fast_path_canvas());
220 EXPECT_EQ(SK_ColorBLACK, GetColor(fast_path_canvas()));
223 TEST_F(SkCanvasVideoRendererTest, SlowPaint_NoFrame) {
224 // Test that black gets painted over canvas.
225 FillCanvas(slow_path_canvas(), SK_ColorRED);
226 PaintWithoutFrame(slow_path_canvas());
227 EXPECT_EQ(SK_ColorBLACK, GetColor(slow_path_canvas()));
230 TEST_F(SkCanvasVideoRendererTest, FastPaint_Natural) {
231 Paint(natural_frame(), fast_path_canvas(), kRed);
232 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
235 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Natural) {
236 Paint(natural_frame(), slow_path_canvas(), kRed);
237 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
240 TEST_F(SkCanvasVideoRendererTest, FastPaint_Larger) {
241 Paint(natural_frame(), fast_path_canvas(), kRed);
242 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
244 Paint(larger_frame(), fast_path_canvas(), kBlue);
245 EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
248 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Larger) {
249 Paint(natural_frame(), slow_path_canvas(), kRed);
250 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
252 Paint(larger_frame(), slow_path_canvas(), kBlue);
253 EXPECT_EQ(SK_ColorBLUE, GetColor(slow_path_canvas()));
256 TEST_F(SkCanvasVideoRendererTest, FastPaint_Smaller) {
257 Paint(natural_frame(), fast_path_canvas(), kRed);
258 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
260 Paint(smaller_frame(), fast_path_canvas(), kBlue);
261 EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
264 TEST_F(SkCanvasVideoRendererTest, SlowPaint_Smaller) {
265 Paint(natural_frame(), slow_path_canvas(), kRed);
266 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
268 Paint(smaller_frame(), slow_path_canvas(), kBlue);
269 EXPECT_EQ(SK_ColorBLUE, GetColor(slow_path_canvas()));
272 TEST_F(SkCanvasVideoRendererTest, FastPaint_NoTimestamp) {
273 VideoFrame* video_frame = natural_frame();
274 video_frame->set_timestamp(media::kNoTimestamp());
275 Paint(video_frame, fast_path_canvas(), kRed);
276 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
279 TEST_F(SkCanvasVideoRendererTest, SlowPaint_NoTimestamp) {
280 VideoFrame* video_frame = natural_frame();
281 video_frame->set_timestamp(media::kNoTimestamp());
282 Paint(video_frame, slow_path_canvas(), kRed);
283 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
286 TEST_F(SkCanvasVideoRendererTest, FastPaint_SameVideoFrame) {
287 Paint(natural_frame(), fast_path_canvas(), kRed);
288 EXPECT_EQ(SK_ColorRED, GetColor(fast_path_canvas()));
290 // Fast paints always get painted to the canvas.
291 Paint(natural_frame(), fast_path_canvas(), kBlue);
292 EXPECT_EQ(SK_ColorBLUE, GetColor(fast_path_canvas()));
295 TEST_F(SkCanvasVideoRendererTest, SlowPaint_SameVideoFrame) {
296 Paint(natural_frame(), slow_path_canvas(), kRed);
297 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
299 // Slow paints can get cached, expect the old color value.
300 Paint(natural_frame(), slow_path_canvas(), kBlue);
301 EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas()));
304 TEST_F(SkCanvasVideoRendererTest, FastPaint_CroppedFrame) {
305 Paint(cropped_frame(), fast_path_canvas(), kNone);
306 // Check the corners.
307 EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), 0, 0));
308 EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth - 1, 0));
309 EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), 0, kHeight - 1));
310 EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth - 1,
312 // Check the interior along the border between color regions. Note that we're
313 // bilinearly upscaling, so we'll need to take care to pick sample points that
314 // are just outside the "zone of resampling".
315 // TODO(sheu): commenting out two checks due to http://crbug.com/158462.
317 EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1,
318 kHeight * 1 / 6 - 1));
320 EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth * 3 / 8,
321 kHeight * 1 / 6 - 1));
323 EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1,
326 EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth * 3 / 8,
330 TEST_F(SkCanvasVideoRendererTest, SlowPaint_CroppedFrame) {
331 Paint(cropped_frame(), slow_path_canvas(), kNone);
332 // Check the corners.
333 EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), 0, 0));
334 EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth - 1, 0));
335 EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), 0, kHeight - 1));
336 EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth - 1,
338 // Check the interior along the border between color regions. Note that we're
339 // bilinearly upscaling, so we'll need to take care to pick sample points that
340 // are just outside the "zone of resampling".
341 EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1,
342 kHeight * 1 / 6 - 1));
343 EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth * 3 / 8,
344 kHeight * 1 / 6 - 1));
345 EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1,
347 EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth * 3 / 8,