[gstreamer1-plugins-good] Fix v4l2-src not working with some v4l2 devices (bgo#735660)

Hans de Goede jwrdegoede at fedoraproject.org
Fri Aug 29 10:56:55 UTC 2014


commit 67202adc8db460dc331c5440741c8c8c91b7578e
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Aug 29 12:56:53 2014 +0200

    Fix v4l2-src not working with some v4l2 devices (bgo#735660)

 ...arest_size-Always-reinit-all-struct-field.patch |   56 ++++++++++
 ...arest_size-Fix-Unsupported-field-type-err.patch |  107 ++++++++++++++++++++
 ...-all-drivers-support-requesting-0-buffers.patch |   68 +++++++++++++
 gstreamer1-plugins-good.spec                       |   12 ++-
 4 files changed, 242 insertions(+), 1 deletions(-)
---
diff --git a/0001-v4l2-get_nearest_size-Always-reinit-all-struct-field.patch b/0001-v4l2-get_nearest_size-Always-reinit-all-struct-field.patch
new file mode 100644
index 0000000..fd859a4
--- /dev/null
+++ b/0001-v4l2-get_nearest_size-Always-reinit-all-struct-field.patch
@@ -0,0 +1,56 @@
+From b3b38ba864ac7eff3cd225ed05c697b67509b263 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 29 Aug 2014 10:57:20 +0200
+Subject: [PATCH 1/3] v4l2: get_nearest_size: Always reinit all struct fields
+ on retry
+
+They may have been modified by the ioctl even if it failed. This also makes
+the S_FMT fallback path try progressive first, making it consistent with the
+preferred TRY_FMT path.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ sys/v4l2/gstv4l2object.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
+index 3b22b1a..881a52d 100644
+--- a/sys/v4l2/gstv4l2object.c
++++ b/sys/v4l2/gstv4l2object.c
+@@ -2171,6 +2171,8 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+   r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+   if (r < 0 && errno == EINVAL) {
+     /* try again with interlaced video */
++    memset (&fmt, 0, sizeof (fmt));
++    fmt.type = v4l2object->type;
+     fmt.fmt.pix.width = *width;
+     fmt.fmt.pix.height = *height;
+     fmt.fmt.pix.pixelformat = pixelformat;
+@@ -2192,16 +2194,22 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+     GST_LOG_OBJECT (v4l2object->element,
+         "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT");
+ 
++    memset (&fmt, 0, sizeof (fmt));
++    fmt.type = v4l2object->type;
+     fmt.fmt.pix.width = *width;
+     fmt.fmt.pix.height = *height;
++    fmt.fmt.pix.pixelformat = pixelformat;
++    fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ 
+     r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
+     if (r < 0 && errno == EINVAL) {
+-      /* try again with progressive video */
++      /* try again with interlaced video */
++      memset (&fmt, 0, sizeof (fmt));
++      fmt.type = v4l2object->type;
+       fmt.fmt.pix.width = *width;
+       fmt.fmt.pix.height = *height;
+       fmt.fmt.pix.pixelformat = pixelformat;
+-      fmt.fmt.pix.field = V4L2_FIELD_NONE;
++      fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+       r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
+     }
+ 
+-- 
+2.1.0
+
diff --git a/0002-v4l2-get_nearest_size-Fix-Unsupported-field-type-err.patch b/0002-v4l2-get_nearest_size-Fix-Unsupported-field-type-err.patch
new file mode 100644
index 0000000..7c62aa3
--- /dev/null
+++ b/0002-v4l2-get_nearest_size-Fix-Unsupported-field-type-err.patch
@@ -0,0 +1,107 @@
+From 92c026bfd32634018c155e458a4df9f6bf8152d3 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 29 Aug 2014 12:01:27 +0200
+Subject: [PATCH 2/3] v4l2: get_nearest_size: Fix "Unsupported field type"
+ errors
+
+Most V4L2 ioctls like try_fmt will adjust input fields to match what the
+hardware can do rather then returning -EINVAL. As is docmented here:
+http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-g-fmt.html
+
+EINVAL is only returned if the buffer type field is invalid or not supported.
+
+So upon requesting V4L2_FIELD_NONE devices which can only do interlaced
+mode will change the field value to e.g. V4L2_FIELD_BOTTOM as only returning
+half the lines is the closest they can do to progressive modes.
+
+In essence this means that we've failed to get a (usable) progessive mode
+and should fall back to interlaced mode.
+
+This commit adds a check for having gotten a usable field value after the first
+try_fmt, to force fallback to interlaced mode even if the try_fmt succeeded,
+thereby fixing get_nearest_size failing on these devices.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ sys/v4l2/gstv4l2object.c | 44 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 27 insertions(+), 17 deletions(-)
+
+diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
+index 881a52d..ef77e71 100644
+--- a/sys/v4l2/gstv4l2object.c
++++ b/sys/v4l2/gstv4l2object.c
+@@ -2141,6 +2141,24 @@ default_frame_sizes:
+ }
+ 
+ static gboolean
++gst_v4l2_object_get_interlace (int field, gboolean * interlaced)
++{
++  switch (field) {
++    case V4L2_FIELD_ANY:
++    case V4L2_FIELD_NONE:
++      *interlaced = FALSE;
++      return TRUE;
++    case V4L2_FIELD_INTERLACED:
++    case V4L2_FIELD_INTERLACED_TB:
++    case V4L2_FIELD_INTERLACED_BT:
++      *interlaced = TRUE;
++      return TRUE;
++    default:
++      return FALSE;
++  }
++}
++
++static gboolean
+ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+     guint32 pixelformat, gint * width, gint * height, gboolean * interlaced)
+ {
+@@ -2169,7 +2187,8 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+   fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ 
+   r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+-  if (r < 0 && errno == EINVAL) {
++  if ((r < 0 && errno == EINVAL) ||
++      !gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
+     /* try again with interlaced video */
+     memset (&fmt, 0, sizeof (fmt));
+     fmt.type = v4l2object->type;
+@@ -2202,7 +2221,8 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+     fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ 
+     r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt);
+-    if (r < 0 && errno == EINVAL) {
++    if ((r < 0 && errno == EINVAL) ||
++        !gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
+       /* try again with interlaced video */
+       memset (&fmt, 0, sizeof (fmt));
+       fmt.type = v4l2object->type;
+@@ -2223,21 +2243,11 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
+   *width = fmt.fmt.pix.width;
+   *height = fmt.fmt.pix.height;
+ 
+-  switch (fmt.fmt.pix.field) {
+-    case V4L2_FIELD_ANY:
+-    case V4L2_FIELD_NONE:
+-      *interlaced = FALSE;
+-      break;
+-    case V4L2_FIELD_INTERLACED:
+-    case V4L2_FIELD_INTERLACED_TB:
+-    case V4L2_FIELD_INTERLACED_BT:
+-      *interlaced = TRUE;
+-      break;
+-    default:
+-      GST_WARNING_OBJECT (v4l2object->element,
+-          "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u",
+-          GST_FOURCC_ARGS (pixelformat), *width, *height);
+-      goto error;
++  if (!gst_v4l2_object_get_interlace (fmt.fmt.pix.field, interlaced)) {
++    GST_WARNING_OBJECT (v4l2object->element,
++        "Unsupported field type for %" GST_FOURCC_FORMAT "@%ux%u: %u",
++        GST_FOURCC_ARGS (pixelformat), *width, *height, fmt.fmt.pix.field);
++    goto error;
+   }
+ 
+   ret = TRUE;
+-- 
+2.1.0
+
diff --git a/0003-v4l2-Not-all-drivers-support-requesting-0-buffers.patch b/0003-v4l2-Not-all-drivers-support-requesting-0-buffers.patch
new file mode 100644
index 0000000..8b588c4
--- /dev/null
+++ b/0003-v4l2-Not-all-drivers-support-requesting-0-buffers.patch
@@ -0,0 +1,68 @@
+From 2f3ea418c9b99486fb8ff72b9c35ef892ffcae1c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Fri, 29 Aug 2014 12:10:01 +0200
+Subject: [PATCH 3/3] v4l2: Not all drivers support requesting 0 buffers
+
+Not all drivers support requesting 0 buffers, specifically any driver using
+the videobuf framework (rather then the new videobuf2 framework) for buffer
+management will not support this.
+
+This commits changes the code to probe available buffer types to request
+atleast one buffer, and to free it again on success, to fix the new gst v4l2
+from not working on these devices.
+
+Also turn being unable to free buffers through requesting 0 buffers from an
+error into a warning for the same reason.
+
+Note these devices do support changing the number of buffers and/or the fmt
+after requesting buffers as long as there is no streaming going on, and the
+buffers will eventually be free-ed when the fd is closed.
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ sys/v4l2/gstv4l2allocator.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/sys/v4l2/gstv4l2allocator.c b/sys/v4l2/gstv4l2allocator.c
+index 68ce902..cbc6a6a 100644
+--- a/sys/v4l2/gstv4l2allocator.c
++++ b/sys/v4l2/gstv4l2allocator.c
+@@ -475,14 +475,20 @@ gst_v4l2_allocator_probe (GstV4l2Allocator * allocator, guint32 memory,
+     guint32 breq_flag, guint32 bcreate_flag)
+ {
+   struct v4l2_requestbuffers breq = { 0 };
++  struct v4l2_create_buffers bcreate = { 0 };
+   guint32 flags = 0;
+ 
+   breq.type = allocator->type;
+-  breq.count = 0;
++  breq.count = 1;
+   breq.memory = memory;
+ 
+   if (v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq) == 0) {
+-    struct v4l2_create_buffers bcreate = { 0 };
++    /* Free the buffers, ignore the result not all drivers support this */
++    memset (&breq, 0, sizeof (breq));
++    breq.type = allocator->type;
++    breq.count = 0;
++    breq.memory = memory;
++    v4l2_ioctl (allocator->video_fd, VIDIOC_REQBUFS, &breq);
+ 
+     flags |= breq_flag;
+ 
+@@ -779,9 +785,10 @@ done:
+ 
+ reqbufs_failed:
+   {
+-    GST_ERROR_OBJECT (allocator,
++    GST_WARNING_OBJECT (allocator,
+         "error releasing buffers buffers: %s", g_strerror (errno));
+-    ret = GST_V4L2_ERROR;
++    /* Not all drivers support freeing buffers by requesting 0 buffers, so
++       we don't set ret to an error here. */
+     goto done;
+   }
+ }
+-- 
+2.1.0
+
diff --git a/gstreamer1-plugins-good.spec b/gstreamer1-plugins-good.spec
index ff2098c..8345bcc 100644
--- a/gstreamer1-plugins-good.spec
+++ b/gstreamer1-plugins-good.spec
@@ -9,12 +9,16 @@
 
 Name:           gstreamer1-plugins-good
 Version:        1.4.1
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        GStreamer plugins with good code and licensing
 
 License:        LGPLv2+
 URL:            http://gstreamer.freedesktop.org/
 Source0:        http://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-%{version}.tar.xz
+# https://bugzilla.gnome.org/show_bug.cgi?id=735660
+Patch1:         0001-v4l2-get_nearest_size-Always-reinit-all-struct-field.patch
+Patch2:         0002-v4l2-get_nearest_size-Fix-Unsupported-field-type-err.patch
+Patch3:         0003-v4l2-Not-all-drivers-support-requesting-0-buffers.patch
 
 BuildRequires:  gstreamer1-devel >= %{version}
 BuildRequires:  gstreamer1-plugins-base-devel >= %{version}
@@ -84,6 +88,9 @@ to be installed.
 
 %prep
 %setup -q -n gst-plugins-good-%{version}
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
 
 %build
 %configure \
@@ -202,6 +209,9 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
 
 
 %changelog
+* Fri Aug 29 2014 Hans de Goede <hdegoede at redhat.com> - 1.4.1-2
+- Fix v4l2-src not working with some v4l2 devices (bgo#735660)
+
 * Fri Aug 29 2014 Wim Taymans <wtaymans at redhat.com> - 1.4.1-1
 - Update to 1.4.1.
 


More information about the scm-commits mailing list