blob: 91a72326cf7fa8283690bbb6d45c0ad5acf71178 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "modules/video_capture/device_info_impl.h"
12
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <stdlib.h>
15
Niels Mölleraa3c1cc2018-11-02 10:54:56 +010016#include "absl/strings/match.h"
Yves Gerey3e707812018-11-28 16:47:49 +010017#include "absl/strings/string_view.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/logging.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000019
niklase@google.com470e71d2011-07-07 08:21:25 +000020#ifndef abs
Mirko Bonadei72c42502017-11-09 09:33:23 +010021#define abs(a) (a >= 0 ? a : -a)
niklase@google.com470e71d2011-07-07 08:21:25 +000022#endif
23
Mirko Bonadei72c42502017-11-09 09:33:23 +010024namespace webrtc {
25namespace videocapturemodule {
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080026
nisseb29b9c82016-12-12 00:22:56 -080027DeviceInfoImpl::DeviceInfoImpl()
Mirko Bonadei72c42502017-11-09 09:33:23 +010028 : _apiLock(*RWLockWrapper::CreateRWLock()),
29 _lastUsedDeviceName(NULL),
30 _lastUsedDeviceNameLength(0) {}
31
32DeviceInfoImpl::~DeviceInfoImpl(void) {
33 _apiLock.AcquireLockExclusive();
34 free(_lastUsedDeviceName);
35 _apiLock.ReleaseLockExclusive();
36
37 delete &_apiLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000038}
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080039
Mirko Bonadei72c42502017-11-09 09:33:23 +010040int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
41 if (!deviceUniqueIdUTF8)
42 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000043
Mirko Bonadei72c42502017-11-09 09:33:23 +010044 _apiLock.AcquireLockShared();
niklase@google.com470e71d2011-07-07 08:21:25 +000045
Niels Mölleraa3c1cc2018-11-02 10:54:56 +010046 // Is it the same device that is asked for again.
47 if (absl::EqualsIgnoreCase(
48 deviceUniqueIdUTF8,
49 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
50 _apiLock.ReleaseLockShared();
51 return static_cast<int32_t>(_captureCapabilities.size());
Mirko Bonadei72c42502017-11-09 09:33:23 +010052 }
53 // Need to get exclusive rights to create the new capability map.
54 _apiLock.ReleaseLockShared();
55 WriteLockScoped cs2(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000056
Mirko Bonadei72c42502017-11-09 09:33:23 +010057 int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
58 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000061int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
62 const uint32_t deviceCapabilityNumber,
Mirko Bonadei72c42502017-11-09 09:33:23 +010063 VideoCaptureCapability& capability) {
64 assert(deviceUniqueIdUTF8 != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000065
Mirko Bonadei72c42502017-11-09 09:33:23 +010066 ReadLockScoped cs(_apiLock);
niklase@google.com470e71d2011-07-07 08:21:25 +000067
Niels Mölleraa3c1cc2018-11-02 10:54:56 +010068 if (!absl::EqualsIgnoreCase(
69 deviceUniqueIdUTF8,
70 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
Mirko Bonadei72c42502017-11-09 09:33:23 +010071 _apiLock.ReleaseLockShared();
72 _apiLock.AcquireLockExclusive();
73 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
74 _apiLock.ReleaseLockExclusive();
75 _apiLock.AcquireLockShared();
76 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000077 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010078 _apiLock.ReleaseLockExclusive();
79 _apiLock.AcquireLockShared();
80 }
niklase@google.com470e71d2011-07-07 08:21:25 +000081
Mirko Bonadei72c42502017-11-09 09:33:23 +010082 // Make sure the number is valid
83 if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010084 RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
85 << deviceCapabilityNumber << ">= number of capabilities ("
86 << _captureCapabilities.size() << ").";
Mirko Bonadei72c42502017-11-09 09:33:23 +010087 return -1;
88 }
niklase@google.com470e71d2011-07-07 08:21:25 +000089
Mirko Bonadei72c42502017-11-09 09:33:23 +010090 capability = _captureCapabilities[deviceCapabilityNumber];
91 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000092}
93
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000094int32_t DeviceInfoImpl::GetBestMatchedCapability(
Mirko Bonadei72c42502017-11-09 09:33:23 +010095 const char* deviceUniqueIdUTF8,
96 const VideoCaptureCapability& requested,
97 VideoCaptureCapability& resulting) {
98 if (!deviceUniqueIdUTF8)
99 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
Mirko Bonadei72c42502017-11-09 09:33:23 +0100101 ReadLockScoped cs(_apiLock);
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100102 if (!absl::EqualsIgnoreCase(
103 deviceUniqueIdUTF8,
104 absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
Mirko Bonadei72c42502017-11-09 09:33:23 +0100105 _apiLock.ReleaseLockShared();
106 _apiLock.AcquireLockExclusive();
107 if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
108 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100110 _apiLock.ReleaseLockExclusive();
111 _apiLock.AcquireLockShared();
112 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
Mirko Bonadei72c42502017-11-09 09:33:23 +0100114 int32_t bestformatIndex = -1;
115 int32_t bestWidth = 0;
116 int32_t bestHeight = 0;
117 int32_t bestFrameRate = 0;
118 VideoType bestVideoType = VideoType::kUnknown;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119
Mirko Bonadei72c42502017-11-09 09:33:23 +0100120 const int32_t numberOfCapabilies =
121 static_cast<int32_t>(_captureCapabilities.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000122
Mirko Bonadei72c42502017-11-09 09:33:23 +0100123 for (int32_t tmp = 0; tmp < numberOfCapabilies;
124 ++tmp) // Loop through all capabilities
125 {
126 VideoCaptureCapability& capability = _captureCapabilities[tmp];
niklase@google.com470e71d2011-07-07 08:21:25 +0000127
Mirko Bonadei72c42502017-11-09 09:33:23 +0100128 const int32_t diffWidth = capability.width - requested.width;
129 const int32_t diffHeight = capability.height - requested.height;
130 const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000131
Mirko Bonadei72c42502017-11-09 09:33:23 +0100132 const int32_t currentbestDiffWith = bestWidth - requested.width;
133 const int32_t currentbestDiffHeight = bestHeight - requested.height;
134 const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
Mirko Bonadei72c42502017-11-09 09:33:23 +0100136 if ((diffHeight >= 0 &&
137 diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt
138 // that previouse.
139 || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) {
140 if (diffHeight ==
141 currentbestDiffHeight) // Found best height. Care about the width)
142 {
143 if ((diffWidth >= 0 &&
144 diffWidth <= abs(currentbestDiffWith)) // Width better or equal
145 || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) {
146 if (diffWidth == currentbestDiffWith &&
147 diffHeight == currentbestDiffHeight) // Same size as previously
148 {
149 // Also check the best frame rate if the diff is the same as
150 // previouse
151 if (((diffFrameRate >= 0 &&
152 diffFrameRate <=
153 currentbestDiffFrameRate) // Frame rate to high but
154 // better match than previouse
155 // and we have not selected IUV
156 || (currentbestDiffFrameRate < 0 &&
157 diffFrameRate >=
158 currentbestDiffFrameRate)) // Current frame rate is
159 // lower than requested.
160 // This is better.
Jonas Olssona4d87372019-07-05 19:08:33 +0200161 ) {
Mirko Bonadei72c42502017-11-09 09:33:23 +0100162 if ((currentbestDiffFrameRate ==
163 diffFrameRate) // Same frame rate as previous or frame rate
164 // allready good enough
165 || (currentbestDiffFrameRate >= 0)) {
166 if (bestVideoType != requested.videoType &&
167 requested.videoType != VideoType::kUnknown &&
168 (capability.videoType == requested.videoType ||
169 capability.videoType == VideoType::kI420 ||
170 capability.videoType == VideoType::kYUY2 ||
171 capability.videoType == VideoType::kYV12)) {
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 bestformatIndex = tmp;
181 }
182 } else // Better frame rate
183 {
nisse1e321222017-02-20 23:27:37 -0800184 bestWidth = capability.width;
185 bestHeight = capability.height;
186 bestFrameRate = capability.maxFPS;
nisseeb44b392017-04-28 07:18:05 -0700187 bestVideoType = capability.videoType;
nisse1e321222017-02-20 23:27:37 -0800188 bestformatIndex = tmp;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100189 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100191 } else // Better width than previously
192 {
193 bestWidth = capability.width;
194 bestHeight = capability.height;
195 bestFrameRate = capability.maxFPS;
196 bestVideoType = capability.videoType;
197 bestformatIndex = tmp;
198 }
199 } // else width no good
200 } else // Better height
201 {
202 bestWidth = capability.width;
203 bestHeight = capability.height;
204 bestFrameRate = capability.maxFPS;
205 bestVideoType = capability.videoType;
206 bestformatIndex = tmp;
207 }
208 } // else height not good
209 } // end for
niklase@google.com470e71d2011-07-07 08:21:25 +0000210
Mirko Bonadei675513b2017-11-09 11:09:25 +0100211 RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
212 << bestHeight << "@" << bestFrameRate
213 << "fps, color format: "
214 << static_cast<int>(bestVideoType);
niklase@google.com470e71d2011-07-07 08:21:25 +0000215
Mirko Bonadei72c42502017-11-09 09:33:23 +0100216 // Copy the capability
217 if (bestformatIndex < 0)
218 return -1;
219 resulting = _captureCapabilities[bestformatIndex];
220 return bestformatIndex;
niklase@google.com470e71d2011-07-07 08:21:25 +0000221}
222
Mirko Bonadei72c42502017-11-09 09:33:23 +0100223// Default implementation. This should be overridden by Mobile implementations.
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000224int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
guoweis@webrtc.org5a7dc392015-02-13 14:31:26 +0000225 VideoRotation& orientation) {
226 orientation = kVideoRotation_0;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100227 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000229} // namespace videocapturemodule
230} // namespace webrtc