registry: don't recreate features on first use. Fixes #584389

The first time one calls gst_element_factory_make(), gst recreates the plugin
feature and the element factory. As a side effect we ref the class to fill
in detail we already have filled from the registry cache. This patch changes
the behaviour to just update the existing entries. The factory is now attached
to the type and set in gst_element_base_class_init().
This commit is contained in:
Stefan Kost 2009-06-07 22:09:14 +03:00
parent fbaa49faf4
commit 55577a48ea
4 changed files with 71 additions and 28 deletions

View file

@ -145,6 +145,9 @@ static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
static GstObjectClass *parent_class = NULL; static GstObjectClass *parent_class = NULL;
static guint gst_element_signals[LAST_SIGNAL] = { 0 }; static guint gst_element_signals[LAST_SIGNAL] = { 0 };
/* this is used in gstelementfactory.c:gst_element_register() */
GQuark _gst_elementclass_factory = 0;
GType GType
gst_element_get_type (void) gst_element_get_type (void)
{ {
@ -167,6 +170,9 @@ gst_element_get_type (void)
_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement", _type = g_type_register_static (GST_TYPE_OBJECT, "GstElement",
&element_info, G_TYPE_FLAG_ABSTRACT); &element_info, G_TYPE_FLAG_ABSTRACT);
_gst_elementclass_factory =
g_quark_from_static_string ("GST_ELEMENTCLASS_FACTORY");
g_once_init_leave (&gst_element_type, _type); g_once_init_leave (&gst_element_type, _type);
} }
return gst_element_type; return gst_element_type;
@ -252,6 +258,13 @@ gst_element_base_class_init (gpointer g_class)
*/ */
memset (&element_class->details, 0, sizeof (GstElementDetails)); memset (&element_class->details, 0, sizeof (GstElementDetails));
element_class->padtemplates = NULL; element_class->padtemplates = NULL;
/* set the factory, see gst_element_register() */
element_class->elementfactory =
g_type_get_qdata (G_TYPE_FROM_CLASS (element_class),
_gst_elementclass_factory);
GST_DEBUG ("type %s : factory %p", G_OBJECT_CLASS_NAME (element_class),
element_class->elementfactory);
} }
static void static void

View file

@ -79,6 +79,9 @@ static GstPluginFeatureClass *parent_class = NULL;
/* static guint gst_element_factory_signals[LAST_SIGNAL] = { 0 }; */ /* static guint gst_element_factory_signals[LAST_SIGNAL] = { 0 }; */
/* this is defined in gstelement.c */
extern GQuark _gst_elementclass_factory;
#define _do_init \ #define _do_init \
{ \ { \
GST_DEBUG_CATEGORY_INIT (element_factory_debug, "GST_ELEMENT_FACTORY", \ GST_DEBUG_CATEGORY_INIT (element_factory_debug, "GST_ELEMENT_FACTORY", \
@ -193,8 +196,7 @@ gst_element_factory_cleanup (GstElementFactory * factory)
__gst_element_details_clear (&factory->details); __gst_element_details_clear (&factory->details);
if (factory->type) { if (factory->type) {
g_type_class_unref (g_type_class_peek (factory->type)); factory->type = G_TYPE_INVALID;
factory->type = 0;
} }
for (item = factory->staticpadtemplates; item; item = item->next) { for (item = factory->staticpadtemplates; item; item = item->next) {
@ -249,6 +251,8 @@ gboolean
gst_element_register (GstPlugin * plugin, const gchar * name, guint rank, gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
GType type) GType type)
{ {
GstPluginFeature *existing_feature;
GstRegistry *registry;
GstElementFactory *factory; GstElementFactory *factory;
GType *interfaces; GType *interfaces;
guint n_interfaces, i; guint n_interfaces, i;
@ -258,6 +262,24 @@ gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (g_type_is_a (type, GST_TYPE_ELEMENT), FALSE); g_return_val_if_fail (g_type_is_a (type, GST_TYPE_ELEMENT), FALSE);
registry = gst_registry_get_default ();
/* 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 there
* feature 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_ELEMENT_FACTORY_CAST (existing_feature);
factory->type = type;
existing_feature->loaded = TRUE;
g_type_set_qdata (type, _gst_elementclass_factory, factory);
gst_object_unref (existing_feature);
return TRUE;
}
factory = factory =
GST_ELEMENT_FACTORY_CAST (g_object_new (GST_TYPE_ELEMENT_FACTORY, NULL)); GST_ELEMENT_FACTORY_CAST (g_object_new (GST_TYPE_ELEMENT_FACTORY, NULL));
gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name); gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);
@ -284,7 +306,7 @@ gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
g_list_append (factory->staticpadtemplates, newt); g_list_append (factory->staticpadtemplates, newt);
} }
factory->numpadtemplates = klass->numpadtemplates; factory->numpadtemplates = klass->numpadtemplates;
klass->elementfactory = factory; g_type_set_qdata (type, _gst_elementclass_factory, factory);
/* special stuff for URI handling */ /* special stuff for URI handling */
if (g_type_is_a (type, GST_TYPE_URI_HANDLER)) { if (g_type_is_a (type, GST_TYPE_URI_HANDLER)) {
@ -322,8 +344,7 @@ gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory), rank); gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory), rank);
GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE; GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE;
gst_registry_add_feature (gst_registry_get_default (), gst_registry_add_feature (registry, GST_PLUGIN_FEATURE_CAST (factory));
GST_PLUGIN_FEATURE_CAST (factory));
return TRUE; return TRUE;
@ -389,12 +410,12 @@ gst_element_factory_create (GstElementFactory * factory, const gchar * name)
/* fill in the pointer to the factory in the element class. The /* fill in the pointer to the factory in the element class. The
* class will not be unreffed currently. * class will not be unreffed currently.
* FIXME: This isn't safe and may leak a refcount on the factory if 2 threads * Be thread safe as there might be 2 threads creating the first instance of
* create the first instance of an element at the same moment */ * an element at the same moment
*/
oclass = GST_ELEMENT_GET_CLASS (element); oclass = GST_ELEMENT_GET_CLASS (element);
if (G_UNLIKELY (oclass->elementfactory == NULL)) if (!g_atomic_pointer_compare_and_exchange (
oclass->elementfactory = factory; (gpointer *) & oclass->elementfactory, NULL, factory))
else
gst_object_unref (factory); gst_object_unref (factory);
if (name) if (name)
@ -407,7 +428,8 @@ gst_element_factory_create (GstElementFactory * factory, const gchar * name)
/* ERRORS */ /* ERRORS */
load_failed: load_failed:
{ {
GST_WARNING_OBJECT (factory, "loading plugin returned NULL!"); GST_WARNING_OBJECT (factory,
"loading plugin containing feature %s returned NULL!", name);
return NULL; return NULL;
} }
no_type: no_type:

View file

@ -535,6 +535,7 @@ gst_plugin_load_file (const gchar * filename, GError ** error)
gpointer ptr; gpointer ptr;
struct stat file_status; struct stat file_status;
GstRegistry *registry; GstRegistry *registry;
gboolean new_plugin = TRUE;
g_return_val_if_fail (filename != NULL, NULL); g_return_val_if_fail (filename != NULL, NULL);
@ -544,11 +545,12 @@ gst_plugin_load_file (const gchar * filename, GError ** error)
plugin = gst_registry_lookup (registry, filename); plugin = gst_registry_lookup (registry, filename);
if (plugin) { if (plugin) {
if (plugin->module) { if (plugin->module) {
/* already loaded */
g_static_mutex_unlock (&gst_plugin_loading_mutex); g_static_mutex_unlock (&gst_plugin_loading_mutex);
return plugin; return plugin;
} else { } else {
gst_object_unref (plugin); /* load plugin and update fields */
plugin = NULL; new_plugin = FALSE;
} }
} }
@ -586,13 +588,14 @@ gst_plugin_load_file (const gchar * filename, GError ** error)
goto return_error; goto return_error;
} }
plugin = g_object_new (GST_TYPE_PLUGIN, NULL); if (new_plugin) {
plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
plugin->file_mtime = file_status.st_mtime;
plugin->file_size = file_status.st_size;
}
plugin->module = module; plugin->module = module;
plugin->filename = g_strdup (filename); plugin->filename = g_strdup (filename);
plugin->basename = g_path_get_basename (filename); plugin->basename = g_path_get_basename (filename);
plugin->file_mtime = file_status.st_mtime;
plugin->file_size = file_status.st_size;
ret = g_module_symbol (module, "gst_plugin_desc", &ptr); ret = g_module_symbol (module, "gst_plugin_desc", &ptr);
if (!ret) { if (!ret) {
@ -606,15 +609,17 @@ gst_plugin_load_file (const gchar * filename, GError ** error)
} }
plugin->orig_desc = (GstPluginDesc *) ptr; plugin->orig_desc = (GstPluginDesc *) ptr;
/* check plugin description: complain about bad values but accept them, to if (new_plugin) {
* maintain backwards compatibility (FIXME: 0.11) */ /* check plugin description: complain about bad values but accept them, to
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, name, filename); * maintain backwards compatibility (FIXME: 0.11) */
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, description, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, name, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, version, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, description, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, license, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, version, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, source, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, license, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, package, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, source, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, origin, filename); CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, package, filename);
CHECK_PLUGIN_DESC_FIELD (plugin->orig_desc, origin, filename);
}
GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...", GST_LOG ("Plugin %p for file \"%s\" prepared, calling entry function...",
plugin, filename); plugin, filename);
@ -645,8 +650,10 @@ gst_plugin_load_file (const gchar * filename, GError ** error)
_gst_plugin_fault_handler_filename = NULL; _gst_plugin_fault_handler_filename = NULL;
GST_INFO ("plugin \"%s\" loaded", plugin->filename); GST_INFO ("plugin \"%s\" loaded", plugin->filename);
gst_object_ref (plugin); if (new_plugin) {
gst_default_registry_add_plugin (plugin); gst_object_ref (plugin);
gst_default_registry_add_plugin (plugin);
}
g_static_mutex_unlock (&gst_plugin_loading_mutex); g_static_mutex_unlock (&gst_plugin_loading_mutex);
return plugin; return plugin;

View file

@ -41,6 +41,7 @@ EXPORTS
_gst_debug_nameof_funcptr _gst_debug_nameof_funcptr
_gst_debug_register_funcptr _gst_debug_register_funcptr
_gst_element_error_printf _gst_element_error_printf
_gst_elementclass_factory DATA
_gst_plugin_register_static _gst_plugin_register_static
_gst_trace_add_entry _gst_trace_add_entry
_gst_trace_on DATA _gst_trace_on DATA