tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

device_info_avfoundation.mm (7534B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "device_info_avfoundation.h"
      8 #include <CoreVideo/CVPixelBuffer.h>
      9 
     10 #include <string>
     11 
     12 #include "components/capturer/RTCCameraVideoCapturer.h"
     13 #import "helpers/NSString+StdString.h"
     14 #include "media/base/video_common.h"
     15 #include "modules/video_capture/video_capture_defines.h"
     16 #include "rtc_base/logging.h"
     17 
     18 namespace webrtc::videocapturemodule {
     19 /* static */
     20 int32_t DeviceInfoAvFoundation::ConvertAVFrameRateToCapabilityFPS(
     21    Float64 aRate) {
     22  return static_cast<int32_t>(aRate);
     23 }
     24 
     25 /* static */
     26 webrtc::VideoType DeviceInfoAvFoundation::ConvertFourCCToVideoType(
     27    FourCharCode aCode) {
     28  switch (aCode) {
     29    case kCVPixelFormatType_420YpCbCr8Planar:
     30    case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
     31      return webrtc::VideoType::kI420;
     32    case kCVPixelFormatType_24BGR:
     33      return webrtc::VideoType::kRGB24;
     34    case kCVPixelFormatType_32ABGR:
     35      return webrtc::VideoType::kABGR;
     36    case kCMPixelFormat_32ARGB:
     37      return webrtc::VideoType::kBGRA;
     38    case kCMPixelFormat_32BGRA:
     39      return webrtc::VideoType::kARGB;
     40    case kCMPixelFormat_16LE565:
     41      return webrtc::VideoType::kRGB565;
     42    case kCMPixelFormat_16LE555:
     43    case kCMPixelFormat_16LE5551:
     44      return webrtc::VideoType::kARGB1555;
     45    case kCMPixelFormat_422YpCbCr8_yuvs:
     46      return webrtc::VideoType::kYUY2;
     47    case kCMPixelFormat_422YpCbCr8:
     48      return webrtc::VideoType::kUYVY;
     49    case kCMVideoCodecType_JPEG:
     50    case kCMVideoCodecType_JPEG_OpenDML:
     51      return webrtc::VideoType::kMJPEG;
     52    case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
     53    case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
     54      return webrtc::VideoType::kNV12;
     55    default:
     56      RTC_LOG(LS_WARNING) << "Unhandled FourCharCode" << aCode;
     57      return webrtc::VideoType::kUnknown;
     58  }
     59 }
     60 
     61 DeviceInfoAvFoundation::DeviceInfoAvFoundation()
     62    : mInvalidateCapabilities(false),
     63      mDeviceChangeCaptureInfo([[DeviceInfoIosObjC alloc] init]) {
     64  [mDeviceChangeCaptureInfo registerOwner:this];
     65 }
     66 
     67 DeviceInfoAvFoundation::~DeviceInfoAvFoundation() {
     68  [mDeviceChangeCaptureInfo registerOwner:nil];
     69 }
     70 
     71 void DeviceInfoAvFoundation::DeviceChange() {
     72  mInvalidateCapabilities = true;
     73  DeviceInfo::DeviceChange();
     74 }
     75 
     76 uint32_t DeviceInfoAvFoundation::NumberOfDevices() {
     77  RTC_DCHECK_RUN_ON(&mChecker);
     78  EnsureCapabilitiesMap();
     79  return mDevicesAndCapabilities.size();
     80 }
     81 
     82 int32_t DeviceInfoAvFoundation::GetDeviceName(
     83    uint32_t aDeviceNumber, char* aDeviceNameUTF8, uint32_t aDeviceNameLength,
     84    char* aDeviceUniqueIdUTF8, uint32_t aDeviceUniqueIdUTF8Length,
     85    char* /* aProductUniqueIdUTF8 */, uint32_t /* aProductUniqueIdUTF8Length */,
     86    pid_t* /* aPid */, bool* /*deviceIsPlaceholder*/) {
     87  RTC_DCHECK_RUN_ON(&mChecker);
     88  // Don't EnsureCapabilitiesMap() here, since:
     89  // 1) That might invalidate the capabilities map
     90  // 2) This function depends on the device index
     91 
     92  if (aDeviceNumber >= mDevicesAndCapabilities.size()) {
     93    return -1;
     94  }
     95 
     96  const auto& [uniqueId, name, _] = mDevicesAndCapabilities[aDeviceNumber];
     97 
     98  strncpy(aDeviceUniqueIdUTF8, uniqueId.c_str(), aDeviceUniqueIdUTF8Length);
     99  aDeviceUniqueIdUTF8[aDeviceUniqueIdUTF8Length - 1] = '\0';
    100 
    101  strncpy(aDeviceNameUTF8, name.c_str(), aDeviceNameLength);
    102  aDeviceNameUTF8[aDeviceNameLength - 1] = '\0';
    103 
    104  return 0;
    105 }
    106 
    107 int32_t DeviceInfoAvFoundation::NumberOfCapabilities(
    108    const char* aDeviceUniqueIdUTF8) {
    109  RTC_DCHECK_RUN_ON(&mChecker);
    110 
    111  std::string deviceUniqueId(aDeviceUniqueIdUTF8);
    112  const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
    113  if (!tup) {
    114    return 0;
    115  }
    116 
    117  const auto& [_, __, capabilities] = *tup;
    118  return static_cast<int32_t>(capabilities.size());
    119 }
    120 
    121 int32_t DeviceInfoAvFoundation::GetCapability(
    122    const char* aDeviceUniqueIdUTF8, const uint32_t aDeviceCapabilityNumber,
    123    VideoCaptureCapability& aCapability) {
    124  RTC_DCHECK_RUN_ON(&mChecker);
    125 
    126  std::string deviceUniqueId(aDeviceUniqueIdUTF8);
    127  const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
    128  if (!tup) {
    129    return -1;
    130  }
    131 
    132  const auto& [_, __, capabilities] = *tup;
    133  if (aDeviceCapabilityNumber >= capabilities.size()) {
    134    return -1;
    135  }
    136 
    137  aCapability = capabilities[aDeviceCapabilityNumber];
    138  return 0;
    139 }
    140 
    141 int32_t DeviceInfoAvFoundation::CreateCapabilityMap(
    142    const char* aDeviceUniqueIdUTF8) {
    143  RTC_DCHECK_RUN_ON(&mChecker);
    144 
    145  const size_t deviceUniqueIdUTF8Length = strlen(aDeviceUniqueIdUTF8);
    146  if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength) {
    147    RTC_LOG(LS_INFO) << "Device name too long";
    148    return -1;
    149  }
    150  RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
    151                   << aDeviceUniqueIdUTF8;
    152  std::string deviceUniqueId(aDeviceUniqueIdUTF8);
    153  const auto* tup = FindDeviceAndCapabilities(deviceUniqueId);
    154  if (!tup) {
    155    RTC_LOG(LS_INFO) << "no matching device found";
    156    return -1;
    157  }
    158 
    159  // Store the new used device name
    160  _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
    161  _lastUsedDeviceName = static_cast<char*>(
    162      realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
    163  memcpy(_lastUsedDeviceName, aDeviceUniqueIdUTF8,
    164         _lastUsedDeviceNameLength + 1);
    165 
    166  const auto& [_, __, capabilities] = *tup;
    167  _captureCapabilities = capabilities;
    168  return static_cast<int32_t>(_captureCapabilities.size());
    169 }
    170 
    171 auto DeviceInfoAvFoundation::FindDeviceAndCapabilities(
    172    const std::string& aDeviceUniqueId) const
    173    -> const std::tuple<std::string, std::string, VideoCaptureCapabilities>* {
    174  RTC_DCHECK_RUN_ON(&mChecker);
    175  for (const auto& tup : mDevicesAndCapabilities) {
    176    if (std::get<0>(tup) == aDeviceUniqueId) {
    177      return &tup;
    178    }
    179  }
    180  return nullptr;
    181 }
    182 
    183 void DeviceInfoAvFoundation::EnsureCapabilitiesMap() {
    184  RTC_DCHECK_RUN_ON(&mChecker);
    185 
    186  if (mInvalidateCapabilities.exchange(false)) {
    187    mDevicesAndCapabilities.clear();
    188  }
    189 
    190  if (!mDevicesAndCapabilities.empty()) {
    191    return;
    192  }
    193 
    194  for (AVCaptureDevice* device in [RTCCameraVideoCapturer
    195           captureDevicesWithDeviceTypes:[RTCCameraVideoCapturer
    196                                             defaultCaptureDeviceTypes]]) {
    197    std::string uniqueId = [NSString stdStringForString:device.uniqueID];
    198    std::string name = [NSString stdStringForString:device.localizedName];
    199    auto& [_, __, capabilities] = mDevicesAndCapabilities.emplace_back(
    200        uniqueId, name, VideoCaptureCapabilities());
    201 
    202    for (AVCaptureDeviceFormat* format in
    203         [RTCCameraVideoCapturer supportedFormatsForDevice:device]) {
    204      VideoCaptureCapability cap;
    205      FourCharCode fourcc =
    206          CMFormatDescriptionGetMediaSubType(format.formatDescription);
    207      cap.videoType = ConvertFourCCToVideoType(fourcc);
    208      CMVideoDimensions dimensions =
    209          CMVideoFormatDescriptionGetDimensions(format.formatDescription);
    210      cap.width = dimensions.width;
    211      cap.height = dimensions.height;
    212 
    213      for (AVFrameRateRange* range in format.videoSupportedFrameRateRanges) {
    214        cap.maxFPS = ConvertAVFrameRateToCapabilityFPS(range.maxFrameRate);
    215        capabilities.push_back(cap);
    216      }
    217 
    218      if (capabilities.empty()) {
    219        cap.maxFPS = 30;
    220        capabilities.push_back(cap);
    221      }
    222    }
    223  }
    224 }
    225 }  // namespace webrtc::videocapturemodule