Home | History | Annotate | Download | only in video_capture
      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 <assert.h>
     12 #include <stdlib.h>
     13 
     14 #include "webrtc/modules/video_capture/device_info_impl.h"
     15 #include "webrtc/modules/video_capture/video_capture_config.h"
     16 #include "webrtc/system_wrappers/interface/logging.h"
     17 
     18 #ifndef abs
     19 #define abs(a) (a>=0?a:-a)
     20 #endif
     21 
     22 namespace webrtc
     23 {
     24 namespace videocapturemodule
     25 {
     26 DeviceInfoImpl::DeviceInfoImpl(const int32_t id)
     27     : _id(id), _apiLock(*RWLockWrapper::CreateRWLock()), _lastUsedDeviceName(NULL),
     28       _lastUsedDeviceNameLength(0)
     29 {
     30 }
     31 
     32 DeviceInfoImpl::~DeviceInfoImpl(void)
     33 {
     34     _apiLock.AcquireLockExclusive();
     35     free(_lastUsedDeviceName);
     36     _apiLock.ReleaseLockExclusive();
     37 
     38     delete &_apiLock;
     39 }
     40 int32_t DeviceInfoImpl::NumberOfCapabilities(
     41                                         const char* deviceUniqueIdUTF8)
     42 {
     43 
     44     if (!deviceUniqueIdUTF8)
     45         return -1;
     46 
     47     _apiLock.AcquireLockShared();
     48 
     49     if (_lastUsedDeviceNameLength == strlen((char*) deviceUniqueIdUTF8))
     50     {
     51         // Is it the same device that is asked for again.
     52 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
     53         if(strncasecmp((char*)_lastUsedDeviceName,
     54                        (char*) deviceUniqueIdUTF8,
     55                        _lastUsedDeviceNameLength)==0)
     56 #else
     57         if (_strnicmp((char*) _lastUsedDeviceName,
     58                       (char*) deviceUniqueIdUTF8,
     59                       _lastUsedDeviceNameLength) == 0)
     60 #endif
     61         {
     62             //yes
     63             _apiLock.ReleaseLockShared();
     64             return static_cast<int32_t>(_captureCapabilities.size());
     65         }
     66     }
     67     // Need to get exclusive rights to create the new capability map.
     68     _apiLock.ReleaseLockShared();
     69     WriteLockScoped cs2(_apiLock);
     70 
     71     int32_t ret = CreateCapabilityMap(deviceUniqueIdUTF8);
     72     return ret;
     73 }
     74 
     75 int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
     76                                       const uint32_t deviceCapabilityNumber,
     77                                       VideoCaptureCapability& capability)
     78 {
     79     assert(deviceUniqueIdUTF8 != NULL);
     80 
     81     ReadLockScoped cs(_apiLock);
     82 
     83     if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8))
     84 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
     85         || (strncasecmp((char*)_lastUsedDeviceName,
     86                         (char*) deviceUniqueIdUTF8,
     87                         _lastUsedDeviceNameLength)!=0))
     88 #else
     89         || (_strnicmp((char*) _lastUsedDeviceName,
     90                       (char*) deviceUniqueIdUTF8,
     91                       _lastUsedDeviceNameLength) != 0))
     92 #endif
     93 
     94     {
     95         _apiLock.ReleaseLockShared();
     96         _apiLock.AcquireLockExclusive();
     97         if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8))
     98         {
     99             _apiLock.ReleaseLockExclusive();
    100             _apiLock.AcquireLockShared();
    101             return -1;
    102         }
    103         _apiLock.ReleaseLockExclusive();
    104         _apiLock.AcquireLockShared();
    105     }
    106 
    107     // Make sure the number is valid
    108     if (deviceCapabilityNumber >= (unsigned int) _captureCapabilities.size())
    109     {
    110         LOG(LS_ERROR) << "Invalid deviceCapabilityNumber "
    111                       << deviceCapabilityNumber << ">= number of capabilities ("
    112                       << _captureCapabilities.size() << ").";
    113         return -1;
    114     }
    115 
    116     capability = _captureCapabilities[deviceCapabilityNumber];
    117     return 0;
    118 }
    119 
    120 int32_t DeviceInfoImpl::GetBestMatchedCapability(
    121                                         const char*deviceUniqueIdUTF8,
    122                                         const VideoCaptureCapability& requested,
    123                                         VideoCaptureCapability& resulting)
    124 {
    125 
    126 
    127     if (!deviceUniqueIdUTF8)
    128         return -1;
    129 
    130     ReadLockScoped cs(_apiLock);
    131     if ((_lastUsedDeviceNameLength != strlen((char*) deviceUniqueIdUTF8))
    132 #if defined(WEBRTC_MAC) || defined(WEBRTC_LINUX)
    133         || (strncasecmp((char*)_lastUsedDeviceName,
    134                         (char*) deviceUniqueIdUTF8,
    135                         _lastUsedDeviceNameLength)!=0))
    136 #else
    137         || (_strnicmp((char*) _lastUsedDeviceName,
    138                       (char*) deviceUniqueIdUTF8,
    139                       _lastUsedDeviceNameLength) != 0))
    140 #endif
    141     {
    142         _apiLock.ReleaseLockShared();
    143         _apiLock.AcquireLockExclusive();
    144         if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8))
    145         {
    146             return -1;
    147         }
    148         _apiLock.ReleaseLockExclusive();
    149         _apiLock.AcquireLockShared();
    150     }
    151 
    152     int32_t bestformatIndex = -1;
    153     int32_t bestWidth = 0;
    154     int32_t bestHeight = 0;
    155     int32_t bestFrameRate = 0;
    156     RawVideoType bestRawType = kVideoUnknown;
    157     webrtc::VideoCodecType bestCodecType = webrtc::kVideoCodecUnknown;
    158 
    159     const int32_t numberOfCapabilies =
    160         static_cast<int32_t>(_captureCapabilities.size());
    161 
    162     for (int32_t tmp = 0; tmp < numberOfCapabilies; ++tmp) // Loop through all capabilities
    163     {
    164         VideoCaptureCapability& capability = _captureCapabilities[tmp];
    165 
    166         const int32_t diffWidth = capability.width - requested.width;
    167         const int32_t diffHeight = capability.height - requested.height;
    168         const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
    169 
    170         const int32_t currentbestDiffWith = bestWidth - requested.width;
    171         const int32_t currentbestDiffHeight = bestHeight - requested.height;
    172         const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
    173 
    174         if ((diffHeight >= 0 && diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt that previouse.
    175             || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight))
    176         {
    177 
    178             if (diffHeight == currentbestDiffHeight) // Found best height. Care about the width)
    179             {
    180                 if ((diffWidth >= 0 && diffWidth <= abs(currentbestDiffWith)) // Width better or equal
    181                     || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith))
    182                 {
    183                     if (diffWidth == currentbestDiffWith && diffHeight
    184                         == currentbestDiffHeight) // Same size as previously
    185                     {
    186                         //Also check the best frame rate if the diff is the same as previouse
    187                         if (((diffFrameRate >= 0 &&
    188                               diffFrameRate <= currentbestDiffFrameRate) // Frame rate to high but better match than previouse and we have not selected IUV
    189                             ||
    190                             (currentbestDiffFrameRate < 0 &&
    191                              diffFrameRate >= currentbestDiffFrameRate)) // Current frame rate is lower than requested. This is better.
    192                         )
    193                         {
    194                             if ((currentbestDiffFrameRate == diffFrameRate) // Same frame rate as previous  or frame rate allready good enough
    195                                 || (currentbestDiffFrameRate >= 0))
    196                             {
    197                                 if (bestRawType != requested.rawType
    198                                     && requested.rawType != kVideoUnknown
    199                                     && (capability.rawType == requested.rawType
    200                                         || capability.rawType == kVideoI420
    201                                         || capability.rawType == kVideoYUY2
    202                                         || capability.rawType == kVideoYV12))
    203                                 {
    204                                     bestCodecType = capability.codecType;
    205                                     bestRawType = capability.rawType;
    206                                     bestformatIndex = tmp;
    207                                 }
    208                                 // If width height and frame rate is full filled we can use the camera for encoding if it is supported.
    209                                 if (capability.height == requested.height
    210                                     && capability.width == requested.width
    211                                     && capability.maxFPS >= requested.maxFPS)
    212                                 {
    213                                     if (capability.codecType == requested.codecType
    214                                         && bestCodecType != requested.codecType)
    215                                     {
    216                                         bestCodecType = capability.codecType;
    217                                         bestformatIndex = tmp;
    218                                     }
    219                                 }
    220                             }
    221                             else // Better frame rate
    222                             {
    223                                 if (requested.codecType == capability.codecType)
    224                                 {
    225 
    226                                     bestWidth = capability.width;
    227                                     bestHeight = capability.height;
    228                                     bestFrameRate = capability.maxFPS;
    229                                     bestCodecType = capability.codecType;
    230                                     bestRawType = capability.rawType;
    231                                     bestformatIndex = tmp;
    232                                 }
    233                             }
    234                         }
    235                     }
    236                     else // Better width than previously
    237                     {
    238                         if (requested.codecType == capability.codecType)
    239                         {
    240                             bestWidth = capability.width;
    241                             bestHeight = capability.height;
    242                             bestFrameRate = capability.maxFPS;
    243                             bestCodecType = capability.codecType;
    244                             bestRawType = capability.rawType;
    245                             bestformatIndex = tmp;
    246                         }
    247                     }
    248                 }// else width no good
    249             }
    250             else // Better height
    251             {
    252                 if (requested.codecType == capability.codecType)
    253                 {
    254                     bestWidth = capability.width;
    255                     bestHeight = capability.height;
    256                     bestFrameRate = capability.maxFPS;
    257                     bestCodecType = capability.codecType;
    258                     bestRawType = capability.rawType;
    259                     bestformatIndex = tmp;
    260                 }
    261             }
    262         }// else height not good
    263     }//end for
    264 
    265     LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x" << bestHeight
    266                     << "@" << bestFrameRate
    267                     << "fps, color format: " << bestRawType;
    268 
    269     // Copy the capability
    270     if (bestformatIndex < 0)
    271         return -1;
    272     resulting = _captureCapabilities[bestformatIndex];
    273     return bestformatIndex;
    274 }
    275 
    276 /* Returns the expected Capture delay*/
    277 int32_t DeviceInfoImpl::GetExpectedCaptureDelay(
    278                                           const DelayValues delayValues[],
    279                                           const uint32_t sizeOfDelayValues,
    280                                           const char* productId,
    281                                           const uint32_t width,
    282                                           const uint32_t height)
    283 {
    284     int32_t bestDelay = kDefaultCaptureDelay;
    285 
    286     for (uint32_t device = 0; device < sizeOfDelayValues; ++device)
    287     {
    288         if (delayValues[device].productId && strncmp((char*) productId,
    289                                                      (char*) delayValues[device].productId,
    290                                                      kVideoCaptureProductIdLength) == 0)
    291         {
    292             // We have found the camera
    293 
    294             int32_t bestWidth = 0;
    295             int32_t bestHeight = 0;
    296 
    297             //Loop through all tested sizes and find one that seems fitting
    298             for (uint32_t delayIndex = 0; delayIndex < NoOfDelayValues; ++delayIndex)
    299             {
    300                 const DelayValue& currentValue = delayValues[device].delayValues[delayIndex];
    301 
    302                 const int32_t diffWidth = currentValue.width - width;
    303                 const int32_t diffHeight = currentValue.height - height;
    304 
    305                 const int32_t currentbestDiffWith = bestWidth - width;
    306                 const int32_t currentbestDiffHeight = bestHeight - height;
    307 
    308                 if ((diffHeight >= 0 && diffHeight <= abs(currentbestDiffHeight)) // Height better or equal than previous.
    309                     || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight))
    310                 {
    311 
    312                     if (diffHeight == currentbestDiffHeight) // Found best height. Care about the width)
    313                     {
    314                         if ((diffWidth >= 0 && diffWidth <= abs(currentbestDiffWith)) // Width better or equal
    315                             || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith))
    316                         {
    317                             if (diffWidth == currentbestDiffWith && diffHeight
    318                                 == currentbestDiffHeight) // Same size as previous
    319                             {
    320                             }
    321                             else // Better width than previously
    322                             {
    323                                 bestWidth = currentValue.width;
    324                                 bestHeight = currentValue.height;
    325                                 bestDelay = currentValue.delay;
    326                             }
    327                         }// else width no good
    328                     }
    329                     else // Better height
    330                     {
    331                         bestWidth = currentValue.width;
    332                         bestHeight = currentValue.height;
    333                         bestDelay = currentValue.delay;
    334                     }
    335                 }// else height not good
    336             }//end for
    337             break;
    338         }
    339     }
    340     if (bestDelay > kMaxCaptureDelay)
    341     {
    342         LOG(LS_WARNING) << "Expected capture delay (" << bestDelay
    343                         << " ms) too high, using " << kMaxCaptureDelay
    344                         << " ms.";
    345         bestDelay = kMaxCaptureDelay;
    346     }
    347 
    348     return bestDelay;
    349 
    350 }
    351 
    352 //Default implementation. This should be overridden by Mobile implementations.
    353 int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
    354                                        VideoCaptureRotation& orientation)
    355 {
    356     orientation = kCameraRotate0;
    357     return -1;
    358 }
    359 }  // namespace videocapturemodule
    360 }  // namespace webrtc
    361