dynamic types: Implement dynamic types in the registry
authorJan Schmidt <jan@centricular.com>
Wed, 13 May 2015 14:25:21 +0000 (00:25 +1000)
committerJan Schmidt <jan@centricular.com>
Wed, 2 Nov 2016 00:21:37 +0000 (11:21 +1100)
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

12 files changed:
gst/Makefile.am
gst/gst.h
gst/gst_private.h
gst/gstdynamictypefactory.c [new file with mode: 0644]
gst/gstdynamictypefactory.h [new file with mode: 0644]
gst/gstelementfactory.h
gst/gstregistrybinary.c
gst/gstregistrychunks.c
gst/gstregistrychunks.h
gst/gststructure.c
gst/gstvalue.c
win32/common/libgstreamer.def

index 4fe947a..ded9880 100644 (file)
@@ -69,6 +69,7 @@ libgstreamer_@GST_API_VERSION@_la_SOURCES = \
        gstdevicemonitor.c      \
        gstdeviceprovider.c     \
        gstdeviceproviderfactory.c \
+       gstdynamictypefactory.c \
        gstelement.c            \
        gstelementfactory.c     \
        gsterror.c              \
index 0b07f41..e104d4e 100644 (file)
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -46,6 +46,7 @@
 #include <gst/gstdevice.h>
 #include <gst/gstdevicemonitor.h>
 #include <gst/gstdeviceprovider.h>
+#include <gst/gstdynamictypefactory.h>
 #include <gst/gstelement.h>
 #include <gst/gstelementmetadata.h>
 #include <gst/gsterror.h>
index 049142c..d84cb5a 100644 (file)
@@ -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 (file)
index 0000000..e6b304e
--- /dev/null
@@ -0,0 +1,177 @@
+/* GStreamer
+ * Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
+ *
+ * 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.
+ *
+ * <example>
+ * <title>Registering a type for dynamic loading</title>
+ * <programlisting language="c">
+ *
+ * static gboolean
+ * plugin_init (GstPlugin * plugin)
+ * {
+ *   return gst_dynamic_type_register (plugin, GST_TYPE_CUSTOM_CAPS_FIELD);
+ * }
+ * </programlisting>
+ * </example>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gst_private.h"
+
+#include <glib-object.h>
+
+#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 (file)
index 0000000..42ec4e0
--- /dev/null
@@ -0,0 +1,56 @@
+/* GStreamer
+ * Copyright (C) 2015 Jan Schmidt <jan@centricular.com>
+ *
+ * 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 <gst/gstconfig.h>
+#include <gst/gstplugin.h>
+#include <gst/gstpluginfeature.h>
+
+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
index 788f1c7..ca1bec0 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
  *               2000,2004 Wim Taymans <wim@fluendo.com>
  *
- * 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
index 7b8556e..f7cc991 100644 (file)
@@ -57,6 +57,7 @@
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
 #include <gst/gstdeviceproviderfactory.h>
+#include <gst/gstdynamictypefactory.h>
 #include <gst/gsturi.h>
 #include <gst/gstinfo.h>
 #include <gst/gstenumtypes.h>
@@ -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 ();
index 48db8b8..193bb60 100644 (file)
@@ -35,6 +35,7 @@
 #include <gst/gsttypefind.h>
 #include <gst/gsttypefindfactory.h>
 #include <gst/gstdeviceproviderfactory.h>
+#include <gst/gstdynamictypefactory.h>
 #include <gst/gsturi.h>
 #include <gst/gstinfo.h>
 #include <gst/gstenumtypes.h>
@@ -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;
index 57ced70..e7b77b3 100644 (file)
@@ -143,6 +143,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:
  *
  * A structure containing the static pad templates of a plugin feature
index 581b00e..5aa9b3e 100644 (file)
@@ -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 *
index 9544641..57f7ba2 100644 (file)
@@ -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) {
index 79fe904..860864d 100644 (file)
@@ -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