From e1dc60524e31a5c52aff7fbb9b67e62b29c0ac66 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 May 2015 00:25:21 +1000 Subject: [PATCH] dynamic types: Implement dynamic types in the registry Implement GstDynamicTypeFactory as a new registry feature. GstDynamicTypeFactory provides a way of registering a GType into the registry, such that it will be registered as a dynamic type when the registry is loaded, and then automatically loaded if the type is needed during caps parsing. This allows using non-core types in pad templates, by loading a registry feature to create the GType on the fly. https://bugzilla.gnome.org/show_bug.cgi?id=750079 --- gst/Makefile.am | 1 + gst/gst.h | 1 + gst/gst_private.h | 10 ++ gst/gstdynamictypefactory.c | 177 ++++++++++++++++++++++++++++++++++ gst/gstdynamictypefactory.h | 56 +++++++++++ gst/gstelementfactory.h | 2 +- gst/gstregistrybinary.c | 2 + gst/gstregistrychunks.c | 15 +++ gst/gstregistrychunks.h | 12 +++ gst/gststructure.c | 7 +- gst/gstvalue.c | 11 ++- win32/common/libgstreamer.def | 3 + 12 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 gst/gstdynamictypefactory.c create mode 100644 gst/gstdynamictypefactory.h diff --git a/gst/Makefile.am b/gst/Makefile.am index 4fe947a624..ded988040d 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -69,6 +69,7 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \ gstdevicemonitor.c \ gstdeviceprovider.c \ gstdeviceproviderfactory.c \ + gstdynamictypefactory.c \ gstelement.c \ gstelementfactory.c \ gsterror.c \ diff --git a/gst/gst.h b/gst/gst.h index 0b07f41aeb..e104d4e929 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/gst/gst_private.h b/gst/gst_private.h index 049142cb28..d84cb5a29a 100644 --- a/gst/gst_private.h +++ b/gst/gst_private.h @@ -484,6 +484,16 @@ struct _GstDeviceProviderFactoryClass { gpointer _gst_reserved[GST_PADDING]; }; +struct _GstDynamicTypeFactory { + GstPluginFeature feature; + + GType type; /* GType of the type, when loaded. 0 if not */ +}; + +struct _GstDynamicTypeFactoryClass { + GstPluginFeatureClass parent; +}; + /* privat flag used by GstBus / GstMessage */ #define GST_MESSAGE_FLAG_ASYNC_DELIVERY (GST_MINI_OBJECT_FLAG_LAST << 0) diff --git a/gst/gstdynamictypefactory.c b/gst/gstdynamictypefactory.c new file mode 100644 index 0000000000..e6b304eea7 --- /dev/null +++ b/gst/gstdynamictypefactory.c @@ -0,0 +1,177 @@ +/* GStreamer + * Copyright (C) 2015 Jan Schmidt + * + * gstdynamictypefactory.c: Implementation of GstDynamicTypeFactory + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstdynamictypefactory + * @short_description: Represents a registered dynamically loadable GType + * @see_also: #GstPlugin, #GstPluginFeature. + * + * #GstDynamicTypeFactory is used to represent a type that can be + * automatically loaded the first time it is used. For example, + * a non-standard type for use in caps fields. + * + * In general, applications and plugins don't need to use the factory + * beyond registering the type in a plugin init function. Once that is + * done, the type is stored in the registry, and ready as soon as the + * registry is loaded. + * + * + * Registering a type for dynamic loading + * + * + * static gboolean + * plugin_init (GstPlugin * plugin) + * { + * return gst_dynamic_type_register (plugin, GST_TYPE_CUSTOM_CAPS_FIELD); + * } + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gst_private.h" + +#include + +#include "gst.h" + +#include "glib-compat-private.h" + + +GST_DEBUG_CATEGORY_STATIC (dynamic_type_factory_debug); +#define GST_CAT_DEFAULT dynamic_type_factory_debug + +#define _do_init \ +{ \ + GST_DEBUG_CATEGORY_INIT (dynamic_type_factory_debug, \ + "GST_DYNAMIC_TYPE_FACTORY", GST_DEBUG_BOLD, \ + "dynamic type factories allow automatically loading a type from a plugin"); \ +} + +G_DEFINE_TYPE_WITH_CODE (GstDynamicTypeFactory, gst_dynamic_type_factory, + GST_TYPE_PLUGIN_FEATURE, _do_init); + +static void +gst_dynamic_type_factory_class_init (GstDynamicTypeFactoryClass * klass) +{ +} + +static void +gst_dynamic_type_factory_init (GstDynamicTypeFactory * factory) +{ +} + +static GstDynamicTypeFactory * +gst_dynamic_type_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_DYNAMIC_TYPE_FACTORY); + if (feature) + return GST_DYNAMIC_TYPE_FACTORY (feature); + + return NULL; +} + +GType +gst_dynamic_type_factory_load (const gchar * factoryname) +{ + GstDynamicTypeFactory *factory = gst_dynamic_type_factory_find (factoryname); + + /* Called with a non-dynamic or unregistered type? */ + if (factory == NULL) + return FALSE; + + factory = + GST_DYNAMIC_TYPE_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE + (factory))); + if (factory == NULL) + return 0; + + GST_DEBUG_OBJECT (factory, "Loaded type %s", factoryname); + + return factory->type; +} + +static GstDynamicTypeFactory * +gst_dynamic_type_factory_create (GstRegistry * registry, + GstPlugin * plugin, const gchar * name) +{ + GstDynamicTypeFactory *factory; + + factory = + GST_DYNAMIC_TYPE_FACTORY_CAST (g_object_newv + (GST_TYPE_DYNAMIC_TYPE_FACTORY, 0, NULL)); + gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name); + GST_LOG_OBJECT (factory, "Created new dynamictypefactory for type %s", name); + + 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_CAST (factory)->loaded = TRUE; + + return factory; +} + +gboolean +gst_dynamic_type_register (GstPlugin * plugin, GType dyn_type) +{ + GstDynamicTypeFactory *factory; + const gchar *name; + GstPluginFeature *existing_feature; + GstRegistry *registry; + + name = g_type_name (dyn_type); + g_return_val_if_fail (name != NULL, FALSE); + + registry = gst_registry_get (); + + /* check if feature already exists, if it exists there is no need to + * update it for this method of dynamic type */ + existing_feature = gst_registry_lookup_feature (registry, name); + if (existing_feature) { + GST_DEBUG_OBJECT (registry, "update existing feature %p (%s)", + existing_feature, name); + existing_feature->loaded = TRUE; + GST_DYNAMIC_TYPE_FACTORY (existing_feature)->type = dyn_type; + gst_object_unref (existing_feature); + return TRUE; + } + + factory = gst_dynamic_type_factory_create (registry, plugin, name); + factory->type = dyn_type; + + gst_registry_add_feature (registry, GST_PLUGIN_FEATURE_CAST (factory)); + + return TRUE; +} diff --git a/gst/gstdynamictypefactory.h b/gst/gstdynamictypefactory.h new file mode 100644 index 0000000000..42ec4e026b --- /dev/null +++ b/gst/gstdynamictypefactory.h @@ -0,0 +1,56 @@ +/* GStreamer + * Copyright (C) 2015 Jan Schmidt + * + * gstdynamictypefactory.h: Header for GstDynamicTypeFactory + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_DYNAMIC_TYPE_FACTORY_H__ +#define __GST_DYNAMIC_TYPE_FACTORY_H__ + +/** + * GstDynamicTypeFactory: + * + * The opaque #GstDynamicTypeFactory data structure. + */ +typedef struct _GstDynamicTypeFactory GstDynamicTypeFactory; +typedef struct _GstDynamicTypeFactoryClass GstDynamicTypeFactoryClass; + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DYNAMIC_TYPE_FACTORY (gst_dynamic_type_factory_get_type()) +#define GST_DYNAMIC_TYPE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DYNAMIC_TYPE_FACTORY,\ + GstDynamicTypeFactory)) +#define GST_DYNAMIC_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DYNAMIC_TYPE_FACTORY,\ + GstDynamicTypeFactoryClass)) +#define GST_IS_DYNAMIC_TYPE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DYNAMIC_TYPE_FACTORY)) +#define GST_IS_DYNAMIC_TYPE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DYNAMIC_TYPE_FACTORY)) +#define GST_DYNAMIC_TYPE_FACTORY_CAST(obj) ((GstDynamicTypeFactory *)(obj)) + +GType gst_dynamic_type_factory_get_type (void); + +GType gst_dynamic_type_factory_load (const gchar *factoryname); + +gboolean gst_dynamic_type_register (GstPlugin *plugin, GType type); + +G_END_DECLS + +#endif diff --git a/gst/gstelementfactory.h b/gst/gstelementfactory.h index 788f1c7f81..ca1bec0d55 100644 --- a/gst/gstelementfactory.h +++ b/gst/gstelementfactory.h @@ -2,7 +2,7 @@ * Copyright (C) 1999,2000 Erik Walthinsen * 2000,2004 Wim Taymans * - * gstelement.h: Header for GstElement + * gstelementfactory.h: Header for GstElementFactory * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/gst/gstregistrybinary.c b/gst/gstregistrybinary.c index 7b8556e682..f7cc991c1d 100644 --- a/gst/gstregistrybinary.c +++ b/gst/gstregistrybinary.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -527,6 +528,7 @@ priv_gst_registry_binary_read_cache (GstRegistry * registry, GST_TYPE_ELEMENT_FACTORY; GST_TYPE_TYPE_FIND_FACTORY; GST_TYPE_DEVICE_PROVIDER_FACTORY; + GST_TYPE_DYNAMIC_TYPE_FACTORY; #ifndef GST_DISABLE_GST_DEBUG timer = g_timer_new (); diff --git a/gst/gstregistrychunks.c b/gst/gstregistrychunks.c index 48db8b80b1..193bb60c59 100644 --- a/gst/gstregistrychunks.c +++ b/gst/gstregistrychunks.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -348,6 +349,14 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature) pf = g_slice_new0 (GstRegistryChunkPluginFeature); pf_size = sizeof (GstRegistryChunkPluginFeature); chk = gst_registry_chunks_make_data (pf, pf_size); + } else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature)) { + GstRegistryChunkDynamicTypeFactory *tmp; + + tmp = g_slice_new0 (GstRegistryChunkDynamicTypeFactory); + chk = + gst_registry_chunks_make_data (tmp, + sizeof (GstRegistryChunkDynamicTypeFactory)); + pf = (GstRegistryChunkPluginFeature *) tmp; } else { GST_WARNING_OBJECT (feature, "unhandled feature type '%s'", type_name); } @@ -697,6 +706,12 @@ gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in, ("Reading/casting for GstRegistryChunkPluginFeature at address %p", *in); unpack_element (*in, pf, GstRegistryChunkPluginFeature, end, fail); + } else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature)) { + GstRegistryChunkDynamicTypeFactory *tmp; + + unpack_element (*in, tmp, GstRegistryChunkDynamicTypeFactory, end, fail); + + pf = (GstRegistryChunkPluginFeature *) tmp; } 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 57ced703f2..e7b77b30f0 100644 --- a/gst/gstregistrychunks.h +++ b/gst/gstregistrychunks.h @@ -142,6 +142,18 @@ typedef struct _GstRegistryChunkDeviceProviderFactory } GstRegistryChunkDeviceProviderFactory; +/* + * GstRegistryChunkDynamicTypeFactory: + * + * A structure containing the dynamic type factory flags field + */ +typedef struct _GstRegistryChunkDynamicTypeFactory +{ + GstRegistryChunkPluginFeature plugin_feature; + + guint type_flags; +} GstRegistryChunkDynamicTypeFactory; + /* * GstRegistryChunkPadTemplate: * diff --git a/gst/gststructure.c b/gst/gststructure.c index 581b00e09e..5aa9b3eb78 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -1841,6 +1841,7 @@ gst_structure_gtype_from_abbr (const char *type_name) int i; GstStructureAbbreviation *abbrs; gint n_abbrs; + GType ret; g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID); @@ -1853,7 +1854,11 @@ gst_structure_gtype_from_abbr (const char *type_name) } /* this is the fallback */ - return g_type_from_name (type_name); + ret = g_type_from_name (type_name); + /* If not found, try it as a dynamic type */ + if (G_UNLIKELY (ret == 0)) + ret = gst_dynamic_type_factory_load (type_name); + return ret; } static const char * diff --git a/gst/gstvalue.c b/gst/gstvalue.c index 9544641902..57f7ba20ef 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -6432,11 +6432,16 @@ try_as_flags_string: if (end != NULL) { gchar *class_name = g_strndup (set_class, end - set_class); GType flags_type = g_type_from_name (class_name); + if (flags_type == 0) { + GST_TRACE ("Looking for dynamic type %s", class_name); + gst_dynamic_type_factory_load (class_name); + } - g_free (class_name); - - if (flags_type != 0) + if (flags_type != 0) { flags_klass = g_type_class_ref (flags_type); + GST_TRACE ("Going to parse %s as %s", s, class_name); + } + g_free (class_name); } if (flags_klass) { diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 79fe90441e..860864dc5c 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -479,6 +479,9 @@ EXPORTS gst_device_provider_unhide_provider gst_device_reconfigure_element gst_double_range_get_type + gst_dynamic_type_factory_get_type + gst_dynamic_type_factory_load + gst_dynamic_type_register gst_element_abort_state gst_element_add_pad gst_element_add_property_deep_notify_watch