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