From: Daniel Drake v4l2src only uses V4L2_FIELD_INTERLACED which is a whole-frame capture mode (it requests interlaced video where the two fields have already been merged together). However most webcams only offer progressive video (i.e. V4L2_FIELD_NONE) and will reject any requests for interlaced video. Other drivers will only offer progressive and will silently 'correct' gstreamer's request for interlaced video. I questioned this driver inconsistency here: http://marc.info/?l=linux-video&m=121434022130546&w=2 And Mauro then told me on IRC that both behaviours are correct: it's fine for drivers to reject unsupported fields with -EINVAL, and it's also fine for simple drivers to silently fix up the user's request. So in order to speak to a wider number of cameras, gstreamer should tolerate the fact that drivers may reject a request for interlaced images with -EINVAL and should then retry for progressive (Mauro confirmed this approach is the best we have at the moment). This patch also allows OLPC to drop a patch that we needed to get the XO webcam working: http://dev.laptop.org/attachment/ticket/7294/v4l2-nointerlace.patch http://dev.laptop.org/ticket/7294 Index: gst-plugins-good-0.10.8/sys/v4l2/v4l2src_calls.c =================================================================== --- gst-plugins-good-0.10.8.orig/sys/v4l2/v4l2src_calls.c +++ gst-plugins-good-0.10.8/sys/v4l2/v4l2src_calls.c @@ -1149,11 +1149,23 @@ gst_v4l2src_set_capture (GstV4l2Src * v4 format.fmt.pix.width = width; format.fmt.pix.height = height; format.fmt.pix.pixelformat = pixelformat; - /* request whole frames; change when gstreamer supports interlaced video */ + /* request whole frames; change when gstreamer supports interlaced video + * (INTERLACED mode returns frames where the fields have already been + * combined, there are other modes for requesting fields individually) */ format.fmt.pix.field = V4L2_FIELD_INTERLACED; - if (ioctl (fd, VIDIOC_S_FMT, &format) < 0) - goto set_fmt_failed; + if (ioctl (fd, VIDIOC_S_FMT, &format) < 0) { + if (errno != EINVAL) + goto set_fmt_failed; + + /* try again with progressive video */ + format.fmt.pix.width = width; + format.fmt.pix.height = height; + format.fmt.pix.pixelformat = pixelformat; + format.fmt.pix.field = V4L2_FIELD_NONE; + if (ioctl (fd, VIDIOC_S_FMT, &format) < 0) + goto set_fmt_failed; + } if (format.fmt.pix.width != width || format.fmt.pix.height != height) goto invalid_dimensions; @@ -1473,6 +1485,7 @@ gst_v4l2src_get_nearest_size (GstV4l2Src { struct v4l2_format fmt; int fd; + int r; g_return_val_if_fail (width != NULL, FALSE); g_return_val_if_fail (height != NULL, FALSE); @@ -1491,7 +1504,17 @@ gst_v4l2src_get_nearest_size (GstV4l2Src fmt.fmt.pix.pixelformat = pixelformat; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - if (ioctl (fd, VIDIOC_TRY_FMT, &fmt) < 0) { + r = ioctl (fd, VIDIOC_TRY_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with progressive video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + r = ioctl (fd, VIDIOC_TRY_FMT, &fmt); + } + + if (r < 0) { /* The driver might not implement TRY_FMT, in which case we will try S_FMT to probe */ if (errno != ENOTTY) @@ -1508,7 +1531,17 @@ gst_v4l2src_get_nearest_size (GstV4l2Src fmt.fmt.pix.width = *width; fmt.fmt.pix.height = *height; - if (ioctl (fd, VIDIOC_S_FMT, &fmt) < 0) + r = ioctl (fd, VIDIOC_S_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with progressive video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + r = ioctl (fd, VIDIOC_S_FMT, &fmt); + } + + if (r < 0) return FALSE; }