Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Linux and multiple USB webcams cause reduced frame resolution and v4l2 error

I have two Logitech Pro 9000 webcams. I have discovered a strange behaviour in cv::VideoCapture::set() when setting the frame size (width and height) for my captures resulting in the infamous error

libv4l2: error turning on stream: No space left on device
VIDIOC_STREAMON: No space left on device
ERROR: Could not read from video stream

for my second camera. In order to fix it I have to reduce my frame size almost 2 times from the initial one. Now here is the interesting thing:

  • Version 1 (without using cv::VideoCapture::set()) - I manage to get both cameras up and running at 15fps (I tried with 20fps but I get the error I have mentioned above) with a resolution of 640x480, which seems to be a sort of a hidden default for those cameras (I was unable to find in the source code of cv::VideoCapture where this is set) if you don't specify these. The two values are retrieved by using cv::VideoCapture::get(CV_CAP_PROP_FRAME_WIDTH) and cv::VideoCapture::get(CV_CAP_PROP_FRAME_HEIGHT) respectively. Here is a small example:

    // The indices are 1 and 2 since 0 is my built-in webcam (I'm using a notebook)
    cv::VideoCapture cap1(1);
    cv::VideoCapture cap2(2);
    
    if(!cap1.isOpened())
    {
      std::cout << "Cannot open the video cam [1]" << std::endl;
      return -1;
    }
    
    if(!cap2.isOpened())
    {
      std::cout << "Cannot open the video cam [2]" << std::endl;
      return -1;
    }
    
    // Set both cameras to 15fps
    cap1.set(CV_CAP_PROP_FPS, 15);
    cap2.set(CV_CAP_PROP_FPS, 15);
    
    double dWidth1 = cap1.get(CV_CAP_PROP_FRAME_WIDTH);
    double dHeight1 = cap1.get(CV_CAP_PROP_FRAME_HEIGHT);
    double dWidth2 = cap2.get(CV_CAP_PROP_FRAME_WIDTH);
    double dHeight2 = cap2.get(CV_CAP_PROP_FRAME_HEIGHT);
    
    // Here I display the frame size that OpenCV has picked for me - it is 640x480 for both cameras
    std:: cout << "cam[1] Frame size: " << dWidth1 << " x " << dHeight1 << std::endl;
    std::cout << "cam[2] Frame size: " << dWidth2 << " x " << dHeight2 << std::endl;
    cv::namedWindow("cam[1]",CV_WINDOW_AUTOSIZE);
    cv::namedWindow("cam[2]",CV_WINDOW_AUTOSIZE);
    
    while(1)    
    {    
      cv::Mat frame1, frame2;    
      bool bSuccess1 = cap1.read(frame1);    
      bool bSuccess2 = cap2.read(frame2);
    
      if (!bSuccess1)
      {
        std::cout << "Cannot read a frame from video stream [1]" << std::endl;
        break;
      }
    
      if (!bSuccess2)
      {
        std::cout << "Cannot read a frame from video stream [2]" << std::endl;
        break;
      }
    
      cv::imshow("cam[1]", frame1);
      cv::imshow("cam[2]", frame2);
    
      if(cv::waitKey(30) == 27)
      {
        std::cout << "ESC key is pressed by user" << std::endl;
        break;
      }
    }
    

This example is working without any issues.

  • Version 2 (using cv::VideoCapture::set()) - if I take the exact same values that I retrieve using cv::VideoCapture::get() and use them with cv::VideoCapture::set() to setup the exact same parameters the above mentioned error occurs:

    cv::VideoCapture cap1(1);
    cv::VideoCapture cap2(2);
    
    if(!cap1.isOpened())
    {
      std::cout << "Cannot open the video cam [1]" << std::endl;
      return -1;
    }
    
    if(!cap2.isOpened())
    {
      std::cout << "Cannot open the video cam [2]" << std::endl;
      return -1;
    }
    
    cap1.set(CV_CAP_PROP_FPS, 15);
    cap2.set(CV_CAP_PROP_FPS, 15);
    
    // Values taken from output of Version 1 and used to setup the exact same parameters with the exact same values!
    cap1.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    cap1.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    cap2.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    cap2.set(CV_CAP_PROP_FRAME_HEIGHT, 480);    
    
    cv::namedWindow("cam[1]",CV_WINDOW_AUTOSIZE);
    cv::namedWindow("cam[2]",CV_WINDOW_AUTOSIZE);
    
    while(1)    
    {    
      cv::Mat frame1, frame2;    
      bool bSuccess1 = cap1.read(frame1);    
      bool bSuccess2 = cap2.read(frame2);
    
      if (!bSuccess1)
      {
        std::cout << "Cannot read a frame from video stream [1]" << std::endl;
        break;
      }
    
      if (!bSuccess2)
      {
        std::cout << "Cannot read a frame from video stream [2]" << std::endl;
        break;
      }
    
      cv::imshow("cam[1]", frame1);
      cv::imshow("cam[2]", frame2);
    
      if(cv::waitKey(30) == 27)
      {
        std::cout << "ESC key is pressed by user" << std::endl;
        break;
      }
    }
    

The more verbose error output is

cam[1] Frame size: 640 x 480
cam[2] Frame size: 640 x 480
init done 
opengl support available 
libv4l2: error turning on stream: No space left on device
VIDIOC_STREAMON: No space left on device
Cannot read a frame from video stream [2]

In order to make it work I have to reduce the frame's width and height of both cameras to 352x288 at 15fps, which is not acceptable.

Has anyone experienced such strange behaviour and/or does know a solution? The code has been tested on 2 Windows machines and it was discovered that it's working without any problems on both. Problem seems to be v4l2 and Linux related.