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