xref: /aosp_15_r20/external/webrtc/modules/video_capture/device_info_impl.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/device_info_impl.h"
12 
13 #include <stdlib.h>
14 
15 #include "absl/strings/match.h"
16 #include "absl/strings/string_view.h"
17 #include "rtc_base/logging.h"
18 
19 #ifndef abs
20 #define abs(a) (a >= 0 ? a : -a)
21 #endif
22 
23 namespace webrtc {
24 namespace videocapturemodule {
25 
DeviceInfoImpl()26 DeviceInfoImpl::DeviceInfoImpl()
27     : _lastUsedDeviceName(NULL), _lastUsedDeviceNameLength(0) {}
28 
~DeviceInfoImpl(void)29 DeviceInfoImpl::~DeviceInfoImpl(void) {
30   MutexLock lock(&_apiLock);
31   free(_lastUsedDeviceName);
32 }
33 
NumberOfCapabilities(const char * deviceUniqueIdUTF8)34 int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
35   if (!deviceUniqueIdUTF8)
36     return -1;
37 
38   MutexLock lock(&_apiLock);
39 
40   // Is it the same device that is asked for again.
41   if (absl::EqualsIgnoreCase(
42           deviceUniqueIdUTF8,
43           absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
44     return static_cast<int32_t>(_captureCapabilities.size());
45   }
46 
47   int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
48   return ret;
49 }
50 
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)51 int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
52                                       const uint32_t deviceCapabilityNumber,
53                                       VideoCaptureCapability& capability) {
54   RTC_DCHECK(deviceUniqueIdUTF8);
55 
56   MutexLock lock(&_apiLock);
57 
58   if (!absl::EqualsIgnoreCase(
59           deviceUniqueIdUTF8,
60           absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
61     if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
62       return -1;
63     }
64   }
65 
66   // Make sure the number is valid
67   if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) {
68     RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
69                       << deviceCapabilityNumber << ">= number of capabilities ("
70                       << _captureCapabilities.size() << ").";
71     return -1;
72   }
73 
74   capability = _captureCapabilities[deviceCapabilityNumber];
75   return 0;
76 }
77 
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)78 int32_t DeviceInfoImpl::GetBestMatchedCapability(
79     const char* deviceUniqueIdUTF8,
80     const VideoCaptureCapability& requested,
81     VideoCaptureCapability& resulting) {
82   if (!deviceUniqueIdUTF8)
83     return -1;
84 
85   MutexLock lock(&_apiLock);
86   if (!absl::EqualsIgnoreCase(
87           deviceUniqueIdUTF8,
88           absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
89     if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
90       return -1;
91     }
92   }
93 
94   int32_t bestformatIndex = -1;
95   int32_t bestWidth = 0;
96   int32_t bestHeight = 0;
97   int32_t bestFrameRate = 0;
98   VideoType bestVideoType = VideoType::kUnknown;
99 
100   const int32_t numberOfCapabilies =
101       static_cast<int32_t>(_captureCapabilities.size());
102 
103   for (int32_t tmp = 0; tmp < numberOfCapabilies;
104        ++tmp)  // Loop through all capabilities
105   {
106     VideoCaptureCapability& capability = _captureCapabilities[tmp];
107 
108     const int32_t diffWidth = capability.width - requested.width;
109     const int32_t diffHeight = capability.height - requested.height;
110     const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
111 
112     const int32_t currentbestDiffWith = bestWidth - requested.width;
113     const int32_t currentbestDiffHeight = bestHeight - requested.height;
114     const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
115 
116     if ((diffHeight >= 0 &&
117          diffHeight <= abs(currentbestDiffHeight))  // Height better or equalt
118                                                     // that previouse.
119         || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) {
120       if (diffHeight ==
121           currentbestDiffHeight)  // Found best height. Care about the width)
122       {
123         if ((diffWidth >= 0 &&
124              diffWidth <= abs(currentbestDiffWith))  // Width better or equal
125             || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) {
126           if (diffWidth == currentbestDiffWith &&
127               diffHeight == currentbestDiffHeight)  // Same size as previously
128           {
129             // Also check the best frame rate if the diff is the same as
130             // previouse
131             if (((diffFrameRate >= 0 &&
132                   diffFrameRate <=
133                       currentbestDiffFrameRate)  // Frame rate to high but
134                                                  // better match than previouse
135                                                  // and we have not selected IUV
136                  || (currentbestDiffFrameRate < 0 &&
137                      diffFrameRate >=
138                          currentbestDiffFrameRate))  // Current frame rate is
139                                                      // lower than requested.
140                                                      // This is better.
141             ) {
142               if ((currentbestDiffFrameRate ==
143                    diffFrameRate)  // Same frame rate as previous  or frame rate
144                                    // allready good enough
145                   || (currentbestDiffFrameRate >= 0)) {
146                 if (bestVideoType != requested.videoType &&
147                     requested.videoType != VideoType::kUnknown &&
148                     (capability.videoType == requested.videoType ||
149                      capability.videoType == VideoType::kI420 ||
150                      capability.videoType == VideoType::kYUY2 ||
151                      capability.videoType == VideoType::kYV12 ||
152                      capability.videoType == VideoType::kNV12)) {
153                   bestVideoType = capability.videoType;
154                   bestformatIndex = tmp;
155                 }
156                 // If width height and frame rate is full filled we can use the
157                 // camera for encoding if it is supported.
158                 if (capability.height == requested.height &&
159                     capability.width == requested.width &&
160                     capability.maxFPS >= requested.maxFPS) {
161                   bestformatIndex = tmp;
162                 }
163               } else  // Better frame rate
164               {
165                 bestWidth = capability.width;
166                 bestHeight = capability.height;
167                 bestFrameRate = capability.maxFPS;
168                 bestVideoType = capability.videoType;
169                 bestformatIndex = tmp;
170               }
171             }
172           } else  // Better width than previously
173           {
174             bestWidth = capability.width;
175             bestHeight = capability.height;
176             bestFrameRate = capability.maxFPS;
177             bestVideoType = capability.videoType;
178             bestformatIndex = tmp;
179           }
180         }     // else width no good
181       } else  // Better height
182       {
183         bestWidth = capability.width;
184         bestHeight = capability.height;
185         bestFrameRate = capability.maxFPS;
186         bestVideoType = capability.videoType;
187         bestformatIndex = tmp;
188       }
189     }  // else height not good
190   }    // end for
191 
192   RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
193                       << bestHeight << "@" << bestFrameRate
194                       << "fps, color format: "
195                       << static_cast<int>(bestVideoType);
196 
197   // Copy the capability
198   if (bestformatIndex < 0)
199     return -1;
200   resulting = _captureCapabilities[bestformatIndex];
201   return bestformatIndex;
202 }
203 
204 // Default implementation. This should be overridden by Mobile implementations.
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)205 int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
206                                        VideoRotation& orientation) {
207   orientation = kVideoRotation_0;
208   return -1;
209 }
210 }  // namespace videocapturemodule
211 }  // namespace webrtc
212