Linux – How to limit the USB bandwidth a device can allocate on Linux

bandwidthlinuxusbusb-2webcam

How do you put an cap on the amount of bandwidth a USB device can allocate on Linux?

I have a couple of cheap USB webcams that I'm trying to running simeltaneously. Running v4l2-ctl --list-formats-ext --device=/dev/videoN shows they both support several uncompressed resolutions at both 30 and 15 FPS.

However, even if I configure one to capture at 15 FPS at 160×120 resolution, it still allocates 480 Mbps of bandwidth, usually preventing me from using any other USB devices, much less the second webcam. Attempting to capture from the second webcam at the same FPS/resolution results in the error:

libv4l2: error turning on stream: No space left on device
VIDIOC_STREAMON: No space left on device

Googling this error usually results in answers like, "you're SOL, maybe buy a camera that supports MJPG?".

But this makes absolutely no sense.

Capturing uncompressed 160×120 RGB equals 160*120*3 = 57600 bytes per frame. At 15 FPS, that requires at least 864000 bytes per second of bandwidth (i.e. a whopping 0.864 Mbps or 6.912 Mbits)! I have USB2 hub, which supports 480 Mbit/s. I should have enough bandwidth to run dozens of these webcams at once, yet running a single one consumes almost all 480 Mbits of my USB hub!

Since the camera doesn't need 480 Mbps to stream 160×120, but it's telling driver to allocate that much, is there any way, at the OS level, to force the driver to allocate a certain amount?

Best Answer

This guy provides a solution that seems to work for some people. In my case, I've tried it and it changed nothing, but it's very hardware-dependant.

The uvcvideo kernel module can be set to ignore the requested bandwidth, and to calculate the right bandwidth. Try:

sudo rmmod uvcvideo
sudo modprobe uvcvideo quirks=128

This will be reset every reboot. If this works, create the following file:

sudo vi /etc/modprobe.d/uvcvideo.conf 

containing the line:

options uvcvideo quirks=128

Indeed, in this page they say that this may not always work and they even give the option to change the code in the function uvc_init_video() of the driver:

/* Isochronous endpoint, select the alternate setting. */
bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
Related Question