clinuxv4l2uvc

Getting the v4l2 device number for a connected USB camera (webcam) from a C application (Linux)


I'm working on a embedded Linux system (yocto) and I'm trying to simply get a list of the camera USB video devices (webcams) numbers with the related connected USB port from a C program.

I'm able to get the devices list with vendor ID and connected port doing this:

void usbdevs()
{
    libusb_device*** list=NULL;
    libusb_context *context = NULL;
    ssize_t count;
    uint8_t port;
    char ncameras=0;

    libusb_init(&context);

    count = libusb_get_device_list(context,&list);

    for(int i=0; i < MAX_NUM_CAMS; i++)
        usb_dev_list[i]=0;

    for (size_t idx = 0; idx < count; ++idx) {
        libusb_device *device = list[idx];
        struct libusb_device_descriptor desc = {0};

        libusb_get_device_descriptor(device, &desc);
        port = libusb_get_port_number(device);
        printf("Vendor:Device = %04x:%04x Port: %d\n", desc.idVendor, desc.idProduct,port);
    }

    libusb_free_device_list(list, count);
    libusb_exit(context);

}

What I need now is to know (from the C application) what v4l2 device number is related to the USB camera port, eg. I've got two webcam (same vendor ID) connected which appear as /dev/video0 and /dev/video1 respectively and I can get the connected port for each one using the above code, but,
how can I know which ports are connected each one?

I tried to get information from the devices using ioctl calls as it is recommended in this question but when I run the code:

int checkvideodev()
{
    int fd;
    struct video_capability video_cap;
    struct video_window     video_win;
    struct video_picture   video_pic;

    if((fd = open("/dev/video0", O_RDONLY)) == -1){
        perror("cam_info: Can't open device");
        return 1;
    }

    if(xioctl(fd, VIDIOCGCAP, &video_cap) == -1)
        perror("cam_info: Can't get capabilities");
    else {
        printf("Name:\t\t '%s'\n", video_cap.name);
        printf("Minimum size:\t%d x %d\n", video_cap.minwidth, video_cap.minheight);
        printf("Maximum size:\t%d x %d\n", video_cap.maxwidth, video_cap.maxheight);
    }

    if(xioctl(fd, VIDIOCGWIN, &video_win) == -1)
        perror("cam_info: Can't get window information");
    else
        printf("Current size:\t%d x %d\n", video_win.width, video_win.height);

    if(xioctl(fd, VIDIOCGPICT, &video_pic) == -1)
        perror("cam_info: Can't get picture information");
    else
        printf("Current depth:\t%d\n", video_pic.depth);

    close(fd);
    return 0;
}

I've got the next errors:

cam_info: Can't get capabilities: Inappropriate ioctl for device
cam_info: Can't get window information: Inappropriate ioctl for device
cam_info: Can't get picture information: Inappropriate ioctl for device

If I'm checking through command line for instance I can get the capabilities without issues running:

v4l2-ctl --device /dev/video0 --list-formats-ext

Any ideas how can this be done?


Solution

  • I don't know if this specifically answers your question, but you can get useful information by globbing certain patterns under /dev or /sys, for example this will return the full device path (including PCI bus) of each video device,

    #include <glob.h>
    #include <unistd.h>
    
    void list_videos() {
      int i;
      glob_t globbuf;
      if (glob("/sys/class/video4linux/video*", 0, NULL, &globbuf) != 0) {
        perror("glob");
        return;
      }
      for (i=0; i < globbuf.gl_pathc; i++) {
        char buf[256] = {};
        if (readlink(globbuf.gl_pathv[i], buf, sizeof(buf)-1) > 0) {
          puts(buf);
        }
      }
    }
    

    On one system with 2 cameras this prints,

    ../../devices/pci0000:00/0000:00:14.0/usb2/2-1/2-1.1/2-1.1:1.0/video4linux/video0
    ../../devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/video4linux/video1
    
    

    Other interesting glob strings include /dev/v4l/by-id/* and /dev/v4l/by-path/*.