1/*
2 * libjingle
3 * Copyright 2008 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28#include <stdio.h>
29#include <vector>
30
31#include "talk/media/base/fakemediaprocessor.h"
32#include "talk/media/base/fakevideocapturer.h"
33#include "talk/media/base/fakevideorenderer.h"
34#include "talk/media/base/testutils.h"
35#include "talk/media/base/videocapturer.h"
36#include "talk/media/base/videoprocessor.h"
37#include "webrtc/base/gunit.h"
38#include "webrtc/base/logging.h"
39#include "webrtc/base/thread.h"
40
41using cricket::FakeVideoCapturer;
42
43namespace {
44
45const int kMsCallbackWait = 500;
46// For HD only the height matters.
47const int kMinHdHeight = 720;
48const uint32 kTimeout = 5000U;
49
50void NormalizeVideoSize(int* expected_width, int* expected_height) {
51  // WebRtcVideoFrame truncates the frame size to a multiple of 4.
52  *expected_width = *expected_width & ~3;
53  *expected_height = *expected_height & ~3;
54}
55
56}  // namespace
57
58// Sets the elapsed time in the video frame to 0.
59class VideoProcessor0 : public cricket::VideoProcessor {
60 public:
61  virtual void OnFrame(uint32 /*ssrc*/, cricket::VideoFrame* frame,
62                       bool* drop_frame) {
63    frame->SetElapsedTime(0u);
64  }
65};
66
67// Adds one to the video frame's elapsed time. Note that VideoProcessor0 and
68// VideoProcessor1 are not commutative.
69class VideoProcessor1 : public cricket::VideoProcessor {
70 public:
71  virtual void OnFrame(uint32 /*ssrc*/, cricket::VideoFrame* frame,
72                       bool* drop_frame) {
73    int64 elapsed_time = frame->GetElapsedTime();
74    frame->SetElapsedTime(elapsed_time + 1);
75  }
76};
77
78class VideoCapturerTest
79    : public sigslot::has_slots<>,
80      public testing::Test {
81 public:
82  VideoCapturerTest()
83      : capture_state_(cricket::CS_STOPPED),
84        num_state_changes_(0),
85        video_frames_received_(0),
86        last_frame_elapsed_time_(0) {
87    capturer_.SignalVideoFrame.connect(this, &VideoCapturerTest::OnVideoFrame);
88    capturer_.SignalStateChange.connect(this,
89                                        &VideoCapturerTest::OnStateChange);
90  }
91
92 protected:
93  void OnVideoFrame(cricket::VideoCapturer*, const cricket::VideoFrame* frame) {
94    ++video_frames_received_;
95    last_frame_elapsed_time_ = frame->GetElapsedTime();
96    renderer_.RenderFrame(frame);
97  }
98  void OnStateChange(cricket::VideoCapturer*,
99                     cricket::CaptureState capture_state) {
100    capture_state_ = capture_state;
101    ++num_state_changes_;
102  }
103  cricket::CaptureState capture_state() { return capture_state_; }
104  int num_state_changes() { return num_state_changes_; }
105  int video_frames_received() const {
106    return video_frames_received_;
107  }
108  int64 last_frame_elapsed_time() const { return last_frame_elapsed_time_; }
109
110  cricket::FakeVideoCapturer capturer_;
111  cricket::CaptureState capture_state_;
112  int num_state_changes_;
113  int video_frames_received_;
114  int64 last_frame_elapsed_time_;
115  cricket::FakeVideoRenderer renderer_;
116};
117
118TEST_F(VideoCapturerTest, CaptureState) {
119  EXPECT_TRUE(capturer_.enable_video_adapter());
120  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
121      640,
122      480,
123      cricket::VideoFormat::FpsToInterval(30),
124      cricket::FOURCC_I420)));
125  EXPECT_TRUE(capturer_.IsRunning());
126  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
127  EXPECT_EQ(1, num_state_changes());
128  capturer_.Stop();
129  EXPECT_EQ_WAIT(cricket::CS_STOPPED, capture_state(), kMsCallbackWait);
130  EXPECT_EQ(2, num_state_changes());
131  capturer_.Stop();
132  rtc::Thread::Current()->ProcessMessages(100);
133  EXPECT_EQ(2, num_state_changes());
134}
135
136TEST_F(VideoCapturerTest, TestRestart) {
137  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
138      640,
139      480,
140      cricket::VideoFormat::FpsToInterval(30),
141      cricket::FOURCC_I420)));
142  EXPECT_TRUE(capturer_.IsRunning());
143  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
144  EXPECT_EQ(1, num_state_changes());
145  EXPECT_TRUE(capturer_.Restart(cricket::VideoFormat(
146      320,
147      240,
148      cricket::VideoFormat::FpsToInterval(30),
149      cricket::FOURCC_I420)));
150  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
151  EXPECT_TRUE(capturer_.IsRunning());
152  EXPECT_GE(1, num_state_changes());
153  capturer_.Stop();
154  rtc::Thread::Current()->ProcessMessages(100);
155  EXPECT_FALSE(capturer_.IsRunning());
156}
157
158TEST_F(VideoCapturerTest, TestStartingWithRestart) {
159  EXPECT_FALSE(capturer_.IsRunning());
160  EXPECT_TRUE(capturer_.Restart(cricket::VideoFormat(
161      640,
162      480,
163      cricket::VideoFormat::FpsToInterval(30),
164      cricket::FOURCC_I420)));
165  EXPECT_TRUE(capturer_.IsRunning());
166  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
167}
168
169TEST_F(VideoCapturerTest, TestRestartWithSameFormat) {
170  cricket::VideoFormat format(640, 480,
171                              cricket::VideoFormat::FpsToInterval(30),
172                              cricket::FOURCC_I420);
173  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(format));
174  EXPECT_TRUE(capturer_.IsRunning());
175  EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait);
176  EXPECT_EQ(1, num_state_changes());
177  EXPECT_TRUE(capturer_.Restart(format));
178  EXPECT_EQ(cricket::CS_RUNNING, capture_state());
179  EXPECT_TRUE(capturer_.IsRunning());
180  EXPECT_EQ(1, num_state_changes());
181}
182
183TEST_F(VideoCapturerTest, CameraOffOnMute) {
184  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
185      640,
186      480,
187      cricket::VideoFormat::FpsToInterval(30),
188      cricket::FOURCC_I420)));
189  EXPECT_TRUE(capturer_.IsRunning());
190  EXPECT_EQ(0, video_frames_received());
191  EXPECT_TRUE(capturer_.CaptureFrame());
192  EXPECT_EQ(1, video_frames_received());
193  EXPECT_FALSE(capturer_.IsMuted());
194
195  // Mute the camera and expect black output frame.
196  capturer_.MuteToBlackThenPause(true);
197  EXPECT_TRUE(capturer_.IsMuted());
198  for (int i = 0; i < 31; ++i) {
199    EXPECT_TRUE(capturer_.CaptureFrame());
200    EXPECT_TRUE(renderer_.black_frame());
201  }
202  EXPECT_EQ(32, video_frames_received());
203  EXPECT_EQ_WAIT(cricket::CS_PAUSED,
204                 capturer_.capture_state(), kTimeout);
205
206  // Verify that the camera is off.
207  EXPECT_FALSE(capturer_.CaptureFrame());
208  EXPECT_EQ(32, video_frames_received());
209
210  // Unmute the camera and expect non-black output frame.
211  capturer_.MuteToBlackThenPause(false);
212  EXPECT_FALSE(capturer_.IsMuted());
213  EXPECT_EQ_WAIT(cricket::CS_RUNNING,
214                 capturer_.capture_state(), kTimeout);
215  EXPECT_TRUE(capturer_.CaptureFrame());
216  EXPECT_FALSE(renderer_.black_frame());
217  EXPECT_EQ(33, video_frames_received());
218}
219
220TEST_F(VideoCapturerTest, ScreencastScaledMaxPixels) {
221  capturer_.SetScreencast(true);
222
223  int kWidth = 1280;
224  int kHeight = 720;
225
226  // Screencasts usually have large weird dimensions and are ARGB.
227  std::vector<cricket::VideoFormat> formats;
228  formats.push_back(cricket::VideoFormat(kWidth, kHeight,
229      cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
230  formats.push_back(cricket::VideoFormat(2 * kWidth, 2 * kHeight,
231      cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
232  capturer_.ResetSupportedFormats(formats);
233
234
235  EXPECT_EQ(0, capturer_.screencast_max_pixels());
236  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
237      2 * kWidth,
238      2 * kHeight,
239      cricket::VideoFormat::FpsToInterval(30),
240      cricket::FOURCC_ARGB)));
241  EXPECT_TRUE(capturer_.IsRunning());
242  EXPECT_EQ(0, renderer_.num_rendered_frames());
243  renderer_.SetSize(2 * kWidth, 2 * kHeight, 0);
244  EXPECT_TRUE(capturer_.CaptureFrame());
245  EXPECT_EQ(1, renderer_.num_rendered_frames());
246
247  capturer_.set_screencast_max_pixels(kWidth * kHeight);
248  renderer_.SetSize(kWidth, kHeight, 0);
249  EXPECT_TRUE(capturer_.CaptureFrame());
250  EXPECT_EQ(2, renderer_.num_rendered_frames());
251}
252
253TEST_F(VideoCapturerTest, ScreencastScaledOddWidth) {
254  capturer_.SetScreencast(true);
255
256  int kWidth = 1281;
257  int kHeight = 720;
258
259  std::vector<cricket::VideoFormat> formats;
260  formats.push_back(cricket::VideoFormat(kWidth, kHeight,
261      cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
262  capturer_.ResetSupportedFormats(formats);
263
264  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
265      kWidth,
266      kHeight,
267      cricket::VideoFormat::FpsToInterval(30),
268      cricket::FOURCC_ARGB)));
269  EXPECT_TRUE(capturer_.IsRunning());
270  EXPECT_EQ(0, renderer_.num_rendered_frames());
271  int expected_width = kWidth;
272  int expected_height = kHeight;
273  NormalizeVideoSize(&expected_width, &expected_height);
274  renderer_.SetSize(expected_width, expected_height, 0);
275  EXPECT_TRUE(capturer_.CaptureFrame());
276  EXPECT_EQ(1, renderer_.num_rendered_frames());
277}
278
279TEST_F(VideoCapturerTest, ScreencastScaledSuperLarge) {
280  capturer_.SetScreencast(true);
281
282  const int kMaxWidth = 4096;
283  const int kMaxHeight = 3072;
284  int kWidth = kMaxWidth + 4;
285  int kHeight = kMaxHeight + 4;
286
287  std::vector<cricket::VideoFormat> formats;
288  formats.push_back(cricket::VideoFormat(kWidth, kHeight,
289      cricket::VideoFormat::FpsToInterval(5), cricket::FOURCC_ARGB));
290  capturer_.ResetSupportedFormats(formats);
291
292  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
293      kWidth,
294      kHeight,
295      cricket::VideoFormat::FpsToInterval(30),
296      cricket::FOURCC_ARGB)));
297  EXPECT_TRUE(capturer_.IsRunning());
298  EXPECT_EQ(0, renderer_.num_rendered_frames());
299  int expected_width = 2050;
300  int expected_height = 1538;
301  NormalizeVideoSize(&expected_width, &expected_height);
302  renderer_.SetSize(expected_width, expected_height, 0);
303  EXPECT_TRUE(capturer_.CaptureFrame());
304  EXPECT_EQ(1, renderer_.num_rendered_frames());
305}
306
307TEST_F(VideoCapturerTest, TestFourccMatch) {
308  cricket::VideoFormat desired(640, 480,
309                               cricket::VideoFormat::FpsToInterval(30),
310                               cricket::FOURCC_ANY);
311  cricket::VideoFormat best;
312  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
313  EXPECT_EQ(640, best.width);
314  EXPECT_EQ(480, best.height);
315  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
316
317  desired.fourcc = cricket::FOURCC_MJPG;
318  EXPECT_FALSE(capturer_.GetBestCaptureFormat(desired, &best));
319
320  desired.fourcc = cricket::FOURCC_I420;
321  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
322}
323
324TEST_F(VideoCapturerTest, TestResolutionMatch) {
325  cricket::VideoFormat desired(1920, 1080,
326                               cricket::VideoFormat::FpsToInterval(30),
327                               cricket::FOURCC_ANY);
328  cricket::VideoFormat best;
329  // Ask for 1920x1080. Get HD 1280x720 which is the highest.
330  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
331  EXPECT_EQ(1280, best.width);
332  EXPECT_EQ(720, best.height);
333  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
334
335  desired.width = 360;
336  desired.height = 250;
337  // Ask for a little higher than QVGA. Get QVGA.
338  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
339  EXPECT_EQ(320, best.width);
340  EXPECT_EQ(240, best.height);
341  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
342
343  desired.width = 480;
344  desired.height = 270;
345  // Ask for HVGA. Get VGA.
346  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
347  EXPECT_EQ(640, best.width);
348  EXPECT_EQ(480, best.height);
349  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
350
351  desired.width = 320;
352  desired.height = 240;
353  // Ask for QVGA. Get QVGA.
354  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
355  EXPECT_EQ(320, best.width);
356  EXPECT_EQ(240, best.height);
357  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
358
359  desired.width = 80;
360  desired.height = 60;
361  // Ask for lower than QQVGA. Get QQVGA, which is the lowest.
362  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
363  EXPECT_EQ(160, best.width);
364  EXPECT_EQ(120, best.height);
365  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
366}
367
368TEST_F(VideoCapturerTest, TestHDResolutionMatch) {
369  // Add some HD formats typical of a mediocre HD webcam.
370  std::vector<cricket::VideoFormat> formats;
371  formats.push_back(cricket::VideoFormat(320, 240,
372      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
373  formats.push_back(cricket::VideoFormat(640, 480,
374      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
375  formats.push_back(cricket::VideoFormat(960, 544,
376      cricket::VideoFormat::FpsToInterval(24), cricket::FOURCC_I420));
377  formats.push_back(cricket::VideoFormat(1280, 720,
378      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
379  formats.push_back(cricket::VideoFormat(2592, 1944,
380      cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
381  capturer_.ResetSupportedFormats(formats);
382
383  cricket::VideoFormat desired(960, 720,
384                               cricket::VideoFormat::FpsToInterval(30),
385                               cricket::FOURCC_ANY);
386  cricket::VideoFormat best;
387  // Ask for 960x720 30 fps. Get qHD 24 fps
388  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
389  EXPECT_EQ(960, best.width);
390  EXPECT_EQ(544, best.height);
391  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(24), best.interval);
392
393  desired.width = 960;
394  desired.height = 544;
395  desired.interval = cricket::VideoFormat::FpsToInterval(30);
396  // Ask for qHD 30 fps. Get qHD 24 fps
397  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
398  EXPECT_EQ(960, best.width);
399  EXPECT_EQ(544, best.height);
400  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(24), best.interval);
401
402  desired.width = 360;
403  desired.height = 250;
404  desired.interval = cricket::VideoFormat::FpsToInterval(30);
405  // Ask for a little higher than QVGA. Get QVGA.
406  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
407  EXPECT_EQ(320, best.width);
408  EXPECT_EQ(240, best.height);
409  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
410
411  desired.width = 480;
412  desired.height = 270;
413  // Ask for HVGA. Get VGA.
414  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
415  EXPECT_EQ(640, best.width);
416  EXPECT_EQ(480, best.height);
417  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
418
419  desired.width = 320;
420  desired.height = 240;
421  // Ask for QVGA. Get QVGA.
422  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
423  EXPECT_EQ(320, best.width);
424  EXPECT_EQ(240, best.height);
425  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
426
427  desired.width = 160;
428  desired.height = 120;
429  // Ask for lower than QVGA. Get QVGA, which is the lowest.
430  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
431  EXPECT_EQ(320, best.width);
432  EXPECT_EQ(240, best.height);
433  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
434
435  desired.width = 1280;
436  desired.height = 720;
437  // Ask for HD. 720p fps is too low. Get VGA which has 30 fps.
438  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
439  EXPECT_EQ(640, best.width);
440  EXPECT_EQ(480, best.height);
441  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
442
443  desired.width = 1280;
444  desired.height = 720;
445  desired.interval = cricket::VideoFormat::FpsToInterval(15);
446  // Ask for HD 15 fps. Fps matches. Get HD
447  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
448  EXPECT_EQ(1280, best.width);
449  EXPECT_EQ(720, best.height);
450  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
451
452  desired.width = 1920;
453  desired.height = 1080;
454  desired.interval = cricket::VideoFormat::FpsToInterval(30);
455  // Ask for 1080p. Fps of HD formats is too low. Get VGA which can do 30 fps.
456  EXPECT_TRUE(capturer_.GetBestCaptureFormat(desired, &best));
457  EXPECT_EQ(640, best.width);
458  EXPECT_EQ(480, best.height);
459  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
460}
461
462// Some cameras support 320x240 and 320x640. Verify we choose 320x240.
463TEST_F(VideoCapturerTest, TestStrangeFormats) {
464  std::vector<cricket::VideoFormat> supported_formats;
465  supported_formats.push_back(cricket::VideoFormat(320, 240,
466      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
467  supported_formats.push_back(cricket::VideoFormat(320, 640,
468      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
469  capturer_.ResetSupportedFormats(supported_formats);
470
471  std::vector<cricket::VideoFormat> required_formats;
472  required_formats.push_back(cricket::VideoFormat(320, 240,
473      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
474  required_formats.push_back(cricket::VideoFormat(320, 200,
475      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
476  required_formats.push_back(cricket::VideoFormat(320, 180,
477      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
478  cricket::VideoFormat best;
479  for (size_t i = 0; i < required_formats.size(); ++i) {
480    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
481    EXPECT_EQ(320, best.width);
482    EXPECT_EQ(240, best.height);
483  }
484
485  supported_formats.clear();
486  supported_formats.push_back(cricket::VideoFormat(320, 640,
487      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
488  supported_formats.push_back(cricket::VideoFormat(320, 240,
489      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
490  capturer_.ResetSupportedFormats(supported_formats);
491
492  for (size_t i = 0; i < required_formats.size(); ++i) {
493    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
494    EXPECT_EQ(320, best.width);
495    EXPECT_EQ(240, best.height);
496  }
497}
498
499// Some cameras only have very low fps. Verify we choose something sensible.
500TEST_F(VideoCapturerTest, TestPoorFpsFormats) {
501  // all formats are low framerate
502  std::vector<cricket::VideoFormat> supported_formats;
503  supported_formats.push_back(cricket::VideoFormat(320, 240,
504      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
505  supported_formats.push_back(cricket::VideoFormat(640, 480,
506      cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
507  supported_formats.push_back(cricket::VideoFormat(1280, 720,
508      cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
509  capturer_.ResetSupportedFormats(supported_formats);
510
511  std::vector<cricket::VideoFormat> required_formats;
512  required_formats.push_back(cricket::VideoFormat(320, 240,
513      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
514  required_formats.push_back(cricket::VideoFormat(640, 480,
515      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
516  cricket::VideoFormat best;
517  for (size_t i = 0; i < required_formats.size(); ++i) {
518    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
519    EXPECT_EQ(required_formats[i].width, best.width);
520    EXPECT_EQ(required_formats[i].height, best.height);
521  }
522
523  // Increase framerate of 320x240. Expect low fps VGA avoided.
524  supported_formats.clear();
525  supported_formats.push_back(cricket::VideoFormat(320, 240,
526      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
527  supported_formats.push_back(cricket::VideoFormat(640, 480,
528      cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420));
529  supported_formats.push_back(cricket::VideoFormat(1280, 720,
530      cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420));
531  capturer_.ResetSupportedFormats(supported_formats);
532
533  for (size_t i = 0; i < required_formats.size(); ++i) {
534    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
535    EXPECT_EQ(320, best.width);
536    EXPECT_EQ(240, best.height);
537  }
538}
539
540// Some cameras support same size with different frame rates. Verify we choose
541// the frame rate properly.
542TEST_F(VideoCapturerTest, TestSameSizeDifferentFpsFormats) {
543  std::vector<cricket::VideoFormat> supported_formats;
544  supported_formats.push_back(cricket::VideoFormat(320, 240,
545      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420));
546  supported_formats.push_back(cricket::VideoFormat(320, 240,
547      cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_I420));
548  supported_formats.push_back(cricket::VideoFormat(320, 240,
549      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
550  capturer_.ResetSupportedFormats(supported_formats);
551
552  std::vector<cricket::VideoFormat> required_formats = supported_formats;
553  cricket::VideoFormat best;
554  for (size_t i = 0; i < required_formats.size(); ++i) {
555    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
556    EXPECT_EQ(320, best.width);
557    EXPECT_EQ(240, best.height);
558    EXPECT_EQ(required_formats[i].interval, best.interval);
559  }
560}
561
562// Some cameras support the correct resolution but at a lower fps than
563// we'd like. This tests we get the expected resolution and fps.
564TEST_F(VideoCapturerTest, TestFpsFormats) {
565  // We have VGA but low fps. Choose VGA, not HD
566  std::vector<cricket::VideoFormat> supported_formats;
567  supported_formats.push_back(cricket::VideoFormat(1280, 720,
568      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
569  supported_formats.push_back(cricket::VideoFormat(640, 480,
570      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
571  supported_formats.push_back(cricket::VideoFormat(640, 400,
572      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
573  supported_formats.push_back(cricket::VideoFormat(640, 360,
574      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
575  capturer_.ResetSupportedFormats(supported_formats);
576
577  std::vector<cricket::VideoFormat> required_formats;
578  required_formats.push_back(cricket::VideoFormat(640, 480,
579      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY));
580  required_formats.push_back(cricket::VideoFormat(640, 480,
581      cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_ANY));
582  required_formats.push_back(cricket::VideoFormat(640, 480,
583      cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY));
584  cricket::VideoFormat best;
585
586  // Expect 30 fps to choose 30 fps format.
587  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
588  EXPECT_EQ(640, best.width);
589  EXPECT_EQ(400, best.height);
590  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
591
592  // Expect 20 fps to choose 30 fps format.
593  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
594  EXPECT_EQ(640, best.width);
595  EXPECT_EQ(400, best.height);
596  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(30), best.interval);
597
598  // Expect 10 fps to choose 15 fps format and set fps to 15.
599  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
600  EXPECT_EQ(640, best.width);
601  EXPECT_EQ(480, best.height);
602  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
603
604  // We have VGA 60 fps and 15 fps. Choose best fps.
605  supported_formats.clear();
606  supported_formats.push_back(cricket::VideoFormat(1280, 720,
607      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
608  supported_formats.push_back(cricket::VideoFormat(640, 480,
609      cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_MJPG));
610  supported_formats.push_back(cricket::VideoFormat(640, 480,
611      cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420));
612  supported_formats.push_back(cricket::VideoFormat(640, 400,
613      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
614  supported_formats.push_back(cricket::VideoFormat(640, 360,
615      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
616  capturer_.ResetSupportedFormats(supported_formats);
617
618  // Expect 30 fps to choose 60 fps format and will set best fps to 60.
619  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[0], &best));
620  EXPECT_EQ(640, best.width);
621  EXPECT_EQ(480, best.height);
622  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
623
624  // Expect 20 fps to choose 60 fps format, and will set best fps to 60.
625  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[1], &best));
626  EXPECT_EQ(640, best.width);
627  EXPECT_EQ(480, best.height);
628  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(60), best.interval);
629
630  // Expect 10 fps to choose 15 fps.
631  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
632  EXPECT_EQ(640, best.width);
633  EXPECT_EQ(480, best.height);
634  EXPECT_EQ(cricket::VideoFormat::FpsToInterval(15), best.interval);
635}
636
637TEST_F(VideoCapturerTest, TestRequest16x10_9) {
638  std::vector<cricket::VideoFormat> supported_formats;
639  // We do not support HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
640  supported_formats.push_back(cricket::VideoFormat(640, 480,
641      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
642  supported_formats.push_back(cricket::VideoFormat(640, 400,
643      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
644  supported_formats.push_back(cricket::VideoFormat(640, 360,
645      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
646  capturer_.ResetSupportedFormats(supported_formats);
647
648  std::vector<cricket::VideoFormat> required_formats = supported_formats;
649  cricket::VideoFormat best;
650  // Expect 4x3, 16x10, and 16x9 requests are respected.
651  for (size_t i = 0; i < required_formats.size(); ++i) {
652    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
653    EXPECT_EQ(required_formats[i].width, best.width);
654    EXPECT_EQ(required_formats[i].height, best.height);
655  }
656
657  // We do not support 16x9 HD, expect 4x3 for 4x3, 16x10, and 16x9 requests.
658  supported_formats.clear();
659  supported_formats.push_back(cricket::VideoFormat(960, 720,
660      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
661  supported_formats.push_back(cricket::VideoFormat(640, 480,
662      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
663  supported_formats.push_back(cricket::VideoFormat(640, 400,
664      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
665  supported_formats.push_back(cricket::VideoFormat(640, 360,
666      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
667  capturer_.ResetSupportedFormats(supported_formats);
668
669  // Expect 4x3, 16x10, and 16x9 requests are respected.
670  for (size_t i = 0; i < required_formats.size(); ++i) {
671    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
672    EXPECT_EQ(required_formats[i].width, best.width);
673    EXPECT_EQ(required_formats[i].height, best.height);
674  }
675
676  // We support 16x9HD, Expect 4x3, 16x10, and 16x9 requests are respected.
677  supported_formats.clear();
678  supported_formats.push_back(cricket::VideoFormat(1280, 720,
679      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
680  supported_formats.push_back(cricket::VideoFormat(640, 480,
681      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
682  supported_formats.push_back(cricket::VideoFormat(640, 400,
683      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
684  supported_formats.push_back(cricket::VideoFormat(640, 360,
685      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
686  capturer_.ResetSupportedFormats(supported_formats);
687
688  // Expect 4x3 for 4x3 and 16x10 requests.
689  for (size_t i = 0; i < required_formats.size() - 1; ++i) {
690    EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[i], &best));
691    EXPECT_EQ(required_formats[i].width, best.width);
692    EXPECT_EQ(required_formats[i].height, best.height);
693  }
694
695  // Expect 16x9 for 16x9 request.
696  EXPECT_TRUE(capturer_.GetBestCaptureFormat(required_formats[2], &best));
697  EXPECT_EQ(640, best.width);
698  EXPECT_EQ(360, best.height);
699}
700
701// If HAVE_WEBRTC_VIDEO is not defined the video capturer will not be able to
702// provide OnVideoFrame-callbacks since they require cricket::CapturedFrame to
703// be decoded as a cricket::VideoFrame (i.e. an I420 frame). This functionality
704// only exist if HAVE_WEBRTC_VIDEO is defined below. I420 frames are also a
705// requirement for the VideoProcessors so they will not be called either.
706#if defined(HAVE_WEBRTC_VIDEO)
707TEST_F(VideoCapturerTest, VideoFrame) {
708  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
709      640,
710      480,
711      cricket::VideoFormat::FpsToInterval(30),
712      cricket::FOURCC_I420)));
713  EXPECT_TRUE(capturer_.IsRunning());
714  EXPECT_EQ(0, video_frames_received());
715  EXPECT_TRUE(capturer_.CaptureFrame());
716  EXPECT_EQ(1, video_frames_received());
717}
718
719TEST_F(VideoCapturerTest, ProcessorChainTest) {
720  VideoProcessor0 processor0;
721  VideoProcessor1 processor1;
722  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
723      640,
724      480,
725      cricket::VideoFormat::FpsToInterval(30),
726      cricket::FOURCC_I420)));
727  EXPECT_TRUE(capturer_.IsRunning());
728  EXPECT_EQ(0, video_frames_received());
729  // First processor sets elapsed time to 0.
730  capturer_.AddVideoProcessor(&processor0);
731  // Second processor adds 1 to the elapsed time. I.e. a frames elapsed time
732  // should now always be 1 (and not 0).
733  capturer_.AddVideoProcessor(&processor1);
734  EXPECT_TRUE(capturer_.CaptureFrame());
735  EXPECT_EQ(1, video_frames_received());
736  EXPECT_EQ(1u, last_frame_elapsed_time());
737  capturer_.RemoveVideoProcessor(&processor1);
738  EXPECT_TRUE(capturer_.CaptureFrame());
739  // Since processor1 has been removed the elapsed time should now be 0.
740  EXPECT_EQ(2, video_frames_received());
741  EXPECT_EQ(0u, last_frame_elapsed_time());
742}
743
744TEST_F(VideoCapturerTest, ProcessorDropFrame) {
745  cricket::FakeMediaProcessor dropping_processor_;
746  dropping_processor_.set_drop_frames(true);
747  EXPECT_EQ(cricket::CS_RUNNING, capturer_.Start(cricket::VideoFormat(
748      640,
749      480,
750      cricket::VideoFormat::FpsToInterval(30),
751      cricket::FOURCC_I420)));
752  EXPECT_TRUE(capturer_.IsRunning());
753  EXPECT_EQ(0, video_frames_received());
754  // Install a processor that always drop frames.
755  capturer_.AddVideoProcessor(&dropping_processor_);
756  EXPECT_TRUE(capturer_.CaptureFrame());
757  EXPECT_EQ(0, video_frames_received());
758}
759#endif  // HAVE_WEBRTC_VIDEO
760
761bool HdFormatInList(const std::vector<cricket::VideoFormat>& formats) {
762  for (std::vector<cricket::VideoFormat>::const_iterator found =
763           formats.begin(); found != formats.end(); ++found) {
764    if (found->height >= kMinHdHeight) {
765      return true;
766    }
767  }
768  return false;
769}
770
771TEST_F(VideoCapturerTest, Whitelist) {
772  // The definition of HD only applies to the height. Set the HD width to the
773  // smallest legal number to document this fact in this test.
774  const int kMinHdWidth = 1;
775  cricket::VideoFormat hd_format(kMinHdWidth,
776                                 kMinHdHeight,
777                                 cricket::VideoFormat::FpsToInterval(30),
778                                 cricket::FOURCC_I420);
779  cricket::VideoFormat vga_format(640, 480,
780                                  cricket::VideoFormat::FpsToInterval(30),
781                                  cricket::FOURCC_I420);
782  std::vector<cricket::VideoFormat> formats = *capturer_.GetSupportedFormats();
783  formats.push_back(hd_format);
784
785  // Enable whitelist. Expect HD not in list.
786  capturer_.set_enable_camera_list(true);
787  capturer_.ResetSupportedFormats(formats);
788  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
789  capturer_.ConstrainSupportedFormats(vga_format);
790  EXPECT_FALSE(HdFormatInList(*capturer_.GetSupportedFormats()));
791
792  // Disable whitelist. Expect HD in list.
793  capturer_.set_enable_camera_list(false);
794  capturer_.ResetSupportedFormats(formats);
795  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
796  capturer_.ConstrainSupportedFormats(vga_format);
797  EXPECT_TRUE(HdFormatInList(*capturer_.GetSupportedFormats()));
798}
799
800TEST_F(VideoCapturerTest, BlacklistAllFormats) {
801  cricket::VideoFormat vga_format(640, 480,
802                                  cricket::VideoFormat::FpsToInterval(30),
803                                  cricket::FOURCC_I420);
804  std::vector<cricket::VideoFormat> supported_formats;
805  // Mock a device that only supports HD formats.
806  supported_formats.push_back(cricket::VideoFormat(1280, 720,
807      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
808  supported_formats.push_back(cricket::VideoFormat(1920, 1080,
809      cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
810  capturer_.ResetSupportedFormats(supported_formats);
811  EXPECT_EQ(2u, capturer_.GetSupportedFormats()->size());
812  // Now, enable the list, which would exclude both formats. However, since
813  // only HD formats are available, we refuse to filter at all, so we don't
814  // break this camera.
815  capturer_.set_enable_camera_list(true);
816  capturer_.ConstrainSupportedFormats(vga_format);
817  EXPECT_EQ(2u, capturer_.GetSupportedFormats()->size());
818  // To make sure it's not just the camera list being broken, add in VGA and
819  // try again. This time, only the VGA format should be there.
820  supported_formats.push_back(vga_format);
821  capturer_.ResetSupportedFormats(supported_formats);
822  ASSERT_EQ(1u, capturer_.GetSupportedFormats()->size());
823  EXPECT_EQ(vga_format.height, capturer_.GetSupportedFormats()->at(0).height);
824}
825