Friday, February 6, 2026

usb – Easy methods to find a UVC machine with unique_id from AVCaptureDevice?

I am writing a program to regulate a PTZ digicam linked through USB.

I can get entry to focus on digicam’s unique_id, and in addition different infos supplied by AVFoundation. However I do not know learn how to find my goal USB machine to ship a UVC ControlRequest.

There’s many Cameras with similar VendorID and ProductID linked at a time, so I would like a extra precise method to discover out which machine is my goal.

It seems to be that the unique_id supplied is (locationID<<32|VendorID<<16|ProductID) as hex string, however I am unsure if I can all the time assume this conduct will not change.

Is there is a doc declares how AVFoundation generate the unique_id for USB digicam, so I can assume this convert will all the time work? Or is there is a method to ship a PTZ management request to AVCaptureDevice?

https://stackoverflow.com/questions/40006908/usb-interface-of-an-avcapturedevice

I’ve seen this related query. However I am worrying that Exacting LocationID+VendorID+ProductID from unique_id looks like programming to implementation as an alternative of interface. So, if there’s some other higher method to management my digicam?

this is my instance code for getting unique_id:

//
// camera_unique_id_test.mm
// clang++ -framework AVFoundation -framework CoreMedia -framework Basis
// camera_unique_id_test.mm -o camera_unique_id_test
//

#embody 
#embody 
#embody 

#import 
#import 

struct CameraInfo {
  std::string uniqueId;
  std::string localizedName;
  std::string modelId;
  bool isConnected;
  bool isDefault;
};

std::vector getAllCameraDevices() {
  std::vector cameras;

  @autoreleasepool {
    // 获取所有视频输入设备
    NSArray* gadgets =
        [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

    // 获取默认摄像头设备
    AVCaptureDevice* defaultDevice =
        [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    // 遍历所有设备
    for (AVCaptureDevice* machine in gadgets) {
      CameraInfo data;

      // 获取unique_id
      data.uniqueId = std::string([device.uniqueID UTF8String]);

      // 获取设备名称
      data.localizedName = std::string([device.localizedName UTF8String]);

      // 获取模型ID
      data.modelId = std::string([device.modelID UTF8String]);

      // 检查是否已连接
      data.isConnected = machine.linked;

      // 检查是否为默认设备
      data.isDefault = [device.uniqueID isEqualToString:defaultDevice.uniqueID];

      cameras.push_back(data);
    }
  }

  return cameras;
}

int most important(int argc, char* argv[]) {
  std::vector cameras = getAllCameraDevices();

  for (size_t i = 0; i < cameras.dimension(); i++) {
    const CameraInfo& digicam = cameras[i];
    std::cout << "   设备 " << (i + 1) << ":" << std::endl;
    std::cout << "     unique_id:     " << digicam.uniqueId << std::endl;
    std::cout << "     设备名称:      " << digicam.localizedName << std::endl;
    std::cout << "     模型ID:        " << digicam.modelId << std::endl;
    std::cout << "     连接状态:      "
              << (digicam.isConnected ? "已连接" : "未连接") << std::endl;
    std::cout << "     是否默认:      " << (digicam.isDefault ? "是" : "否")
              << std::endl;
    std::cout << std::endl;
  }

  return 0;
}

and this is my code for UVC management:

// clang++ -framework Basis -framework IOKit uvc_test.cpp -o uvc_test

#embody 

#embody 
#embody 
#embody 
#embody 
#embody 
#embody 

CFStringRef CreateCFStringFromIORegistryKey(io_service_t ioService,
                                            const char* key) {
  CFStringRef keyString = CFStringCreateWithCString(kCFAllocatorDefault, key,
                                                    kCFStringEncodingUTF8);
  if (!keyString)
    return nullptr;

  CFStringRef outcome = static_cast(
      IORegistryEntryCreateCFProperty(ioService, keyString, kCFAllocatorDefault,
                                      kIORegistryIterateRecursively));
  CFRelease(keyString);
  return outcome;
}

std::string GetStringFromIORegistry(io_service_t ioService, const char* key) {
  CFStringRef cfString = CreateCFStringFromIORegistryKey(ioService, key);
  if (!cfString)
    return "";

  char buffer[256];
  Boolean success = CFStringGetCString(cfString, buffer, sizeof(buffer),
                                       kCFStringEncodingUTF8);
  CFRelease(cfString);

  return success ? std::string(buffer) : std::string("");
}

uint32_t GetUInt32FromIORegistry(io_service_t ioService, const char* key) {
  CFStringRef keyString = CFStringCreateWithCString(kCFAllocatorDefault, key,
                                                    kCFStringEncodingUTF8);
  if (!keyString)
    return 0;

  CFNumberRef quantity = static_cast(
      IORegistryEntryCreateCFProperty(ioService, keyString, kCFAllocatorDefault,
                                      kIORegistryIterateRecursively));
  CFRelease(keyString);

  if (!quantity)
    return 0;

  uint32_t worth = 0;
  CFNumberGetValue(quantity, kCFNumberSInt32Type, &worth);
  CFRelease(quantity);
  return worth;
}

int most important() {
  // Get matching dictionary for USB gadgets
  CFMutableDictionaryRef matchingDict =
      IOServiceMatching(kIOUSBDeviceClassName);

  // Get iterator for matching providers
  io_iterator_t serviceIterator;
  IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict,
                               &serviceIterator);

  // Iterate by matching gadgets
  io_service_t usbService;
  whereas ((usbService = IOIteratorNext(serviceIterator))) {
    uint32_t locationId = GetUInt32FromIORegistry(usbService, "locationID");
    uint32_t vendorId = GetUInt32FromIORegistry(usbService, "idVendor");
    uint32_t productId = GetUInt32FromIORegistry(usbService, "idProduct");

    IOCFPlugInInterface** plugInInterface = nullptr;
    IOUSBDeviceInterface** deviceInterface = nullptr;
    SInt32 rating;

    // Get machine plugin interface
    IOCreatePlugInInterfaceForService(usbService, kIOUSBDeviceUserClientTypeID,
                                      kIOCFPlugInInterfaceID, &plugInInterface,
                                      &rating);
    // Get machine interface

    (*plugInInterface)
        ->QueryInterface(plugInInterface,
                         CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),
                         (LPVOID*)&deviceInterface);

    (*plugInInterface)->Launch(plugInInterface);

    // Attempt to discover UVC management interface utilizing CreateInterfaceIterator
    io_iterator_t interfaceIterator;
    IOUSBFindInterfaceRequest interfaceRequest;
    interfaceRequest.bInterfaceClass = kUSBVideoInterfaceClass;      // 14
    interfaceRequest.bInterfaceSubClass = kUSBVideoControlSubClass;  // 1
    interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
    interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;

    (*deviceInterface)
        ->CreateInterfaceIterator(deviceInterface, &interfaceRequest,
                                  &interfaceIterator);
    (*deviceInterface)->Launch(deviceInterface);

    io_service_t usbInterface = IOIteratorNext(interfaceIterator);
    IOObjectRelease(interfaceIterator);

    if (usbInterface) {
      std::cout << "Get UVC machine with:" << std::endl;
      std::cout << "locationId: " << std::hex << locationId << std::endl;
      std::cout << "vendorId: " << std::hex << vendorId << std::endl;
      std::cout << "productId: " << std::hex << productId << std::endl
                << std::endl;
      IOObjectRelease(usbInterface);
    }

    IOObjectRelease(usbService);
  }

  IOObjectRelease(serviceIterator);
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles