device_info_impl.cc (8662B)
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 "modules/video_capture/device_info_impl.h" 12 13 #include <cstdint> 14 #include <cstdlib> 15 16 #include "absl/strings/match.h" 17 #include "absl/strings/string_view.h" 18 #include "api/video/video_rotation.h" 19 #include "common_video/libyuv/include/webrtc_libyuv.h" 20 #include "modules/video_capture/video_capture_defines.h" 21 #include "rtc_base/checks.h" 22 #include "rtc_base/logging.h" 23 #include "rtc_base/synchronization/mutex.h" 24 25 #ifndef abs 26 #define abs(a) (a >= 0 ? a : -a) 27 #endif 28 29 namespace webrtc { 30 namespace videocapturemodule { 31 32 DeviceInfoImpl::DeviceInfoImpl() 33 : _lastUsedDeviceName(nullptr), _lastUsedDeviceNameLength(0) {} 34 35 DeviceInfoImpl::~DeviceInfoImpl(void) { 36 MutexLock lock(&_apiLock); 37 free(_lastUsedDeviceName); 38 } 39 40 int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) { 41 if (!deviceUniqueIdUTF8) 42 return -1; 43 44 MutexLock lock(&_apiLock); 45 46 // Is it the same device that is asked for again. 47 if (absl::EqualsIgnoreCase( 48 deviceUniqueIdUTF8, 49 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) { 50 return static_cast<int32_t>(_captureCapabilities.size()); 51 } 52 53 int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8); 54 return ret; 55 } 56 57 int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8, 58 const uint32_t deviceCapabilityNumber, 59 VideoCaptureCapability& capability) { 60 RTC_DCHECK(deviceUniqueIdUTF8); 61 62 MutexLock lock(&_apiLock); 63 64 if (!absl::EqualsIgnoreCase( 65 deviceUniqueIdUTF8, 66 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) { 67 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) { 68 return -1; 69 } 70 } 71 72 // Make sure the number is valid 73 if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) { 74 RTC_LOG(LS_ERROR) << deviceUniqueIdUTF8 << " Invalid deviceCapabilityNumber " 75 << deviceCapabilityNumber << ">= number of capabilities (" 76 << _captureCapabilities.size() << ")."; 77 return -1; 78 } 79 80 capability = _captureCapabilities[deviceCapabilityNumber]; 81 return 0; 82 } 83 84 int32_t DeviceInfoImpl::GetBestMatchedCapability( 85 const char* deviceUniqueIdUTF8, 86 const VideoCaptureCapability& requested, 87 VideoCaptureCapability& resulting) { 88 if (!deviceUniqueIdUTF8) 89 return -1; 90 91 MutexLock lock(&_apiLock); 92 if (!absl::EqualsIgnoreCase( 93 deviceUniqueIdUTF8, 94 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) { 95 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) { 96 return -1; 97 } 98 } 99 100 int32_t bestformatIndex = -1; 101 int32_t bestWidth = 0; 102 int32_t bestHeight = 0; 103 int32_t bestFrameRate = 0; 104 VideoType bestVideoType = VideoType::kUnknown; 105 106 const int32_t numberOfCapabilies = 107 static_cast<int32_t>(_captureCapabilities.size()); 108 109 bool hasNonRGB24Capability = false; 110 for (int32_t tmp = 0; tmp < numberOfCapabilies; 111 ++tmp) // Loop through all capabilities 112 { 113 VideoCaptureCapability& capability = _captureCapabilities[tmp]; 114 if (capability.videoType != VideoType::kRGB24) { 115 hasNonRGB24Capability = true; 116 } 117 } 118 119 for (int32_t tmp = 0; tmp < numberOfCapabilies; 120 ++tmp) // Loop through all capabilities 121 { 122 VideoCaptureCapability& capability = _captureCapabilities[tmp]; 123 if (hasNonRGB24Capability && capability.videoType == VideoType::kRGB24) { 124 continue; 125 } 126 127 const int32_t diffWidth = capability.width - requested.width; 128 const int32_t diffHeight = capability.height - requested.height; 129 const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS; 130 131 const int32_t currentbestDiffWith = bestWidth - requested.width; 132 const int32_t currentbestDiffHeight = bestHeight - requested.height; 133 const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS; 134 135 if ((diffHeight >= 0 && 136 diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt 137 // that previouse. 138 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) { 139 if (diffHeight == 140 currentbestDiffHeight) // Found best height. Care about the width) 141 { 142 if ((diffWidth >= 0 && 143 diffWidth <= abs(currentbestDiffWith)) // Width better or equal 144 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) { 145 if (diffWidth == currentbestDiffWith && 146 diffHeight == currentbestDiffHeight) // Same size as previously 147 { 148 // Also check the best frame rate if the diff is the same as 149 // previouse 150 if (((diffFrameRate >= 0 && 151 diffFrameRate <= 152 currentbestDiffFrameRate) // Frame rate to high but 153 // better match than previouse 154 // and we have not selected IUV 155 || (currentbestDiffFrameRate < 0 && 156 diffFrameRate >= 157 currentbestDiffFrameRate)) // Current frame rate is 158 // lower than requested. 159 // This is better. 160 ) { 161 if ((currentbestDiffFrameRate == 162 diffFrameRate) // Same frame rate as previous or frame rate 163 // allready good enough 164 || (currentbestDiffFrameRate >= 0)) { 165 if (bestVideoType != requested.videoType && 166 requested.videoType != VideoType::kUnknown && 167 (capability.videoType == requested.videoType || 168 capability.videoType == VideoType::kI420 || 169 capability.videoType == VideoType::kYUY2 || 170 capability.videoType == VideoType::kYV12 || 171 capability.videoType == VideoType::kNV12)) { 172 bestVideoType = capability.videoType; 173 bestformatIndex = tmp; 174 } 175 // If width height and frame rate is full filled we can use the 176 // camera for encoding if it is supported. 177 if (capability.height == requested.height && 178 capability.width == requested.width && 179 capability.maxFPS >= requested.maxFPS) { 180 bestVideoType = capability.videoType; 181 bestformatIndex = tmp; 182 } 183 } else // Better frame rate 184 { 185 bestWidth = capability.width; 186 bestHeight = capability.height; 187 bestFrameRate = capability.maxFPS; 188 bestVideoType = capability.videoType; 189 bestformatIndex = tmp; 190 } 191 } 192 } else // Better width than previously 193 { 194 bestWidth = capability.width; 195 bestHeight = capability.height; 196 bestFrameRate = capability.maxFPS; 197 bestVideoType = capability.videoType; 198 bestformatIndex = tmp; 199 } 200 } // else width no good 201 } else // Better height 202 { 203 bestWidth = capability.width; 204 bestHeight = capability.height; 205 bestFrameRate = capability.maxFPS; 206 bestVideoType = capability.videoType; 207 bestformatIndex = tmp; 208 } 209 } // else height not good 210 } // end for 211 212 RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x" 213 << bestHeight << "@" << bestFrameRate 214 << "fps, color format: " 215 << static_cast<int>(bestVideoType); 216 217 // Copy the capability 218 if (bestformatIndex < 0) 219 return -1; 220 resulting = _captureCapabilities[bestformatIndex]; 221 return bestformatIndex; 222 } 223 224 // Default implementation. This should be overridden by Mobile implementations. 225 int32_t DeviceInfoImpl::GetOrientation(const char* /* deviceUniqueIdUTF8 */, 226 VideoRotation& orientation) { 227 orientation = kVideoRotation_0; 228 return -1; 229 } 230 } // namespace videocapturemodule 231 } // namespace webrtc