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