v4l2: Move M2M template caps probe into v4l2object
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Thu, 15 Aug 2024 17:07:31 +0000 (13:07 -0400)
committerNicolas Dufresne <nicolas@ndufresne.ca>
Tue, 24 Sep 2024 20:19:12 +0000 (20:19 +0000)
This allow reusing the code that produces output and capture devices
templates. This fixes the lack of Interlaced caps feature for M2M
devices such as decoder, encoder or converters.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7563>

subprojects/gst-plugins-good/sys/v4l2/gstv4l2.c
subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.c
subprojects/gst-plugins-good/sys/v4l2/gstv4l2object.h

index 2d607094475a7f522c90ebe3cbe4b6083f89c4fb..3944a6a2b7ff639d0c3e1667bc855f275a7b5653 100644 (file)
@@ -62,63 +62,6 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 #define GST_CAT_DEFAULT v4l2_debug
 
 #ifdef GST_V4L2_ENABLE_PROBE
-/* This is a minimalist probe, for speed, we only enumerate formats */
-static GstCaps *
-gst_v4l2_probe_template_caps (const gchar * device, gint video_fd,
-    enum v4l2_buf_type type)
-{
-  gint n;
-  struct v4l2_fmtdesc format;
-  GstCaps *caps;
-
-  GST_DEBUG ("Getting %s format enumerations", device);
-  caps = gst_caps_new_empty ();
-
-  for (n = 0;; n++) {
-    GstStructure *template;
-
-    memset (&format, 0, sizeof (format));
-
-    format.index = n;
-    format.type = type;
-
-    if (ioctl (video_fd, VIDIOC_ENUM_FMT, &format) < 0)
-      break;                    /* end of enumeration */
-
-    GST_LOG ("index:       %u", format.index);
-    GST_LOG ("type:        %d", format.type);
-    GST_LOG ("flags:       %08x", format.flags);
-    GST_LOG ("description: '%s'", format.description);
-    GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
-        GST_FOURCC_ARGS (format.pixelformat));
-
-    template = gst_v4l2_object_v4l2fourcc_to_structure (format.pixelformat);
-
-    if (template) {
-      GstStructure *alt_t = NULL;
-
-      switch (format.pixelformat) {
-        case V4L2_PIX_FMT_RGB32:
-          alt_t = gst_structure_copy (template);
-          gst_structure_set (alt_t, "format", G_TYPE_STRING, "ARGB", NULL);
-          break;
-        case V4L2_PIX_FMT_BGR32:
-          alt_t = gst_structure_copy (template);
-          gst_structure_set (alt_t, "format", G_TYPE_STRING, "BGRA", NULL);
-        default:
-          break;
-      }
-
-      gst_caps_append_structure (caps, template);
-
-      if (alt_t)
-        gst_caps_append_structure (caps, alt_t);
-    }
-  }
-
-  return gst_caps_simplify (caps);
-}
-
 static gboolean
 gst_v4l2_probe_and_register (GstPlugin * plugin)
 {
@@ -126,6 +69,7 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
   gint video_fd = -1;
   struct v4l2_capability vcap;
   guint32 device_caps;
+  enum v4l2_buf_type output_type, capture_type;
 
   v4l2_element_init (plugin);
 
@@ -140,6 +84,7 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
     if (video_fd >= 0)
       close (video_fd);
 
+    /* FIXME, missing libv4l2 support */
     video_fd = open (it->device_path, O_RDWR | O_CLOEXEC);
 
     if (video_fd == -1) {
@@ -150,7 +95,8 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
     memset (&vcap, 0, sizeof (vcap));
 
     if (ioctl (video_fd, VIDIOC_QUERYCAP, &vcap) < 0) {
-      GST_DEBUG ("Failed to get device capabilities: %s", g_strerror (errno));
+      GST_DEBUG ("Failed to get device '%s' capabilities: %s",
+          it->device_path, g_strerror (errno));
       continue;
     }
 
@@ -162,26 +108,33 @@ gst_v4l2_probe_and_register (GstPlugin * plugin)
     if (!GST_V4L2_IS_M2M (device_caps))
       continue;
 
+    if (device_caps & V4L2_CAP_VIDEO_M2M_MPLANE) {
+      output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    } else {
+      output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+      capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    }
+
     GST_DEBUG ("Probing '%s' located at '%s'",
         it->device_name ? it->device_name : (const gchar *) vcap.driver,
         it->device_path);
 
     /* get sink supported format (no MPLANE for codec) */
-    sink_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
-            video_fd, V4L2_BUF_TYPE_VIDEO_OUTPUT),
-        gst_v4l2_probe_template_caps (it->device_path, video_fd,
-            V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE));
-
+    sink_caps = gst_v4l2_object_probe_template_caps (it->device_path,
+        video_fd, output_type);
     /* get src supported format */
-    src_caps = gst_caps_merge (gst_v4l2_probe_template_caps (it->device_path,
-            video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE),
-        gst_v4l2_probe_template_caps (it->device_path, video_fd,
-            V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE));
+    src_caps = gst_v4l2_object_probe_template_caps (it->device_path,
+        video_fd, capture_type);
 
     /* Skip devices without any supported formats */
     if (gst_caps_is_empty (sink_caps) || gst_caps_is_empty (src_caps)) {
       gst_caps_unref (sink_caps);
       gst_caps_unref (src_caps);
+
+      GST_DEBUG ("Skipping unsupported device '%s' located at '%s'",
+          it->device_name ? it->device_name : (const gchar *) vcap.driver,
+          it->device_path);
       continue;
     }
 
index 4d39819483e1798dd3eb44edb07cfff5a3570356..1431b98b42d50f71d831811a3d33817e0bfac342 100644 (file)
@@ -1696,7 +1696,8 @@ add_non_colorimetry_caps (GstV4l2Object * v4l2object, GstCaps * caps)
 }
 
 static GstCaps *
-gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags)
+gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags,
+    const GstV4L2FormatDesc * formats, const guint len)
 {
   GstStructure *structure;
   GstCaps *caps, *caps_interlaced;
@@ -1704,10 +1705,10 @@ gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags)
 
   caps = gst_caps_new_empty ();
   caps_interlaced = gst_caps_new_empty ();
-  for (i = 0; i < GST_V4L2_FORMAT_COUNT; i++) {
-    guint32 fourcc = gst_v4l2_formats[i].v4l2_format;
+  for (i = 0; i < len; i++) {
+    guint32 fourcc = formats[i].v4l2_format;
 
-    if ((gst_v4l2_formats[i].flags & flags) == 0)
+    if ((formats[i].flags & flags) == 0)
       continue;
 
     structure = gst_v4l2_object_v4l2fourcc_to_bare_struct (fourcc);
@@ -1715,7 +1716,7 @@ gst_v4l2_object_get_caps_helper (GstV4L2FormatFlags flags)
     if (structure) {
       GstStructure *alt_s = NULL;
 
-      if (gst_v4l2_formats[i].flags & GST_V4L2_RESOLUTION_AND_RATE) {
+      if (formats[i].flags & GST_V4L2_RESOLUTION_AND_RATE) {
         gst_structure_set (structure,
             "width", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
             "height", GST_TYPE_INT_RANGE, 1, GST_V4L2_MAX_SIZE,
@@ -1757,7 +1758,8 @@ gst_v4l2_object_get_all_caps (void)
   static GstCaps *caps = NULL;
 
   if (g_once_init_enter (&caps)) {
-    GstCaps *all_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_ALL);
+    GstCaps *all_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_ALL,
+        gst_v4l2_formats, GST_V4L2_FORMAT_COUNT);
     GST_MINI_OBJECT_FLAG_SET (all_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
     g_once_init_leave (&caps, all_caps);
   }
@@ -1771,7 +1773,8 @@ gst_v4l2_object_get_raw_caps (void)
   static GstCaps *caps = NULL;
 
   if (g_once_init_enter (&caps)) {
-    GstCaps *raw_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_RAW);
+    GstCaps *raw_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_RAW,
+        gst_v4l2_formats, GST_V4L2_FORMAT_COUNT);
     GST_MINI_OBJECT_FLAG_SET (raw_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
     g_once_init_leave (&caps, raw_caps);
   }
@@ -1785,7 +1788,8 @@ gst_v4l2_object_get_codec_caps (void)
   static GstCaps *caps = NULL;
 
   if (g_once_init_enter (&caps)) {
-    GstCaps *codec_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_CODEC);
+    GstCaps *codec_caps = gst_v4l2_object_get_caps_helper (GST_V4L2_CODEC,
+        gst_v4l2_formats, GST_V4L2_FORMAT_COUNT);
     GST_MINI_OBJECT_FLAG_SET (codec_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
     g_once_init_leave (&caps, codec_caps);
   }
@@ -1793,6 +1797,46 @@ gst_v4l2_object_get_codec_caps (void)
   return caps;
 }
 
+/* This is a minimalist probe, for speed, we only enumerate formats */
+GstCaps *
+gst_v4l2_object_probe_template_caps (const gchar * device, gint video_fd,
+    enum v4l2_buf_type type)
+{
+  GArray *formats = g_array_new (FALSE, TRUE, sizeof (GstV4L2FormatDesc));
+  GstCaps *caps;
+  gint n;
+
+  GST_DEBUG ("Getting %s format enumerations", device);
+  for (n = 0;; n++) {
+    const GstV4L2FormatDesc *desc;
+    struct v4l2_fmtdesc fmtdesc = {
+      .index = n,
+      .type = type,
+    };
+
+    /* FIXME, missing libv4l2 support */
+    if (ioctl (video_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0)
+      break;                    /* end of enumeration */
+
+    GST_LOG ("index:       %u", fmtdesc.index);
+    GST_LOG ("type:        %d", fmtdesc.type);
+    GST_LOG ("flags:       %08x", fmtdesc.flags);
+    GST_LOG ("description: '%s'", fmtdesc.description);
+    GST_LOG ("pixelformat: %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (fmtdesc.pixelformat));
+
+    desc = gst_v4l2_object_get_desc_from_v4l2fourcc (fmtdesc.pixelformat);
+    if (desc)
+      g_array_append_val (formats, *desc);
+  }
+
+  caps = gst_v4l2_object_get_caps_helper (GST_V4L2_ALL,
+      (const GstV4L2FormatDesc *) formats->data, formats->len);
+  g_array_free (formats, TRUE);
+
+  return caps;
+}
+
 /* collect data for the given caps
  * @caps: given input caps
  * @format: location for the v4l format
index 1485fbe91f7323b29728a87a9010ad030bb5ee35..2e8d9264daad2f14f06510e2a42e69693fce2c10 100644 (file)
@@ -296,6 +296,9 @@ GstCaps*     gst_v4l2_object_get_raw_caps (void);
 
 GstCaps*     gst_v4l2_object_get_codec_caps (void);
 
+GstCaps*     gst_v4l2_object_probe_template_caps (const gchar * device, gint video_fd,
+                                                  enum v4l2_buf_type type);
+
 gboolean     gst_v4l2_object_set_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
 gboolean     gst_v4l2_object_try_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
 gboolean     gst_v4l2_object_try_import  (GstV4l2Object * v4l2object, GstBuffer * buffer);