• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <assert.h>
14 #include <stdlib.h>
15 
16 #include "absl/strings/match.h"
17 #include "absl/strings/string_view.h"
18 #include "rtc_base/logging.h"
19 
20 #ifndef abs
21 #define abs(a) (a >= 0 ? a : -a)
22 #endif
23 
24 namespace webrtc {
25 namespace videocapturemodule {
26 
DeviceInfoImpl()27 DeviceInfoImpl::DeviceInfoImpl()
28     : _apiLock(*RWLockWrapper::CreateRWLock()),
29       _lastUsedDeviceName(NULL),
30       _lastUsedDeviceNameLength(0) {}
31 
~DeviceInfoImpl(void)32 DeviceInfoImpl::~DeviceInfoImpl(void) {
33   _apiLock.AcquireLockExclusive();
34   free(_lastUsedDeviceName);
35   _apiLock.ReleaseLockExclusive();
36 
37   delete &_apiLock;
38 }
39 
NumberOfCapabilities(const char * deviceUniqueIdUTF8)40 int32_t DeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
41   if (!deviceUniqueIdUTF8)
42     return -1;
43 
44   _apiLock.AcquireLockShared();
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     _apiLock.ReleaseLockShared();
51     return static_cast<int32_t>(_captureCapabilities.size());
52   }
53   // Need to get exclusive rights to create the new capability map.
54   _apiLock.ReleaseLockShared();
55   WriteLockScoped cs2(_apiLock);
56 
57   int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
58   return ret;
59 }
60 
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)61 int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
62                                       const uint32_t deviceCapabilityNumber,
63                                       VideoCaptureCapability& capability) {
64   assert(deviceUniqueIdUTF8 != NULL);
65 
66   ReadLockScoped cs(_apiLock);
67 
68   if (!absl::EqualsIgnoreCase(
69           deviceUniqueIdUTF8,
70           absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
71     _apiLock.ReleaseLockShared();
72     _apiLock.AcquireLockExclusive();
73     if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
74       _apiLock.ReleaseLockExclusive();
75       _apiLock.AcquireLockShared();
76       return -1;
77     }
78     _apiLock.ReleaseLockExclusive();
79     _apiLock.AcquireLockShared();
80   }
81 
82   // Make sure the number is valid
83   if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) {
84     RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
85                       << deviceCapabilityNumber << ">= number of capabilities ("
86                       << _captureCapabilities.size() << ").";
87     return -1;
88   }
89 
90   capability = _captureCapabilities[deviceCapabilityNumber];
91   return 0;
92 }
93 
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)94 int32_t DeviceInfoImpl::GetBestMatchedCapability(
95     const char* deviceUniqueIdUTF8,
96     const VideoCaptureCapability& requested,
97     VideoCaptureCapability& resulting) {
98   if (!deviceUniqueIdUTF8)
99     return -1;
100 
101   ReadLockScoped cs(_apiLock);
102   if (!absl::EqualsIgnoreCase(
103           deviceUniqueIdUTF8,
104           absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
105     _apiLock.ReleaseLockShared();
106     _apiLock.AcquireLockExclusive();
107     if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
108       return -1;
109     }
110     _apiLock.ReleaseLockExclusive();
111     _apiLock.AcquireLockShared();
112   }
113 
114   int32_t bestformatIndex = -1;
115   int32_t bestWidth = 0;
116   int32_t bestHeight = 0;
117   int32_t bestFrameRate = 0;
118   VideoType bestVideoType = VideoType::kUnknown;
119 
120   const int32_t numberOfCapabilies =
121       static_cast<int32_t>(_captureCapabilities.size());
122 
123   for (int32_t tmp = 0; tmp < numberOfCapabilies;
124        ++tmp)  // Loop through all capabilities
125   {
126     VideoCaptureCapability& capability = _captureCapabilities[tmp];
127 
128     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;
131 
132     const int32_t currentbestDiffWith = bestWidth - requested.width;
133     const int32_t currentbestDiffHeight = bestHeight - requested.height;
134     const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
135 
136     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.
161             ) {
162               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               {
184                 bestWidth = capability.width;
185                 bestHeight = capability.height;
186                 bestFrameRate = capability.maxFPS;
187                 bestVideoType = capability.videoType;
188                 bestformatIndex = tmp;
189               }
190             }
191           } 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
210 
211   RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
212                       << bestHeight << "@" << bestFrameRate
213                       << "fps, color format: "
214                       << static_cast<int>(bestVideoType);
215 
216   // Copy the capability
217   if (bestformatIndex < 0)
218     return -1;
219   resulting = _captureCapabilities[bestformatIndex];
220   return bestformatIndex;
221 }
222 
223 // Default implementation. This should be overridden by Mobile implementations.
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)224 int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
225                                        VideoRotation& orientation) {
226   orientation = kVideoRotation_0;
227   return -1;
228 }
229 }  // namespace videocapturemodule
230 }  // namespace webrtc
231