blob: 2f0a39f2964fb37c703f9864f14ad77a0eb361fa [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"
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080017#include "rtc_base/stringutils.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000018
niklase@google.com470e71d2011-07-07 08:21:25 +000019#ifndef abs
Mirko Bonadei72c42502017-11-09 09:33:23 +010020#define abs(a) (a >= 0 ? a : -a)
niklase@google.com470e71d2011-07-07 08:21:25 +000021#endif
22
Mirko Bonadei72c42502017-11-09 09:33:23 +010023namespace webrtc {
24namespace videocapturemodule {
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080025
nisseb29b9c82016-12-12 00:22:56 -080026DeviceInfoImpl::DeviceInfoImpl()
Mirko Bonadei72c42502017-11-09 09:33:23 +010027 : _apiLock(*RWLockWrapper::CreateRWLock()),
28 _lastUsedDeviceName(NULL),
29 _lastUsedDeviceNameLength(0) {}
30
31DeviceInfoImpl::~DeviceInfoImpl(void) {
32 _apiLock.AcquireLockExclusive();
33 free(_lastUsedDeviceName);
34 _apiLock.ReleaseLockExclusive();
35
36 delete &_apiLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000037}
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080038
Mirko Bonadei72c42502017-11-09 09:33:23 +010039int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
40 if (!deviceUniqueIdUTF8)
41 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000042
Mirko Bonadei72c42502017-11-09 09:33:23 +010043 _apiLock.AcquireLockShared();
niklase@google.com470e71d2011-07-07 08:21:25 +000044
Mirko Bonadei72c42502017-11-09 09:33:23 +010045 if (_lastUsedDeviceNameLength == strlen((char*)deviceUniqueIdUTF8)) {
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080046 // Is it the same device that is asked for again.
Mirko Bonadei72c42502017-11-09 09:33:23 +010047 if (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080048 _lastUsedDeviceNameLength) == 0) {
Mirko Bonadei72c42502017-11-09 09:33:23 +010049 // yes
50 _apiLock.ReleaseLockShared();
51 return static_cast<int32_t>(_captureCapabilities.size());
niklase@google.com470e71d2011-07-07 08:21:25 +000052 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010053 }
54 // Need to get exclusive rights to create the new capability map.
55 _apiLock.ReleaseLockShared();
56 WriteLockScoped cs2(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000057
Mirko Bonadei72c42502017-11-09 09:33:23 +010058 int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
59 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +000060}
61
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000062int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
63 const uint32_t deviceCapabilityNumber,
Mirko Bonadei72c42502017-11-09 09:33:23 +010064 VideoCaptureCapability& capability) {
65 assert(deviceUniqueIdUTF8 != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000066
Mirko Bonadei72c42502017-11-09 09:33:23 +010067 ReadLockScoped cs(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000068
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080069 if ((_lastUsedDeviceNameLength != strlen((char*)deviceUniqueIdUTF8)) ||
70 (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
71 _lastUsedDeviceNameLength) != 0)) {
Mirko Bonadei72c42502017-11-09 09:33:23 +010072 _apiLock.ReleaseLockShared();
73 _apiLock.AcquireLockExclusive();
74 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
75 _apiLock.ReleaseLockExclusive();
76 _apiLock.AcquireLockShared();
77 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000078 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010079 _apiLock.ReleaseLockExclusive();
80 _apiLock.AcquireLockShared();
81 }
niklase@google.com470e71d2011-07-07 08:21:25 +000082
Mirko Bonadei72c42502017-11-09 09:33:23 +010083 // Make sure the number is valid
84 if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010085 RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
86 << deviceCapabilityNumber << ">= number of capabilities ("
87 << _captureCapabilities.size() << ").";
Mirko Bonadei72c42502017-11-09 09:33:23 +010088 return -1;
89 }
niklase@google.com470e71d2011-07-07 08:21:25 +000090
Mirko Bonadei72c42502017-11-09 09:33:23 +010091 capability = _captureCapabilities[deviceCapabilityNumber];
92 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000093}
94
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000095int32_t DeviceInfoImpl::GetBestMatchedCapability(
Mirko Bonadei72c42502017-11-09 09:33:23 +010096 const char* deviceUniqueIdUTF8,
97 const VideoCaptureCapability& requested,
98 VideoCaptureCapability& resulting) {
99 if (!deviceUniqueIdUTF8)
100 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
Mirko Bonadei72c42502017-11-09 09:33:23 +0100102 ReadLockScoped cs(_apiLock);
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800103 if ((_lastUsedDeviceNameLength != strlen((char*)deviceUniqueIdUTF8)) ||
104 (_strnicmp((char*)_lastUsedDeviceName, (char*)deviceUniqueIdUTF8,
105 _lastUsedDeviceNameLength) != 0)) {
Mirko Bonadei72c42502017-11-09 09:33:23 +0100106 _apiLock.ReleaseLockShared();
107 _apiLock.AcquireLockExclusive();
108 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
109 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100111 _apiLock.ReleaseLockExclusive();
112 _apiLock.AcquireLockShared();
113 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000114
Mirko Bonadei72c42502017-11-09 09:33:23 +0100115 int32_t bestformatIndex = -1;
116 int32_t bestWidth = 0;
117 int32_t bestHeight = 0;
118 int32_t bestFrameRate = 0;
119 VideoType bestVideoType = VideoType::kUnknown;
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
Mirko Bonadei72c42502017-11-09 09:33:23 +0100121 const int32_t numberOfCapabilies =
122 static_cast<int32_t>(_captureCapabilities.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
Mirko Bonadei72c42502017-11-09 09:33:23 +0100124 for (int32_t tmp = 0; tmp < numberOfCapabilies;
125 ++tmp) // Loop through all capabilities
126 {
127 VideoCaptureCapability& capability = _captureCapabilities[tmp];
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
Mirko Bonadei72c42502017-11-09 09:33:23 +0100129 const int32_t diffWidth = capability.width - requested.width;
130 const int32_t diffHeight = capability.height - requested.height;
131 const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000132
Mirko Bonadei72c42502017-11-09 09:33:23 +0100133 const int32_t currentbestDiffWith = bestWidth - requested.width;
134 const int32_t currentbestDiffHeight = bestHeight - requested.height;
135 const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
Mirko Bonadei72c42502017-11-09 09:33:23 +0100137 if ((diffHeight >= 0 &&
138 diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt
139 // that previouse.
140 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) {
141 if (diffHeight ==
142 currentbestDiffHeight) // Found best height. Care about the width)
143 {
144 if ((diffWidth >= 0 &&
145 diffWidth <= abs(currentbestDiffWith)) // Width better or equal
146 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) {
147 if (diffWidth == currentbestDiffWith &&
148 diffHeight == currentbestDiffHeight) // Same size as previously
149 {
150 // Also check the best frame rate if the diff is the same as
151 // previouse
152 if (((diffFrameRate >= 0 &&
153 diffFrameRate <=
154 currentbestDiffFrameRate) // Frame rate to high but
155 // better match than previouse
156 // and we have not selected IUV
157 || (currentbestDiffFrameRate < 0 &&
158 diffFrameRate >=
159 currentbestDiffFrameRate)) // Current frame rate is
160 // lower than requested.
161 // This is better.
162 ) {
163 if ((currentbestDiffFrameRate ==
164 diffFrameRate) // Same frame rate as previous or frame rate
165 // allready good enough
166 || (currentbestDiffFrameRate >= 0)) {
167 if (bestVideoType != requested.videoType &&
168 requested.videoType != VideoType::kUnknown &&
169 (capability.videoType == requested.videoType ||
170 capability.videoType == VideoType::kI420 ||
171 capability.videoType == VideoType::kYUY2 ||
172 capability.videoType == VideoType::kYV12)) {
173 bestVideoType = capability.videoType;
174 bestformatIndex = tmp;
175 }
176 // If width height and frame rate is full filled we can use the
177 // camera for encoding if it is supported.
178 if (capability.height == requested.height &&
179 capability.width == requested.width &&
180 capability.maxFPS >= requested.maxFPS) {
181 bestformatIndex = tmp;
182 }
183 } else // Better frame rate
184 {
nisse1e321222017-02-20 23:27:37 -0800185 bestWidth = capability.width;
186 bestHeight = capability.height;
187 bestFrameRate = capability.maxFPS;
nisseeb44b392017-04-28 07:18:05 -0700188 bestVideoType = capability.videoType;
nisse1e321222017-02-20 23:27:37 -0800189 bestformatIndex = tmp;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100190 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100192 } 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
niklase@google.com470e71d2011-07-07 08:21:25 +0000211
Mirko Bonadei675513b2017-11-09 11:09:25 +0100212 RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
213 << bestHeight << "@" << bestFrameRate
214 << "fps, color format: "
215 << static_cast<int>(bestVideoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216
Mirko Bonadei72c42502017-11-09 09:33:23 +0100217 // Copy the capability
218 if (bestformatIndex < 0)
219 return -1;
220 resulting = _captureCapabilities[bestformatIndex];
221 return bestformatIndex;
niklase@google.com470e71d2011-07-07 08:21:25 +0000222}
223
Mirko Bonadei72c42502017-11-09 09:33:23 +0100224// Default implementation. This should be overridden by Mobile implementations.
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000225int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +0000226 VideoRotation& orientation) {
227 orientation = kVideoRotation_0;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100228 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000229}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000230} // namespace videocapturemodule
231} // namespace webrtc