devicemonitor: Add GstDeviceMonitor and related
authorOlivier Crête <olivier.crete@collabora.com>
Tue, 16 Oct 2012 16:27:04 +0000 (12:27 -0400)
committerTim-Philipp Müller <tim@centricular.com>
Sun, 16 Mar 2014 14:38:07 +0000 (14:38 +0000)
Also add GstDevice and GstDeviceMonitorFactory
And add code to the registry to save them

https://bugzilla.gnome.org/show_bug.cgi?id=678402

18 files changed:
gst/Makefile.am
gst/gst.h
gst/gst_private.h
gst/gstdevice.c [new file with mode: 0644]
gst/gstdevice.h [new file with mode: 0644]
gst/gstdevicemonitor.c [new file with mode: 0644]
gst/gstdevicemonitor.h [new file with mode: 0644]
gst/gstdevicemonitorfactory.c [new file with mode: 0644]
gst/gstdevicemonitorfactory.h [new file with mode: 0644]
gst/gstmessage.c
gst/gstmessage.h
gst/gstquark.c
gst/gstquark.h
gst/gstregistry.c
gst/gstregistrybinary.c
gst/gstregistrychunks.c
gst/gstregistrychunks.h
win32/common/libgstreamer.def

index b6cf720..af84844 100644 (file)
@@ -71,6 +71,9 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
        gstcontrolsource.c \
        gstdatetime.c           \
        gstdebugutils.c         \
+       gstdevice.c             \
+       gstdevicemonitor.c      \
+       gstdevicemonitorfactory.c \
        gstelement.c            \
        gstelementfactory.c     \
        gsterror.c              \
@@ -172,6 +175,9 @@ gst_headers =                       \
        gstdebugutils.h         \
        gstelement.h            \
        gstelementmetadata.h    \
+       gstdevice.h             \
+       gstdevicemonitor.h      \
+       gstdevicemonitorfactory.h \
        gstelementfactory.h     \
        gsterror.h              \
        gstevent.h              \
index 82f6bf9..5e24e17 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -42,6 +42,8 @@
 #include <gst/gstcontrolsource.h>
 #include <gst/gstdatetime.h>
 #include <gst/gstdebugutils.h>
+#include <gst/gstdevice.h>
+#include <gst/gstdevicemonitor.h>
 #include <gst/gstelement.h>
 #include <gst/gstelementmetadata.h>
 #include <gst/gsterror.h>
index 0e2d0b3..d610560 100644 (file)
@@ -54,6 +54,9 @@ extern const char             g_log_domain_gstreamer[];
 /* for GstElement */
 #include "gstelement.h"
 
+/* for GstDeviceMonitor */
+#include "gstdevicemonitor.h"
+
 /* for GstToc */
 #include "gsttoc.h"
 
@@ -393,5 +396,24 @@ struct _GstElementFactoryClass {
   gpointer _gst_reserved[GST_PADDING];
 };
 
+struct _GstDeviceMonitorFactory {
+  GstPluginFeature           feature;
+  /* <private> */
+
+  GType                      type;              /* unique GType the device factory or 0 if not loaded */
+
+  volatile GstDeviceMonitor *monitor;
+  gpointer                   metadata;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstDeviceMonitorFactoryClass {
+  GstPluginFeatureClass         parent;
+  /* <private> */
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
 G_END_DECLS
 #endif /* __GST_PRIVATE_H__ */
diff --git a/gst/gstdevice.c b/gst/gstdevice.c
new file mode 100644 (file)
index 0000000..64f3925
--- /dev/null
@@ -0,0 +1,231 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstdevice.c: Device discovery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst/gst_private.h"
+
+#include <gst/gstdevice.h>
+#include <gst/gst.h>
+
+enum
+{
+  PROP_DISPLAY_NAME = 1,
+  PROP_CAPS
+};
+
+enum
+{
+  REMOVED,
+  LAST_SIGNAL
+};
+
+struct _GstDevicePrivate
+{
+  GstCaps *caps;
+  gchar *display_name;
+};
+
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_ABSTRACT_TYPE (GstDevice, gst_device, GST_TYPE_OBJECT);
+
+static void gst_device_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_device_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_device_finalize (GObject * object);
+
+
+static void
+gst_device_class_init (GstDeviceClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GstDevicePrivate));
+
+  object_class->get_property = gst_device_get_property;
+  object_class->set_property = gst_device_set_property;
+  object_class->finalize = gst_device_finalize;
+
+  g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
+      g_param_spec_string ("display-name", "Display Name",
+          "The user-friendly name of the device", "",
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+  g_object_class_install_property (object_class, PROP_CAPS,
+      g_param_spec_boxed ("caps", "Device Caps",
+          "The possible caps of a device", GST_TYPE_CAPS,
+          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  signals[REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+static void
+gst_device_init (GstDevice * device)
+{
+  device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, GST_TYPE_DEVICE,
+      GstDevicePrivate);
+}
+
+static void
+gst_device_finalize (GObject * object)
+{
+  GstDevice *device = GST_DEVICE (object);
+
+  gst_caps_replace (&device->priv->caps, NULL);
+
+  g_free (device->priv->display_name);
+
+  G_OBJECT_CLASS (gst_device_parent_class)->finalize (object);
+}
+
+static void
+gst_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDevice *gstdevice;
+
+  gstdevice = GST_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_NAME:
+      g_value_take_string (value, gst_device_get_display_name (gstdevice));
+      break;
+    case PROP_CAPS:
+      if (gstdevice->priv->caps)
+        g_value_take_boxed (value, gst_device_get_caps (gstdevice));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+gst_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDevice *gstdevice;
+
+  gstdevice = GST_DEVICE_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_NAME:
+      gstdevice->priv->display_name = g_value_dup_string (value);
+      break;
+    case PROP_CAPS:
+      gst_caps_replace (&gstdevice->priv->caps, g_value_get_boxed (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+/**
+ * gst_device_create_element:
+ * @device: a #GstDevice
+ * @name: (allow-none): name of new element, or NULL to automatically
+ * create a unique name.
+ *
+ * Returns: (transfer full): a new #GstElement configured to use this device
+ *
+ * Since: 1.4
+ */
+GstElement *
+gst_device_create_element (GstDevice * device, const gchar * name)
+{
+  GstDeviceClass *klass = GST_DEVICE_GET_CLASS (device);
+
+  if (klass->create_element)
+    return klass->create_element (device, name);
+  else
+    return NULL;
+}
+
+/**
+ * gst_device_get_caps:
+ * @device: a #GstDevice
+ *
+ * Getter for the #GstCaps that this device supports.
+ *
+ * Returns: The #GstCaps supported by this device. Unref with
+ * gst_caps_unref() when done.
+ *
+ * Since: 1.4
+ */
+GstCaps *
+gst_device_get_caps (GstDevice * device)
+{
+  if (device->priv->caps)
+    return gst_caps_ref (device->priv->caps);
+  else
+    return NULL;
+}
+
+/**
+ * gst_device_get_display_name:
+ * @device: a #GstDevice
+ *
+ * Gets the user-friendly name of the device.
+ *
+ * Returns: The device name. Free with g_free() after use.
+ *
+ * Since: 1.4
+ */
+gchar *
+gst_device_get_display_name (GstDevice * device)
+{
+  return g_strdup (device->priv->display_name);
+}
+
+/**
+ * gst_device_reconfigure_element:
+ * @device: a #GstDevice
+ * @element: a #GstElement
+ *
+ * Tries to reconfigure an existing element to use the device. If this
+ * function fails, then one must destroy the element and create a new one
+ * using gst_device_create_element().
+ *
+ * Note: This should only be implemented for elements can change their
+ * device in the PLAYING state.
+ *
+ * Returns: %TRUE if the element could be reconfigured to use this device,
+ * %FALSE otherwise.
+ *
+ * Since: 1.4
+ */
+gboolean
+gst_device_reconfigure_element (GstDevice * device, GstElement * element)
+{
+  GstDeviceClass *klass = GST_DEVICE_GET_CLASS (device);
+
+  if (klass->reconfigure_element)
+    return klass->reconfigure_element (device, element);
+  else
+    return FALSE;
+}
diff --git a/gst/gstdevice.h b/gst/gstdevice.h
new file mode 100644 (file)
index 0000000..dc71eeb
--- /dev/null
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstdevice.c: Device discovery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_DEVICE_H__
+#define __GST_DEVICE_H__
+
+typedef struct _GstDevice GstDevice;
+typedef struct _GstDeviceClass GstDeviceClass;
+
+#include <gst/gstelement.h>
+#include <gst/gstcaps.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GstDevicePrivate GstDevicePrivate;
+
+#define GST_TYPE_DEVICE                 (gst_device_get_type())
+#define GST_IS_DEVICE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEVICE))
+#define GST_IS_DEVICE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEVICE))
+#define GST_DEVICE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEVICE, GstDeviceClass))
+#define GST_DEVICE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEVICE, GstDevice))
+#define GST_DEVICE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE, GstDeviceClass))
+#define GST_DEVICE_CAST(obj)            ((GstDevice *)(obj))
+
+
+struct _GstDevice {
+  GstObject         parent;
+
+  /*< private >*/
+  GstDevicePrivate *priv;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstDeviceClass {
+  GstObjectClass    parent_class;
+
+  GstElement * (*create_element) (GstDevice * device, const gchar * name);
+  gboolean (*reconfigure_element) (GstDevice * device, GstElement * element);
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType        gst_device_get_type (void);
+
+GstElement * gst_device_create_element (GstDevice * device, const gchar * name);
+
+GstCaps *    gst_device_get_caps (GstDevice * device);
+gchar *      gst_device_get_display_name (GstDevice * device);
+gboolean     gst_device_reconfigure_element (GstDevice * device,
+                                             GstElement * element);
+
+G_END_DECLS
+
+#endif /* __GST_DEVICE_H__ */
diff --git a/gst/gstdevicemonitor.c b/gst/gstdevicemonitor.c
new file mode 100644 (file)
index 0000000..bd61a2c
--- /dev/null
@@ -0,0 +1,570 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstdevicemonitor.c: Device probing and monitoring
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gstdevicemonitor.h>
+
+#include "gst/gst_private.h"
+#include <gst/gst.h>
+
+#include <gst/gstelementmetadata.h>
+#include <gst/gstquark.h>
+
+struct _GstDeviceMonitorPrivate
+{
+  GstBus *bus;
+
+  GMutex start_lock;
+
+  gboolean started_count;
+};
+
+/* this is used in gstelementfactory.c:gst_element_register() */
+GQuark __gst_devicemonitorclass_factory = 0;
+
+static void gst_device_monitor_class_init (GstDeviceMonitorClass * klass);
+static void gst_device_monitor_init (GstDeviceMonitor * element);
+static void gst_device_monitor_base_class_init (gpointer g_class);
+static void gst_device_monitor_base_class_finalize (gpointer g_class);
+static void gst_device_monitor_dispose (GObject * object);
+static void gst_device_monitor_finalize (GObject * object);
+
+static gpointer gst_device_monitor_parent_class = NULL;
+
+GType
+gst_device_monitor_get_type (void)
+{
+  static volatile gsize gst_device_monitor_type = 0;
+
+  if (g_once_init_enter (&gst_device_monitor_type)) {
+    GType _type;
+    static const GTypeInfo element_info = {
+      sizeof (GstDeviceMonitorClass),
+      gst_device_monitor_base_class_init,
+      gst_device_monitor_base_class_finalize,
+      (GClassInitFunc) gst_device_monitor_class_init,
+      NULL,
+      NULL,
+      sizeof (GstDeviceMonitor),
+      0,
+      (GInstanceInitFunc) gst_device_monitor_init,
+      NULL
+    };
+
+    _type = g_type_register_static (GST_TYPE_OBJECT, "GstDeviceMonitor",
+        &element_info, G_TYPE_FLAG_ABSTRACT);
+
+    __gst_devicemonitorclass_factory =
+        g_quark_from_static_string ("GST_DEVICEMONITORCLASS_FACTORY");
+    g_once_init_leave (&gst_device_monitor_type, _type);
+  }
+  return gst_device_monitor_type;
+}
+
+static void
+gst_device_monitor_base_class_init (gpointer g_class)
+{
+  GstDeviceMonitorClass *klass = GST_DEVICE_MONITOR_CLASS (g_class);
+
+  /* Copy the element details here so elements can inherit the
+   * details from their base class and classes only need to set
+   * the details in class_init instead of base_init */
+  klass->metadata =
+      klass->metadata ? gst_structure_copy (klass->metadata) :
+      gst_structure_new_empty ("metadata");
+
+  klass->factory = g_type_get_qdata (G_TYPE_FROM_CLASS (klass),
+      __gst_devicemonitorclass_factory);
+}
+
+static void
+gst_device_monitor_base_class_finalize (gpointer g_class)
+{
+  GstDeviceMonitorClass *klass = GST_DEVICE_MONITOR_CLASS (g_class);
+
+  gst_structure_free (klass->metadata);
+}
+
+static void
+gst_device_monitor_class_init (GstDeviceMonitorClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gst_device_monitor_parent_class = g_type_class_peek_parent (klass);
+
+  g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate));
+
+  gobject_class->dispose = gst_device_monitor_dispose;
+  gobject_class->finalize = gst_device_monitor_finalize;
+}
+
+static void
+gst_device_monitor_init (GstDeviceMonitor * monitor)
+{
+  monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
+      GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate);
+
+  g_mutex_init (&monitor->priv->start_lock);
+
+  monitor->priv->bus = gst_bus_new ();
+  gst_bus_set_flushing (monitor->priv->bus, TRUE);
+}
+
+
+static void
+gst_device_monitor_dispose (GObject * object)
+{
+  GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
+
+  gst_object_replace ((GstObject **) & monitor->priv->bus, NULL);
+
+  GST_OBJECT_LOCK (monitor);
+  g_list_free_full (monitor->devices, (GDestroyNotify) gst_object_unparent);
+  monitor->devices = NULL;
+  GST_OBJECT_UNLOCK (monitor);
+
+  G_OBJECT_CLASS (gst_device_monitor_parent_class)->dispose (object);
+}
+
+static void
+gst_device_monitor_finalize (GObject * object)
+{
+  GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object);
+
+  g_mutex_clear (&monitor->priv->start_lock);
+
+  G_OBJECT_CLASS (gst_device_monitor_parent_class)->finalize (object);
+}
+
+/**
+ * gst_device_monitor_class_add_metadata:
+ * @klass: class to set metadata for
+ * @key: the key to set
+ * @value: the value to set
+ *
+ * Set @key with @value as metadata in @klass.
+ */
+void
+gst_device_monitor_class_add_metadata (GstDeviceMonitorClass * klass,
+    const gchar * key, const gchar * value)
+{
+  g_return_if_fail (GST_IS_DEVICE_MONITOR_CLASS (klass));
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (value != NULL);
+
+  gst_structure_set ((GstStructure *) klass->metadata,
+      key, G_TYPE_STRING, value, NULL);
+}
+
+/**
+ * gst_device_monitor_class_add_static_metadata:
+ * @klass: class to set metadata for
+ * @key: the key to set
+ * @value: the value to set
+ *
+ * Set @key with @value as metadata in @klass.
+ *
+ * Same as gst_device_monitor_class_add_metadata(), but @value must be a static string
+ * or an inlined string, as it will not be copied. (GStreamer plugins will
+ * be made resident once loaded, so this function can be used even from
+ * dynamically loaded plugins.)
+ *
+ * Since: 1.4
+ */
+void
+gst_device_monitor_class_add_static_metadata (GstDeviceMonitorClass * klass,
+    const gchar * key, const gchar * value)
+{
+  GValue val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_DEVICE_MONITOR_CLASS (klass));
+  g_return_if_fail (key != NULL);
+  g_return_if_fail (value != NULL);
+
+  g_value_init (&val, G_TYPE_STRING);
+  g_value_set_static_string (&val, value);
+  gst_structure_take_value ((GstStructure *) klass->metadata, key, &val);
+}
+
+/**
+ * gst_device_monitor_class_set_metadata:
+ * @klass: class to set metadata for
+ * @longname: The long English name of the device monitor. E.g. "File Sink"
+ * @classification: String describing the type of device monitor, as an unordered list
+ * separated with slashes ('/'). See draft-klass.txt of the design docs
+ * for more details and common types. E.g: "Sink/File"
+ * @description: Sentence describing the purpose of the device monitor.
+ * E.g: "Write stream to a file"
+ * @author: Name and contact details of the author(s). Use \n to separate
+ * multiple author metadata. E.g: "Joe Bloggs &lt;joe.blogs at foo.com&gt;"
+ *
+ * Sets the detailed information for a #GstDeviceMonitorClass.
+ * <note>This function is for use in _class_init functions only.</note>
+ *
+ * Since: 1.4
+ */
+void
+gst_device_monitor_class_set_metadata (GstDeviceMonitorClass * klass,
+    const gchar * longname, const gchar * classification,
+    const gchar * description, const gchar * author)
+{
+  g_return_if_fail (GST_IS_DEVICE_MONITOR_CLASS (klass));
+  g_return_if_fail (longname != NULL && *longname != '\0');
+  g_return_if_fail (classification != NULL && *classification != '\0');
+  g_return_if_fail (description != NULL && *description != '\0');
+  g_return_if_fail (author != NULL && *author != '\0');
+
+  gst_structure_id_set ((GstStructure *) klass->metadata,
+      GST_QUARK (ELEMENT_METADATA_LONGNAME), G_TYPE_STRING, longname,
+      GST_QUARK (ELEMENT_METADATA_KLASS), G_TYPE_STRING, classification,
+      GST_QUARK (ELEMENT_METADATA_DESCRIPTION), G_TYPE_STRING, description,
+      GST_QUARK (ELEMENT_METADATA_AUTHOR), G_TYPE_STRING, author, NULL);
+}
+
+/**
+ * gst_device_monitor_class_set_static_metadata:
+ * @klass: class to set metadata for
+ * @longname: The long English name of the element. E.g. "File Sink"
+ * @classification: String describing the type of element, as an unordered list
+ * separated with slashes ('/'). See draft-klass.txt of the design docs
+ * for more details and common types. E.g: "Sink/File"
+ * @description: Sentence describing the purpose of the element.
+ * E.g: "Write stream to a file"
+ * @author: Name and contact details of the author(s). Use \n to separate
+ * multiple author metadata. E.g: "Joe Bloggs &lt;joe.blogs at foo.com&gt;"
+ *
+ * Sets the detailed information for a #GstDeviceMonitorClass.
+ * <note>This function is for use in _class_init functions only.</note>
+ *
+ * Same as gst_device_monitor_class_set_metadata(), but @longname, @classification,
+ * @description, and @author must be static strings or inlined strings, as
+ * they will not be copied. (GStreamer plugins will be made resident once
+ * loaded, so this function can be used even from dynamically loaded plugins.)
+ *
+ * Since: 1.4
+ */
+void
+gst_device_monitor_class_set_static_metadata (GstDeviceMonitorClass * klass,
+    const gchar * longname, const gchar * classification,
+    const gchar * description, const gchar * author)
+{
+  GstStructure *s = (GstStructure *) klass->metadata;
+  GValue val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_DEVICE_MONITOR_CLASS (klass));
+  g_return_if_fail (longname != NULL && *longname != '\0');
+  g_return_if_fail (classification != NULL && *classification != '\0');
+  g_return_if_fail (description != NULL && *description != '\0');
+  g_return_if_fail (author != NULL && *author != '\0');
+
+  g_value_init (&val, G_TYPE_STRING);
+
+  g_value_set_static_string (&val, longname);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_LONGNAME), &val);
+
+  g_value_set_static_string (&val, classification);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_KLASS), &val);
+
+  g_value_set_static_string (&val, description);
+  gst_structure_id_set_value (s, GST_QUARK (ELEMENT_METADATA_DESCRIPTION),
+      &val);
+
+  g_value_set_static_string (&val, author);
+  gst_structure_id_take_value (s, GST_QUARK (ELEMENT_METADATA_AUTHOR), &val);
+}
+
+/**
+ * gst_device_monitor_class_get_metadata:
+ * @klass: class to get metadata for
+ * @key: the key to get
+ *
+ * Get metadata with @key in @klass.
+ *
+ * Returns: the metadata for @key.
+ *
+ * Since: 1.4
+ */
+const gchar *
+gst_device_monitor_class_get_metadata (GstDeviceMonitorClass * klass,
+    const gchar * key)
+{
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR_CLASS (klass), NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  return gst_structure_get_string ((GstStructure *) klass->metadata, key);
+}
+
+/**
+ * gst_device_monitor_get_devices:
+ * @monitor: A #GstDeviceMonitor
+ *
+ * Gets a list of devices that this monitor understands. This may actually
+ * probe the hardware if the monitor is not currently started.
+ *
+ * Returns: (transfer full) (element-type GstDevice): a #GList of
+ *   #GstDevice
+ *
+ * Since: 1.4
+ */
+
+GList *
+gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
+{
+  GstDeviceMonitorClass *klass;
+  GList *devices = NULL;
+  gboolean started;
+  GList *item;
+
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
+  klass = GST_DEVICE_MONITOR_GET_CLASS (monitor);
+
+  g_mutex_lock (&monitor->priv->start_lock);
+  started = (monitor->priv->started_count > 0);
+
+  if (started) {
+    GST_OBJECT_LOCK (monitor);
+    for (item = monitor->devices; item; item = item->next)
+      devices = g_list_prepend (devices, gst_object_ref (item->data));
+    GST_OBJECT_UNLOCK (monitor);
+  } else if (klass->probe)
+    devices = klass->probe (monitor);
+
+  g_mutex_unlock (&monitor->priv->start_lock);
+
+  return devices;
+}
+
+/**
+ * gst_device_monitor_start:
+ * @monitor: A #GstDeviceMonitor
+ *
+ * Starts monitoring the devices. This will cause #GST_MESSAGE_DEVICE messages
+ * to be posted on the monitor's bus when devices are added or removed from
+ * the system.
+ *
+ * Since the #GstDeviceMonitor is a singleton,
+ * gst_device_monitor_start() may already have been called by another
+ * user of the object, gst_device_monitor_stop() needs to be called the same
+ * number of times.
+ *
+ * Returns: %TRUE if the device monitoring could be started
+ *
+ * Since: 1.4
+ */
+
+gboolean
+gst_device_monitor_start (GstDeviceMonitor * monitor)
+{
+  GstDeviceMonitorClass *klass;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
+  klass = GST_DEVICE_MONITOR_GET_CLASS (monitor);
+
+  g_mutex_lock (&monitor->priv->start_lock);
+
+  if (monitor->priv->started_count > 0) {
+    ret = TRUE;
+    goto started;
+  }
+
+  if (klass->start)
+    ret = klass->start (monitor);
+
+  if (ret) {
+    monitor->priv->started_count++;
+    gst_bus_set_flushing (monitor->priv->bus, FALSE);
+  }
+
+started:
+
+  g_mutex_unlock (&monitor->priv->start_lock);
+
+  return ret;
+}
+
+/**
+ * gst_device_monitor_stop:
+ * @monitor: A #GstDeviceMonitor
+ *
+ * Decreases the use-count by one. If the use count reaches zero, this
+ * #GstDeviceMonitor will stop monitoring the devices. This needs to be
+ * called the same number of times that gst_device_monitor_start() was called.
+ *
+ * Since: 1.4
+ */
+
+void
+gst_device_monitor_stop (GstDeviceMonitor * monitor)
+{
+  GstDeviceMonitorClass *klass;
+
+  g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor));
+  klass = GST_DEVICE_MONITOR_GET_CLASS (monitor);
+
+  g_mutex_lock (&monitor->priv->start_lock);
+
+  if (monitor->priv->started_count == 1) {
+    gst_bus_set_flushing (monitor->priv->bus, TRUE);
+    if (klass->stop)
+      klass->stop (monitor);
+    GST_OBJECT_LOCK (monitor);
+    g_list_free_full (monitor->devices, (GDestroyNotify) gst_object_unparent);
+    monitor->devices = NULL;
+    GST_OBJECT_UNLOCK (monitor);
+  } else if (monitor->priv->started_count < 1) {
+    g_critical ("Trying to stop a GstDeviceMonitor %s which is already stopped",
+        GST_OBJECT_NAME (monitor));
+  }
+
+  monitor->priv->started_count--;
+  g_mutex_unlock (&monitor->priv->start_lock);
+}
+
+
+/**
+ * gst_device_monitor_get_factory:
+ * @monitor: a #GstDeviceMonitor to request the device monitor factory of.
+ *
+ * Retrieves the factory that was used to create this device monitor.
+ *
+ * Returns: (transfer none): the #GstDeviceMonitorFactory used for creating this
+ *     device monitor. no refcounting is needed.
+ *
+ * Since: 1.4
+ */
+GstDeviceMonitorFactory *
+gst_device_monitor_get_factory (GstDeviceMonitor * monitor)
+{
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
+
+  return GST_DEVICE_MONITOR_GET_CLASS (monitor)->factory;
+}
+
+/**
+ * gst_device_monitor_can_monitor:
+ * @monitor: a #GstDeviceMonitor
+ *
+ * If this function returns %TRUE, then the device monitor can monitor if
+ * devices are added or removed. Otherwise, it can only do static probing.
+ *
+ * Returns: %TRUE if the #GstDeviceMonitor support monitoring, %FALSE otherwise
+ */
+gboolean
+gst_device_monitor_can_monitor (GstDeviceMonitor * monitor)
+{
+  GstDeviceMonitorClass *klass;
+
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE);
+  klass = GST_DEVICE_MONITOR_GET_CLASS (monitor);
+
+  if (klass->start)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+/**
+ * gst_device_monitor_get_bus:
+ * @monitor: a #GstDeviceMonitor
+ *
+ * Gets the #GstBus of this #GstDeviceMonitor
+ *
+ * Returns: (transfer full): a #GstBus
+ *
+ * Since: 1.4
+ */
+GstBus *
+gst_device_monitor_get_bus (GstDeviceMonitor * monitor)
+{
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);
+
+  return gst_object_ref (monitor->priv->bus);
+}
+
+/**
+ * gst_device_monitor_device_add:
+ * @monitor: a #GstDeviceMonitor
+ * @device: (transfer full): a #GstDevice that has been added
+ *
+ * Posts a message on the monitor's #GstBus to inform applications that
+ * a new device has been added.
+ *
+ * This is for use by subclasses.
+ *
+ * Since: 1.4
+ */
+void
+gst_device_monitor_device_add (GstDeviceMonitor * monitor, GstDevice * device)
+{
+  GstMessage *message;
+
+  if (!gst_object_set_parent (GST_OBJECT (device), GST_OBJECT (monitor))) {
+    GST_WARNING_OBJECT (monitor, "Could not parent device %p to monitor,"
+        " it already has a parent", device);
+    return;
+  }
+
+  GST_OBJECT_LOCK (monitor);
+  monitor->devices = g_list_prepend (monitor->devices, gst_object_ref (device));
+  GST_OBJECT_UNLOCK (monitor);
+
+  message = gst_message_new_device_added (GST_OBJECT (monitor), device);
+  gst_bus_post (monitor->priv->bus, message);
+  gst_object_unref (device);
+}
+
+
+/**
+ * gst_device_monitor_device_remove:
+ * @monitor: a #GstDeviceMonitor
+ * @device: a #GstDevice that has been removed
+ *
+ * Posts a message on the monitor's #GstBus to inform applications that
+ * a device has been removed.
+ *
+ * This is for use by subclasses.
+ *
+ * Since: 1.4
+ */
+void
+gst_device_monitor_device_remove (GstDeviceMonitor * monitor,
+    GstDevice * device)
+{
+  GstMessage *message;
+  GList *item;
+
+  GST_OBJECT_LOCK (monitor);
+  item = g_list_find (monitor->devices, device);
+  if (item) {
+    monitor->devices = g_list_delete_link (monitor->devices, item);
+  }
+  GST_OBJECT_UNLOCK (monitor);
+
+  message = gst_message_new_device_removed (GST_OBJECT (monitor), device);
+  g_signal_emit_by_name (device, "removed");
+  gst_bus_post (monitor->priv->bus, message);
+  if (item)
+    gst_object_unparent (GST_OBJECT (device));
+}
diff --git a/gst/gstdevicemonitor.h b/gst/gstdevicemonitor.h
new file mode 100644 (file)
index 0000000..35b94e7
--- /dev/null
@@ -0,0 +1,130 @@
+/* GStreamer
+ * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstdevicemonitor.h: Device probing and monitoring
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gstdevicemonitorfactory.h>
+
+
+#ifndef __GST_DEVICE_MONITOR_H__
+#define __GST_DEVICE_MONITOR_H__
+
+#include <gst/gstelement.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstDeviceMonitor GstDeviceMonitor;
+typedef struct _GstDeviceMonitorClass GstDeviceMonitorClass;
+typedef struct _GstDeviceMonitorPrivate GstDeviceMonitorPrivate;
+
+#define GST_TYPE_DEVICE_MONITOR                 (gst_device_monitor_get_type())
+#define GST_IS_DEVICE_MONITOR(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEVICE_MONITOR))
+#define GST_IS_DEVICE_MONITOR_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEVICE_MONITOR))
+#define GST_DEVICE_MONITOR_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorClass))
+#define GST_DEVICE_MONITOR(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEVICE_MONITOR, GstDeviceMonitor))
+#define GST_DEVICE_MONITOR_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorClass))
+#define GST_DEVICE_MONITOR_CAST(obj)            ((GstDeviceMonitor *)(obj))
+
+
+struct _GstDeviceMonitor {
+  GstObject         parent;
+
+  /*< private >*/
+
+  /* Protected by the Object lock */
+  GList *devices;
+
+  GstDeviceMonitorPrivate *priv;
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstDeviceMonitorClass:
+ * @factory: a pointer to the #GstDeviceMonitorFactory that creates this
+ *  monitor
+ * @get_devices: Returns a list of devices that are currently available.
+ *  This should never block.
+ * @start: Starts monitoring for new devices.
+ * @stop: Stops monitoring for new devices
+ *
+ * The structure of the base #GstDeviceMonitorClass
+ *
+ * Since: 1.4
+ */
+
+struct _GstDeviceMonitorClass {
+  GstObjectClass    parent_class;
+
+  GstDeviceMonitorFactory     *factory;
+
+  GList*      (*probe) (GstDeviceMonitor * monitor);
+
+  gboolean    (*start) (GstDeviceMonitor * monitor);
+  void        (*stop)  (GstDeviceMonitor * monitor);
+
+
+  gpointer metadata;
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+GType       gst_device_monitor_get_type (void);
+
+
+GList *     gst_device_monitor_get_devices    (GstDeviceMonitor * monitor);
+
+gboolean    gst_device_monitor_start          (GstDeviceMonitor * monitor);
+void        gst_device_monitor_stop           (GstDeviceMonitor * monitor);
+
+gboolean    gst_device_monitor_can_monitor    (GstDeviceMonitor * monitor);
+
+GstBus *    gst_device_monitor_get_bus        (GstDeviceMonitor * monitor);
+
+void        gst_device_monitor_device_add     (GstDeviceMonitor * monitor,
+                                               GstDevice * device);
+void        gst_device_monitor_device_remove  (GstDeviceMonitor * monitor,
+                                               GstDevice * device);
+
+
+/* device monitor class meta data */
+void        gst_device_monitor_class_set_metadata          (GstDeviceMonitorClass *klass,
+                                                            const gchar     *longname,
+                                                            const gchar     *classification,
+                                                            const gchar     *description,
+                                                            const gchar     *author);
+void        gst_device_monitor_class_set_static_metadata   (GstDeviceMonitorClass *klass,
+                                                            const gchar     *longname,
+                                                            const gchar     *classification,
+                                                            const gchar     *description,
+                                                            const gchar     *author);
+void        gst_device_monitor_class_add_metadata          (GstDeviceMonitorClass * klass,
+                                                            const gchar * key, const gchar * value);
+void        gst_device_monitor_class_add_static_metadata   (GstDeviceMonitorClass * klass,
+                                                            const gchar * key, const gchar * value);
+const gchar * gst_device_monitor_class_get_metadata        (GstDeviceMonitorClass * klass,
+                                                              const gchar * key);
+
+/* factory management */
+GstDeviceMonitorFactory * gst_device_monitor_get_factory   (GstDeviceMonitor * monitor);
+
+G_END_DECLS
+
+#endif /* __GST_DEVICE_MONITOR_H__ */
diff --git a/gst/gstdevicemonitorfactory.c b/gst/gstdevicemonitorfactory.c
new file mode 100644 (file)
index 0000000..a621c8d
--- /dev/null
@@ -0,0 +1,566 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * gstdevicemonitorfactory.c: GstDeviceMonitorFactory object, support routines
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstdevicemonitorfactory
+ * @short_description: Create GstDeviceMonitors from a factory
+ * @see_also: #GstDeviceMonitor, #GstPlugin, #GstPluginFeature, #GstPadTemplate.
+ *
+ * #GstDeviceMonitorFactory is used to create instances of device monitors. A
+ * GstDeviceMonitorfactory can be added to a #GstPlugin as it is also a
+ * #GstPluginFeature.
+ *
+ * Use the gst_device_monitor_factory_find() and gst_device_monitor_factory_create()
+ * functions to create device monitor instances or use gst_device_monitor_factory_make() as a
+ * convenient shortcut.
+ *
+ * Since: 1.4
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst_private.h"
+
+#include "gstdevicemonitorfactory.h"
+#include "gst.h"
+
+#include "glib-compat-private.h"
+
+GST_DEBUG_CATEGORY_STATIC (device_monitor_factory_debug);
+#define GST_CAT_DEFAULT device_monitor_factory_debug
+
+static void gst_device_monitor_factory_finalize (GObject * object);
+static void gst_device_monitor_factory_cleanup (GstDeviceMonitorFactory *
+    factory);
+
+/* static guint gst_device_monitor_factory_signals[LAST_SIGNAL] = { 0 }; */
+
+/* this is defined in gstelement.c */
+extern GQuark __gst_devicemonitorclass_factory;
+
+#define _do_init \
+{ \
+  GST_DEBUG_CATEGORY_INIT (device_monitor_factory_debug, "GST_DEVICE_MONITOR_FACTORY", \
+      GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, \
+      "device monitor factories keep information about installed device monitors"); \
+}
+
+G_DEFINE_TYPE_WITH_CODE (GstDeviceMonitorFactory, gst_device_monitor_factory,
+    GST_TYPE_PLUGIN_FEATURE, _do_init);
+
+static void
+gst_device_monitor_factory_class_init (GstDeviceMonitorFactoryClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->finalize = gst_device_monitor_factory_finalize;
+}
+
+static void
+gst_device_monitor_factory_init (GstDeviceMonitorFactory * factory)
+{
+}
+
+static void
+gst_device_monitor_factory_finalize (GObject * object)
+{
+  GstDeviceMonitorFactory *factory = GST_DEVICE_MONITOR_FACTORY (object);
+  GstDeviceMonitor *monitor;
+
+  gst_device_monitor_factory_cleanup (factory);
+
+  monitor = g_atomic_pointer_get (&factory->monitor);
+  if (monitor)
+    gst_object_unref (monitor);
+
+  G_OBJECT_CLASS (gst_device_monitor_factory_parent_class)->finalize (object);
+}
+
+/**
+ * gst_device_monitor_factory_find:
+ * @name: name of factory to find
+ *
+ * Search for an device monitor factory of the given name. Refs the returned
+ * device monitor factory; caller is responsible for unreffing.
+ *
+ * Returns: (transfer full): #GstDeviceMonitorFactory if found, NULL otherwise
+ *
+ * Since: 1.4
+ */
+GstDeviceMonitorFactory *
+gst_device_monitor_factory_find (const gchar * name)
+{
+  GstPluginFeature *feature;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  feature = gst_registry_find_feature (gst_registry_get (), name,
+      GST_TYPE_DEVICE_MONITOR_FACTORY);
+  if (feature)
+    return GST_DEVICE_MONITOR_FACTORY (feature);
+
+  /* this isn't an error, for instance when you query if an device monitor factory is
+   * present */
+  GST_LOG ("no such device monitor factory \"%s\"", name);
+
+  return NULL;
+}
+
+static void
+gst_device_monitor_factory_cleanup (GstDeviceMonitorFactory * factory)
+{
+  if (factory->metadata) {
+    gst_structure_free ((GstStructure *) factory->metadata);
+    factory->metadata = NULL;
+  }
+  if (factory->type) {
+    factory->type = G_TYPE_INVALID;
+  }
+}
+
+#define CHECK_METADATA_FIELD(klass, name, key)                                 \
+  G_STMT_START {                                                               \
+    const gchar *metafield = gst_device_monitor_class_get_metadata (klass, key);      \
+    if (G_UNLIKELY (metafield == NULL || *metafield == '\0')) {                \
+      g_warning ("Device monitor factory metadata for '%s' has no valid %s field", name, key);    \
+      goto detailserror;                                                       \
+    } \
+  } G_STMT_END;
+
+/**
+ * gst_device_monitor_register:
+ * @plugin: (allow-none): #GstPlugin to register the device monitor with, or NULL for
+ *     a static device monitor.
+ * @name: name of device monitors of this type
+ * @rank: rank of device monitor (higher rank means more importance when autoplugging)
+ * @type: GType of device monitor to register
+ *
+ * Create a new device monitorfactory capable of instantiating objects of the
+ * @type and add the factory to @plugin.
+ *
+ * Returns: TRUE, if the registering succeeded, FALSE on error
+ *
+ * Since: 1.4
+ */
+gboolean
+gst_device_monitor_register (GstPlugin * plugin, const gchar * name, guint rank,
+    GType type)
+{
+  GstPluginFeature *existing_feature;
+  GstRegistry *registry;
+  GstDeviceMonitorFactory *factory;
+  GstDeviceMonitorClass *klass;
+
+  g_return_val_if_fail (name != NULL, FALSE);
+  g_return_val_if_fail (g_type_is_a (type, GST_TYPE_DEVICE_MONITOR), FALSE);
+
+  registry = gst_registry_get ();
+
+  /* check if feature already exists, if it exists there is no need to update it
+   * when the registry is getting updated, outdated plugins and all their
+   * features are removed and readded.
+   */
+  existing_feature = gst_registry_lookup_feature (registry, name);
+  if (existing_feature) {
+    GST_DEBUG_OBJECT (registry, "update existing feature %p (%s)",
+        existing_feature, name);
+    factory = GST_DEVICE_MONITOR_FACTORY_CAST (existing_feature);
+    factory->type = type;
+    existing_feature->loaded = TRUE;
+    g_type_set_qdata (type, __gst_devicemonitorclass_factory, factory);
+    gst_object_unref (existing_feature);
+    return TRUE;
+  }
+
+  factory =
+      GST_DEVICE_MONITOR_FACTORY_CAST (g_object_newv
+      (GST_TYPE_DEVICE_MONITOR_FACTORY, 0, NULL));
+  gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);
+  GST_LOG_OBJECT (factory, "Created new device monitorfactory for type %s",
+      g_type_name (type));
+
+  /* provide info needed during class structure setup */
+  g_type_set_qdata (type, __gst_devicemonitorclass_factory, factory);
+  klass = GST_DEVICE_MONITOR_CLASS (g_type_class_ref (type));
+
+  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_LONGNAME);
+  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_KLASS);
+  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_DESCRIPTION);
+  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_AUTHOR);
+
+  factory->type = type;
+  factory->metadata = gst_structure_copy ((GstStructure *) klass->metadata);
+
+  if (plugin && plugin->desc.name) {
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = plugin->desc.name;
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin = plugin;
+    g_object_add_weak_pointer ((GObject *) plugin,
+        (gpointer *) & GST_PLUGIN_FEATURE_CAST (factory)->plugin);
+  } else {
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = "NULL";
+    GST_PLUGIN_FEATURE_CAST (factory)->plugin = NULL;
+  }
+  gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory), rank);
+  GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE;
+
+  gst_registry_add_feature (registry, GST_PLUGIN_FEATURE_CAST (factory));
+
+  return TRUE;
+
+  /* ERRORS */
+detailserror:
+  {
+    gst_device_monitor_factory_cleanup (factory);
+    return FALSE;
+  }
+}
+
+/**
+ * gst_device_monitor_factory_get:
+ * @factory: factory to instantiate
+ *
+ * Returns the device monitor of the type defined by the given device
+ * monitorfactory.
+ *
+ * Returns: (transfer full): the #GstDeviceMonitor or NULL if the
+ *     device monitor couldn't be created
+ *
+ * Since: 1.4
+ */
+GstDeviceMonitor *
+gst_device_monitor_factory_get (GstDeviceMonitorFactory * factory)
+{
+  GstDeviceMonitor *device_monitor;
+  GstDeviceMonitorClass *oclass;
+  GstDeviceMonitorFactory *newfactory;
+
+  g_return_val_if_fail (factory != NULL, NULL);
+
+  newfactory =
+      GST_DEVICE_MONITOR_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
+          (factory)));
+
+  if (newfactory == NULL)
+    goto load_failed;
+
+  factory = newfactory;
+
+  GST_INFO ("getting device monitor \"%s\"", GST_OBJECT_NAME (factory));
+
+  if (factory->type == 0)
+    goto no_type;
+
+  device_monitor = g_atomic_pointer_get (&newfactory->monitor);
+  if (device_monitor)
+    return gst_object_ref (device_monitor);
+
+  /* create an instance of the device monitor, cast so we don't assert on NULL
+   * also set name as early as we can
+   */
+  device_monitor = GST_DEVICE_MONITOR_CAST (g_object_newv (factory->type, 0,
+          NULL));
+  if (G_UNLIKELY (device_monitor == NULL))
+    goto no_device_monitor;
+
+  /* fill in the pointer to the factory in the device monitor class. The
+   * class will not be unreffed currently.
+   * Be thread safe as there might be 2 threads creating the first instance of
+   * an device monitor at the same moment
+   */
+  oclass = GST_DEVICE_MONITOR_GET_CLASS (device_monitor);
+  if (!g_atomic_pointer_compare_and_exchange (&oclass->factory, NULL, factory))
+    gst_object_unref (factory);
+
+  gst_object_ref_sink (device_monitor);
+
+  /* We use an atomic to make sure we don't create two in parallel */
+  if (!g_atomic_pointer_compare_and_exchange (&newfactory->monitor, NULL,
+          device_monitor)) {
+    gst_object_unref (device_monitor);
+
+    device_monitor = g_atomic_pointer_get (&newfactory->monitor);
+  }
+
+  GST_DEBUG ("created device monitor \"%s\"", GST_OBJECT_NAME (factory));
+
+  return gst_object_ref (device_monitor);
+
+  /* ERRORS */
+load_failed:
+  {
+    GST_WARNING_OBJECT (factory,
+        "loading plugin containing feature %s returned NULL!",
+        GST_OBJECT_NAME (factory));
+    return NULL;
+  }
+no_type:
+  {
+    GST_WARNING_OBJECT (factory, "factory has no type");
+    gst_object_unref (factory);
+    return NULL;
+  }
+no_device_monitor:
+  {
+    GST_WARNING_OBJECT (factory, "could not create device monitor");
+    gst_object_unref (factory);
+    return NULL;
+  }
+}
+
+/**
+ * gst_device_monitor_factory_get_by_name:
+ * @factoryname: a named factory to instantiate
+ *
+ * Returns the device monitor of the type defined by the given device
+ * monitor factory.
+ *
+ * Returns: (transfer full): a #GstDeviceMonitor or NULL if unable to
+ * create device monitor
+ *
+ * Since: 1.4
+ */
+GstDeviceMonitor *
+gst_device_monitor_factory_get_by_name (const gchar * factoryname)
+{
+  GstDeviceMonitorFactory *factory;
+  GstDeviceMonitor *device_monitor;
+
+  g_return_val_if_fail (factoryname != NULL, NULL);
+  g_return_val_if_fail (gst_is_initialized (), NULL);
+
+  GST_LOG ("gstdevicemonitorfactory: get_by_name \"%s\"", factoryname);
+
+  factory = gst_device_monitor_factory_find (factoryname);
+  if (factory == NULL)
+    goto no_factory;
+
+  GST_LOG_OBJECT (factory, "found factory %p", factory);
+  device_monitor = gst_device_monitor_factory_get (factory);
+  if (device_monitor == NULL)
+    goto create_failed;
+
+  gst_object_unref (factory);
+  return device_monitor;
+
+  /* ERRORS */
+no_factory:
+  {
+    GST_INFO ("no such device monitor factory \"%s\"!", factoryname);
+    return NULL;
+  }
+create_failed:
+  {
+    GST_INFO_OBJECT (factory, "couldn't create instance!");
+    gst_object_unref (factory);
+    return NULL;
+  }
+}
+
+/**
+ * gst_device_monitor_factory_get_device_monitor_type:
+ * @factory: factory to get managed #GType from
+ *
+ * Get the #GType for device monitors managed by this factory. The type can
+ * only be retrieved if the device monitor factory is loaded, which can be
+ * assured with gst_plugin_feature_load().
+ *
+ * Returns: the #GType for device monitors managed by this factory or 0 if
+ * the factory is not loaded.
+ *
+ * Since: 1.4
+ */
+GType
+gst_device_monitor_factory_get_device_monitor_type (GstDeviceMonitorFactory *
+    factory)
+{
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR_FACTORY (factory), 0);
+
+  return factory->type;
+}
+
+/**
+ * gst_device_monitor_factory_get_metadata:
+ * @factory: a #GstDeviceMonitorFactory
+ * @key: a key
+ *
+ * Get the metadata on @factory with @key.
+ *
+ * Returns: the metadata with @key on @factory or %NULL when there was no
+ * metadata with the given @key.
+ *
+ * Since: 1.4
+ */
+const gchar *
+gst_device_monitor_factory_get_metadata (GstDeviceMonitorFactory * factory,
+    const gchar * key)
+{
+  return gst_structure_get_string ((GstStructure *) factory->metadata, key);
+}
+
+/**
+ * gst_device_monitor_factory_get_metadata_keys:
+ * @factory: a #GstDeviceMonitorFactory
+ *
+ * Get the available keys for the metadata on @factory.
+ *
+ * Returns: (transfer full) (element-type utf8) (array zero-terminated=1):
+ * a %NULL-terminated array of key strings, or %NULL when there is no
+ * metadata. Free with g_strfreev() when no longer needed.
+ *
+ * Since: 1.4
+ */
+gchar **
+gst_device_monitor_factory_get_metadata_keys (GstDeviceMonitorFactory * factory)
+{
+  GstStructure *metadata;
+  gchar **arr;
+  gint i, num;
+
+  g_return_val_if_fail (GST_IS_DEVICE_MONITOR_FACTORY (factory), NULL);
+
+  metadata = (GstStructure *) factory->metadata;
+  if (metadata == NULL)
+    return NULL;
+
+  num = gst_structure_n_fields (metadata);
+  if (num == 0)
+    return NULL;
+
+  arr = g_new (gchar *, num + 1);
+  for (i = 0; i < num; ++i) {
+    arr[i] = g_strdup (gst_structure_nth_field_name (metadata, i));
+  }
+  arr[i] = NULL;
+  return arr;
+}
+
+typedef struct
+{
+  GstDeviceMonitorFactoryListType type;
+  GstRank minrank;
+} FilterData;
+
+
+/**
+ * gst_device_monitor_factory_list_is_type:
+ * @factory: a #GstDeviceMonitorFactory
+ * @type: a #GstDeviceMonitorFactoryListType
+ *
+ * Check if @factory is of the given types.
+ *
+ * Returns: %TRUE if @factory is of @type.
+ *
+ * Since: 1.4
+ */
+gboolean
+gst_device_monitor_factory_list_is_type (GstDeviceMonitorFactory * factory,
+    GstDeviceMonitorFactoryListType type)
+{
+  gboolean res = FALSE;
+  const gchar *klass;
+
+  klass = gst_device_monitor_factory_get_metadata (factory,
+      GST_ELEMENT_METADATA_KLASS);
+
+  if (klass == NULL) {
+    GST_ERROR_OBJECT (factory,
+        "device monitor factory is missing klass identifiers");
+    return res;
+  }
+
+  /* Filter by device monitor type first, as soon as it matches
+   * one type, we skip all other tests */
+  if (!res && (type & GST_DEVICE_MONITOR_FACTORY_TYPE_SINK))
+    res = (strstr (klass, "Sink") != NULL);
+
+  if (!res && (type & GST_DEVICE_MONITOR_FACTORY_TYPE_SRC))
+    res = (strstr (klass, "Source") != NULL);
+
+  /* Filter by media type now, we only test if it
+   * matched any of the types above. */
+  if (res
+      && (type & (GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_AUDIO |
+              GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_VIDEO |
+              GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_IMAGE)))
+    res = ((type & GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_AUDIO)
+        && (strstr (klass, "Audio") != NULL))
+        || ((type & GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_VIDEO)
+        && (strstr (klass, "Video") != NULL))
+        || ((type & GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_IMAGE)
+        && (strstr (klass, "Image") != NULL));
+
+  return res;
+}
+
+static gboolean
+device_monitor_filter (GstPluginFeature * feature, FilterData * data)
+{
+  gboolean res;
+
+  /* we only care about device monitor factories */
+  if (G_UNLIKELY (!GST_IS_DEVICE_MONITOR_FACTORY (feature)))
+    return FALSE;
+
+  res = (gst_plugin_feature_get_rank (feature) >= data->minrank) &&
+      gst_device_monitor_factory_list_is_type (GST_DEVICE_MONITOR_FACTORY_CAST
+      (feature), data->type);
+
+  return res;
+}
+
+/**
+ * gst_device_monitor_factory_list_get_device_monitors:
+ * @type: a #GstDeviceMonitorFactoryListType
+ * @minrank: Minimum rank
+ *
+ * Get a list of factories that match the given @type. Only device monitors
+ * with a rank greater or equal to @minrank will be returned.
+ * The list of factories is returned by decreasing rank.
+ *
+ * Returns: (transfer full) (element-type Gst.DeviceMonitorFactory): a #GList of
+ *     #GstDeviceMonitorFactory device monitors. Use gst_plugin_feature_list_free() after
+ *     usage.
+ *
+ * Since: 1.4
+ */
+GList *gst_device_monitor_factory_list_get_device_monitors
+    (GstDeviceMonitorFactoryListType type, GstRank minrank)
+{
+  GList *result;
+  FilterData data;
+
+  /* prepare type */
+  data.type = type;
+  data.minrank = minrank;
+
+  /* get the feature list using the filter */
+  result = gst_registry_feature_filter (gst_registry_get (),
+      (GstPluginFeatureFilter) device_monitor_filter, FALSE, &data);
+
+  /* sort on rank and name */
+  result = g_list_sort (result, gst_plugin_feature_rank_compare_func);
+
+  return result;
+}
diff --git a/gst/gstdevicemonitorfactory.h b/gst/gstdevicemonitorfactory.h
new file mode 100644 (file)
index 0000000..b094cc8
--- /dev/null
@@ -0,0 +1,124 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ *               2000,2004 Wim Taymans <wim@fluendo.com>
+ *               2012 Olivier Crete <olivier.crete@collabora.com>
+ *
+ * gstdevicemonitorfactory.h: Header for GstDeviceMonitorFactory
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+
+#ifndef __GST_DEVICE_MONITOR_FACTORY_H__
+#define __GST_DEVICE_MONITOR_FACTORY_H__
+
+/**
+ * GstDeviceMonitorFactory:
+ *
+ * The opaque #GstDeviceMonitorFactory data structure.
+ *
+ * Since: 1.4
+ */
+typedef struct _GstDeviceMonitorFactory GstDeviceMonitorFactory;
+typedef struct _GstDeviceMonitorFactoryClass GstDeviceMonitorFactoryClass;
+
+#include <gst/gstconfig.h>
+#include <gst/gstplugin.h>
+#include <gst/gstpluginfeature.h>
+#include <gst/gstdevicemonitor.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DEVICE_MONITOR_FACTORY            (gst_device_monitor_factory_get_type())
+#define GST_DEVICE_MONITOR_FACTORY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEVICE_MONITOR_FACTORY,\
+                                                 GstDeviceMonitorFactory))
+#define GST_DEVICE_MONITOR_FACTORY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEVICE_MONITOR_FACTORY,\
+                                                 GstDeviceMonitorFactoryClass))
+#define GST_IS_DEVICE_MONITOR_FACTORY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEVICE_MONITOR_FACTORY))
+#define GST_IS_DEVICE_MONITOR_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEVICE_MONITOR_FACTORY))
+#define GST_DEVICE_MONITOR_FACTORY_CAST(obj)       ((GstDeviceMonitorFactory *)(obj))
+
+GType                   gst_device_monitor_factory_get_type          (void);
+
+GstDeviceMonitorFactory * gst_device_monitor_factory_find            (const gchar *name);
+
+GType                   gst_device_monitor_factory_get_device_monitor_type (GstDeviceMonitorFactory *factory);
+
+const gchar *           gst_device_monitor_factory_get_metadata       (GstDeviceMonitorFactory *factory, const gchar *key);
+gchar **                gst_device_monitor_factory_get_metadata_keys  (GstDeviceMonitorFactory *factory);
+
+GstDeviceMonitor*       gst_device_monitor_factory_get                (GstDeviceMonitorFactory *factory) G_GNUC_MALLOC;
+GstDeviceMonitor*       gst_device_monitor_factory_get_by_name        (const gchar *factoryname) G_GNUC_MALLOC;
+
+gboolean                gst_device_monitor_register                   (GstPlugin *plugin, const gchar *name,
+                                                                       guint rank,
+                                                                       GType type);
+
+/* Factory list functions */
+
+/**
+ * GstDeviceMonitorFactoryListType:
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_SINK: Sink elements
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_SRC: Source elements
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MAX_DEVICE_MONITORS: Private, do not use
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_VIDEO: Elements handling video media types
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_AUDIO: Elements handling audio media types
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_IMAGE: Elements handling image media types
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_SUBTITLE: Elements handling subtitle media types
+ * @GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_METADATA: Elements handling metadata media types
+ *
+ * The type of #GstDeviceMonitorFactory to filter.
+ *
+ * All @GstDeviceMonitorFactoryListType up to @GST_DEVICE_MONITOR_FACTORY_TYPE_MAX_DEVICE_MONITORS are exclusive.
+ *
+ * If one or more of the MEDIA types are specified, then only elements
+ * matching the specified media types will be selected.
+ *
+ * Since: 1.4
+ */
+
+typedef guint64 GstDeviceMonitorFactoryListType;
+
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_SINK           (G_GUINT64_CONSTANT (1) << 0)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_SRC            (G_GUINT64_CONSTANT (1) << 1)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MAX_DEVICE_MONITORS   (G_GUINT64_CONSTANT (1) << 48)
+
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_VIDEO    (G_GUINT64_CONSTANT (1) << 49)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_AUDIO    (G_GUINT64_CONSTANT (1) << 50)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_IMAGE    (G_GUINT64_CONSTANT (1) << 51)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_SUBTITLE (G_GUINT64_CONSTANT (1) << 52)
+#define  GST_DEVICE_MONITOR_FACTORY_TYPE_MEDIA_METADATA (G_GUINT64_CONSTANT (1) << 53)
+
+/* Element klass defines */
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_DECODER               "Decoder"
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_ENCODER               "Encoder"
+
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_MEDIA_VIDEO           "Video"
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_MEDIA_AUDIO           "Audio"
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_MEDIA_IMAGE           "Image"
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_MEDIA_SUBTITLE        "Subtitle"
+#define GST_DEVICE_MONITOR_FACTORY_KLASS_MEDIA_METADATA        "Metadata"
+
+gboolean      gst_device_monitor_factory_list_is_type (GstDeviceMonitorFactory *factory,
+                                                       GstDeviceMonitorFactoryListType type);
+
+GList *       gst_device_monitor_factory_list_get_device_monitors (GstDeviceMonitorFactoryListType type,
+                                                                   GstRank minrank) G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* __GST_DEVICE_MONITOR_FACTORY_H__ */
index debc526..3735c55 100644 (file)
@@ -108,7 +108,8 @@ static GstMessageQuarks message_quarks[] = {
   {GST_MESSAGE_NEED_CONTEXT, "need-context", 0},
   {GST_MESSAGE_HAVE_CONTEXT, "have-context", 0},
   {GST_MESSAGE_EXTENDED, "extended", 0},
-  {GST_MESSAGE_DEVICE, "device", 0},
+  {GST_MESSAGE_DEVICE_ADDED, "device-added", 0},
+  {GST_MESSAGE_DEVICE_REMOVED, "device-removed", 0},
   {0, NULL, 0}
 };
 
@@ -2357,3 +2358,104 @@ gst_message_parse_have_context (GstMessage * message, GstContext ** context)
     gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
         GST_QUARK (CONTEXT), GST_TYPE_CONTEXT, context, NULL);
 }
+
+/**
+ * gst_message_new_device_added:
+ * @src: The #GstObject that created the message
+ * @device: (transfer none): The new #GstDevice
+ *
+ * Creates a new device-added message. The device-added message is produced by
+ * #GstDeviceMonitor or a #GstGlobalDeviceMonitor. They announce the appearance
+ * of monitored devices.
+ *
+ * Returns: a newly allocated #GstMessage
+ *
+ * Since: 1.4
+ */
+GstMessage *
+gst_message_new_device_added (GstObject * src, GstDevice * device)
+{
+  GstMessage *message;
+  GstStructure *structure;
+
+  structure = gst_structure_new_id (GST_QUARK (MESSAGE_DEVICE_ADDED),
+      GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL);
+  message = gst_message_new_extended (GST_MESSAGE_DEVICE_ADDED, src, structure);
+
+  return message;
+}
+
+/**
+ * gst_message_parse_device_added:
+ * @device: (out) (allow-none) (transfer none): A location where to store a
+ *  pointer to the new #GstDevice, or %NULL
+ * 
+ * Parses a device-added message. The device-added message is produced by
+ * #GstDeviceMonitor or a #GstGlobalDeviceMonitor. It announces the appearance
+ * of monitored devices.
+ *
+ * Since: 1.4
+ */
+void
+gst_message_parse_device_added (GstMessage * message, GstDevice ** device)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EXTENDED);
+  g_return_if_fail (gst_message_get_extended_type (message) ==
+      GST_MESSAGE_DEVICE_ADDED);
+
+  if (device)
+    gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
+        GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL);
+}
+
+/**
+ * gst_message_new_device_removed:
+ * @src: The #GstObject that created the message
+ * @device: (transfer none): The removed #GstDevice
+ *
+ * Creates a new device-removed message. The device-removed message is produced
+ * by #GstDeviceMonitor or a #GstGlobalDeviceMonitor. They announce the
+ * disappearance of monitored devices.
+ *
+ * Returns: a newly allocated #GstMessage
+ *
+ * Since: 1.4
+ */
+GstMessage *
+gst_message_new_device_removed (GstObject * src, GstDevice * device)
+{
+  GstMessage *message;
+  GstStructure *structure;
+
+  structure = gst_structure_new_id (GST_QUARK (MESSAGE_DEVICE_REMOVED),
+      GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL);
+  message = gst_message_new_extended (GST_MESSAGE_DEVICE_REMOVED, src,
+      structure);
+
+  return message;
+}
+
+/**
+ * gst_message_parse_device_removed:
+ * @device: (out) (allow-none) (transfer none): A location where to store a
+ *  pointer to the removed #GstDevice, or %NULL
+ *
+ * Parses a device-removed message. The device-removed message is produced by
+ * #GstDeviceMonitor or a #GstGlobalDeviceMonitor. It announces the
+ * disappearance of monitored devices.
+ *
+ * Since: 1.4
+ */
+void
+gst_message_parse_device_removed (GstMessage * message, GstDevice ** device)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_EXTENDED);
+  g_return_if_fail (gst_message_get_extended_type (message) ==
+      GST_MESSAGE_DEVICE_REMOVED);
+
+  if (device)
+    gst_structure_id_get (GST_MESSAGE_STRUCTURE (message),
+        GST_QUARK (DEVICE), GST_TYPE_DEVICE, device, NULL);
+}
index 951a620..24e2783 100644 (file)
@@ -149,15 +149,20 @@ typedef enum
 
 /**
  * GstMessageExtendedType:
- * @GST_MESSAGE_DEVICE: A #GstDevice addition or removal according to
- * a #GstDeviceMonitor
+ * @GST_MESSAGE_DEVICE_ADDED: A #GstDevice addition according to
+ * a #GstDeviceMonitor (Since 1.4)
+ * @GST_MESSAGE_DEVICE_REMOVED: A #GstDevice removal according to
+ * a #GstDeviceMonitor (Since 1.4)
  *
  * Extra message types, see #GstMessageType for the basic types
+ *
+ * Since: 1.4
  */
 
 typedef enum {
   /* Skip those defined in #GstMessage to avoid confusion */
-  GST_MESSAGE_DEVICE            = 3
+  GST_MESSAGE_DEVICE_ADDED               = 3,
+  GST_MESSAGE_DEVICE_REMOVED             = 5
 } GstMessageExtendedType;
 
 #include <gst/gstminiobject.h>
@@ -167,6 +172,7 @@ typedef enum {
 #include <gst/gststructure.h>
 #include <gst/gstquery.h>
 #include <gst/gsttoc.h>
+#include <gst/gstdevice.h>
 
 #define GST_TYPE_MESSAGE                         (gst_message_get_type())
 #define GST_IS_MESSAGE(obj)                      (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_MESSAGE))
@@ -591,6 +597,15 @@ gboolean        gst_message_parse_context_type  (GstMessage * message, const gch
 GstMessage *    gst_message_new_have_context    (GstObject * src, GstContext *context) G_GNUC_MALLOC;
 void            gst_message_parse_have_context  (GstMessage *message, GstContext **context);
 
+/* DEVICE_ADDED */
+GstMessage *    gst_message_new_device_added    (GstObject * src, GstDevice * device) G_GNUC_MALLOC;
+void            gst_message_parse_device_added  (GstMessage * message, GstDevice ** device);
+
+/* DEVICE_REMOVED */
+GstMessage *    gst_message_new_device_removed    (GstObject * src, GstDevice * device) G_GNUC_MALLOC;
+void            gst_message_parse_device_removed  (GstMessage * message, GstDevice ** device);
+
+
 G_END_DECLS
 
 #endif /* __GST_MESSAGE_H__ */
index 714aac8..39849fd 100644 (file)
@@ -68,7 +68,8 @@ static const gchar *_quark_strings[] = {
   "GstEventSegmentDone",
   "GstEventStreamStart", "stream-id", "GstQueryContext",
   "GstMessageNeedContext", "GstMessageHaveContext", "context", "context-type",
-  "GstMessageStreamStart", "group-id", "uri-redirection", "GstMessageExtended"
+  "GstMessageStreamStart", "group-id", "uri-redirection", "GstMessageExtended",
+  "GstMessageDeviceAdded", "GstMessageDeviceRemoved", "device"
 };
 
 GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 3a3f440..837ca5a 100644 (file)
@@ -197,7 +197,10 @@ typedef enum _GstQuarkId
   GST_QUARK_GROUP_ID = 168,
   GST_QUARK_URI_REDIRECTION = 169,
   GST_QUARK_MESSAGE_EXTENDED = 170,
-  GST_QUARK_MAX = 171
+  GST_QUARK_MESSAGE_DEVICE_ADDED = 171,
+  GST_QUARK_MESSAGE_DEVICE_REMOVED = 172,
+  GST_QUARK_DEVICE = 173,
+  GST_QUARK_MAX = 174
 } GstQuarkId;
 
 extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index dfd87d0..745ca4f 100644 (file)
 #include "gstinfo.h"
 #include "gsterror.h"
 #include "gstregistry.h"
+#include "gstdevicemonitorfactory.h"
 
 #include "gstpluginloader.h"
 
@@ -167,6 +168,8 @@ struct _GstRegistryPrivate
   guint32 efl_cookie;
   GList *typefind_factory_list;
   guint32 tfl_cookie;
+  GList *device_monitor_factory_list;
+  guint32 dmfl_cookie;
 };
 
 /* the one instance of the default registry and the mutex protecting the
@@ -316,6 +319,12 @@ gst_registry_finalize (GObject * object)
     gst_plugin_feature_list_free (registry->priv->typefind_factory_list);
   }
 
+  if (registry->priv->device_monitor_factory_list) {
+    GST_DEBUG_OBJECT (registry,
+        "Cleaning up cached device monitor factory list");
+    gst_plugin_feature_list_free (registry->priv->device_monitor_factory_list);
+  }
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -780,6 +789,28 @@ gst_registry_get_typefind_factory_list (GstRegistry * registry)
   return list;
 }
 
+
+static GList *
+gst_registry_get_device_monitor_factory_list (GstRegistry * registry)
+{
+  GList *list;
+
+  GST_OBJECT_LOCK (registry);
+
+  gst_registry_get_feature_list_or_create (registry,
+      &registry->priv->device_monitor_factory_list,
+      &registry->priv->dmfl_cookie, GST_TYPE_DEVICE_MONITOR_FACTORY);
+
+  /* Return reffed copy */
+  list =
+      gst_plugin_feature_list_copy (registry->priv->
+      device_monitor_factory_list);
+
+  GST_OBJECT_UNLOCK (registry);
+
+  return list;
+}
+
 /**
  * gst_registry_feature_filter:
  * @registry: registry to query
@@ -922,6 +953,8 @@ gst_registry_get_feature_list (GstRegistry * registry, GType type)
     return gst_registry_get_element_factory_list (registry);
   else if (type == GST_TYPE_TYPE_FIND_FACTORY)
     return gst_registry_get_typefind_factory_list (registry);
+  else if (type == GST_TYPE_DEVICE_MONITOR_FACTORY)
+    return gst_registry_get_device_monitor_factory_list (registry);
 
   data.type = type;
   data.name = NULL;
index 837e3b4..ee4a7a0 100644 (file)
@@ -56,6 +56,7 @@
 #include <gst/gstelement.h>
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
+#include <gst/gstdevicemonitorfactory.h>
 #include <gst/gsturi.h>
 #include <gst/gstinfo.h>
 #include <gst/gstenumtypes.h>
@@ -525,6 +526,7 @@ priv_gst_registry_binary_read_cache (GstRegistry * registry,
   /* make sure these types exist */
   GST_TYPE_ELEMENT_FACTORY;
   GST_TYPE_TYPE_FIND_FACTORY;
+  GST_TYPE_DEVICE_MONITOR_FACTORY;
 
 #ifndef GST_DISABLE_GST_DEBUG
   timer = g_timer_new ();
index 0ee7a05..fcacd6b 100644 (file)
@@ -33,6 +33,7 @@
 #include <gst/gstelement.h>
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
+#include <gst/gstdevicemonitorfactory.h>
 #include <gst/gsturi.h>
 #include <gst/gstinfo.h>
 #include <gst/gstenumtypes.h>
@@ -332,6 +333,23 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     } else {
       gst_registry_chunks_save_const_string (list, "");
     }
+  } else if (GST_IS_DEVICE_MONITOR_FACTORY (feature)) {
+    GstRegistryChunkDeviceMonitorFactory *tff;
+    GstDeviceMonitorFactory *factory = GST_DEVICE_MONITOR_FACTORY (feature);
+
+    /* Initialize with zeroes because of struct padding and
+     * valgrind complaining about copying unitialized memory
+     */
+    tff = g_slice_new0 (GstRegistryChunkDeviceMonitorFactory);
+    chk =
+        gst_registry_chunks_make_data (tff,
+        sizeof (GstRegistryChunkDeviceMonitorFactory));
+    pf = (GstRegistryChunkPluginFeature *) tff;
+
+
+    /* pack element metadata strings */
+    gst_registry_chunks_save_string (list,
+        gst_structure_to_string (factory->metadata));
   } else {
     GST_WARNING_OBJECT (feature, "unhandled feature type '%s'", type_name);
   }
@@ -650,6 +668,30 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
         factory->extensions[i - 1] = str;
       }
     }
+  } else if (GST_IS_DEVICE_MONITOR_FACTORY (feature)) {
+    GstRegistryChunkDeviceMonitorFactory *dmf;
+    GstDeviceMonitorFactory *factory = GST_DEVICE_MONITOR_FACTORY (feature);
+    const gchar *meta_data_str;
+
+    align (*in);
+    GST_DEBUG
+        ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
+        *in);
+    unpack_element (*in, dmf, GstRegistryChunkDeviceMonitorFactory, end, fail);
+
+    pf = (GstRegistryChunkPluginFeature *) dmf;
+
+    /* unpack element factory strings */
+    unpack_string_nocopy (*in, meta_data_str, end, fail);
+    if (meta_data_str && *meta_data_str) {
+      factory->metadata = gst_structure_from_string (meta_data_str, NULL);
+      if (!factory->metadata) {
+        GST_ERROR
+            ("Error when trying to deserialize structure for metadata '%s'",
+            meta_data_str);
+        goto fail;
+      }
+    }
   } else {
     GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
     goto fail;
index 3e6e923..e2c86ba 100644 (file)
@@ -122,7 +122,7 @@ typedef struct _GstRegistryChunkElementFactory
  * GstRegistryChunkTypeFindFactory:
  * @nextensions: stores the number of typefind extensions
  *
- * A structure containing the element factory fields
+ * A structure containing the type find factory fields
  */
 typedef struct _GstRegistryChunkTypeFindFactory
 {
@@ -132,6 +132,17 @@ typedef struct _GstRegistryChunkTypeFindFactory
 } GstRegistryChunkTypeFindFactory;
 
 /*
+ * GstRegistryChunkDeviceMonitorFactory:
+ *
+ * A structure containing the device monitor factory fields
+ */
+typedef struct _GstRegistryChunkDeviceMonitorFactory
+{
+  GstRegistryChunkPluginFeature plugin_feature;
+
+} GstRegistryChunkDeviceMonitorFactory;
+
+/*
  * GstRegistryChunkPadTemplate:
  *
  * A structure containing the static pad templates of a plugin feature
index 89dd9da..281f51d 100644 (file)
@@ -390,6 +390,35 @@ EXPORTS
        gst_debug_set_threshold_from_string
        gst_debug_unset_threshold_for_name
        gst_deinit
+       gst_device_create_element
+       gst_device_get_caps
+       gst_device_get_display_name
+       gst_device_get_type
+       gst_device_monitor_can_monitor
+       gst_device_monitor_class_add_metadata
+       gst_device_monitor_class_add_static_metadata
+       gst_device_monitor_class_get_metadata
+       gst_device_monitor_class_set_metadata
+       gst_device_monitor_class_set_static_metadata
+       gst_device_monitor_device_add
+       gst_device_monitor_device_remove
+       gst_device_monitor_factory_find
+       gst_device_monitor_factory_get
+       gst_device_monitor_factory_get_by_name
+       gst_device_monitor_factory_get_device_monitor_type
+       gst_device_monitor_factory_get_metadata
+       gst_device_monitor_factory_get_metadata_keys
+       gst_device_monitor_factory_get_type
+       gst_device_monitor_factory_list_get_device_monitors
+       gst_device_monitor_factory_list_is_type
+       gst_device_monitor_get_bus
+       gst_device_monitor_get_devices
+       gst_device_monitor_get_factory
+       gst_device_monitor_get_type
+       gst_device_monitor_register
+       gst_device_monitor_start
+       gst_device_monitor_stop
+       gst_device_reconfigure_element
        gst_double_range_get_type
        gst_element_abort_state
        gst_element_add_pad
@@ -592,6 +621,8 @@ EXPORTS
        gst_memory_resize
        gst_memory_share
        gst_memory_unmap
+       gst_message_extended_type_get_type
+       gst_message_get_extended_type
        gst_message_get_seqnum
        gst_message_get_stream_status_object
        gst_message_get_structure
@@ -604,6 +635,8 @@ EXPORTS
        gst_message_new_clock_lost
        gst_message_new_clock_provide
        gst_message_new_custom
+       gst_message_new_device_added
+       gst_message_new_device_removed
        gst_message_new_duration_changed
        gst_message_new_element
        gst_message_new_eos
@@ -635,6 +668,8 @@ EXPORTS
        gst_message_parse_clock_lost
        gst_message_parse_clock_provide
        gst_message_parse_context_type
+       gst_message_parse_device_added
+       gst_message_parse_device_removed
        gst_message_parse_error
        gst_message_parse_group_id
        gst_message_parse_have_context