diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index ae1b591b80..24a4123f82 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -1991,9 +1991,10 @@ static gboolean gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, guint32 pixelformat, gint * width, gint * height, gboolean * interlaced) { - struct v4l2_format fmt; + struct v4l2_format fmt, prevfmt; int fd; int r; + int prevfmt_valid; g_return_val_if_fail (width != NULL, FALSE); g_return_val_if_fail (height != NULL, FALSE); @@ -2004,6 +2005,11 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, fd = v4l2object->video_fd; + /* Some drivers are buggy and will modify the currently set format + when processing VIDIOC_TRY_FMT, so we remember what is set at the + minute, and will reset it when done. */ + prevfmt_valid = (v4l2_ioctl (fd, VIDIOC_G_FMT, &prevfmt) >= 0); + /* get size delimiters */ memset (&fmt, 0, sizeof (fmt)); fmt.type = v4l2object->type; @@ -2026,12 +2032,12 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, /* The driver might not implement TRY_FMT, in which case we will try S_FMT to probe */ if (errno != ENOTTY) - return FALSE; + goto error; /* Only try S_FMT if we're not actively capturing yet, which we shouldn't be, because we're still probing */ if (GST_V4L2_IS_ACTIVE (v4l2object)) - return FALSE; + goto error; GST_LOG_OBJECT (v4l2object->element, "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT"); @@ -2050,7 +2056,7 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, } if (r < 0) - return FALSE; + goto error; } GST_LOG_OBJECT (v4l2object->element, @@ -2073,10 +2079,17 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object, GST_WARNING_OBJECT (v4l2object->element, "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u", GST_FOURCC_ARGS (pixelformat), *width, *height); - return FALSE; + goto error; } + if (prevfmt_valid) + v4l2_ioctl (fd, VIDIOC_S_FMT, &prevfmt); return TRUE; + +error: + if (prevfmt_valid) + v4l2_ioctl (fd, VIDIOC_S_FMT, &prevfmt); + return FALSE; }