v4l2rc: Add DV_TIMINGS query and locking
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 10 Feb 2021 20:52:55 +0000 (15:52 -0500)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Fri, 19 Feb 2021 21:02:02 +0000 (16:02 -0500)
This adds support to DV_TIMINGS query and locking. The timing width and
height is then used as a preference.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/870>

sys/v4l2/gstv4l2bufferpool.h
sys/v4l2/gstv4l2object.h
sys/v4l2/gstv4l2src.c
sys/v4l2/v4l2_calls.c

index b61a6ea..f4fdf92 100644 (file)
@@ -41,6 +41,10 @@ G_BEGIN_DECLS
 #define GST_V4L2_BUFFER_POOL(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
 #define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
 
+/* Returns true if the pool is streaming. Must be called with stream lock
+ * held. */
+#define GST_V4L2_BUFFER_POOL_IS_STREAMING(obj) (GST_V4L2_BUFFER_POOL (obj)->streaming)
+
 /* This flow return is used to indicate that the last buffer has been dequeued
  * during draining. This should normally only occur for mem-2-mem devices. */
 #define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS
index 394f429..e5ed0ac 100644 (file)
@@ -330,6 +330,10 @@ gboolean     gst_v4l2_query_input    (GstV4l2Object * v4l2object, struct v4l2_in
 gboolean     gst_v4l2_get_output     (GstV4l2Object * v4l2object, guint32 * output);
 gboolean     gst_v4l2_set_output     (GstV4l2Object * v4l2object, guint32 output);
 
+/* dv timings */
+gboolean     gst_v4l2_set_dv_timings   (GstV4l2Object * v4l2object, struct v4l2_dv_timings *timings);
+gboolean     gst_v4l2_query_dv_timings (GstV4l2Object * v4l2object, struct v4l2_dv_timings *timings);
+
 /* frequency control */
 gboolean     gst_v4l2_get_frequency   (GstV4l2Object * v4l2object, gint tunernum, gulong * frequency);
 gboolean     gst_v4l2_set_frequency   (GstV4l2Object * v4l2object, gint tunernum, gulong frequency);
index 5c3888a..e2aa918 100644 (file)
@@ -491,8 +491,22 @@ static gboolean
 gst_v4l2src_query_preferred_dv_timings (GstV4l2Src * v4l2src,
     struct PreferredCapsInfo *pref)
 {
-  GST_FIXME_OBJECT (v4l2src, "query dv_timings not implements");
-  return NULL;
+  GstV4l2Object *obj = v4l2src->v4l2object;
+  struct v4l2_dv_timings dv_timings = { 0, };
+
+  if (!gst_v4l2_query_dv_timings (obj, &dv_timings))
+    return FALSE;
+
+  pref->width = dv_timings.bt.width;
+  pref->height = dv_timings.bt.height;
+  /* FIXME calculate frame rate */
+
+  /* If are are not streaming (e.g. we received source-change event), lock the
+   * new timing immediatly so that TRY_FMT can properly work */
+  if (!obj->pool || !GST_V4L2_BUFFER_POOL_IS_STREAMING (obj->pool))
+    gst_v4l2_set_dv_timings (obj, &dv_timings);
+
+  return TRUE;
 }
 
 static gboolean
index dce8e33..2dada91 100644 (file)
@@ -1286,3 +1286,74 @@ gst_v4l2_dequeue_event (GstV4l2Object * v4l2object, struct v4l2_event * event)
 
   return TRUE;
 }
+
+gboolean
+gst_v4l2_set_dv_timings (GstV4l2Object * v4l2object,
+    struct v4l2_dv_timings * timings)
+{
+  gint ret;
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_DV_TIMINGS, timings);
+
+  if (ret < 0) {
+    GST_ERROR_OBJECT (v4l2object->dbg_obj, "S_DV_TIMINGS failed: %s (%i)",
+        g_strerror (errno), errno);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+gboolean
+gst_v4l2_query_dv_timings (GstV4l2Object * v4l2object,
+    struct v4l2_dv_timings * timings)
+{
+  gint ret;
+
+  if (!GST_V4L2_IS_OPEN (v4l2object))
+    return FALSE;
+
+  ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERY_DV_TIMINGS,
+      timings);
+
+  if (ret < 0) {
+    switch (errno) {
+      case ENODATA:
+        GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+            "QUERY_DV_TIMINGS not supported for this input/output");
+        break;
+      case ENOLINK:
+        GST_DEBUG_OBJECT (v4l2object->dbg_obj,
+            "No timings could be detected because no signal was found.");
+        break;
+      case ENOLCK:
+        GST_INFO_OBJECT (v4l2object->dbg_obj,
+            "The signal was unstable and the hardware could not lock on to it.");
+        break;
+      case ERANGE:
+        GST_INFO_OBJECT (v4l2object->dbg_obj,
+            "Timings were found, but they are out of range of the hardware capabilities.");
+        break;
+      default:
+        GST_ERROR_OBJECT (v4l2object->dbg_obj,
+            "QUERY_DV_TIMINGS failed: %s (%i)", g_strerror (errno), errno);
+        break;
+    }
+
+    return FALSE;
+  }
+
+  if (timings->type != V4L2_DV_BT_656_1120) {
+    GST_FIXME_OBJECT (v4l2object->dbg_obj, "Unsupported DV Timings type (%i)",
+        timings->type);
+    return FALSE;
+  }
+
+  GST_INFO_OBJECT (v4l2object->dbg_obj, "Detected DV Timings (%i x %i)",
+      timings->bt.width, timings->bt.height);
+
+  return TRUE;
+}