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