• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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