Merge pull request #15973 from VadimLevin:dev/vlevin/video_capture_inf_loop
authorVadim Levin <vadim.levin@xperience.ai>
Fri, 22 Nov 2019 22:10:16 +0000 (01:10 +0300)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Fri, 22 Nov 2019 22:10:16 +0000 (01:10 +0300)
* Fix infinite loop when trying to change state of the busy camera

  - Add finite number of attempts in tryIoctl functions
    10 by default.

* Introduced new flag for ioctl call to handle EBUSY

modules/videoio/src/cap_v4l.cpp

index 645aa67..a0a4cd8 100644 (file)
@@ -353,7 +353,7 @@ struct CvCaptureCAM_V4L CV_FINAL : public CvCapture
     bool initCapture();
     bool streaming(bool startStream);
     bool setFps(int value);
-    bool tryIoctl(unsigned long ioctlCode, void *parameter) const;
+    bool tryIoctl(unsigned long ioctlCode, void *parameter, bool failIfBusy = true, int attempts = 10) const;
     bool controlInfo(int property_id, __u32 &v4l2id, cv::Range &range) const;
     bool icvControl(__u32 v4l2id, int &value, bool isSet) const;
 
@@ -406,10 +406,10 @@ bool CvCaptureCAM_V4L::try_palette_v4l2()
     form.fmt.pix.field       = V4L2_FIELD_ANY;
     form.fmt.pix.width       = width;
     form.fmt.pix.height      = height;
-
     if (!tryIoctl(VIDIOC_S_FMT, &form))
+    {
         return false;
-
+    }
     return palette == form.fmt.pix.pixelformat;
 }
 
@@ -481,6 +481,8 @@ bool CvCaptureCAM_V4L::autosetup_capture_mode_v4l2()
     //in case palette is already set and works, no need to setup.
     if (palette != 0 && try_palette_v4l2()) {
         return true;
+    } else if (errno == EBUSY) {
+        return false;
     }
     __u32 try_order[] = {
             V4L2_PIX_FMT_BGR24,
@@ -637,7 +639,9 @@ bool CvCaptureCAM_V4L::initCapture()
     }
 
     if (!autosetup_capture_mode_v4l2()) {
-        fprintf(stderr, "VIDEOIO ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n");
+        if (errno != EBUSY) {
+            fprintf(stderr, "VIDEOIO ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n");
+        }
         return false;
     }
 
@@ -857,10 +861,21 @@ bool CvCaptureCAM_V4L::read_frame_v4l2()
     return true;
 }
 
-bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter) const
+bool CvCaptureCAM_V4L::tryIoctl(unsigned long ioctlCode, void *parameter, bool failIfBusy, int attempts) const
 {
+    if (attempts == 0) {
+        return false;
+    }
     while (-1 == ioctl(deviceHandle, ioctlCode, parameter)) {
-        if (!(errno == EBUSY || errno == EAGAIN))
+        const bool isBusy = (errno == EBUSY);
+        if (isBusy & failIfBusy) {
+            return false;
+        }
+        if ((attempts > 0) && (--attempts == 0)) {
+            return false;
+        }
+
+        if (!(isBusy || errno == EAGAIN))
             return false;
 
         fd_set fds;
@@ -1969,8 +1984,9 @@ CvCapture* cvCreateCameraCapture_V4L( int index )
 {
     cv::CvCaptureCAM_V4L* capture = new cv::CvCaptureCAM_V4L();
 
-    if(capture->open(index))
+    if(capture->open(index)) {
         return capture;
+    }
 
     delete capture;
     return NULL;