Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / renderer / media / media_stream_video_capturer_source_unittest.cc
blobc0187764c5bb4a3ce67c558827604817a11944f0
1 // Copyright 2014 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 "base/bind.h"
6 #include "base/callback_helpers.h"
7 #include "base/location.h"
8 #include "base/run_loop.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/child/child_process.h"
12 #include "content/public/renderer/media_stream_video_sink.h"
13 #include "content/renderer/media/media_stream_video_capturer_source.h"
14 #include "content/renderer/media/media_stream_video_track.h"
15 #include "content/renderer/media/mock_media_constraint_factory.h"
16 #include "media/base/bind_to_current_loop.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/WebKit/public/web/WebHeap.h"
21 using ::testing::_;
22 using ::testing::InSequence;
23 using ::testing::Invoke;
24 using ::testing::WithArgs;
26 namespace content {
28 class MockVideoCapturerSource : public media::VideoCapturerSource {
29 public:
30 MockVideoCapturerSource() {
31 ON_CALL(*this, GetCurrentSupportedFormats(_, _, _, _))
32 .WillByDefault(WithArgs<3>(
33 Invoke(this, &MockVideoCapturerSource::EnumerateDeviceFormats)));
36 MOCK_METHOD4(GetCurrentSupportedFormats,
37 void(int max_requested_width,
38 int max_requested_height,
39 double max_requested_frame_rate,
40 const VideoCaptureDeviceFormatsCB& callback));
41 MOCK_METHOD3(StartCapture,
42 void(const media::VideoCaptureParams& params,
43 const VideoCaptureDeliverFrameCB& new_frame_callback,
44 const RunningCallback& running_callback));
45 MOCK_METHOD0(StopCapture, void());
47 void EnumerateDeviceFormats(const VideoCaptureDeviceFormatsCB& callback) {
48 media::VideoCaptureFormat kFormatSmall(gfx::Size(640, 480), 30.0,
49 media::PIXEL_FORMAT_I420);
50 media::VideoCaptureFormat kFormatLarge(gfx::Size(1920, 1080), 30.0,
51 media::PIXEL_FORMAT_I420);
52 media::VideoCaptureFormats formats;
53 formats.push_back(kFormatSmall);
54 formats.push_back(kFormatLarge);
55 callback.Run(formats);
60 class MediaStreamVideoCapturerSourceTest : public testing::Test {
61 public:
62 MediaStreamVideoCapturerSourceTest()
63 : child_process_(new ChildProcess()),
64 source_(nullptr),
65 delegate_(nullptr),
66 source_stopped_(false) {}
68 void TearDown() override {
69 webkit_source_.reset();
70 blink::WebHeap::collectAllGarbageForTesting();
73 void InitWithDeviceInfo(const StreamDeviceInfo& device_info) {
74 scoped_ptr<MockVideoCapturerSource> delegate(new MockVideoCapturerSource());
75 delegate_ = delegate.get();
76 source_ = new MediaStreamVideoCapturerSource(
77 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
78 base::Unretained(this)),
79 delegate.Pass());
80 source_->SetDeviceInfo(device_info);
82 webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
83 blink::WebMediaStreamSource::TypeVideo,
84 base::UTF8ToUTF16("dummy_source_name"),
85 false /* remote */,
86 true /* readonly */);
87 webkit_source_.setExtraData(source_);
88 webkit_source_id_ = webkit_source_.id();
91 MockMediaConstraintFactory* constraint_factory() {
92 return &constraint_factory_;
95 blink::WebMediaStreamTrack StartSource() {
96 bool enabled = true;
97 // CreateVideoTrack will trigger OnConstraintsApplied.
98 return MediaStreamVideoTrack::CreateVideoTrack(
99 source_, constraint_factory_.CreateWebMediaConstraints(),
100 base::Bind(&MediaStreamVideoCapturerSourceTest::OnConstraintsApplied,
101 base::Unretained(this)),
102 enabled);
105 MockVideoCapturerSource& mock_delegate() { return *delegate_; }
107 const char* GetPowerLineFrequencyForTesting() const {
108 return source_->GetPowerLineFrequencyForTesting();
111 void OnSourceStopped(const blink::WebMediaStreamSource& source) {
112 source_stopped_ = true;
113 EXPECT_EQ(source.id(), webkit_source_id_);
115 void OnStarted(bool result) { source_->OnStarted(result); }
117 protected:
118 void OnConstraintsApplied(MediaStreamSource* source,
119 MediaStreamRequestResult result,
120 const blink::WebString& result_name) {}
122 // A ChildProcess and a MessageLoopForUI are both needed to fool the Tracks
123 // and Sources below into believing they are on the right threads.
124 base::MessageLoopForUI message_loop_;
125 scoped_ptr<ChildProcess> child_process_;
127 blink::WebMediaStreamSource webkit_source_;
128 MediaStreamVideoCapturerSource* source_; // owned by |webkit_source_|.
129 MockVideoCapturerSource* delegate_; // owned by |source|.
130 blink::WebString webkit_source_id_;
131 bool source_stopped_;
132 MockMediaConstraintFactory constraint_factory_;
135 TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureFixedResolutionByDefault) {
136 StreamDeviceInfo device_info;
137 device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
138 InitWithDeviceInfo(device_info);
140 // No constraints are being provided to the implementation, so expect only
141 // default values.
142 media::VideoCaptureParams expected_params;
143 expected_params.requested_format.frame_size.SetSize(
144 MediaStreamVideoSource::kDefaultWidth,
145 MediaStreamVideoSource::kDefaultHeight);
146 expected_params.requested_format.frame_rate =
147 MediaStreamVideoSource::kDefaultFrameRate;
148 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
149 expected_params.resolution_change_policy =
150 media::RESOLUTION_POLICY_FIXED_RESOLUTION;
152 InSequence s;
153 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
154 EXPECT_CALL(mock_delegate(), StartCapture(expected_params, _, _));
155 blink::WebMediaStreamTrack track = StartSource();
156 // When the track goes out of scope, the source will be stopped.
157 EXPECT_CALL(mock_delegate(), StopCapture());
160 TEST_F(MediaStreamVideoCapturerSourceTest,
161 DesktopCaptureAllowAnyResolutionChangeByDefault) {
162 StreamDeviceInfo device_info;
163 device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
164 InitWithDeviceInfo(device_info);
166 // No constraints are being provided to the implementation, so expect only
167 // default values.
168 media::VideoCaptureParams expected_params;
169 expected_params.requested_format.frame_size.SetSize(
170 MediaStreamVideoSource::kDefaultWidth,
171 MediaStreamVideoSource::kDefaultHeight);
172 expected_params.requested_format.frame_rate =
173 MediaStreamVideoSource::kDefaultFrameRate;
174 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
175 expected_params.resolution_change_policy =
176 media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
178 InSequence s;
179 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
180 EXPECT_CALL(mock_delegate(), StartCapture(expected_params, _, _));
181 blink::WebMediaStreamTrack track = StartSource();
182 // When the track goes out of scope, the source will be stopped.
183 EXPECT_CALL(mock_delegate(), StopCapture());
186 TEST_F(MediaStreamVideoCapturerSourceTest,
187 TabCaptureConstraintsImplyFixedAspectRatio) {
188 StreamDeviceInfo device_info;
189 device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
190 InitWithDeviceInfo(device_info);
192 // Specify max and min size constraints that have the same ~16:9 aspect ratio.
193 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxWidth, 1920);
194 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxHeight, 1080);
195 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinWidth, 854);
196 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
197 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxFrameRate,
198 60.0);
200 media::VideoCaptureParams expected_params;
201 expected_params.requested_format.frame_size.SetSize(1920, 1080);
202 expected_params.requested_format.frame_rate = 60.0;
203 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
204 expected_params.resolution_change_policy =
205 media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO;
207 InSequence s;
208 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
209 EXPECT_CALL(
210 mock_delegate(),
211 StartCapture(
212 testing::Field(&media::VideoCaptureParams::resolution_change_policy,
213 media::RESOLUTION_POLICY_FIXED_ASPECT_RATIO),
214 _, _))
216 blink::WebMediaStreamTrack track = StartSource();
217 // When the track goes out of scope, the source will be stopped.
218 EXPECT_CALL(mock_delegate(), StopCapture());
221 TEST_F(MediaStreamVideoCapturerSourceTest,
222 TabCaptureConstraintsImplyAllowingAnyResolutionChange) {
223 StreamDeviceInfo device_info;
224 device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
225 InitWithDeviceInfo(device_info);
227 // Specify max and min size constraints with different aspect ratios.
228 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxWidth, 1920);
229 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxHeight, 1080);
230 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinWidth, 0);
231 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMinHeight, 0);
232 constraint_factory()->AddMandatory(MediaStreamVideoSource::kMaxFrameRate,
233 60.0);
235 media::VideoCaptureParams expected_params;
236 expected_params.requested_format.frame_size.SetSize(1920, 1080);
237 expected_params.requested_format.frame_rate = 60.0;
238 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
239 expected_params.resolution_change_policy =
240 media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT;
242 InSequence s;
243 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
244 EXPECT_CALL(
245 mock_delegate(),
246 StartCapture(
247 testing::Field(&media::VideoCaptureParams::resolution_change_policy,
248 media::RESOLUTION_POLICY_ANY_WITHIN_LIMIT),
249 _, _))
251 blink::WebMediaStreamTrack track = StartSource();
252 // When the track goes out of scope, the source will be stopped.
253 EXPECT_CALL(mock_delegate(), StopCapture());
256 TEST_F(MediaStreamVideoCapturerSourceTest,
257 DeviceCaptureConstraintsSupportPowerLineFrequency) {
258 for (int frequency = -100; frequency < 100; ++frequency) {
259 StreamDeviceInfo device_info;
260 device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
261 InitWithDeviceInfo(device_info);
262 constraint_factory_ = MockMediaConstraintFactory();
264 constraint_factory()->AddOptional(GetPowerLineFrequencyForTesting(),
265 frequency);
267 media::VideoCaptureParams expected_params;
268 expected_params.requested_format.frame_size.SetSize(
269 MediaStreamVideoSource::kDefaultWidth,
270 MediaStreamVideoSource::kDefaultHeight);
271 expected_params.requested_format.frame_rate =
272 MediaStreamVideoSource::kDefaultFrameRate;
273 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
274 expected_params.resolution_change_policy =
275 media::RESOLUTION_POLICY_FIXED_RESOLUTION;
276 if (frequency == 50) {
277 expected_params.power_line_frequency =
278 media::PowerLineFrequency::FREQUENCY_50HZ;
279 } else if (frequency == 60) {
280 expected_params.power_line_frequency =
281 media::PowerLineFrequency::FREQUENCY_60HZ;
282 } else {
283 expected_params.power_line_frequency =
284 media::PowerLineFrequency::FREQUENCY_DEFAULT;
287 InSequence s;
288 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
289 EXPECT_CALL(mock_delegate(), StartCapture(expected_params, _, _));
290 blink::WebMediaStreamTrack track = StartSource();
291 // When the track goes out of scope, the source will be stopped.
292 EXPECT_CALL(mock_delegate(), StopCapture());
296 TEST_F(MediaStreamVideoCapturerSourceTest,
297 InvalidPowerLineFrequencyHandledProperly) {
298 // Test out other varieties of invalid input, like non-numeric strings.
299 StreamDeviceInfo device_info;
300 device_info.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
301 InitWithDeviceInfo(device_info);
302 constraint_factory_ = MockMediaConstraintFactory();
304 constraint_factory()->AddOptional(GetPowerLineFrequencyForTesting(),
305 std::string("this is not a frequency"));
307 media::VideoCaptureParams expected_params;
308 expected_params.requested_format.frame_size.SetSize(
309 MediaStreamVideoSource::kDefaultWidth,
310 MediaStreamVideoSource::kDefaultHeight);
311 expected_params.requested_format.frame_rate =
312 MediaStreamVideoSource::kDefaultFrameRate;
313 expected_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
314 expected_params.resolution_change_policy =
315 media::RESOLUTION_POLICY_FIXED_RESOLUTION;
316 // Invalid frequencies should result in default setting.
317 expected_params.power_line_frequency =
318 media::PowerLineFrequency::FREQUENCY_DEFAULT;
320 InSequence s;
321 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
322 EXPECT_CALL(mock_delegate(), StartCapture(expected_params, _, _));
323 blink::WebMediaStreamTrack track = StartSource();
324 // When the track goes out of scope, the source will be stopped.
325 EXPECT_CALL(mock_delegate(), StopCapture());
328 TEST_F(MediaStreamVideoCapturerSourceTest, Ended) {
329 scoped_ptr<MockVideoCapturerSource> delegate(new MockVideoCapturerSource());
330 delegate_ = delegate.get();
331 source_ = new MediaStreamVideoCapturerSource(
332 base::Bind(&MediaStreamVideoCapturerSourceTest::OnSourceStopped,
333 base::Unretained(this)),
334 delegate.Pass());
335 webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
336 blink::WebMediaStreamSource::TypeVideo,
337 base::UTF8ToUTF16("dummy_source_name"),
338 false /* remote */, true /* readonly */);
339 webkit_source_.setExtraData(source_);
340 webkit_source_id_ = webkit_source_.id();
342 InSequence s;
343 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
344 EXPECT_CALL(mock_delegate(), StartCapture(_, _, _));
345 blink::WebMediaStreamTrack track = StartSource();
346 message_loop_.RunUntilIdle();
348 OnStarted(true);
349 message_loop_.RunUntilIdle();
350 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
351 webkit_source_.readyState());
353 EXPECT_FALSE(source_stopped_);
355 EXPECT_CALL(mock_delegate(), StopCapture());
356 OnStarted(false);
357 message_loop_.RunUntilIdle();
358 EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded,
359 webkit_source_.readyState());
360 // Verify that MediaStreamSource::SourceStoppedCallback has been triggered.
361 EXPECT_TRUE(source_stopped_);
364 class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
365 public:
366 FakeMediaStreamVideoSink(base::TimeTicks* capture_time,
367 media::VideoFrameMetadata* metadata,
368 base::Closure got_frame_cb)
369 : capture_time_(capture_time),
370 metadata_(metadata),
371 got_frame_cb_(got_frame_cb) {}
373 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& frame,
374 base::TimeTicks capture_time) {
375 *capture_time_ = capture_time;
376 metadata_->Clear();
377 base::DictionaryValue tmp;
378 frame->metadata()->MergeInternalValuesInto(&tmp);
379 metadata_->MergeInternalValuesFrom(tmp);
380 base::ResetAndReturn(&got_frame_cb_).Run();
383 private:
384 base::TimeTicks* const capture_time_;
385 media::VideoFrameMetadata* const metadata_;
386 base::Closure got_frame_cb_;
389 TEST_F(MediaStreamVideoCapturerSourceTest, CaptureTimeAndMetadataPlumbing) {
390 StreamDeviceInfo device_info;
391 device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
392 InitWithDeviceInfo(device_info);
394 VideoCaptureDeliverFrameCB deliver_frame_cb;
395 media::VideoCapturerSource::RunningCallback running_cb;
397 InSequence s;
398 EXPECT_CALL(mock_delegate(), GetCurrentSupportedFormats(_, _, _, _));
399 EXPECT_CALL(mock_delegate(), StartCapture(_, _, _))
400 .WillOnce(testing::DoAll(testing::SaveArg<1>(&deliver_frame_cb),
401 testing::SaveArg<2>(&running_cb)));
402 EXPECT_CALL(mock_delegate(), StopCapture());
403 blink::WebMediaStreamTrack track = StartSource();
404 running_cb.Run(true);
406 base::RunLoop run_loop;
407 base::TimeTicks reference_capture_time =
408 base::TimeTicks::FromInternalValue(60013);
409 base::TimeTicks capture_time;
410 media::VideoFrameMetadata metadata;
411 FakeMediaStreamVideoSink fake_sink(
412 &capture_time, &metadata,
413 media::BindToCurrentLoop(run_loop.QuitClosure()));
414 FakeMediaStreamVideoSink::AddToVideoTrack(
415 &fake_sink, base::Bind(&FakeMediaStreamVideoSink::OnVideoFrame,
416 base::Unretained(&fake_sink)),
417 track);
418 const scoped_refptr<media::VideoFrame> frame =
419 media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2));
420 frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30.0);
421 child_process_->io_task_runner()->PostTask(
422 FROM_HERE, base::Bind(deliver_frame_cb, frame, reference_capture_time));
423 run_loop.Run();
424 FakeMediaStreamVideoSink::RemoveFromVideoTrack(&fake_sink, track);
425 EXPECT_EQ(reference_capture_time, capture_time);
426 double metadata_value;
427 EXPECT_TRUE(metadata.GetDouble(media::VideoFrameMetadata::FRAME_RATE,
428 &metadata_value));
429 EXPECT_EQ(30.0, metadata_value);
432 } // namespace content