• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/video_capture/video_capture.h"
12 
13 #include <stdio.h>
14 
15 #include <map>
16 #include <memory>
17 #include <sstream>
18 
19 #include "absl/memory/memory.h"
20 #include "api/scoped_refptr.h"
21 #include "api/video/i420_buffer.h"
22 #include "api/video/video_frame.h"
23 #include "common_video/libyuv/include/webrtc_libyuv.h"
24 #include "modules/utility/include/process_thread.h"
25 #include "modules/video_capture/video_capture_factory.h"
26 #include "rtc_base/synchronization/mutex.h"
27 #include "rtc_base/time_utils.h"
28 #include "system_wrappers/include/sleep.h"
29 #include "test/frame_utils.h"
30 #include "test/gtest.h"
31 
32 using webrtc::SleepMs;
33 using webrtc::VideoCaptureCapability;
34 using webrtc::VideoCaptureFactory;
35 using webrtc::VideoCaptureModule;
36 
37 #define WAIT_(ex, timeout, res)                           \
38   do {                                                    \
39     res = (ex);                                           \
40     int64_t start = rtc::TimeMillis();                    \
41     while (!res && rtc::TimeMillis() < start + timeout) { \
42       SleepMs(5);                                         \
43       res = (ex);                                         \
44     }                                                     \
45   } while (0)
46 
47 #define EXPECT_TRUE_WAIT(ex, timeout) \
48   do {                                \
49     bool res;                         \
50     WAIT_(ex, timeout, res);          \
51     if (!res)                         \
52       EXPECT_TRUE(ex);                \
53   } while (0)
54 
55 static const int kTimeOut = 5000;
56 #ifdef WEBRTC_MAC
57 static const int kTestHeight = 288;
58 static const int kTestWidth = 352;
59 static const int kTestFramerate = 30;
60 #endif
61 
62 class TestVideoCaptureCallback
63     : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
64  public:
TestVideoCaptureCallback()65   TestVideoCaptureCallback()
66       : last_render_time_ms_(0),
67         incoming_frames_(0),
68         timing_warnings_(0),
69         rotate_frame_(webrtc::kVideoRotation_0) {}
70 
~TestVideoCaptureCallback()71   ~TestVideoCaptureCallback() override {
72     if (timing_warnings_ > 0)
73       printf("No of timing warnings %d\n", timing_warnings_);
74   }
75 
OnFrame(const webrtc::VideoFrame & videoFrame)76   void OnFrame(const webrtc::VideoFrame& videoFrame) override {
77     webrtc::MutexLock lock(&capture_lock_);
78     int height = videoFrame.height();
79     int width = videoFrame.width();
80 #if defined(WEBRTC_ANDROID) && WEBRTC_ANDROID
81     // Android camera frames may be rotated depending on test device
82     // orientation.
83     EXPECT_TRUE(height == capability_.height || height == capability_.width);
84     EXPECT_TRUE(width == capability_.width || width == capability_.height);
85 #else
86     EXPECT_EQ(height, capability_.height);
87     EXPECT_EQ(width, capability_.width);
88     EXPECT_EQ(rotate_frame_, videoFrame.rotation());
89 #endif
90     // RenderTimstamp should be the time now.
91     EXPECT_TRUE(videoFrame.render_time_ms() >= rtc::TimeMillis() - 30 &&
92                 videoFrame.render_time_ms() <= rtc::TimeMillis());
93 
94     if ((videoFrame.render_time_ms() >
95              last_render_time_ms_ + (1000 * 1.1) / capability_.maxFPS &&
96          last_render_time_ms_ > 0) ||
97         (videoFrame.render_time_ms() <
98              last_render_time_ms_ + (1000 * 0.9) / capability_.maxFPS &&
99          last_render_time_ms_ > 0)) {
100       timing_warnings_++;
101     }
102 
103     incoming_frames_++;
104     last_render_time_ms_ = videoFrame.render_time_ms();
105     last_frame_ = videoFrame.video_frame_buffer();
106   }
107 
SetExpectedCapability(VideoCaptureCapability capability)108   void SetExpectedCapability(VideoCaptureCapability capability) {
109     webrtc::MutexLock lock(&capture_lock_);
110     capability_ = capability;
111     incoming_frames_ = 0;
112     last_render_time_ms_ = 0;
113   }
incoming_frames()114   int incoming_frames() {
115     webrtc::MutexLock lock(&capture_lock_);
116     return incoming_frames_;
117   }
118 
timing_warnings()119   int timing_warnings() {
120     webrtc::MutexLock lock(&capture_lock_);
121     return timing_warnings_;
122   }
capability()123   VideoCaptureCapability capability() {
124     webrtc::MutexLock lock(&capture_lock_);
125     return capability_;
126   }
127 
CompareLastFrame(const webrtc::VideoFrame & frame)128   bool CompareLastFrame(const webrtc::VideoFrame& frame) {
129     webrtc::MutexLock lock(&capture_lock_);
130     return webrtc::test::FrameBufsEqual(last_frame_,
131                                         frame.video_frame_buffer());
132   }
133 
SetExpectedCaptureRotation(webrtc::VideoRotation rotation)134   void SetExpectedCaptureRotation(webrtc::VideoRotation rotation) {
135     webrtc::MutexLock lock(&capture_lock_);
136     rotate_frame_ = rotation;
137   }
138 
139  private:
140   webrtc::Mutex capture_lock_;
141   VideoCaptureCapability capability_;
142   int64_t last_render_time_ms_;
143   int incoming_frames_;
144   int timing_warnings_;
145   rtc::scoped_refptr<webrtc::VideoFrameBuffer> last_frame_;
146   webrtc::VideoRotation rotate_frame_;
147 };
148 
149 class VideoCaptureTest : public ::testing::Test {
150  public:
VideoCaptureTest()151   VideoCaptureTest() : number_of_devices_(0) {}
152 
SetUp()153   void SetUp() override {
154     device_info_.reset(VideoCaptureFactory::CreateDeviceInfo());
155     assert(device_info_.get());
156     number_of_devices_ = device_info_->NumberOfDevices();
157     ASSERT_GT(number_of_devices_, 0u);
158   }
159 
OpenVideoCaptureDevice(unsigned int device,rtc::VideoSinkInterface<webrtc::VideoFrame> * callback)160   rtc::scoped_refptr<VideoCaptureModule> OpenVideoCaptureDevice(
161       unsigned int device,
162       rtc::VideoSinkInterface<webrtc::VideoFrame>* callback) {
163     char device_name[256];
164     char unique_name[256];
165 
166     EXPECT_EQ(0, device_info_->GetDeviceName(device, device_name, 256,
167                                              unique_name, 256));
168 
169     rtc::scoped_refptr<VideoCaptureModule> module(
170         VideoCaptureFactory::Create(unique_name));
171     if (module.get() == NULL)
172       return NULL;
173 
174     EXPECT_FALSE(module->CaptureStarted());
175 
176     module->RegisterCaptureDataCallback(callback);
177     return module;
178   }
179 
StartCapture(VideoCaptureModule * capture_module,VideoCaptureCapability capability)180   void StartCapture(VideoCaptureModule* capture_module,
181                     VideoCaptureCapability capability) {
182     ASSERT_EQ(0, capture_module->StartCapture(capability));
183     EXPECT_TRUE(capture_module->CaptureStarted());
184 
185     VideoCaptureCapability resulting_capability;
186     EXPECT_EQ(0, capture_module->CaptureSettings(resulting_capability));
187     EXPECT_EQ(capability.width, resulting_capability.width);
188     EXPECT_EQ(capability.height, resulting_capability.height);
189   }
190 
191   std::unique_ptr<VideoCaptureModule::DeviceInfo> device_info_;
192   unsigned int number_of_devices_;
193 };
194 
195 #ifdef WEBRTC_MAC
196 // Currently fails on Mac 64-bit, see
197 // https://bugs.chromium.org/p/webrtc/issues/detail?id=5406
198 #define MAYBE_CreateDelete DISABLED_CreateDelete
199 #else
200 #define MAYBE_CreateDelete CreateDelete
201 #endif
TEST_F(VideoCaptureTest,MAYBE_CreateDelete)202 TEST_F(VideoCaptureTest, MAYBE_CreateDelete) {
203   for (int i = 0; i < 5; ++i) {
204     int64_t start_time = rtc::TimeMillis();
205     TestVideoCaptureCallback capture_observer;
206     rtc::scoped_refptr<VideoCaptureModule> module(
207         OpenVideoCaptureDevice(0, &capture_observer));
208     ASSERT_TRUE(module.get() != NULL);
209 
210     VideoCaptureCapability capability;
211 #ifndef WEBRTC_MAC
212     device_info_->GetCapability(module->CurrentDeviceName(), 0, capability);
213 #else
214     capability.width = kTestWidth;
215     capability.height = kTestHeight;
216     capability.maxFPS = kTestFramerate;
217     capability.videoType = webrtc::VideoType::kUnknown;
218 #endif
219     capture_observer.SetExpectedCapability(capability);
220     ASSERT_NO_FATAL_FAILURE(StartCapture(module.get(), capability));
221 
222     // Less than 4s to start the camera.
223     EXPECT_LE(rtc::TimeMillis() - start_time, 4000);
224 
225     // Make sure 5 frames are captured.
226     EXPECT_TRUE_WAIT(capture_observer.incoming_frames() >= 5, kTimeOut);
227 
228     int64_t stop_time = rtc::TimeMillis();
229     EXPECT_EQ(0, module->StopCapture());
230     EXPECT_FALSE(module->CaptureStarted());
231 
232     // Less than 3s to stop the camera.
233     EXPECT_LE(rtc::TimeMillis() - stop_time, 3000);
234   }
235 }
236 
237 #ifdef WEBRTC_MAC
238 // Currently fails on Mac 64-bit, see
239 // https://bugs.chromium.org/p/webrtc/issues/detail?id=5406
240 #define MAYBE_Capabilities DISABLED_Capabilities
241 #else
242 #define MAYBE_Capabilities Capabilities
243 #endif
TEST_F(VideoCaptureTest,MAYBE_Capabilities)244 TEST_F(VideoCaptureTest, MAYBE_Capabilities) {
245   TestVideoCaptureCallback capture_observer;
246 
247   rtc::scoped_refptr<VideoCaptureModule> module(
248       OpenVideoCaptureDevice(0, &capture_observer));
249   ASSERT_TRUE(module.get() != NULL);
250 
251   int number_of_capabilities =
252       device_info_->NumberOfCapabilities(module->CurrentDeviceName());
253   EXPECT_GT(number_of_capabilities, 0);
254   // Key is <width>x<height>, value is vector of maxFPS values at that
255   // resolution.
256   typedef std::map<std::string, std::vector<int> > FrameRatesByResolution;
257   FrameRatesByResolution frame_rates_by_resolution;
258   for (int i = 0; i < number_of_capabilities; ++i) {
259     VideoCaptureCapability capability;
260     EXPECT_EQ(0, device_info_->GetCapability(module->CurrentDeviceName(), i,
261                                              capability));
262     std::ostringstream resolutionStream;
263     resolutionStream << capability.width << "x" << capability.height;
264     resolutionStream.flush();
265     std::string resolution = resolutionStream.str();
266     frame_rates_by_resolution[resolution].push_back(capability.maxFPS);
267 
268     // Since Android presents so many resolution/FPS combinations and the test
269     // runner imposes a timeout, we only actually start the capture and test
270     // that a frame was captured for 2 frame-rates at each resolution.
271     if (frame_rates_by_resolution[resolution].size() > 2)
272       continue;
273 
274     capture_observer.SetExpectedCapability(capability);
275     ASSERT_NO_FATAL_FAILURE(StartCapture(module.get(), capability));
276     // Make sure at least one frame is captured.
277     EXPECT_TRUE_WAIT(capture_observer.incoming_frames() >= 1, kTimeOut);
278 
279     EXPECT_EQ(0, module->StopCapture());
280   }
281 
282 #if defined(WEBRTC_ANDROID) && WEBRTC_ANDROID
283   // There's no reason for this to _necessarily_ be true, but in practice all
284   // Android devices this test runs on in fact do support multiple capture
285   // resolutions and multiple frame-rates per captured resolution, so we assert
286   // this fact here as a regression-test against the time that we only noticed a
287   // single frame-rate per resolution (bug 2974).  If this test starts being run
288   // on devices for which this is untrue (e.g. Nexus4) then the following should
289   // probably be wrapped in a base::android::BuildInfo::model()/device() check.
290   EXPECT_GT(frame_rates_by_resolution.size(), 1U);
291   for (FrameRatesByResolution::const_iterator it =
292            frame_rates_by_resolution.begin();
293        it != frame_rates_by_resolution.end(); ++it) {
294     EXPECT_GT(it->second.size(), 1U) << it->first;
295   }
296 #endif  // WEBRTC_ANDROID
297 }
298 
299 // NOTE: flaky, crashes sometimes.
300 // http://code.google.com/p/webrtc/issues/detail?id=777
TEST_F(VideoCaptureTest,DISABLED_TestTwoCameras)301 TEST_F(VideoCaptureTest, DISABLED_TestTwoCameras) {
302   if (number_of_devices_ < 2) {
303     printf("There are not two cameras available. Aborting test. \n");
304     return;
305   }
306 
307   TestVideoCaptureCallback capture_observer1;
308   rtc::scoped_refptr<VideoCaptureModule> module1(
309       OpenVideoCaptureDevice(0, &capture_observer1));
310   ASSERT_TRUE(module1.get() != NULL);
311   VideoCaptureCapability capability1;
312 #ifndef WEBRTC_MAC
313   device_info_->GetCapability(module1->CurrentDeviceName(), 0, capability1);
314 #else
315   capability1.width = kTestWidth;
316   capability1.height = kTestHeight;
317   capability1.maxFPS = kTestFramerate;
318   capability1.videoType = webrtc::VideoType::kUnknown;
319 #endif
320   capture_observer1.SetExpectedCapability(capability1);
321 
322   TestVideoCaptureCallback capture_observer2;
323   rtc::scoped_refptr<VideoCaptureModule> module2(
324       OpenVideoCaptureDevice(1, &capture_observer2));
325   ASSERT_TRUE(module1.get() != NULL);
326 
327   VideoCaptureCapability capability2;
328 #ifndef WEBRTC_MAC
329   device_info_->GetCapability(module2->CurrentDeviceName(), 0, capability2);
330 #else
331   capability2.width = kTestWidth;
332   capability2.height = kTestHeight;
333   capability2.maxFPS = kTestFramerate;
334   capability2.videoType = webrtc::VideoType::kUnknown;
335 #endif
336   capture_observer2.SetExpectedCapability(capability2);
337 
338   ASSERT_NO_FATAL_FAILURE(StartCapture(module1.get(), capability1));
339   ASSERT_NO_FATAL_FAILURE(StartCapture(module2.get(), capability2));
340   EXPECT_TRUE_WAIT(capture_observer1.incoming_frames() >= 5, kTimeOut);
341   EXPECT_TRUE_WAIT(capture_observer2.incoming_frames() >= 5, kTimeOut);
342   EXPECT_EQ(0, module2->StopCapture());
343   EXPECT_EQ(0, module1->StopCapture());
344 }
345