From e4e85fc88af4df1948c65f2c1ffaed36739f1cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Tue, 16 Oct 2012 12:27:04 -0400 Subject: [PATCH] devicemonitor: Add GstDeviceMonitor and related Also add GstDevice and GstDeviceMonitorFactory And add code to the registry to save them https://bugzilla.gnome.org/show_bug.cgi?id=678402 --- gst/Makefile.am | 6 + gst/gst.h | 2 + gst/gst_private.h | 22 ++ gst/gstdevice.c | 231 ++++++++++++++ gst/gstdevice.h | 76 +++++ gst/gstdevicemonitor.c | 570 ++++++++++++++++++++++++++++++++++ gst/gstdevicemonitor.h | 130 ++++++++ gst/gstdevicemonitorfactory.c | 566 +++++++++++++++++++++++++++++++++ gst/gstdevicemonitorfactory.h | 124 ++++++++ gst/gstmessage.c | 104 ++++++- gst/gstmessage.h | 21 +- gst/gstquark.c | 3 +- gst/gstquark.h | 5 +- gst/gstregistry.c | 33 ++ gst/gstregistrybinary.c | 2 + gst/gstregistrychunks.c | 42 +++ gst/gstregistrychunks.h | 13 +- win32/common/libgstreamer.def | 35 +++ 18 files changed, 1978 insertions(+), 7 deletions(-) create mode 100644 gst/gstdevice.c create mode 100644 gst/gstdevice.h create mode 100644 gst/gstdevicemonitor.c create mode 100644 gst/gstdevicemonitor.h create mode 100644 gst/gstdevicemonitorfactory.c create mode 100644 gst/gstdevicemonitorfactory.h diff --git a/gst/Makefile.am b/gst/Makefile.am index b6cf720e2e..af84844f47 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -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 \ diff --git a/gst/gst.h b/gst/gst.h index 82f6bf961a..5e24e1792f 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/gst/gst_private.h b/gst/gst_private.h index 0e2d0b3f43..d610560b4e 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -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; + /* */ + + 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; + /* */ + + 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 index 0000000000..64f39253e2 --- /dev/null +++ b/gst/gstdevice.c @@ -0,0 +1,231 @@ +/* GStreamer + * Copyright (C) 2012 Olivier Crete + * + * 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 +#include + +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 index 0000000000..dc71eeb803 --- /dev/null +++ b/gst/gstdevice.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2012 Olivier Crete + * + * 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 +#include + + +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 index 0000000000..bd61a2c889 --- /dev/null +++ b/gst/gstdevicemonitor.c @@ -0,0 +1,570 @@ +/* GStreamer + * Copyright (C) 2012 Olivier Crete + * + * 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 + +#include "gst/gst_private.h" +#include + +#include +#include + +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 <joe.blogs at foo.com>" + * + * Sets the detailed information for a #GstDeviceMonitorClass. + * This function is for use in _class_init functions only. + * + * 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 <joe.blogs at foo.com>" + * + * Sets the detailed information for a #GstDeviceMonitorClass. + * This function is for use in _class_init functions only. + * + * 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 index 0000000000..35b94e71ec --- /dev/null +++ b/gst/gstdevicemonitor.h @@ -0,0 +1,130 @@ +/* GStreamer + * Copyright (C) 2012 Olivier Crete + * + * 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 + + +#ifndef __GST_DEVICE_MONITOR_H__ +#define __GST_DEVICE_MONITOR_H__ + +#include + +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 index 0000000000..a621c8de55 --- /dev/null +++ b/gst/gstdevicemonitorfactory.c @@ -0,0 +1,566 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2003 Benjamin Otte + * + * 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 index 0000000000..b094cc8afa --- /dev/null +++ b/gst/gstdevicemonitorfactory.h @@ -0,0 +1,124 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000,2004 Wim Taymans + * 2012 Olivier Crete + * + * 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 +#include +#include +#include + +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__ */ diff --git a/gst/gstmessage.c b/gst/gstmessage.c index debc526445..3735c550da 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -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); +} diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 951a62015c..24e2783226 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -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 @@ -167,6 +172,7 @@ typedef enum { #include #include #include +#include #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__ */ diff --git a/gst/gstquark.c b/gst/gstquark.c index 714aac8e58..39849fdaa9 100644 --- a/gst/gstquark.c +++ b/gst/gstquark.c @@ -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]; diff --git a/gst/gstquark.h b/gst/gstquark.h index 3a3f440f89..837ca5a913 100644 --- a/gst/gstquark.h +++ b/gst/gstquark.h @@ -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]; diff --git a/gst/gstregistry.c b/gst/gstregistry.c index dfd87d0ce3..745ca4f8b6 100644 --- a/gst/gstregistry.c +++ b/gst/gstregistry.c @@ -129,6 +129,7 @@ #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, + ®istry->priv->device_monitor_factory_list, + ®istry->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; diff --git a/gst/gstregistrybinary.c b/gst/gstregistrybinary.c index 837e3b419b..ee4a7a089d 100644 --- a/gst/gstregistrybinary.c +++ b/gst/gstregistrybinary.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -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 (); diff --git a/gst/gstregistrychunks.c b/gst/gstregistrychunks.c index 0ee7a0506c..fcacd6b6dc 100644 --- a/gst/gstregistrychunks.c +++ b/gst/gstregistrychunks.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/gst/gstregistrychunks.h b/gst/gstregistrychunks.h index 3e6e923d9b..e2c86baaa0 100644 --- a/gst/gstregistrychunks.h +++ b/gst/gstregistrychunks.h @@ -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 { @@ -131,6 +131,17 @@ typedef struct _GstRegistryChunkTypeFindFactory guint nextensions; } GstRegistryChunkTypeFindFactory; +/* + * GstRegistryChunkDeviceMonitorFactory: + * + * A structure containing the device monitor factory fields + */ +typedef struct _GstRegistryChunkDeviceMonitorFactory +{ + GstRegistryChunkPluginFeature plugin_feature; + +} GstRegistryChunkDeviceMonitorFactory; + /* * GstRegistryChunkPadTemplate: * diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 89dd9dae50..281f51db08 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -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