Blob Blame History Raw
From 92c026bfd32634018c155e458a4df9f6bf8152d3 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@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@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