v4lsrc: optional support for device probing with gudev
authorFilippo Argiolas <filippo.argiolas@gmail.com>
Fri, 3 Jul 2009 09:38:01 +0000 (11:38 +0200)
committerFilippo Argiolas <filippo.argiolas@gmail.com>
Mon, 13 Jul 2009 14:13:25 +0000 (16:13 +0200)
Enumerate v4l devices using gudev if available.

Fixes bug #583640.

configure.ac
sys/v4l/Makefile.am
sys/v4l/gstv4lelement.c

index da8f5395b4e9039b4f7324dc3b86bc27b0eabf3d..5b9c84f78f6497b8060d5d4d55d7385adef3bca9 100644 (file)
@@ -436,6 +436,29 @@ AG_GST_CHECK_FEATURE(GST_V4L, [Video 4 Linux], video4linux, [
   fi
 ])
 
+# Optional gudev for device probing
+AC_ARG_WITH([gudev],
+  AC_HELP_STRING([--with-gudev],
+    [device detection with gudev]),
+  [],
+  [with_gudev=check])
+if test x$HAVE_GST_V4L = xyes; then
+  if test x$with_gudev != xno; then
+      PKG_CHECK_MODULES(GUDEV, [ gudev-1.0 >= 143 ],
+          [ have_gudev=yes
+            AC_DEFINE(HAVE_GUDEV, 1,
+               [Whether gudev is available for device detection])
+            AC_DEFINE([G_UDEV_API_IS_SUBJECT_TO_CHANGE], 1, [I know the API is subject to change.])
+          ], [
+          have_gudev=no
+          ])
+  else
+    have_gudev=no
+  fi
+fi
+AC_SUBST(GUDEV_CFLAGS)
+AC_SUBST(GUDEV_LIBS)
+
 dnl *** ext plug-ins ***
 dnl keep this list sorted alphabetically !
 
index fc106948ed5c6c5531c0e561c6c35237c99fa072..688ec963938b3182e963a610bb07fe0b21e4953f 100644 (file)
@@ -22,10 +22,12 @@ libgstvideo4linux_la_SOURCES = \
 #      gstv4lmjpegsink.c v4lmjpegsink_calls.c
 
 libgstvideo4linux_la_CFLAGS = \
-       $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS)
+       $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) \
+       $(GUDEV_CFLAGS)
 libgstvideo4linux_la_LIBADD = \
        $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
-       $(GST_BASE_LIBS) $(GST_LIBS) $(xv_libs)
+       $(GST_BASE_LIBS) $(GST_LIBS) $(xv_libs) \
+       $(GUDEV_LIBS)
 libgstvideo4linux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstvideo4linux_la_LIBTOOLFLAGS = --tag=disable-static
 
index f536aaaabf4ea87957b90952f5a989411736e79e..81a76d43335c3ae0c7bc7d47216df72018e84511 100644 (file)
 
 #include <gst/interfaces/propertyprobe.h>
 
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+#endif
+
 #include "v4l_calls.h"
 #include "gstv4ltuner.h"
 #ifdef HAVE_XVIDEO
@@ -48,6 +52,8 @@ enum
   PROP_FLAGS
 };
 
+GST_DEBUG_CATEGORY (v4lelement_debug);
+#define GST_CAT_DEFAULT v4lelement_debug
 
 static void gst_v4lelement_init_interfaces (GType type);
 
@@ -108,20 +114,76 @@ gst_v4l_probe_get_properties (GstPropertyProbe * probe)
   return list;
 }
 
+static gboolean init = FALSE;
+static GList *devices = NULL;
+
+#ifdef HAVE_GUDEV
 static gboolean
-gst_v4l_class_probe_devices (GstV4lElementClass * klass, gboolean check)
+gst_v4l_class_probe_devices_with_udev (GstV4lElementClass * klass,
+    gboolean check)
 {
-  static gboolean init = FALSE;
-  static GList *devices = NULL;
+  GUdevClient *client;
+  GList *item;
+
+  if (!check) {
+    while (devices) {
+      gchar *device = devices->data;
+      devices = g_list_remove (devices, device);
+      g_free (device);
+    }
+
+    GST_INFO ("Enumerating video4linux devices from udev");
+    client = g_udev_client_new (NULL);
+    if (!client) {
+      GST_WARNING ("Failed to initialize gudev client");
+      goto finish;
+    }
+
+    item = g_udev_client_query_by_subsystem (client, "video4linux");
+    while (item) {
+      GUdevDevice *device = item->data;
+      gchar *devnode = g_strdup (g_udev_device_get_device_file (device));
+      gint api = g_udev_device_get_property_as_int (device, "ID_V4L_VERSION");
+      GST_INFO ("Found new device: %s, API: %d", devnode, api);
+      /* Append v4l1 devices only. If api is 0 probably v4l_id has
+         been stripped out of the current udev installation, append
+         anyway */
+      if (api == 0) {
+        GST_WARNING
+            ("Couldn't retrieve ID_V4L_VERSION, silly udev installation?");
+      }
+      if ((api == 1 || api == 0)) {
+        devices = g_list_append (devices, devnode);
+      } else {
+        g_free (devnode);
+      }
+      g_object_unref (device);
+      item = item->next;
+    }
+    g_list_free (item);
+    init = TRUE;
+  }
+
+finish:
+  if (client) {
+    g_object_unref (client);
+  }
+
+  klass->devices = devices;
+
+  return init;
+}
+#endif /* HAVE_GUDEV */
 
+static gboolean
+gst_v4l_class_probe_devices (GstV4lElementClass * klass, gboolean check)
+{
   if (!check) {
     gchar *dev_base[] = { "/dev/video", "/dev/v4l/video", NULL };
     gint base, n, fd;
 
     while (devices) {
-      GList *item = devices;
-      gchar *device = item->data;
-
+      gchar *device = devices->data;
       devices = g_list_remove (devices, device);
       g_free (device);
     }
@@ -163,7 +225,12 @@ gst_v4l_probe_probe_property (GstPropertyProbe * probe,
 
   switch (prop_id) {
     case PROP_DEVICE:
+#ifdef HAVE_GUDEV
+      if (!gst_v4l_class_probe_devices_with_udev (klass, FALSE))
+        gst_v4l_class_probe_devices (klass, FALSE);
+#else /* !HAVE_GUDEV */
       gst_v4l_class_probe_devices (klass, FALSE);
+#endif /* HAVE_GUDEV */
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
@@ -180,6 +247,11 @@ gst_v4l_probe_needs_probe (GstPropertyProbe * probe,
 
   switch (prop_id) {
     case PROP_DEVICE:
+#ifdef HAVE_GUDEV
+      ret = !gst_v4l_class_probe_devices_with_udev (klass, FALSE);
+#else /* !HAVE_GUDEV */
+      ret = !gst_v4l_class_probe_devices (klass, TRUE);
+#endif /* HAVE_GUDEV */
       ret = !gst_v4l_class_probe_devices (klass, TRUE);
       break;
     default:
@@ -319,6 +391,9 @@ gst_v4lelement_base_init (gpointer g_class)
   GstV4lElementClass *klass = GST_V4LELEMENT_CLASS (g_class);
 
   klass->devices = NULL;
+
+  GST_DEBUG_CATEGORY_INIT (v4lelement_debug, "v4lelement", 0,
+      "V4L Base Class debug");
 }
 
 static void