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