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 <assert.h>
12 #include <stdlib.h>
13
14 #include "webrtc/modules/video_capture/device_info_impl.h"
15 #include "webrtc/modules/video_capture/video_capture_config.h"
16 #include "webrtc/system_wrappers/include/logging.h"
17
18 #ifndef abs
19 #define abs(a) (a>=0?a:-a)
20 #endif
21
22 namespace webrtc
23 {
24 namespace videocapturemodule
25 {
DeviceInfoImpl(const int32_t id)26 DeviceInfoImpl::DeviceInfoImpl(const int32_t id)
27 : _id(id), _apiLock(*RWLockWrapper::CreateRWLock()), _lastUsedDeviceName(NULL),
28 _lastUsedDeviceNameLength(0)
29 {
30 }
31
~DeviceInfoImpl(void)32 DeviceInfoImpl::~DeviceInfoImpl(void)
33 {
34 _apiLock.AcquireLockExclusive();
35 free(_lastUsedDeviceName);
36 _apiLock.ReleaseLockExclusive();
37
38 delete &_apiLock;
39 }
NumberOfCapabilities(const char * deviceUniqueIdUTF8)40 int32_t DeviceInfoImpl::NumberOfCapabilities(
41 const char* deviceUniqueIdUTF8)
42 {
43
44 if (!deviceUniqueIdUTF8)
45 return -1;
46
47 _apiLock.AcquireLockShared();
48
49 if (_lastUsedDeviceNameLength == strlen((char*) deviceUniqueIdUTF8))
50 {
51 // Is it the same device that is asked for again.
52 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
53 if(strncasecmp((char*)_lastUsedDeviceName,
54 (char*) deviceUniqueIdUTF8,
55 _lastUsedDeviceNameLength)==0)
56 #else
57 if (_strnicmp((char*) _lastUsedDeviceName,
58 (char*) deviceUniqueIdUTF8,
59 _lastUsedDeviceNameLength) == 0)
60 #endif
61 {
62 //yes
63 _apiLock.ReleaseLockShared();
64 return static_cast<int32_t>(_captureCapabilities.size());
65 }
66 }
67 // Need to get exclusive rights to create the new capability map.
68 _apiLock.ReleaseLockShared();
69 WriteLockScoped cs2(_apiLock);
70
71 int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
72 return ret;
73 }
74
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)75 int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
76 const uint32_t deviceCapabilityNumber,
77 VideoCaptureCapability& capability)
78 {
79 assert(deviceUniqueIdUTF8 != NULL);
80
81 ReadLockScoped cs(_apiLock);
82
83 if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8))
84 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
85 || (strncasecmp((char*)_lastUsedDeviceName,
86 (char*) deviceUniqueIdUTF8,
87 _lastUsedDeviceNameLength)!=0))
88 #else
89 || (_strnicmp((char*) _lastUsedDeviceName,
90 (char*) deviceUniqueIdUTF8,
91 _lastUsedDeviceNameLength) != 0))
92 #endif
93
94 {
95 _apiLock.ReleaseLockShared();
96 _apiLock.AcquireLockExclusive();
97 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8))
98 {
99 _apiLock.ReleaseLockExclusive();
100 _apiLock.AcquireLockShared();
101 return -1;
102 }
103 _apiLock.ReleaseLockExclusive();
104 _apiLock.AcquireLockShared();
105 }
106
107 // Make sure the number is valid
108 if (deviceCapabilityNumber >= (unsigned int) _captureCapabilities.size())
109 {
110 LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
111 << deviceCapabilityNumber << ">= number of capabilities ("
112 << _captureCapabilities.size() << ").";
113 return -1;
114 }
115
116 capability = _captureCapabilities[deviceCapabilityNumber];
117 return 0;
118 }
119
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)120 int32_t DeviceInfoImpl::GetBestMatchedCapability(
121 const char*deviceUniqueIdUTF8,
122 const VideoCaptureCapability& requested,
123 VideoCaptureCapability& resulting)
124 {
125
126
127 if (!deviceUniqueIdUTF8)
128 return -1;
129
130 ReadLockScoped cs(_apiLock);
131 if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8))
132 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
133 || (strncasecmp((char*)_lastUsedDeviceName,
134 (char*) deviceUniqueIdUTF8,
135 _lastUsedDeviceNameLength)!=0))
136 #else
137 || (_strnicmp((char*) _lastUsedDeviceName,
138 (char*) deviceUniqueIdUTF8,
139 _lastUsedDeviceNameLength) != 0))
140 #endif
141 {
142 _apiLock.ReleaseLockShared();
143 _apiLock.AcquireLockExclusive();
144 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8))
145 {
146 return -1;
147 }
148 _apiLock.ReleaseLockExclusive();
149 _apiLock.AcquireLockShared();
150 }
151
152 int32_t bestformatIndex = -1;
153 int32_t bestWidth = 0;
154 int32_t bestHeight = 0;
155 int32_t bestFrameRate = 0;
156 RawVideoType bestRawType = kVideoUnknown;
157 webrtc::VideoCodecType bestCodecType = webrtc::kVideoCodecUnknown;
158
159 const int32_t numberOfCapabilies =
160 static_cast<int32_t>(_captureCapabilities.size());
161
162 for (int32_t tmp = 0; tmp < numberOfCapabilies; ++tmp) // Loop through all capabilities
163 {
164 VideoCaptureCapability& capability = _captureCapabilities[tmp];
165
166 const int32_t diffWidth = capability.width - requested.width;
167 const int32_t diffHeight = capability.height - requested.height;
168 const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
169
170 const int32_t currentbestDiffWith = bestWidth - requested.width;
171 const int32_t currentbestDiffHeight = bestHeight - requested.height;
172 const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
173
174 if ((diffHeight >= 0 && diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt that previouse.
175 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight))
176 {
177
178 if (diffHeight == currentbestDiffHeight) // Found best height. Care about the width)
179 {
180 if ((diffWidth >= 0 && diffWidth <= abs(currentbestDiffWith)) // Width better or equal
181 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith))
182 {
183 if (diffWidth == currentbestDiffWith && diffHeight
184 == currentbestDiffHeight) // Same size as previously
185 {
186 //Also check the best frame rate if the diff is the same as previouse
187 if (((diffFrameRate >= 0 &&
188 diffFrameRate <= currentbestDiffFrameRate) // Frame rate to high but better match than previouse and we have not selected IUV
189 ||
190 (currentbestDiffFrameRate < 0 &&
191 diffFrameRate >= currentbestDiffFrameRate)) // Current frame rate is lower than requested. This is better.
192 )
193 {
194 if ((currentbestDiffFrameRate == diffFrameRate) // Same frame rate as previous or frame rate allready good enough
195 || (currentbestDiffFrameRate >= 0))
196 {
197 if (bestRawType != requested.rawType
198 && requested.rawType != kVideoUnknown
199 && (capability.rawType == requested.rawType
200 || capability.rawType == kVideoI420
201 || capability.rawType == kVideoYUY2
202 || capability.rawType == kVideoYV12))
203 {
204 bestCodecType = capability.codecType;
205 bestRawType = capability.rawType;
206 bestformatIndex = tmp;
207 }
208 // If width height and frame rate is full filled we can use the camera for encoding if it is supported.
209 if (capability.height == requested.height
210 && capability.width == requested.width
211 && capability.maxFPS >= requested.maxFPS)
212 {
213 if (capability.codecType == requested.codecType
214 && bestCodecType != requested.codecType)
215 {
216 bestCodecType = capability.codecType;
217 bestformatIndex = tmp;
218 }
219 }
220 }
221 else // Better frame rate
222 {
223 if (requested.codecType == capability.codecType)
224 {
225
226 bestWidth = capability.width;
227 bestHeight = capability.height;
228 bestFrameRate = capability.maxFPS;
229 bestCodecType = capability.codecType;
230 bestRawType = capability.rawType;
231 bestformatIndex = tmp;
232 }
233 }
234 }
235 }
236 else // Better width than previously
237 {
238 if (requested.codecType == capability.codecType)
239 {
240 bestWidth = capability.width;
241 bestHeight = capability.height;
242 bestFrameRate = capability.maxFPS;
243 bestCodecType = capability.codecType;
244 bestRawType = capability.rawType;
245 bestformatIndex = tmp;
246 }
247 }
248 }// else width no good
249 }
250 else // Better height
251 {
252 if (requested.codecType == capability.codecType)
253 {
254 bestWidth = capability.width;
255 bestHeight = capability.height;
256 bestFrameRate = capability.maxFPS;
257 bestCodecType = capability.codecType;
258 bestRawType = capability.rawType;
259 bestformatIndex = tmp;
260 }
261 }
262 }// else height not good
263 }//end for
264
265 LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x" << bestHeight
266 << "@" << bestFrameRate
267 << "fps, color format: " << bestRawType;
268
269 // Copy the capability
270 if (bestformatIndex < 0)
271 return -1;
272 resulting = _captureCapabilities[bestformatIndex];
273 return bestformatIndex;
274 }
275
276 /* Returns the expected Capture delay*/
GetExpectedCaptureDelay(const DelayValues delayValues[],const uint32_t sizeOfDelayValues,const char * productId,const uint32_t width,const uint32_t height)277 int32_t DeviceInfoImpl::GetExpectedCaptureDelay(
278 const DelayValues delayValues[],
279 const uint32_t sizeOfDelayValues,
280 const char* productId,
281 const uint32_t width,
282 const uint32_t height)
283 {
284 int32_t bestDelay = kDefaultCaptureDelay;
285
286 for (uint32_t device = 0; device < sizeOfDelayValues; ++device)
287 {
288 if (delayValues[device].productId && strncmp((char*) productId,
289 (char*) delayValues[device].productId,
290 kVideoCaptureProductIdLength) == 0)
291 {
292 // We have found the camera
293
294 int32_t bestWidth = 0;
295 int32_t bestHeight = 0;
296
297 //Loop through all tested sizes and find one that seems fitting
298 for (uint32_t delayIndex = 0; delayIndex < NoOfDelayValues; ++delayIndex)
299 {
300 const DelayValue& currentValue = delayValues[device].delayValues[delayIndex];
301
302 const int32_t diffWidth = currentValue.width - width;
303 const int32_t diffHeight = currentValue.height - height;
304
305 const int32_t currentbestDiffWith = bestWidth - width;
306 const int32_t currentbestDiffHeight = bestHeight - height;
307
308 if ((diffHeight >= 0 && diffHeight <= abs(currentbestDiffHeight)) // Height better or equal than previous.
309 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight))
310 {
311
312 if (diffHeight == currentbestDiffHeight) // Found best height. Care about the width)
313 {
314 if ((diffWidth >= 0 && diffWidth <= abs(currentbestDiffWith)) // Width better or equal
315 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith))
316 {
317 if (diffWidth == currentbestDiffWith && diffHeight
318 == currentbestDiffHeight) // Same size as previous
319 {
320 }
321 else // Better width than previously
322 {
323 bestWidth = currentValue.width;
324 bestHeight = currentValue.height;
325 bestDelay = currentValue.delay;
326 }
327 }// else width no good
328 }
329 else // Better height
330 {
331 bestWidth = currentValue.width;
332 bestHeight = currentValue.height;
333 bestDelay = currentValue.delay;
334 }
335 }// else height not good
336 }//end for
337 break;
338 }
339 }
340 if (bestDelay > kMaxCaptureDelay)
341 {
342 LOG(LS_WARNING) << "Expected capture delay (" << bestDelay
343 << " ms) too high, using " << kMaxCaptureDelay
344 << " ms.";
345 bestDelay = kMaxCaptureDelay;
346 }
347
348 return bestDelay;
349
350 }
351
352 //Default implementation. This should be overridden by Mobile implementations.
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)353 int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
354 VideoRotation& orientation) {
355 orientation = kVideoRotation_0;
356 return -1;
357 }
358 } // namespace videocapturemodule
359 } // namespace webrtc
360