3 * Copyright 2012, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "talk/app/webrtc/remotevideocapturer.h"
32 #include "talk/app/webrtc/test/fakeconstraints.h"
33 #include "talk/app/webrtc/videosource.h"
34 #include "talk/media/base/fakemediaengine.h"
35 #include "talk/media/base/fakevideorenderer.h"
36 #include "talk/media/devices/fakedevicemanager.h"
37 #include "talk/media/webrtc/webrtcvideoframe.h"
38 #include "talk/session/media/channelmanager.h"
39 #include "webrtc/base/gunit.h"
41 using webrtc::FakeConstraints;
42 using webrtc::VideoSource;
43 using webrtc::MediaConstraintsInterface;
44 using webrtc::MediaSourceInterface;
45 using webrtc::ObserverInterface;
46 using webrtc::VideoSourceInterface;
50 // Max wait time for a test.
51 const int kMaxWaitMs = 100;
53 } // anonymous namespace
56 // TestVideoCapturer extends cricket::FakeVideoCapturer so it can be used for
57 // testing without known camera formats.
58 // It keeps its own lists of cricket::VideoFormats for the unit tests in this
60 class TestVideoCapturer : public cricket::FakeVideoCapturer {
62 TestVideoCapturer() : test_without_formats_(false) {
63 std::vector<cricket::VideoFormat> formats;
64 formats.push_back(cricket::VideoFormat(1280, 720,
65 cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
66 formats.push_back(cricket::VideoFormat(640, 480,
67 cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
68 formats.push_back(cricket::VideoFormat(640, 400,
69 cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
70 formats.push_back(cricket::VideoFormat(320, 240,
71 cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
72 formats.push_back(cricket::VideoFormat(352, 288,
73 cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
74 ResetSupportedFormats(formats);
77 // This function is used for resetting the supported capture formats and
78 // simulating a cricket::VideoCapturer implementation that don't support
79 // capture format enumeration. This is used to simulate the current
80 // Chrome implementation.
81 void TestWithoutCameraFormats() {
82 test_without_formats_ = true;
83 std::vector<cricket::VideoFormat> formats;
84 ResetSupportedFormats(formats);
87 virtual cricket::CaptureState Start(
88 const cricket::VideoFormat& capture_format) {
89 if (test_without_formats_) {
90 std::vector<cricket::VideoFormat> formats;
91 formats.push_back(capture_format);
92 ResetSupportedFormats(formats);
94 return FakeVideoCapturer::Start(capture_format);
97 virtual bool GetBestCaptureFormat(const cricket::VideoFormat& desired,
98 cricket::VideoFormat* best_format) {
99 if (test_without_formats_) {
100 *best_format = desired;
103 return FakeVideoCapturer::GetBestCaptureFormat(desired,
108 bool test_without_formats_;
111 class StateObserver : public ObserverInterface {
113 explicit StateObserver(VideoSourceInterface* source)
114 : state_(source->state()),
117 virtual void OnChanged() {
118 state_ = source_->state();
120 MediaSourceInterface::SourceState state() const { return state_; }
123 MediaSourceInterface::SourceState state_;
124 rtc::scoped_refptr<VideoSourceInterface> source_;
127 class VideoSourceTest : public testing::Test {
130 : capturer_cleanup_(new TestVideoCapturer()),
131 capturer_(capturer_cleanup_.get()),
132 channel_manager_(new cricket::ChannelManager(
133 new cricket::FakeMediaEngine(),
134 new cricket::FakeDeviceManager(), rtc::Thread::Current())) {
138 ASSERT_TRUE(channel_manager_->Init());
141 void CreateVideoSource() {
142 CreateVideoSource(NULL);
145 void CreateVideoSource(
146 const webrtc::MediaConstraintsInterface* constraints) {
147 // VideoSource take ownership of |capturer_|
148 source_ = VideoSource::Create(channel_manager_.get(),
149 capturer_cleanup_.release(),
152 ASSERT_TRUE(source_.get() != NULL);
153 EXPECT_EQ(capturer_, source_->GetVideoCapturer());
155 state_observer_.reset(new StateObserver(source_));
156 source_->RegisterObserver(state_observer_.get());
157 source_->AddSink(&renderer_);
160 rtc::scoped_ptr<TestVideoCapturer> capturer_cleanup_;
161 TestVideoCapturer* capturer_;
162 cricket::FakeVideoRenderer renderer_;
163 rtc::scoped_ptr<cricket::ChannelManager> channel_manager_;
164 rtc::scoped_ptr<StateObserver> state_observer_;
165 rtc::scoped_refptr<VideoSource> source_;
169 // Test that a VideoSource transition to kLive state when the capture
170 // device have started and kEnded if it is stopped.
171 // It also test that an output can receive video frames.
172 TEST_F(VideoSourceTest, StartStop) {
173 // Initialize without constraints.
175 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
178 ASSERT_TRUE(capturer_->CaptureFrame());
179 EXPECT_EQ(1, renderer_.num_rendered_frames());
182 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
186 // Test start stop with a remote VideoSource - the video source that has a
187 // RemoteVideoCapturer and takes video frames from FrameInput.
188 TEST_F(VideoSourceTest, StartStopRemote) {
189 source_ = VideoSource::Create(channel_manager_.get(),
190 new webrtc::RemoteVideoCapturer(),
193 ASSERT_TRUE(source_.get() != NULL);
194 EXPECT_TRUE(NULL != source_->GetVideoCapturer());
196 state_observer_.reset(new StateObserver(source_));
197 source_->RegisterObserver(state_observer_.get());
198 source_->AddSink(&renderer_);
200 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
203 cricket::VideoRenderer* frameinput = source_->FrameInput();
204 cricket::WebRtcVideoFrame test_frame;
205 frameinput->SetSize(1280, 720, 0);
206 frameinput->RenderFrame(&test_frame);
207 EXPECT_EQ(1, renderer_.num_rendered_frames());
209 source_->GetVideoCapturer()->Stop();
210 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
214 // Test that a VideoSource transition to kEnded if the capture device
216 TEST_F(VideoSourceTest, CameraFailed) {
218 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
221 capturer_->SignalStateChange(capturer_, cricket::CS_FAILED);
222 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
226 // Test that the capture output is CIF if we set max constraints to CIF.
227 // and the capture device support CIF.
228 TEST_F(VideoSourceTest, MandatoryConstraintCif5Fps) {
229 FakeConstraints constraints;
230 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352);
231 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288);
232 constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 5);
234 CreateVideoSource(&constraints);
235 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
237 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
238 ASSERT_TRUE(format != NULL);
239 EXPECT_EQ(352, format->width);
240 EXPECT_EQ(288, format->height);
241 EXPECT_EQ(30, format->framerate());
244 // Test that the capture output is 720P if the camera support it and the
245 // optional constraint is set to 720P.
246 TEST_F(VideoSourceTest, MandatoryMinVgaOptional720P) {
247 FakeConstraints constraints;
248 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
249 constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480);
250 constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280);
251 constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio,
254 CreateVideoSource(&constraints);
255 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
257 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
258 ASSERT_TRUE(format != NULL);
259 EXPECT_EQ(1280, format->width);
260 EXPECT_EQ(720, format->height);
261 EXPECT_EQ(30, format->framerate());
264 // Test that the capture output have aspect ratio 4:3 if a mandatory constraint
265 // require it even if an optional constraint request a higher resolution
266 // that don't have this aspect ratio.
267 TEST_F(VideoSourceTest, MandatoryAspectRatio4To3) {
268 FakeConstraints constraints;
269 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
270 constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480);
271 constraints.AddMandatory(MediaConstraintsInterface::kMaxAspectRatio,
273 constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280);
275 CreateVideoSource(&constraints);
276 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
278 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
279 ASSERT_TRUE(format != NULL);
280 EXPECT_EQ(640, format->width);
281 EXPECT_EQ(480, format->height);
282 EXPECT_EQ(30, format->framerate());
286 // Test that the source state transition to kEnded if the mandatory aspect ratio
287 // is set higher than supported.
288 TEST_F(VideoSourceTest, MandatoryAspectRatioTooHigh) {
289 FakeConstraints constraints;
290 constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio, 2);
291 CreateVideoSource(&constraints);
292 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
296 // Test that the source ignores an optional aspect ratio that is higher than
298 TEST_F(VideoSourceTest, OptionalAspectRatioTooHigh) {
299 FakeConstraints constraints;
300 constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio, 2);
301 CreateVideoSource(&constraints);
302 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
304 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
305 ASSERT_TRUE(format != NULL);
306 double aspect_ratio = static_cast<double>(format->width) / format->height;
307 EXPECT_LT(aspect_ratio, 2);
310 // Test that the source starts video with the default resolution if the
311 // camera doesn't support capability enumeration and there are no constraints.
312 TEST_F(VideoSourceTest, NoCameraCapability) {
313 capturer_->TestWithoutCameraFormats();
316 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
318 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
319 ASSERT_TRUE(format != NULL);
320 EXPECT_EQ(640, format->width);
321 EXPECT_EQ(480, format->height);
322 EXPECT_EQ(30, format->framerate());
325 // Test that the source can start the video and get the requested aspect ratio
326 // if the camera doesn't support capability enumeration and the aspect ratio is
328 TEST_F(VideoSourceTest, NoCameraCapability16To9Ratio) {
329 capturer_->TestWithoutCameraFormats();
331 FakeConstraints constraints;
332 double requested_aspect_ratio = 640.0 / 360;
333 constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
334 constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio,
335 requested_aspect_ratio);
337 CreateVideoSource(&constraints);
338 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
340 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
341 double aspect_ratio = static_cast<double>(format->width) / format->height;
342 EXPECT_LE(requested_aspect_ratio, aspect_ratio);
345 // Test that the source state transitions to kEnded if an unknown mandatory
346 // constraint is found.
347 TEST_F(VideoSourceTest, InvalidMandatoryConstraint) {
348 FakeConstraints constraints;
349 constraints.AddMandatory("weird key", 640);
351 CreateVideoSource(&constraints);
352 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
356 // Test that the source ignores an unknown optional constraint.
357 TEST_F(VideoSourceTest, InvalidOptionalConstraint) {
358 FakeConstraints constraints;
359 constraints.AddOptional("weird key", 640);
361 CreateVideoSource(&constraints);
362 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
366 TEST_F(VideoSourceTest, SetValidOptionValues) {
367 FakeConstraints constraints;
368 constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, "false");
370 CreateVideoSource(&constraints);
373 EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
377 TEST_F(VideoSourceTest, OptionNotSet) {
378 FakeConstraints constraints;
379 CreateVideoSource(&constraints);
381 EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
384 TEST_F(VideoSourceTest, MandatoryOptionOverridesOptional) {
385 FakeConstraints constraints;
386 constraints.AddMandatory(
387 MediaConstraintsInterface::kNoiseReduction, true);
388 constraints.AddOptional(
389 MediaConstraintsInterface::kNoiseReduction, false);
391 CreateVideoSource(&constraints);
394 EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
398 TEST_F(VideoSourceTest, InvalidOptionKeyOptional) {
399 FakeConstraints constraints;
400 constraints.AddOptional(
401 MediaConstraintsInterface::kNoiseReduction, false);
402 constraints.AddOptional("invalidKey", false);
404 CreateVideoSource(&constraints);
406 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
409 EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
413 TEST_F(VideoSourceTest, InvalidOptionKeyMandatory) {
414 FakeConstraints constraints;
415 constraints.AddMandatory(
416 MediaConstraintsInterface::kNoiseReduction, false);
417 constraints.AddMandatory("invalidKey", false);
419 CreateVideoSource(&constraints);
421 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
424 EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
427 TEST_F(VideoSourceTest, InvalidOptionValueOptional) {
428 FakeConstraints constraints;
429 constraints.AddOptional(
430 MediaConstraintsInterface::kNoiseReduction, "not a boolean");
432 CreateVideoSource(&constraints);
434 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
437 EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
440 TEST_F(VideoSourceTest, InvalidOptionValueMandatory) {
441 FakeConstraints constraints;
442 // Optional constraints should be ignored if the mandatory constraints fail.
443 constraints.AddOptional(
444 MediaConstraintsInterface::kNoiseReduction, "false");
445 // Values are case-sensitive and must be all lower-case.
446 constraints.AddMandatory(
447 MediaConstraintsInterface::kNoiseReduction, "True");
449 CreateVideoSource(&constraints);
451 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
454 EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
457 TEST_F(VideoSourceTest, MixedOptionsAndConstraints) {
458 FakeConstraints constraints;
459 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352);
460 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288);
461 constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 5);
463 constraints.AddMandatory(
464 MediaConstraintsInterface::kNoiseReduction, false);
465 constraints.AddOptional(
466 MediaConstraintsInterface::kNoiseReduction, true);
468 CreateVideoSource(&constraints);
469 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
471 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
472 ASSERT_TRUE(format != NULL);
473 EXPECT_EQ(352, format->width);
474 EXPECT_EQ(288, format->height);
475 EXPECT_EQ(30, format->framerate());
478 EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
482 // Tests that the source starts video with the default resolution for
483 // screencast if no constraint is set.
484 TEST_F(VideoSourceTest, ScreencastResolutionNoConstraint) {
485 capturer_->TestWithoutCameraFormats();
486 capturer_->SetScreencast(true);
489 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
491 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
492 ASSERT_TRUE(format != NULL);
493 EXPECT_EQ(640, format->width);
494 EXPECT_EQ(480, format->height);
495 EXPECT_EQ(30, format->framerate());
498 // Tests that the source starts video with the max width and height set by
499 // constraints for screencast.
500 TEST_F(VideoSourceTest, ScreencastResolutionWithConstraint) {
501 FakeConstraints constraints;
502 constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 480);
503 constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 270);
505 capturer_->TestWithoutCameraFormats();
506 capturer_->SetScreencast(true);
508 CreateVideoSource(&constraints);
509 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
511 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
512 ASSERT_TRUE(format != NULL);
513 EXPECT_EQ(480, format->width);
514 EXPECT_EQ(270, format->height);
515 EXPECT_EQ(30, format->framerate());
518 TEST_F(VideoSourceTest, MandatorySubOneFpsConstraints) {
519 FakeConstraints constraints;
520 constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 0.5);
522 CreateVideoSource(&constraints);
523 EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
525 ASSERT_TRUE(capturer_->GetCaptureFormat() == NULL);
528 TEST_F(VideoSourceTest, OptionalSubOneFpsConstraints) {
529 FakeConstraints constraints;
530 constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 0.5);
532 CreateVideoSource(&constraints);
533 EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
535 const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
536 ASSERT_TRUE(format != NULL);
537 EXPECT_EQ(30, format->framerate());