From 5a7b7e66bdc0a5d31f3821cab18348685934671d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 16 Jul 2015 18:56:00 +0200 Subject: [PATCH] deviceprovider: Add method to hide devices from a provider Add methods to add/remove the providers that should be hidden by this provider. Also make a method to get a list of hidden providers. This makes it possible to have multiple systems monitor the same devices and remove duplicates. Add a property to see all devices, even duplicate ones from hidden providers. --- gst/gstdevicemonitor.c | 192 ++++++++++++++++++++++++++++++++++++++++-- gst/gstdevicemonitor.h | 3 + gst/gstdeviceprovider.c | 141 +++++++++++++++++++++++++++++++ gst/gstdeviceprovider.h | 8 +- win32/common/libgstreamer.def | 5 ++ 5 files changed, 342 insertions(+), 7 deletions(-) diff --git a/gst/gstdevicemonitor.c b/gst/gstdevicemonitor.c index 9784232..7092fcc 100644 --- a/gst/gstdevicemonitor.c +++ b/gst/gstdevicemonitor.c @@ -108,8 +108,16 @@ struct _GstDeviceMonitorPrivate GPtrArray *filters; guint last_id; + GList *hidden; + gboolean show_all; }; +#define DEFAULT_SHOW_ALL FALSE + +enum +{ + PROP_SHOW_ALL = 1, +}; G_DEFINE_TYPE (GstDeviceMonitor, gst_device_monitor, GST_TYPE_OBJECT); @@ -133,13 +141,90 @@ device_filter_free (struct DeviceFilter *filter) } static void +gst_device_monitor_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object); + + switch (prop_id) { + case PROP_SHOW_ALL: + g_value_set_boolean (value, + gst_device_monitor_get_show_all_devices (monitor)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_device_monitor_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDeviceMonitor *monitor = GST_DEVICE_MONITOR (object); + + switch (prop_id) { + case PROP_SHOW_ALL: + gst_device_monitor_set_show_all_devices (monitor, + g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void gst_device_monitor_class_init (GstDeviceMonitorClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (GstDeviceMonitorPrivate)); + object_class->get_property = gst_device_monitor_get_property; + object_class->set_property = gst_device_monitor_set_property; object_class->dispose = gst_device_monitor_dispose; + + g_object_class_install_property (object_class, PROP_SHOW_ALL, + g_param_spec_boolean ("show-all", "Show All", + "Show all devices, even those from hidden providers", + DEFAULT_SHOW_ALL, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); +} + +/* must be called with monitor lock */ +static gboolean +is_provider_hidden (GstDeviceMonitor * monitor, GList * hidden, + GstDeviceProvider * provider) +{ + GstDeviceProviderFactory *factory; + + if (monitor->priv->show_all) + return FALSE; + + factory = gst_device_provider_get_factory (provider); + if (g_list_find_custom (hidden, GST_OBJECT_NAME (factory), + (GCompareFunc) g_strcmp0)) + return TRUE; + + return FALSE; +} + +/* must be called with monitor lock */ +static void +update_hidden_providers_list (GList ** hidden, GstDeviceProvider * provider) +{ + gchar **obs; + + obs = gst_device_provider_get_hidden_providers (provider); + if (obs) { + gint i; + + for (i = 0; obs[i]; i++) + *hidden = g_list_prepend (*hidden, obs[i]); + + g_free (obs); + } } static void @@ -151,6 +236,7 @@ bus_sync_message (GstBus * bus, GstMessage * message, if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) { gboolean matches; GstDevice *device; + GstDeviceProvider *provider; if (type == GST_MESSAGE_DEVICE_ADDED) gst_message_parse_device_added (message, &device); @@ -158,7 +244,11 @@ bus_sync_message (GstBus * bus, GstMessage * message, gst_message_parse_device_removed (message, &device); GST_OBJECT_LOCK (monitor); - if (monitor->priv->filters->len) { + provider = + GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device))); + if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) { + matches = FALSE; + } else if (monitor->priv->filters->len) { guint i; for (i = 0; i < monitor->priv->filters->len; i++) { @@ -192,6 +282,8 @@ gst_device_monitor_init (GstDeviceMonitor * self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_DEVICE_MONITOR, GstDeviceMonitorPrivate); + self->priv->show_all = DEFAULT_SHOW_ALL; + self->priv->bus = gst_bus_new (); gst_bus_set_flushing (self->priv->bus, TRUE); @@ -258,7 +350,7 @@ gst_device_monitor_dispose (GObject * object) GList * gst_device_monitor_get_devices (GstDeviceMonitor * monitor) { - GList *devices = NULL; + GList *devices = NULL, *hidden = NULL; guint i; guint cookie; @@ -281,7 +373,9 @@ gst_device_monitor_get_devices (GstDeviceMonitor * monitor) again: g_list_free_full (devices, gst_object_unref); + g_list_free_full (hidden, g_free); devices = NULL; + hidden = NULL; cookie = monitor->priv->cookie; @@ -291,11 +385,17 @@ again: gst_object_ref (g_ptr_array_index (monitor->priv->providers, i)); GList *item; - GST_OBJECT_UNLOCK (monitor); + if (!is_provider_hidden (monitor, hidden, provider)) { + GST_OBJECT_UNLOCK (monitor); - tmpdev = gst_device_provider_get_devices (provider); + tmpdev = gst_device_provider_get_devices (provider); + + GST_OBJECT_LOCK (monitor); + update_hidden_providers_list (&hidden, provider); + } else { + tmpdev = NULL; + } - GST_OBJECT_LOCK (monitor); for (item = tmpdev; item; item = item->next) { GstDevice *dev = GST_DEVICE (item->data); @@ -305,6 +405,7 @@ again: for (j = 0; j < monitor->priv->filters->len; j++) { struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, j); + if (gst_caps_can_intersect (filter->caps, caps) && gst_device_has_classesv (dev, filter->classesv)) { devices = g_list_prepend (devices, gst_object_ref (dev)); @@ -317,10 +418,10 @@ again: g_list_free_full (tmpdev, gst_object_unref); gst_object_unref (provider); - if (monitor->priv->cookie != cookie) goto again; } + g_list_free_full (hidden, g_free); GST_OBJECT_UNLOCK (monitor); @@ -478,6 +579,33 @@ gst_device_monitor_stop (GstDeviceMonitor * monitor) } +static void +provider_hidden (GstDeviceProvider * provider, const gchar * hidden, + GstDeviceMonitor * monitor) +{ + GST_OBJECT_LOCK (monitor); + monitor->priv->hidden = + g_list_prepend (monitor->priv->hidden, g_strdup (hidden)); + GST_OBJECT_UNLOCK (monitor); +} + +static void +provider_unhidden (GstDeviceProvider * provider, const gchar * hidden, + GstDeviceMonitor * monitor) +{ + GList *find; + + GST_OBJECT_LOCK (monitor); + find = + g_list_find_custom (monitor->priv->hidden, hidden, + (GCompareFunc) g_strcmp0); + if (find) { + g_free (find->data); + monitor->priv->hidden = g_list_delete_link (monitor->priv->hidden, find); + } + GST_OBJECT_UNLOCK (monitor); +} + /** * gst_device_monitor_add_filter: * @monitor: a device monitor @@ -543,6 +671,12 @@ gst_device_monitor_add_filter (GstDeviceMonitor * monitor, if (provider) { GstBus *bus = gst_device_provider_get_bus (provider); + update_hidden_providers_list (&monitor->priv->hidden, provider); + g_signal_connect (provider, "provider-hidden", + (GCallback) provider_hidden, monitor); + g_signal_connect (provider, "provider-unhidden", + (GCallback) provider_unhidden, monitor); + matched = TRUE; gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message", @@ -716,3 +850,49 @@ done: return res; } + +/** + * gst_device_monitor_set_show_all_devices: + * @monitor: a #GstDeviceMonitor + * @show_all: show all devices + * + * Set if all devices should be visible, even those devices from hidden + * providers. Setting @show_all to true might show some devices multiple times. + * + * Since: 1.6 + */ +void +gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor, + gboolean show_all) +{ + g_return_if_fail (GST_IS_DEVICE_MONITOR (monitor)); + + GST_OBJECT_LOCK (monitor); + monitor->priv->show_all = show_all; + GST_OBJECT_UNLOCK (monitor); +} + +/** + * gst_device_monitor_get_show_all_devices: + * @monitor: a #GstDeviceMonitor + * + * Get if @monitor is curretly showing all devices, even those from hidden + * providers. + * + * Returns: %TRUE when all devices will be shown. + * + * Since: 1.6 + */ +gboolean +gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor) +{ + gboolean res; + + g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), FALSE); + + GST_OBJECT_LOCK (monitor); + res = monitor->priv->show_all; + GST_OBJECT_UNLOCK (monitor); + + return res; +} diff --git a/gst/gstdevicemonitor.h b/gst/gstdevicemonitor.h index 5fe4677..4d9c014 100644 --- a/gst/gstdevicemonitor.h +++ b/gst/gstdevicemonitor.h @@ -97,6 +97,9 @@ gboolean gst_device_monitor_remove_filter (GstDeviceMonitor * monitor, gchar ** gst_device_monitor_get_providers (GstDeviceMonitor * monitor); +void gst_device_monitor_set_show_all_devices (GstDeviceMonitor * monitor, gboolean show_all); +gboolean gst_device_monitor_get_show_all_devices (GstDeviceMonitor * monitor); + G_END_DECLS #endif /* __GST_DEVICE_MONITOR_H__ */ diff --git a/gst/gstdeviceprovider.c b/gst/gstdeviceprovider.c index 995c2ff..363b1b8 100644 --- a/gst/gstdeviceprovider.c +++ b/gst/gstdeviceprovider.c @@ -55,8 +55,19 @@ struct _GstDeviceProviderPrivate GMutex start_lock; gboolean started_count; + + GList *hidden_providers; +}; + +enum +{ + PROVIDER_HIDDEN, + PROVIDER_UNHIDDEN, + LAST_SIGNAL }; +static guint gst_device_provider_signals[LAST_SIGNAL] = { 0 }; + /* this is used in gstelementfactory.c:gst_element_register() */ GQuark __gst_deviceproviderclass_factory = 0; @@ -134,6 +145,16 @@ gst_device_provider_class_init (GstDeviceProviderClass * klass) gobject_class->dispose = gst_device_provider_dispose; gobject_class->finalize = gst_device_provider_finalize; + + gst_device_provider_signals[PROVIDER_HIDDEN] = + g_signal_new ("provider-hidden", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, 0, NULL, + NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_STRING); + + gst_device_provider_signals[PROVIDER_UNHIDDEN] = + g_signal_new ("provider-unhidden", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, 0, NULL, + NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_STRING); } static void @@ -598,3 +619,123 @@ gst_device_provider_device_remove (GstDeviceProvider * provider, if (item) gst_object_unparent (GST_OBJECT (device)); } + +/** + * gst_device_provider_get_hidden_providers: + * @provider: a #GstDeviceProvider + * + * Get the provider factory names of the #GstDeviceProvider instances that + * are hidden by @provider. + * + * Returns: (transfer full) (array zero-terminated=1) (element-type gchar*): + * a list of hidden providers factory names or %NULL when + * nothing is hidden by @provider. Free with g_strfreev. + * + * Since: 1.6 + */ +gchar ** +gst_device_provider_get_hidden_providers (GstDeviceProvider * provider) +{ + GList *walk; + guint i, len; + gchar **res = NULL; + + g_return_val_if_fail (GST_IS_DEVICE_PROVIDER (provider), NULL); + + GST_OBJECT_LOCK (provider); + len = g_list_length (provider->priv->hidden_providers); + if (len == 0) + goto done; + + res = g_new (gchar *, len + 1); + for (i = 0, walk = provider->priv->hidden_providers; walk; + walk = g_list_next (walk), i++) + res[i] = g_strdup (walk->data); + res[i] = NULL; + +done: + GST_OBJECT_UNLOCK (provider); + + return res; +} + +/** + * gst_device_provider_hide_provider: + * @provider: a #GstDeviceProvider + * @name: a provider factory name + * + * Make @provider hide the devices from the factory with @name. + * + * This function is used when @provider will also provide the devices reported + * by provider factory @name. A monitor should stop monitoring the + * device provider with @name to avoid duplicate devices. + * + * Since: 1.6 + */ +void +gst_device_provider_hide_provider (GstDeviceProvider * provider, + const gchar * name) +{ + GList *find; + const gchar *hidden_name = NULL; + + g_return_if_fail (GST_IS_DEVICE_PROVIDER (provider)); + g_return_if_fail (name != NULL); + + GST_OBJECT_LOCK (provider); + find = + g_list_find_custom (provider->priv->hidden_providers, name, + (GCompareFunc) g_strcmp0); + if (find == NULL) { + hidden_name = name; + provider->priv->hidden_providers = + g_list_prepend (provider->priv->hidden_providers, g_strdup (name)); + } + GST_OBJECT_UNLOCK (provider); + + if (hidden_name) + g_signal_emit (provider, gst_device_provider_signals[PROVIDER_HIDDEN], + 0, hidden_name); +} + +/** + * gst_device_provider_unhide_provider: + * @provider: a #GstDeviceProvider + * @name: a provider factory name + * + * Make @provider unhide the devices from factory @name. + * + * This function is used when @provider will no longer provide the devices + * reported by provider factory @name. A monitor should start + * monitoring the devices from provider factory @name in order to see + * all devices again. + * + * Since: 1.6 + */ +void +gst_device_provider_unhide_provider (GstDeviceProvider * provider, + const gchar * name) +{ + GList *find; + gchar *unhidden_name = NULL; + + g_return_if_fail (GST_IS_DEVICE_PROVIDER (provider)); + g_return_if_fail (unhidden_name != NULL); + + GST_OBJECT_LOCK (provider); + find = + g_list_find_custom (provider->priv->hidden_providers, name, + (GCompareFunc) g_strcmp0); + if (find) { + unhidden_name = find->data; + provider->priv->hidden_providers = + g_list_delete_link (provider->priv->hidden_providers, find); + } + GST_OBJECT_UNLOCK (provider); + + if (unhidden_name) { + g_signal_emit (provider, + gst_device_provider_signals[PROVIDER_UNHIDDEN], 0, unhidden_name); + g_free (unhidden_name); + } +} diff --git a/gst/gstdeviceprovider.h b/gst/gstdeviceprovider.h index 3982f3b..d53ba53 100644 --- a/gst/gstdeviceprovider.h +++ b/gst/gstdeviceprovider.h @@ -113,7 +113,13 @@ GstBus * gst_device_provider_get_bus (GstDeviceProvider * provider); void gst_device_provider_device_add (GstDeviceProvider * provider, GstDevice * device); void gst_device_provider_device_remove (GstDeviceProvider * provider, - GstDevice * device); + GstDevice * device); + +gchar ** gst_device_provider_get_hidden_providers (GstDeviceProvider * provider); +void gst_device_provider_hide_provider (GstDeviceProvider * provider, + const gchar * name); +void gst_device_provider_unhide_provider (GstDeviceProvider * provider, + const gchar * name); /* device provider class meta data */ diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 0e6963a..43979cc 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -436,9 +436,11 @@ EXPORTS gst_device_monitor_get_bus gst_device_monitor_get_devices gst_device_monitor_get_providers + gst_device_monitor_get_show_all_devices gst_device_monitor_get_type gst_device_monitor_new gst_device_monitor_remove_filter + gst_device_monitor_set_show_all_devices gst_device_monitor_start gst_device_monitor_stop gst_device_provider_can_monitor @@ -462,10 +464,13 @@ EXPORTS gst_device_provider_get_bus gst_device_provider_get_devices gst_device_provider_get_factory + gst_device_provider_get_hidden_providers gst_device_provider_get_type + gst_device_provider_hide_provider gst_device_provider_register gst_device_provider_start gst_device_provider_stop + gst_device_provider_unhide_provider gst_device_reconfigure_element gst_double_range_get_type gst_element_abort_state -- 2.7.4