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