2
votes

I'm working on a embedded linux system (yocto based) 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?

Thanks in advance.

1
Ugly alternative to libusb: glob("/dev/v4l/by-path/*") and look at the strings. Then you could readlink(2) each path.jamieguinan
Even if the devices have the same vendor ID, do they have unique serial numbers? Then you could which one is plugged in where by globbing "/dev/v4l/by-id/*".jamieguinan
Hi @jamieguinan, thanks for your suggestion looks promising solution, but I've never used the glob function before, could you please expand it and show or point me to an example on how to use it to get the strings?joe

1 Answers

1
votes

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/*.