blob: 0f8198c97174d1a2c440e7d2791ee9487e454732 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mallinath@webrtc.org12984f02012-02-16 18:18:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +000011#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000012#include <stdlib.h>
13
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "modules/video_capture/device_info_impl.h"
15#include "modules/video_capture/video_capture_config.h"
16#include "rtc_base/logging.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000017
niklase@google.com470e71d2011-07-07 08:21:25 +000018#ifndef abs
Mirko Bonadei72c42502017-11-09 09:33:23 +010019#define abs(a) (a >= 0 ? a : -a)
niklase@google.com470e71d2011-07-07 08:21:25 +000020#endif
21
Mirko Bonadei72c42502017-11-09 09:33:23 +010022namespace webrtc {
23namespace videocapturemodule {
nisseb29b9c82016-12-12 00:22:56 -080024DeviceInfoImpl::DeviceInfoImpl()
Mirko Bonadei72c42502017-11-09 09:33:23 +010025 : _apiLock(*RWLockWrapper::CreateRWLock()),
26 _lastUsedDeviceName(NULL),
27 _lastUsedDeviceNameLength(0) {}
28
29DeviceInfoImpl::~DeviceInfoImpl(void) {
30 _apiLock.AcquireLockExclusive();
31 free(_lastUsedDeviceName);
32 _apiLock.ReleaseLockExclusive();
33
34 delete &_apiLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
Mirko Bonadei72c42502017-11-09 09:33:23 +010036int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
37 if (!deviceUniqueIdUTF8)
38 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000039
Mirko Bonadei72c42502017-11-09 09:33:23 +010040 _apiLock.AcquireLockShared();
niklase@google.com470e71d2011-07-07 08:21:25 +000041
Mirko Bonadei72c42502017-11-09 09:33:23 +010042 if (_lastUsedDeviceNameLength == strlen((char*)deviceUniqueIdUTF8)) {
43// Is it the same device that is asked for again.
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +000044#if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
Mirko Bonadei72c42502017-11-09 09:33:23 +010045 if (strncasecmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
46 _lastUsedDeviceNameLength) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +000047#else
Mirko Bonadei72c42502017-11-09 09:33:23 +010048 if (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
49 _lastUsedDeviceNameLength) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +000050#endif
Mirko Bonadei72c42502017-11-09 09:33:23 +010051 {
52 // yes
53 _apiLock.ReleaseLockShared();
54 return static_cast<int32_t>(_captureCapabilities.size());
niklase@google.com470e71d2011-07-07 08:21:25 +000055 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010056 }
57 // Need to get exclusive rights to create the new capability map.
58 _apiLock.ReleaseLockShared();
59 WriteLockScoped cs2(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000060
Mirko Bonadei72c42502017-11-09 09:33:23 +010061 int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
62 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +000063}
64
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000065int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
66 const uint32_t deviceCapabilityNumber,
Mirko Bonadei72c42502017-11-09 09:33:23 +010067 VideoCaptureCapability& capability) {
68 assert(deviceUniqueIdUTF8 != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000069
Mirko Bonadei72c42502017-11-09 09:33:23 +010070 ReadLockScoped cs(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000071
Mirko Bonadei72c42502017-11-09 09:33:23 +010072 if ((_lastUsedDeviceNameLength != strlen((char*)deviceUniqueIdUTF8))
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +000073#if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
Mirko Bonadei72c42502017-11-09 09:33:23 +010074 || (strncasecmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
niklase@google.com470e71d2011-07-07 08:21:25 +000075 _lastUsedDeviceNameLength) != 0))
Mirko Bonadei72c42502017-11-09 09:33:23 +010076#else
77 || (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
78 _lastUsedDeviceNameLength) != 0))
niklase@google.com470e71d2011-07-07 08:21:25 +000079#endif
80
Mirko Bonadei72c42502017-11-09 09:33:23 +010081 {
82 _apiLock.ReleaseLockShared();
83 _apiLock.AcquireLockExclusive();
84 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
85 _apiLock.ReleaseLockExclusive();
86 _apiLock.AcquireLockShared();
87 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000088 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010089 _apiLock.ReleaseLockExclusive();
90 _apiLock.AcquireLockShared();
91 }
niklase@google.com470e71d2011-07-07 08:21:25 +000092
Mirko Bonadei72c42502017-11-09 09:33:23 +010093 // Make sure the number is valid
94 if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010095 RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
96 << deviceCapabilityNumber << ">= number of capabilities ("
97 << _captureCapabilities.size() << ").";
Mirko Bonadei72c42502017-11-09 09:33:23 +010098 return -1;
99 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
Mirko Bonadei72c42502017-11-09 09:33:23 +0100101 capability = _captureCapabilities[deviceCapabilityNumber];
102 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103}
104
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000105int32_t DeviceInfoImpl::GetBestMatchedCapability(
Mirko Bonadei72c42502017-11-09 09:33:23 +0100106 const char* deviceUniqueIdUTF8,
107 const VideoCaptureCapability& requested,
108 VideoCaptureCapability& resulting) {
109 if (!deviceUniqueIdUTF8)
110 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
Mirko Bonadei72c42502017-11-09 09:33:23 +0100112 ReadLockScoped cs(_apiLock);
113 if ((_lastUsedDeviceNameLength != strlen((char*)deviceUniqueIdUTF8))
andrew@webrtc.orgf3b65db2012-09-06 18:17:00 +0000114#if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
Mirko Bonadei72c42502017-11-09 09:33:23 +0100115 || (strncasecmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 _lastUsedDeviceNameLength) != 0))
Mirko Bonadei72c42502017-11-09 09:33:23 +0100117#else
118 || (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
119 _lastUsedDeviceNameLength) != 0))
niklase@google.com470e71d2011-07-07 08:21:25 +0000120#endif
Mirko Bonadei72c42502017-11-09 09:33:23 +0100121 {
122 _apiLock.ReleaseLockShared();
123 _apiLock.AcquireLockExclusive();
124 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
125 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100127 _apiLock.ReleaseLockExclusive();
128 _apiLock.AcquireLockShared();
129 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000130
Mirko Bonadei72c42502017-11-09 09:33:23 +0100131 int32_t bestformatIndex = -1;
132 int32_t bestWidth = 0;
133 int32_t bestHeight = 0;
134 int32_t bestFrameRate = 0;
135 VideoType bestVideoType = VideoType::kUnknown;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
Mirko Bonadei72c42502017-11-09 09:33:23 +0100137 const int32_t numberOfCapabilies =
138 static_cast<int32_t>(_captureCapabilities.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000139
Mirko Bonadei72c42502017-11-09 09:33:23 +0100140 for (int32_t tmp = 0; tmp < numberOfCapabilies;
141 ++tmp) // Loop through all capabilities
142 {
143 VideoCaptureCapability& capability = _captureCapabilities[tmp];
niklase@google.com470e71d2011-07-07 08:21:25 +0000144
Mirko Bonadei72c42502017-11-09 09:33:23 +0100145 const int32_t diffWidth = capability.width - requested.width;
146 const int32_t diffHeight = capability.height - requested.height;
147 const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
Mirko Bonadei72c42502017-11-09 09:33:23 +0100149 const int32_t currentbestDiffWith = bestWidth - requested.width;
150 const int32_t currentbestDiffHeight = bestHeight - requested.height;
151 const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000152
Mirko Bonadei72c42502017-11-09 09:33:23 +0100153 if ((diffHeight >= 0 &&
154 diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt
155 // that previouse.
156 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) {
157 if (diffHeight ==
158 currentbestDiffHeight) // Found best height. Care about the width)
159 {
160 if ((diffWidth >= 0 &&
161 diffWidth <= abs(currentbestDiffWith)) // Width better or equal
162 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) {
163 if (diffWidth == currentbestDiffWith &&
164 diffHeight == currentbestDiffHeight) // Same size as previously
165 {
166 // Also check the best frame rate if the diff is the same as
167 // previouse
168 if (((diffFrameRate >= 0 &&
169 diffFrameRate <=
170 currentbestDiffFrameRate) // Frame rate to high but
171 // better match than previouse
172 // and we have not selected IUV
173 || (currentbestDiffFrameRate < 0 &&
174 diffFrameRate >=
175 currentbestDiffFrameRate)) // Current frame rate is
176 // lower than requested.
177 // This is better.
178 ) {
179 if ((currentbestDiffFrameRate ==
180 diffFrameRate) // Same frame rate as previous or frame rate
181 // allready good enough
182 || (currentbestDiffFrameRate >= 0)) {
183 if (bestVideoType != requested.videoType &&
184 requested.videoType != VideoType::kUnknown &&
185 (capability.videoType == requested.videoType ||
186 capability.videoType == VideoType::kI420 ||
187 capability.videoType == VideoType::kYUY2 ||
188 capability.videoType == VideoType::kYV12)) {
189 bestVideoType = capability.videoType;
190 bestformatIndex = tmp;
191 }
192 // If width height and frame rate is full filled we can use the
193 // camera for encoding if it is supported.
194 if (capability.height == requested.height &&
195 capability.width == requested.width &&
196 capability.maxFPS >= requested.maxFPS) {
197 bestformatIndex = tmp;
198 }
199 } else // Better frame rate
200 {
nisse1e321222017-02-20 23:27:37 -0800201 bestWidth = capability.width;
202 bestHeight = capability.height;
203 bestFrameRate = capability.maxFPS;
nisseeb44b392017-04-28 07:18:05 -0700204 bestVideoType = capability.videoType;
nisse1e321222017-02-20 23:27:37 -0800205 bestformatIndex = tmp;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100206 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100208 } else // Better width than previously
209 {
210 bestWidth = capability.width;
211 bestHeight = capability.height;
212 bestFrameRate = capability.maxFPS;
213 bestVideoType = capability.videoType;
214 bestformatIndex = tmp;
215 }
216 } // else width no good
217 } else // Better height
218 {
219 bestWidth = capability.width;
220 bestHeight = capability.height;
221 bestFrameRate = capability.maxFPS;
222 bestVideoType = capability.videoType;
223 bestformatIndex = tmp;
224 }
225 } // else height not good
226 } // end for
niklase@google.com470e71d2011-07-07 08:21:25 +0000227
Mirko Bonadei675513b2017-11-09 11:09:25 +0100228 RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
229 << bestHeight << "@" << bestFrameRate
230 << "fps, color format: "
231 << static_cast<int>(bestVideoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
Mirko Bonadei72c42502017-11-09 09:33:23 +0100233 // Copy the capability
234 if (bestformatIndex < 0)
235 return -1;
236 resulting = _captureCapabilities[bestformatIndex];
237 return bestformatIndex;
niklase@google.com470e71d2011-07-07 08:21:25 +0000238}
239
Mirko Bonadei72c42502017-11-09 09:33:23 +0100240// Default implementation. This should be overridden by Mobile implementations.
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000241int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +0000242 VideoRotation& orientation) {
243 orientation = kVideoRotation_0;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000246} // namespace videocapturemodule
247} // namespace webrtc