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 22namespace webrtc 23{ 24namespace videocapturemodule 25{ 26DeviceInfoImpl::DeviceInfoImpl(const int32_t id) 27 : _id(id), _apiLock(*RWLockWrapper::CreateRWLock()), _lastUsedDeviceName(NULL), 28 _lastUsedDeviceNameLength(0) 29{ 30} 31 32DeviceInfoImpl::~DeviceInfoImpl(void) 33{ 34 _apiLock.AcquireLockExclusive(); 35 free(_lastUsedDeviceName); 36 _apiLock.ReleaseLockExclusive(); 37 38 delete &_apiLock; 39} 40int32_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 75int32_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 120int32_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*/ 277int32_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. 353int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, 354 VideoRotation& orientation) { 355 orientation = kVideoRotation_0; 356 return -1; 357} 358} // namespace videocapturemodule 359} // namespace webrtc 360