1 // Copyright 2015 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 "third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.h"
6
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/test/gmock_callback_support.h"
10 #include "media/base/limits.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
14 #include "third_party/blink/public/platform/web_size.h"
15 #include "third_party/blink/public/web/web_heap.h"
16 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_capturer_source.h"
17 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
18 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
19 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
20 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
21 #include "third_party/skia/include/core/SkImage.h"
22 #include "third_party/skia/include/core/SkRefCnt.h"
23
24 using base::test::RunOnceClosure;
25 using ::testing::_;
26 using ::testing::InSequence;
27 using ::testing::Mock;
28 using ::testing::SaveArg;
29 using ::testing::Test;
30 using ::testing::TestWithParam;
31
32 namespace blink {
33
34 namespace {
35
36 static const int kTestCanvasCaptureWidth = 320;
37 static const int kTestCanvasCaptureHeight = 240;
38 static const double kTestCanvasCaptureFramesPerSecond = 55.5;
39
40 static const int kTestCanvasCaptureFrameEvenSize = 2;
41 static const int kTestCanvasCaptureFrameOddSize = 3;
42 static const int kTestCanvasCaptureFrameColorErrorTolerance = 2;
43 static const int kTestAlphaValue = 175;
44
45 } // namespace
46
47 class CanvasCaptureHandlerTest
48 : public TestWithParam<testing::tuple<bool, int, int>> {
49 public:
50 CanvasCaptureHandlerTest() = default;
51
SetUp()52 void SetUp() override {
53 MediaStreamComponent* component = nullptr;
54 canvas_capture_handler_ = CanvasCaptureHandler::CreateCanvasCaptureHandler(
55 /*LocalFrame =*/nullptr,
56 blink::WebSize(kTestCanvasCaptureWidth, kTestCanvasCaptureHeight),
57 kTestCanvasCaptureFramesPerSecond,
58 blink::scheduler::GetSingleThreadTaskRunnerForTesting(), &component);
59 component_ = component;
60 }
61
TearDown()62 void TearDown() override {
63 component_ = nullptr;
64 blink::WebHeap::CollectAllGarbageForTesting();
65 canvas_capture_handler_.reset();
66
67 // Let the message loop run to finish destroying the capturer.
68 base::RunLoop().RunUntilIdle();
69 }
70
71 // Necessary callbacks and MOCK_METHODS for VideoCapturerSource.
72 MOCK_METHOD2(DoOnDeliverFrame,
73 void(scoped_refptr<media::VideoFrame>, base::TimeTicks));
OnDeliverFrame(scoped_refptr<media::VideoFrame> video_frame,base::TimeTicks estimated_capture_time)74 void OnDeliverFrame(scoped_refptr<media::VideoFrame> video_frame,
75 base::TimeTicks estimated_capture_time) {
76 DoOnDeliverFrame(std::move(video_frame), estimated_capture_time);
77 }
78
79 MOCK_METHOD1(DoOnRunning, void(bool));
OnRunning(bool state)80 void OnRunning(bool state) { DoOnRunning(state); }
81
82 // Verify returned frames.
GenerateTestImage(bool opaque,int width,int height)83 static scoped_refptr<StaticBitmapImage> GenerateTestImage(bool opaque,
84 int width,
85 int height) {
86 SkImageInfo info = SkImageInfo::MakeN32(
87 width, height, opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
88 SkColorSpace::MakeSRGB());
89 SkBitmap testBitmap;
90 testBitmap.allocPixels(info);
91 testBitmap.eraseARGB(opaque ? 255 : kTestAlphaValue, 30, 60, 200);
92 return UnacceleratedStaticBitmapImage::Create(
93 SkImage::MakeFromBitmap(testBitmap));
94 }
95
OnVerifyDeliveredFrame(bool opaque,int expected_width,int expected_height,scoped_refptr<media::VideoFrame> video_frame,base::TimeTicks estimated_capture_time)96 void OnVerifyDeliveredFrame(bool opaque,
97 int expected_width,
98 int expected_height,
99 scoped_refptr<media::VideoFrame> video_frame,
100 base::TimeTicks estimated_capture_time) {
101 if (opaque)
102 EXPECT_EQ(media::PIXEL_FORMAT_I420, video_frame->format());
103 else
104 EXPECT_EQ(media::PIXEL_FORMAT_I420A, video_frame->format());
105
106 const gfx::Size& size = video_frame->visible_rect().size();
107 EXPECT_EQ(expected_width, size.width());
108 EXPECT_EQ(expected_height, size.height());
109 const uint8_t* y_plane =
110 video_frame->visible_data(media::VideoFrame::kYPlane);
111 EXPECT_NEAR(74, y_plane[0], kTestCanvasCaptureFrameColorErrorTolerance);
112 const uint8_t* u_plane =
113 video_frame->visible_data(media::VideoFrame::kUPlane);
114 EXPECT_NEAR(193, u_plane[0], kTestCanvasCaptureFrameColorErrorTolerance);
115 const uint8_t* v_plane =
116 video_frame->visible_data(media::VideoFrame::kVPlane);
117 EXPECT_NEAR(105, v_plane[0], kTestCanvasCaptureFrameColorErrorTolerance);
118 if (!opaque) {
119 const uint8_t* a_plane =
120 video_frame->visible_data(media::VideoFrame::kAPlane);
121 EXPECT_EQ(kTestAlphaValue, a_plane[0]);
122 }
123 }
124
125 Persistent<MediaStreamComponent> component_;
126 // The Class under test. Needs to be scoped_ptr to force its destruction.
127 std::unique_ptr<CanvasCaptureHandler> canvas_capture_handler_;
128
129 protected:
GetVideoCapturerSource(blink::MediaStreamVideoCapturerSource * ms_source)130 media::VideoCapturerSource* GetVideoCapturerSource(
131 blink::MediaStreamVideoCapturerSource* ms_source) {
132 return ms_source->GetSourceForTesting();
133 }
134
135 ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
136
137 private:
138 DISALLOW_COPY_AND_ASSIGN(CanvasCaptureHandlerTest);
139 };
140
141 // Checks that the initialization-destruction sequence works fine.
TEST_F(CanvasCaptureHandlerTest,ConstructAndDestruct)142 TEST_F(CanvasCaptureHandlerTest, ConstructAndDestruct) {
143 EXPECT_TRUE(canvas_capture_handler_->NeedsNewFrame());
144 base::RunLoop().RunUntilIdle();
145 }
146
147 // Checks that the destruction sequence works fine.
TEST_F(CanvasCaptureHandlerTest,DestructTrack)148 TEST_F(CanvasCaptureHandlerTest, DestructTrack) {
149 EXPECT_TRUE(canvas_capture_handler_->NeedsNewFrame());
150 component_ = nullptr;
151 base::RunLoop().RunUntilIdle();
152 }
153
154 // Checks that the destruction sequence works fine.
TEST_F(CanvasCaptureHandlerTest,DestructHandler)155 TEST_F(CanvasCaptureHandlerTest, DestructHandler) {
156 EXPECT_TRUE(canvas_capture_handler_->NeedsNewFrame());
157 canvas_capture_handler_.reset();
158 base::RunLoop().RunUntilIdle();
159 }
160
161 // Checks that VideoCapturerSource call sequence works fine.
TEST_P(CanvasCaptureHandlerTest,GetFormatsStartAndStop)162 TEST_P(CanvasCaptureHandlerTest, GetFormatsStartAndStop) {
163 InSequence s;
164 MediaStreamSource* const media_stream_source = component_->Source();
165 EXPECT_TRUE(media_stream_source);
166 blink::MediaStreamVideoCapturerSource* const ms_source =
167 static_cast<blink::MediaStreamVideoCapturerSource*>(
168 media_stream_source->GetPlatformSource());
169 EXPECT_TRUE(ms_source);
170 media::VideoCapturerSource* source = GetVideoCapturerSource(ms_source);
171 EXPECT_TRUE(source);
172
173 media::VideoCaptureFormats formats = source->GetPreferredFormats();
174 ASSERT_EQ(2u, formats.size());
175 EXPECT_EQ(kTestCanvasCaptureWidth, formats[0].frame_size.width());
176 EXPECT_EQ(kTestCanvasCaptureHeight, formats[0].frame_size.height());
177 media::VideoCaptureParams params;
178 params.requested_format = formats[0];
179
180 base::RunLoop run_loop;
181 base::RepeatingClosure quit_closure = run_loop.QuitClosure();
182 EXPECT_CALL(*this, DoOnRunning(true)).Times(1);
183 EXPECT_CALL(*this, DoOnDeliverFrame(_, _))
184 .Times(1)
185 .WillOnce(RunOnceClosure(std::move(quit_closure)));
186 source->StartCapture(
187 params,
188 base::BindRepeating(&CanvasCaptureHandlerTest::OnDeliverFrame,
189 base::Unretained(this)),
190 base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
191 base::Unretained(this)));
192 canvas_capture_handler_->SendNewFrame(
193 GenerateTestImage(testing::get<0>(GetParam()),
194 testing::get<1>(GetParam()),
195 testing::get<2>(GetParam())),
196 nullptr);
197 run_loop.Run();
198
199 source->StopCapture();
200 }
201
202 // Verifies that SkImage is processed and produces VideoFrame as expected.
TEST_P(CanvasCaptureHandlerTest,VerifyFrame)203 TEST_P(CanvasCaptureHandlerTest, VerifyFrame) {
204 const bool opaque_frame = testing::get<0>(GetParam());
205 const bool width = testing::get<1>(GetParam());
206 const bool height = testing::get<1>(GetParam());
207 InSequence s;
208 media::VideoCapturerSource* const source = GetVideoCapturerSource(
209 static_cast<blink::MediaStreamVideoCapturerSource*>(
210 component_->Source()->GetPlatformSource()));
211 EXPECT_TRUE(source);
212
213 base::RunLoop run_loop;
214 EXPECT_CALL(*this, DoOnRunning(true)).Times(1);
215 media::VideoCaptureParams params;
216 source->StartCapture(
217 params,
218 base::BindRepeating(&CanvasCaptureHandlerTest::OnVerifyDeliveredFrame,
219 base::Unretained(this), opaque_frame, width, height),
220 base::BindRepeating(&CanvasCaptureHandlerTest::OnRunning,
221 base::Unretained(this)));
222 canvas_capture_handler_->SendNewFrame(
223 GenerateTestImage(opaque_frame, width, height), nullptr);
224 run_loop.RunUntilIdle();
225 }
226
227 // Checks that needsNewFrame() works as expected.
TEST_F(CanvasCaptureHandlerTest,CheckNeedsNewFrame)228 TEST_F(CanvasCaptureHandlerTest, CheckNeedsNewFrame) {
229 InSequence s;
230 media::VideoCapturerSource* source = GetVideoCapturerSource(
231 static_cast<blink::MediaStreamVideoCapturerSource*>(
232 component_->Source()->GetPlatformSource()));
233 EXPECT_TRUE(source);
234 EXPECT_TRUE(canvas_capture_handler_->NeedsNewFrame());
235 source->StopCapture();
236 EXPECT_FALSE(canvas_capture_handler_->NeedsNewFrame());
237 }
238
239 INSTANTIATE_TEST_SUITE_P(
240 All,
241 CanvasCaptureHandlerTest,
242 ::testing::Combine(::testing::Bool(),
243 ::testing::Values(kTestCanvasCaptureFrameEvenSize,
244 kTestCanvasCaptureFrameOddSize),
245 ::testing::Values(kTestCanvasCaptureFrameEvenSize,
246 kTestCanvasCaptureFrameOddSize)));
247
248 } // namespace blink
249