From 373160ce0042f9db10481479b4a23a47bbe0150e Mon Sep 17 00:00:00 2001 From: Vadim Levin Date: Sat, 23 Nov 2019 01:10:16 +0300 Subject: [PATCH] Merge pull request #15973 from VadimLevin:dev/vlevin/video_capture_inf_loop * 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 | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp index 645aa67e40..a0a4cd86e0 100644 --- a/modules/videoio/src/cap_v4l.cpp +++ b/modules/videoio/src/cap_v4l.cpp @@ -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;