| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| |
| #include "modules/video_capture/device_info_impl.h" |
| #include "modules/video_capture/video_capture_config.h" |
| #include "rtc_base/logging.h" |
| |
| #ifndef abs |
| #define abs(a) (a>=0?a:-a) |
| #endif |
| |
| namespace webrtc |
| { |
| namespace videocapturemodule |
| { |
| DeviceInfoImpl::DeviceInfoImpl() |
| : _apiLock(*RWLockWrapper::CreateRWLock()), _lastUsedDeviceName(NULL), |
| _lastUsedDeviceNameLength(0) |
| { |
| } |
| |
| DeviceInfoImpl::~DeviceInfoImpl(void) |
| { |
| _apiLock.AcquireLockExclusive(); |
| free(_lastUsedDeviceName); |
| _apiLock.ReleaseLockExclusive(); |
| |
| delete &_apiLock; |
| } |
| int32_t DeviceInfoImpl::NumberOfCapabilities( |
| const char* deviceUniqueIdUTF8) |
| { |
| |
| if (!deviceUniqueIdUTF8) |
| return -1; |
| |
| _apiLock.AcquireLockShared(); |
| |
| if (_lastUsedDeviceNameLength == strlen((char*) deviceUniqueIdUTF8)) |
| { |
| // Is it the same device that is asked for again. |
| #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX) |
| if(strncasecmp((char*)_lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength)==0) |
| #else |
| if (_strnicmp((char*) _lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength) == 0) |
| #endif |
| { |
| //yes |
| _apiLock.ReleaseLockShared(); |
| return static_cast<int32_t>(_captureCapabilities.size()); |
| } |
| } |
| // Need to get exclusive rights to create the new capability map. |
| _apiLock.ReleaseLockShared(); |
| WriteLockScoped cs2(_apiLock); |
| |
| int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8); |
| return ret; |
| } |
| |
| int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8, |
| const uint32_t deviceCapabilityNumber, |
| VideoCaptureCapability& capability) |
| { |
| assert(deviceUniqueIdUTF8 != NULL); |
| |
| ReadLockScoped cs(_apiLock); |
| |
| if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8)) |
| #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX) |
| || (strncasecmp((char*)_lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength)!=0)) |
| #else |
| || (_strnicmp((char*) _lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength) != 0)) |
| #endif |
| |
| { |
| _apiLock.ReleaseLockShared(); |
| _apiLock.AcquireLockExclusive(); |
| if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) |
| { |
| _apiLock.ReleaseLockExclusive(); |
| _apiLock.AcquireLockShared(); |
| return -1; |
| } |
| _apiLock.ReleaseLockExclusive(); |
| _apiLock.AcquireLockShared(); |
| } |
| |
| // Make sure the number is valid |
| if (deviceCapabilityNumber >= (unsigned int) _captureCapabilities.size()) |
| { |
| LOG(LS_ERROR) << "Invalid deviceCapabilityNumber " |
| << deviceCapabilityNumber << ">= number of capabilities (" |
| << _captureCapabilities.size() << ")."; |
| return -1; |
| } |
| |
| capability = _captureCapabilities[deviceCapabilityNumber]; |
| return 0; |
| } |
| |
| int32_t DeviceInfoImpl::GetBestMatchedCapability( |
| const char*deviceUniqueIdUTF8, |
| const VideoCaptureCapability& requested, |
| VideoCaptureCapability& resulting) |
| { |
| |
| |
| if (!deviceUniqueIdUTF8) |
| return -1; |
| |
| ReadLockScoped cs(_apiLock); |
| if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8)) |
| #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX) |
| || (strncasecmp((char*)_lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength)!=0)) |
| #else |
| || (_strnicmp((char*) _lastUsedDeviceName, |
| (char*) deviceUniqueIdUTF8, |
| _lastUsedDeviceNameLength) != 0)) |
| #endif |
| { |
| _apiLock.ReleaseLockShared(); |
| _apiLock.AcquireLockExclusive(); |
| if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) |
| { |
| return -1; |
| } |
| _apiLock.ReleaseLockExclusive(); |
| _apiLock.AcquireLockShared(); |
| } |
| |
| int32_t bestformatIndex = -1; |
| int32_t bestWidth = 0; |
| int32_t bestHeight = 0; |
| int32_t bestFrameRate = 0; |
| VideoType bestVideoType = VideoType::kUnknown; |
| |
| const int32_t numberOfCapabilies = |
| static_cast<int32_t>(_captureCapabilities.size()); |
| |
| for (int32_t tmp = 0; tmp < numberOfCapabilies; ++tmp) // Loop through all capabilities |
| { |
| VideoCaptureCapability& capability = _captureCapabilities[tmp]; |
| |
| const int32_t diffWidth = capability.width - requested.width; |
| const int32_t diffHeight = capability.height - requested.height; |
| const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS; |
| |
| const int32_t currentbestDiffWith = bestWidth - requested.width; |
| const int32_t currentbestDiffHeight = bestHeight - requested.height; |
| const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS; |
| |
| if ((diffHeight >= 0 && diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt that previouse. |
| || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) |
| { |
| |
| if (diffHeight == currentbestDiffHeight) // Found best height. Care about the width) |
| { |
| if ((diffWidth >= 0 && diffWidth <= abs(currentbestDiffWith)) // Width better or equal |
| || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) |
| { |
| if (diffWidth == currentbestDiffWith && diffHeight |
| == currentbestDiffHeight) // Same size as previously |
| { |
| //Also check the best frame rate if the diff is the same as previouse |
| if (((diffFrameRate >= 0 && |
| diffFrameRate <= currentbestDiffFrameRate) // Frame rate to high but better match than previouse and we have not selected IUV |
| || |
| (currentbestDiffFrameRate < 0 && |
| diffFrameRate >= currentbestDiffFrameRate)) // Current frame rate is lower than requested. This is better. |
| ) |
| { |
| if ((currentbestDiffFrameRate == diffFrameRate) // Same frame rate as previous or frame rate allready good enough |
| || (currentbestDiffFrameRate >= 0)) |
| { |
| if (bestVideoType != requested.videoType && |
| requested.videoType != VideoType::kUnknown && |
| (capability.videoType == |
| requested.videoType || |
| capability.videoType == VideoType::kI420 || |
| capability.videoType == VideoType::kYUY2 || |
| capability.videoType == VideoType::kYV12)) { |
| bestVideoType = capability.videoType; |
| bestformatIndex = tmp; |
| } |
| // If width height and frame rate is full filled we can use the camera for encoding if it is supported. |
| if (capability.height == requested.height |
| && capability.width == requested.width |
| && capability.maxFPS >= requested.maxFPS) |
| { |
| bestformatIndex = tmp; |
| } |
| } |
| else // Better frame rate |
| { |
| bestWidth = capability.width; |
| bestHeight = capability.height; |
| bestFrameRate = capability.maxFPS; |
| bestVideoType = capability.videoType; |
| bestformatIndex = tmp; |
| } |
| } |
| } |
| else // Better width than previously |
| { |
| bestWidth = capability.width; |
| bestHeight = capability.height; |
| bestFrameRate = capability.maxFPS; |
| bestVideoType = capability.videoType; |
| bestformatIndex = tmp; |
| } |
| }// else width no good |
| } |
| else // Better height |
| { |
| bestWidth = capability.width; |
| bestHeight = capability.height; |
| bestFrameRate = capability.maxFPS; |
| bestVideoType = capability.videoType; |
| bestformatIndex = tmp; |
| } |
| }// else height not good |
| }//end for |
| |
| LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x" << bestHeight |
| << "@" << bestFrameRate |
| << "fps, color format: " << static_cast<int>(bestVideoType); |
| |
| // Copy the capability |
| if (bestformatIndex < 0) |
| return -1; |
| resulting = _captureCapabilities[bestformatIndex]; |
| return bestformatIndex; |
| } |
| |
| //Default implementation. This should be overridden by Mobile implementations. |
| int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8, |
| VideoRotation& orientation) { |
| orientation = kVideoRotation_0; |
| return -1; |
| } |
| } // namespace videocapturemodule |
| } // namespace webrtc |