xref: /aosp_15_r20/external/webrtc/modules/video_capture/test/video_capture_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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