OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <memory> | |
12 #include <string> | |
13 #include <vector> | |
14 | |
15 #include "webrtc/api/test/fakeconstraints.h" | |
16 #include "webrtc/api/videocapturertracksource.h" | |
17 #include "webrtc/base/gunit.h" | |
18 #include "webrtc/media/base/fakemediaengine.h" | |
19 #include "webrtc/media/base/fakevideocapturer.h" | |
20 #include "webrtc/media/base/fakevideorenderer.h" | |
21 | |
22 using webrtc::FakeConstraints; | |
23 using webrtc::VideoCapturerTrackSource; | |
24 using webrtc::MediaConstraintsInterface; | |
25 using webrtc::MediaSourceInterface; | |
26 using webrtc::ObserverInterface; | |
27 using webrtc::VideoTrackSourceInterface; | |
28 | |
29 namespace { | |
30 | |
31 // Max wait time for a test. | |
32 const int kMaxWaitMs = 100; | |
33 | |
34 } // anonymous namespace | |
35 | |
36 // TestVideoCapturer extends cricket::FakeVideoCapturer so it can be used for | |
37 // testing without known camera formats. | |
38 // It keeps its own lists of cricket::VideoFormats for the unit tests in this | |
39 // file. | |
40 class TestVideoCapturer : public cricket::FakeVideoCapturer { | |
41 public: | |
42 explicit TestVideoCapturer(bool is_screencast) | |
43 : FakeVideoCapturer(is_screencast), test_without_formats_(false) { | |
44 std::vector<cricket::VideoFormat> formats; | |
45 formats.push_back( | |
46 cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), | |
47 cricket::FOURCC_I420)); | |
48 formats.push_back( | |
49 cricket::VideoFormat(640, 480, cricket::VideoFormat::FpsToInterval(30), | |
50 cricket::FOURCC_I420)); | |
51 formats.push_back( | |
52 cricket::VideoFormat(640, 400, cricket::VideoFormat::FpsToInterval(30), | |
53 cricket::FOURCC_I420)); | |
54 formats.push_back( | |
55 cricket::VideoFormat(320, 240, cricket::VideoFormat::FpsToInterval(30), | |
56 cricket::FOURCC_I420)); | |
57 formats.push_back( | |
58 cricket::VideoFormat(352, 288, cricket::VideoFormat::FpsToInterval(30), | |
59 cricket::FOURCC_I420)); | |
60 ResetSupportedFormats(formats); | |
61 } | |
62 | |
63 // This function is used for resetting the supported capture formats and | |
64 // simulating a cricket::VideoCapturer implementation that don't support | |
65 // capture format enumeration. This is used to simulate the current | |
66 // Chrome implementation. | |
67 void TestWithoutCameraFormats() { | |
68 test_without_formats_ = true; | |
69 std::vector<cricket::VideoFormat> formats; | |
70 ResetSupportedFormats(formats); | |
71 } | |
72 | |
73 virtual cricket::CaptureState Start( | |
74 const cricket::VideoFormat& capture_format) { | |
75 if (test_without_formats_) { | |
76 std::vector<cricket::VideoFormat> formats; | |
77 formats.push_back(capture_format); | |
78 ResetSupportedFormats(formats); | |
79 } | |
80 return FakeVideoCapturer::Start(capture_format); | |
81 } | |
82 | |
83 virtual bool GetBestCaptureFormat(const cricket::VideoFormat& desired, | |
84 cricket::VideoFormat* best_format) { | |
85 if (test_without_formats_) { | |
86 *best_format = desired; | |
87 return true; | |
88 } | |
89 return FakeVideoCapturer::GetBestCaptureFormat(desired, best_format); | |
90 } | |
91 | |
92 private: | |
93 bool test_without_formats_; | |
94 }; | |
95 | |
96 class StateObserver : public ObserverInterface { | |
97 public: | |
98 explicit StateObserver(VideoTrackSourceInterface* source) | |
99 : state_(source->state()), source_(source) {} | |
100 virtual void OnChanged() { state_ = source_->state(); } | |
101 MediaSourceInterface::SourceState state() const { return state_; } | |
102 | |
103 private: | |
104 MediaSourceInterface::SourceState state_; | |
105 rtc::scoped_refptr<VideoTrackSourceInterface> source_; | |
106 }; | |
107 | |
108 class VideoCapturerTrackSourceTest : public testing::Test { | |
109 protected: | |
110 VideoCapturerTrackSourceTest() { InitCapturer(false); } | |
111 void InitCapturer(bool is_screencast) { | |
112 capturer_cleanup_ = std::unique_ptr<TestVideoCapturer>( | |
113 new TestVideoCapturer(is_screencast)); | |
114 capturer_ = capturer_cleanup_.get(); | |
115 } | |
116 | |
117 void InitScreencast() { InitCapturer(true); } | |
118 | |
119 void CreateVideoCapturerSource() { CreateVideoCapturerSource(NULL); } | |
120 | |
121 void CreateVideoCapturerSource( | |
122 const webrtc::MediaConstraintsInterface* constraints) { | |
123 // VideoSource take ownership of |capturer_| | |
124 source_ = VideoCapturerTrackSource::Create(rtc::Thread::Current(), | |
125 capturer_cleanup_.release(), | |
126 constraints, false); | |
127 | |
128 ASSERT_TRUE(source_.get() != NULL); | |
129 | |
130 state_observer_.reset(new StateObserver(source_)); | |
131 source_->RegisterObserver(state_observer_.get()); | |
132 source_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants()); | |
133 } | |
134 | |
135 std::unique_ptr<TestVideoCapturer> capturer_cleanup_; | |
136 TestVideoCapturer* capturer_; | |
137 cricket::FakeVideoRenderer renderer_; | |
138 std::unique_ptr<StateObserver> state_observer_; | |
139 rtc::scoped_refptr<VideoTrackSourceInterface> source_; | |
140 }; | |
141 | |
142 // Test that a VideoSource transition to kLive state when the capture | |
143 // device have started and kEnded if it is stopped. | |
144 // It also test that an output can receive video frames. | |
145 TEST_F(VideoCapturerTrackSourceTest, CapturerStartStop) { | |
146 // Initialize without constraints. | |
147 CreateVideoCapturerSource(); | |
148 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
149 kMaxWaitMs); | |
150 | |
151 ASSERT_TRUE(capturer_->CaptureFrame()); | |
152 EXPECT_EQ(1, renderer_.num_rendered_frames()); | |
153 | |
154 capturer_->Stop(); | |
155 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
156 kMaxWaitMs); | |
157 } | |
158 | |
159 // Test that a VideoSource transition to kEnded if the capture device | |
160 // fails. | |
161 TEST_F(VideoCapturerTrackSourceTest, CameraFailed) { | |
162 CreateVideoCapturerSource(); | |
163 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
164 kMaxWaitMs); | |
165 | |
166 capturer_->SignalStateChange(capturer_, cricket::CS_FAILED); | |
167 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
168 kMaxWaitMs); | |
169 } | |
170 | |
171 // Test that the capture output is CIF if we set max constraints to CIF. | |
172 // and the capture device support CIF. | |
173 TEST_F(VideoCapturerTrackSourceTest, MandatoryConstraintCif5Fps) { | |
174 FakeConstraints constraints; | |
175 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352); | |
176 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288); | |
177 constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 5); | |
178 | |
179 CreateVideoCapturerSource(&constraints); | |
180 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
181 kMaxWaitMs); | |
182 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
183 ASSERT_TRUE(format != NULL); | |
184 EXPECT_EQ(352, format->width); | |
185 EXPECT_EQ(288, format->height); | |
186 EXPECT_EQ(5, format->framerate()); | |
187 } | |
188 | |
189 // Test that the capture output is 720P if the camera support it and the | |
190 // optional constraint is set to 720P. | |
191 TEST_F(VideoCapturerTrackSourceTest, MandatoryMinVgaOptional720P) { | |
192 FakeConstraints constraints; | |
193 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640); | |
194 constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480); | |
195 constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280); | |
196 constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio, | |
197 1280.0 / 720); | |
198 | |
199 CreateVideoCapturerSource(&constraints); | |
200 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
201 kMaxWaitMs); | |
202 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
203 ASSERT_TRUE(format != NULL); | |
204 EXPECT_EQ(1280, format->width); | |
205 EXPECT_EQ(720, format->height); | |
206 EXPECT_EQ(30, format->framerate()); | |
207 } | |
208 | |
209 // Test that the capture output have aspect ratio 4:3 if a mandatory constraint | |
210 // require it even if an optional constraint request a higher resolution | |
211 // that don't have this aspect ratio. | |
212 TEST_F(VideoCapturerTrackSourceTest, MandatoryAspectRatio4To3) { | |
213 FakeConstraints constraints; | |
214 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640); | |
215 constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480); | |
216 constraints.AddMandatory(MediaConstraintsInterface::kMaxAspectRatio, | |
217 640.0 / 480); | |
218 constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280); | |
219 | |
220 CreateVideoCapturerSource(&constraints); | |
221 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
222 kMaxWaitMs); | |
223 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
224 ASSERT_TRUE(format != NULL); | |
225 EXPECT_EQ(640, format->width); | |
226 EXPECT_EQ(480, format->height); | |
227 EXPECT_EQ(30, format->framerate()); | |
228 } | |
229 | |
230 // Test that the source state transition to kEnded if the mandatory aspect ratio | |
231 // is set higher than supported. | |
232 TEST_F(VideoCapturerTrackSourceTest, MandatoryAspectRatioTooHigh) { | |
233 FakeConstraints constraints; | |
234 constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio, 2); | |
235 CreateVideoCapturerSource(&constraints); | |
236 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
237 kMaxWaitMs); | |
238 } | |
239 | |
240 // Test that the source ignores an optional aspect ratio that is higher than | |
241 // supported. | |
242 TEST_F(VideoCapturerTrackSourceTest, OptionalAspectRatioTooHigh) { | |
243 FakeConstraints constraints; | |
244 constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio, 2); | |
245 CreateVideoCapturerSource(&constraints); | |
246 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
247 kMaxWaitMs); | |
248 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
249 ASSERT_TRUE(format != NULL); | |
250 double aspect_ratio = static_cast<double>(format->width) / format->height; | |
251 EXPECT_LT(aspect_ratio, 2); | |
252 } | |
253 | |
254 // Test that the source starts video with the default resolution if the | |
255 // camera doesn't support capability enumeration and there are no constraints. | |
256 TEST_F(VideoCapturerTrackSourceTest, NoCameraCapability) { | |
257 capturer_->TestWithoutCameraFormats(); | |
258 | |
259 CreateVideoCapturerSource(); | |
260 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
261 kMaxWaitMs); | |
262 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
263 ASSERT_TRUE(format != NULL); | |
264 EXPECT_EQ(640, format->width); | |
265 EXPECT_EQ(480, format->height); | |
266 EXPECT_EQ(30, format->framerate()); | |
267 } | |
268 | |
269 // Test that the source can start the video and get the requested aspect ratio | |
270 // if the camera doesn't support capability enumeration and the aspect ratio is | |
271 // set. | |
272 TEST_F(VideoCapturerTrackSourceTest, NoCameraCapability16To9Ratio) { | |
273 capturer_->TestWithoutCameraFormats(); | |
274 | |
275 FakeConstraints constraints; | |
276 double requested_aspect_ratio = 640.0 / 360; | |
277 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640); | |
278 constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio, | |
279 requested_aspect_ratio); | |
280 | |
281 CreateVideoCapturerSource(&constraints); | |
282 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
283 kMaxWaitMs); | |
284 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
285 double aspect_ratio = static_cast<double>(format->width) / format->height; | |
286 EXPECT_LE(requested_aspect_ratio, aspect_ratio); | |
287 } | |
288 | |
289 // Test that the source state transitions to kEnded if an unknown mandatory | |
290 // constraint is found. | |
291 TEST_F(VideoCapturerTrackSourceTest, InvalidMandatoryConstraint) { | |
292 FakeConstraints constraints; | |
293 constraints.AddMandatory("weird key", 640); | |
294 | |
295 CreateVideoCapturerSource(&constraints); | |
296 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
297 kMaxWaitMs); | |
298 } | |
299 | |
300 // Test that the source ignores an unknown optional constraint. | |
301 TEST_F(VideoCapturerTrackSourceTest, InvalidOptionalConstraint) { | |
302 FakeConstraints constraints; | |
303 constraints.AddOptional("weird key", 640); | |
304 | |
305 CreateVideoCapturerSource(&constraints); | |
306 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
307 kMaxWaitMs); | |
308 } | |
309 | |
310 TEST_F(VideoCapturerTrackSourceTest, SetValidDenoisingConstraint) { | |
311 FakeConstraints constraints; | |
312 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, "false"); | |
313 | |
314 CreateVideoCapturerSource(&constraints); | |
315 | |
316 EXPECT_EQ(rtc::Optional<bool>(false), source_->needs_denoising()); | |
317 } | |
318 | |
319 TEST_F(VideoCapturerTrackSourceTest, NoiseReductionConstraintNotSet) { | |
320 FakeConstraints constraints; | |
321 CreateVideoCapturerSource(&constraints); | |
322 EXPECT_EQ(rtc::Optional<bool>(), source_->needs_denoising()); | |
323 } | |
324 | |
325 TEST_F(VideoCapturerTrackSourceTest, | |
326 MandatoryDenoisingConstraintOverridesOptional) { | |
327 FakeConstraints constraints; | |
328 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, false); | |
329 constraints.AddOptional(MediaConstraintsInterface::kNoiseReduction, true); | |
330 | |
331 CreateVideoCapturerSource(&constraints); | |
332 | |
333 EXPECT_EQ(rtc::Optional<bool>(false), source_->needs_denoising()); | |
334 } | |
335 | |
336 TEST_F(VideoCapturerTrackSourceTest, NoiseReductionAndInvalidKeyOptional) { | |
337 FakeConstraints constraints; | |
338 constraints.AddOptional(MediaConstraintsInterface::kNoiseReduction, true); | |
339 constraints.AddOptional("invalidKey", false); | |
340 | |
341 CreateVideoCapturerSource(&constraints); | |
342 | |
343 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
344 kMaxWaitMs); | |
345 EXPECT_EQ(rtc::Optional<bool>(true), source_->needs_denoising()); | |
346 } | |
347 | |
348 TEST_F(VideoCapturerTrackSourceTest, NoiseReductionAndInvalidKeyMandatory) { | |
349 FakeConstraints constraints; | |
350 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, false); | |
351 constraints.AddMandatory("invalidKey", false); | |
352 | |
353 CreateVideoCapturerSource(&constraints); | |
354 | |
355 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
356 kMaxWaitMs); | |
357 EXPECT_EQ(rtc::Optional<bool>(), source_->needs_denoising()); | |
358 } | |
359 | |
360 TEST_F(VideoCapturerTrackSourceTest, InvalidDenoisingValueOptional) { | |
361 FakeConstraints constraints; | |
362 constraints.AddOptional(MediaConstraintsInterface::kNoiseReduction, | |
363 "not a boolean"); | |
364 | |
365 CreateVideoCapturerSource(&constraints); | |
366 | |
367 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
368 kMaxWaitMs); | |
369 | |
370 EXPECT_EQ(rtc::Optional<bool>(), source_->needs_denoising()); | |
371 } | |
372 | |
373 TEST_F(VideoCapturerTrackSourceTest, InvalidDenoisingValueMandatory) { | |
374 FakeConstraints constraints; | |
375 // Optional constraints should be ignored if the mandatory constraints fail. | |
376 constraints.AddOptional(MediaConstraintsInterface::kNoiseReduction, "false"); | |
377 // Values are case-sensitive and must be all lower-case. | |
378 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, "True"); | |
379 | |
380 CreateVideoCapturerSource(&constraints); | |
381 | |
382 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
383 kMaxWaitMs); | |
384 EXPECT_EQ(rtc::Optional<bool>(), source_->needs_denoising()); | |
385 } | |
386 | |
387 TEST_F(VideoCapturerTrackSourceTest, MixedOptionsAndConstraints) { | |
388 FakeConstraints constraints; | |
389 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352); | |
390 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288); | |
391 constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 5); | |
392 | |
393 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, false); | |
394 constraints.AddOptional(MediaConstraintsInterface::kNoiseReduction, true); | |
395 | |
396 CreateVideoCapturerSource(&constraints); | |
397 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
398 kMaxWaitMs); | |
399 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
400 ASSERT_TRUE(format != NULL); | |
401 EXPECT_EQ(352, format->width); | |
402 EXPECT_EQ(288, format->height); | |
403 EXPECT_EQ(5, format->framerate()); | |
404 | |
405 EXPECT_EQ(rtc::Optional<bool>(false), source_->needs_denoising()); | |
406 } | |
407 | |
408 // Tests that the source starts video with the default resolution for | |
409 // screencast if no constraint is set. | |
410 TEST_F(VideoCapturerTrackSourceTest, ScreencastResolutionNoConstraint) { | |
411 InitScreencast(); | |
412 capturer_->TestWithoutCameraFormats(); | |
413 | |
414 CreateVideoCapturerSource(); | |
415 ASSERT_TRUE(source_->is_screencast()); | |
416 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
417 kMaxWaitMs); | |
418 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
419 ASSERT_TRUE(format != NULL); | |
420 EXPECT_EQ(640, format->width); | |
421 EXPECT_EQ(480, format->height); | |
422 EXPECT_EQ(30, format->framerate()); | |
423 } | |
424 | |
425 // Tests that the source starts video with the max width and height set by | |
426 // constraints for screencast. | |
427 TEST_F(VideoCapturerTrackSourceTest, ScreencastResolutionWithConstraint) { | |
428 FakeConstraints constraints; | |
429 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 480); | |
430 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 270); | |
431 | |
432 InitScreencast(); | |
433 capturer_->TestWithoutCameraFormats(); | |
434 | |
435 CreateVideoCapturerSource(&constraints); | |
436 ASSERT_TRUE(source_->is_screencast()); | |
437 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
438 kMaxWaitMs); | |
439 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
440 ASSERT_TRUE(format != NULL); | |
441 EXPECT_EQ(480, format->width); | |
442 EXPECT_EQ(270, format->height); | |
443 EXPECT_EQ(30, format->framerate()); | |
444 } | |
445 | |
446 TEST_F(VideoCapturerTrackSourceTest, MandatorySubOneFpsConstraints) { | |
447 FakeConstraints constraints; | |
448 constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 0.5); | |
449 | |
450 CreateVideoCapturerSource(&constraints); | |
451 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(), | |
452 kMaxWaitMs); | |
453 ASSERT_TRUE(capturer_->GetCaptureFormat() == NULL); | |
454 } | |
455 | |
456 TEST_F(VideoCapturerTrackSourceTest, OptionalSubOneFpsConstraints) { | |
457 FakeConstraints constraints; | |
458 constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 0.5); | |
459 | |
460 CreateVideoCapturerSource(&constraints); | |
461 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(), | |
462 kMaxWaitMs); | |
463 const cricket::VideoFormat* format = capturer_->GetCaptureFormat(); | |
464 ASSERT_TRUE(format != NULL); | |
465 EXPECT_EQ(1, format->framerate()); | |
466 } | |
OLD | NEW |