diff --git a/ges/ges-asset.c b/ges/ges-asset.c index 19d17b5b45..60385dc641 100644 --- a/ges/ges-asset.c +++ b/ges/ges-asset.c @@ -144,8 +144,6 @@ typedef struct GESAsset *asset; } GESAssetCacheEntry; -/* Also protect all the entries in the cache */ -G_LOCK_DEFINE_STATIC (asset_cache_lock); /* We are mapping entries by types and ID, such as: * * { @@ -169,8 +167,10 @@ G_LOCK_DEFINE_STATIC (asset_cache_lock); * different extractable types. **/ static GHashTable *type_entries_table = NULL; -#define LOCK_CACHE (G_LOCK (asset_cache_lock)) -#define UNLOCK_CACHE (G_UNLOCK (asset_cache_lock)) +/* Protect all the entries in the cache */ +static GRecMutex asset_cache_lock; +#define LOCK_CACHE (g_rec_mutex_lock (&asset_cache_lock)) +#define UNLOCK_CACHE (g_rec_mutex_unlock (&asset_cache_lock)) static gchar * _check_and_update_parameters (GType * extractable_type, const gchar * id, @@ -470,12 +470,39 @@ _extractable_type_name (GType type) } } +static void +ges_asset_cache_init_unlocked (void) +{ + if (type_entries_table) + return; + + type_entries_table = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_hash_table_unref); + + _init_formatter_assets (); + _init_standard_transition_assets (); +} + + +/* WITH LOCK_CACHE */ +static GHashTable * +_get_type_entries () +{ + if (type_entries_table) + return type_entries_table; + + ges_asset_cache_init_unlocked (); + + return type_entries_table; +} + +/* WITH LOCK_CACHE */ static inline GESAssetCacheEntry * _lookup_entry (GType extractable_type, const gchar * id) { GHashTable *entries_table; - entries_table = g_hash_table_lookup (type_entries_table, + entries_table = g_hash_table_lookup (_get_type_entries (), _extractable_type_name (extractable_type)); if (entries_table) return g_hash_table_lookup (entries_table, id); @@ -608,13 +635,13 @@ ges_asset_cache_put (GESAsset * asset, GTask * task) if (!(entry = _lookup_entry (extractable_type, asset_id))) { GHashTable *entries_table; - entries_table = g_hash_table_lookup (type_entries_table, + entries_table = g_hash_table_lookup (_get_type_entries (), _extractable_type_name (extractable_type)); if (entries_table == NULL) { entries_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _free_entries); - g_hash_table_insert (type_entries_table, + g_hash_table_insert (_get_type_entries (), g_strdup (_extractable_type_name (extractable_type)), entries_table); } @@ -637,18 +664,20 @@ ges_asset_cache_put (GESAsset * asset, GTask * task) void ges_asset_cache_init (void) { - type_entries_table = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) g_hash_table_unref); - - _init_formatter_assets (); - _init_standard_transition_assets (); + LOCK_CACHE; + ges_asset_cache_init_unlocked (); + UNLOCK_CACHE; } void ges_asset_cache_deinit (void) { + _deinit_formatter_assets (); + + LOCK_CACHE; g_hash_table_destroy (type_entries_table); type_entries_table = NULL; + UNLOCK_CACHE; } gboolean @@ -750,17 +779,21 @@ ges_asset_set_proxy (GESAsset * asset, GESAsset * proxy) GHashTable *entries_table; GESAssetCacheEntry *entry; - entries_table = g_hash_table_lookup (type_entries_table, + LOCK_CACHE; + entries_table = g_hash_table_lookup (_get_type_entries (), _extractable_type_name (proxy->priv->extractable_type)); entry = g_hash_table_find (entries_table, (GHRFunc) _lookup_proxied_asset, (gpointer) ges_asset_get_id (proxy)); if (!entry) { + UNLOCK_CACHE; GST_DEBUG_OBJECT (asset, "Not proxying any asset %s", proxy->priv->id); return FALSE; } asset = entry->asset; + UNLOCK_CACHE; + while (asset->priv->proxies) asset = asset->priv->proxies->data; @@ -914,7 +947,7 @@ ges_asset_set_id (GESAsset * asset, const gchar * id) } LOCK_CACHE; - entries = g_hash_table_lookup (type_entries_table, + entries = g_hash_table_lookup (_get_type_entries (), _extractable_type_name (asset->priv->extractable_type)); g_return_if_fail (g_hash_table_lookup_extended (entries, priv->id, &orig_id, @@ -1369,7 +1402,7 @@ ges_list_assets (GType filter) g_return_val_if_fail (g_type_is_a (filter, GES_TYPE_EXTRACTABLE), NULL); LOCK_CACHE; - g_hash_table_iter_init (&types_iter, type_entries_table); + g_hash_table_iter_init (&types_iter, _get_type_entries ()); while (g_hash_table_iter_next (&types_iter, &typename, &assets)) { if (g_type_is_a (filter, g_type_from_name ((gchar *) typename)) == FALSE) continue; diff --git a/ges/ges-formatter.c b/ges/ges-formatter.c index 4bbdb0a0c4..2f5d81527d 100644 --- a/ges/ges-formatter.c +++ b/ges/ges-formatter.c @@ -36,6 +36,10 @@ #include "ges-formatter.h" #include "ges-internal.h" #include "ges.h" +#ifndef DISABLE_XPTV +#include "ges-pitivi-formatter.h" +#endif + #ifdef HAS_PYTHON #include #include "ges-resources.h" @@ -44,6 +48,7 @@ GST_DEBUG_CATEGORY_STATIC (ges_formatter_debug); #undef GST_CAT_DEFAULT #define GST_CAT_DEFAULT ges_formatter_debug +static gboolean initialized = FALSE; /* TODO Add a GCancellable somewhere in the API */ static void ges_extractable_interface_init (GESExtractableInterface * iface); @@ -477,9 +482,10 @@ ges_formatter_class_register_metas (GESFormatterClass * class, class->version = version; class->rank = rank; - if (ges_is_initialized () && g_type_class_peek (G_OBJECT_CLASS_TYPE (class))) + if (g_atomic_int_get (&initialized) + && g_type_class_peek (G_OBJECT_CLASS_TYPE (class))) gst_object_unref (ges_asset_request (G_OBJECT_CLASS_TYPE (class), NULL, - NULL)); + NULL)); } /* Main Formatter methods */ @@ -622,12 +628,34 @@ _init_formatter_assets (void) g_once_init_leave (&init_debug, TRUE); } - load_python_formatters (); + if (g_atomic_int_compare_and_exchange (&initialized, FALSE, TRUE)) { + /* register formatter types with the system */ +#ifndef DISABLE_XPTV + g_type_class_ref (GES_TYPE_PITIVI_FORMATTER); +#endif + g_type_class_ref (GES_TYPE_COMMAND_LINE_FORMATTER); + g_type_class_ref (GES_TYPE_XML_FORMATTER); + load_python_formatters (); - formatters = g_type_children (GES_TYPE_FORMATTER, &n_formatters); - _list_formatters (formatters, n_formatters); - g_free (formatters); + formatters = g_type_children (GES_TYPE_FORMATTER, &n_formatters); + _list_formatters (formatters, n_formatters); + g_free (formatters); + } +} + +void +_deinit_formatter_assets (void) +{ + if (g_atomic_int_compare_and_exchange (&initialized, TRUE, FALSE)) { + +#ifndef DISABLE_XPTV + g_type_class_unref (g_type_class_peek (GES_TYPE_PITIVI_FORMATTER)); +#endif + + g_type_class_unref (g_type_class_peek (GES_TYPE_COMMAND_LINE_FORMATTER)); + g_type_class_unref (g_type_class_peek (GES_TYPE_XML_FORMATTER)); + } } static gint diff --git a/ges/ges-internal.h b/ges/ges-internal.h index e109b4965a..c3ba7dcbe4 100644 --- a/ges/ges-internal.h +++ b/ges/ges-internal.h @@ -343,6 +343,7 @@ G_GNUC_INTERNAL GstElement * get_element_for_encoding_profile (GstEncodingProf /* Function to initialise GES */ G_GNUC_INTERNAL void _init_standard_transition_assets (void); G_GNUC_INTERNAL void _init_formatter_assets (void); +G_GNUC_INTERNAL void _deinit_formatter_assets (void); /* Utilities */ G_GNUC_INTERNAL gint element_start_compare (GESTimelineElement * a, diff --git a/ges/ges.c b/ges/ges.c index eb81fadb16..2896ac6f70 100644 --- a/ges/ges.c +++ b/ges/ges.c @@ -83,6 +83,7 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data, uriasset_klass = g_type_class_ref (GES_TYPE_URI_CLIP_ASSET); + _init_formatter_assets (); if (!_ges_uri_asset_ensure_setup (uriasset_klass)) { GST_ERROR ("cannot setup uri asset"); goto failed; @@ -99,8 +100,6 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data, } gst_object_unref (nlecomposition_factory); - - /* register clip classes with the system */ g_type_class_ref (GES_TYPE_TEST_CLIP); @@ -112,13 +111,6 @@ ges_init_post (GOptionContext * context, GOptionGroup * group, gpointer data, g_type_class_ref (GES_TYPE_GROUP); - /* register formatter types with the system */ -#ifndef DISABLE_XPTV - g_type_class_ref (GES_TYPE_PITIVI_FORMATTER); -#endif - g_type_class_ref (GES_TYPE_COMMAND_LINE_FORMATTER); - g_type_class_ref (GES_TYPE_XML_FORMATTER); - /* Register track elements */ g_type_class_ref (GES_TYPE_EFFECT); @@ -209,15 +201,6 @@ ges_deinit (void) g_type_class_unref (g_type_class_peek (GES_TYPE_OVERLAY_TEXT_CLIP)); g_type_class_unref (g_type_class_peek (GES_TYPE_GROUP)); - - /* register formatter types with the system */ -#ifndef DISABLE_XPTV - g_type_class_unref (g_type_class_peek (GES_TYPE_PITIVI_FORMATTER)); -#endif - - g_type_class_unref (g_type_class_peek (GES_TYPE_COMMAND_LINE_FORMATTER)); - g_type_class_unref (g_type_class_peek (GES_TYPE_XML_FORMATTER)); - /* Register track elements */ g_type_class_unref (g_type_class_peek (GES_TYPE_EFFECT)); diff --git a/ges/python/gesotioformatter.py b/ges/python/gesotioformatter.py index 2815e26b74..2692445155 100644 --- a/ges/python/gesotioformatter.py +++ b/ges/python/gesotioformatter.py @@ -85,7 +85,7 @@ if otio is not None: GObject.type_register(GESOtioFormatter) known_extensions_mimetype_map = [ ("otio", "xml", "fcpxml"), - ("application/otio", "application/xmeml", "application/fcpxml") + ("application/vnd.pixar.opentimelineio+json", "application/vnd.apple-xmeml+xml", "application/vnd.apple-fcp+xml") ] extensions = [] diff --git a/plugins/ges/gesdemux.c b/plugins/ges/gesdemux.c index cfa850805c..a5bcdcab4e 100644 --- a/plugins/ges/gesdemux.c +++ b/plugins/ges/gesdemux.c @@ -47,11 +47,6 @@ GST_DEBUG_CATEGORY_STATIC (gesdemux); #define GST_CAT_DEFAULT gesdemux -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/xges")); - G_DECLARE_FINAL_TYPE (GESDemux, ges_demux, GES, Demux, GESBaseBin); struct _GESDemux @@ -79,6 +74,92 @@ enum static GParamSpec *properties[PROP_LAST]; +static GstCaps * +ges_demux_get_sinkpad_caps () +{ + GList *tmp, *formatters; + GstCaps *sinkpad_caps = gst_caps_new_empty (); + + formatters = ges_list_assets (GES_TYPE_FORMATTER); + for (tmp = formatters; tmp; tmp = tmp->next) { + GstCaps *caps; + const gchar *mimetype = + ges_meta_container_get_string (GES_META_CONTAINER (tmp->data), + GES_META_FORMATTER_MIMETYPE); + if (!mimetype) + continue; + + caps = gst_caps_from_string (mimetype); + + if (!caps) { + GST_INFO_OBJECT (tmp->data, + "%s - could not create caps from mimetype: %s", + ges_meta_container_get_string (GES_META_CONTAINER (tmp->data), + GES_META_FORMATTER_NAME), mimetype); + + continue; + } + + gst_caps_append (sinkpad_caps, caps); + } + g_list_free (formatters); + + return sinkpad_caps; +} + +static gchar * +ges_demux_get_extension (GstStructure * _struct) +{ + GList *tmp, *formatters; + gchar *ext = NULL; + + formatters = ges_list_assets (GES_TYPE_FORMATTER); + for (tmp = formatters; tmp; tmp = tmp->next) { + gchar **extensions_a; + gint i, n_exts; + GstCaps *caps; + const gchar *mimetype = + ges_meta_container_get_string (GES_META_CONTAINER (tmp->data), + GES_META_FORMATTER_MIMETYPE); + const gchar *extensions = + ges_meta_container_get_string (GES_META_CONTAINER (tmp->data), + GES_META_FORMATTER_EXTENSION); + if (!mimetype) + continue; + + if (!extensions) + continue; + + caps = gst_caps_from_string (mimetype); + if (!caps) { + GST_INFO_OBJECT (tmp->data, + "%s - could not create caps from mimetype: %s", + ges_meta_container_get_string (GES_META_CONTAINER (tmp->data), + GES_META_FORMATTER_NAME), mimetype); + + continue; + } + + extensions_a = g_strsplit (extensions, ",", -1); + n_exts = g_strv_length (extensions_a); + for (i = 0; i < gst_caps_get_size (caps) && i < n_exts; i++) { + GstStructure *structure = gst_caps_get_structure (caps, i); + + if (gst_structure_has_name (_struct, gst_structure_get_name (structure))) { + ext = g_strdup (extensions_a[i]); + g_strfreev (extensions_a); + gst_caps_unref (caps); + goto done; + } + } + g_strfreev (extensions_a); + } +done: + g_list_free (formatters); + + return ext; +} + static void ges_demux_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) @@ -110,6 +191,7 @@ ges_demux_class_init (GESDemuxClass * self_class) { GObjectClass *gclass = G_OBJECT_CLASS (self_class); GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (self_class); + GstCaps *sinkpad_caps = ges_demux_get_sinkpad_caps (); GST_DEBUG_CATEGORY_INIT (gesdemux, "gesdemux", 0, "ges demux element"); @@ -128,13 +210,16 @@ ges_demux_class_init (GESDemuxClass * self_class) GES_TYPE_TIMELINE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_override_property (gclass, PROP_TIMELINE, "timeline"); - gst_element_class_add_pad_template (gstelement_klass, - gst_static_pad_template_get (&sink_template)); gst_element_class_set_static_metadata (gstelement_klass, "GStreamer Editing Services based 'demuxer'", "Codec/Demux/Editing", "Demuxer for complex timeline file formats using GES.", "Thibault Saunier input_adapter, available); if (gst_buffer_map (xges_buffer, &map, GST_MAP_READ)) { + gint f; GError *err = NULL; + gchar *template = NULL; gchar *filename = NULL, *uri = NULL; - GError *error = NULL; - gint f = g_file_open_tmp (NULL, &filename, &err); + GstCaps *caps = gst_pad_get_current_caps (pad); + GstStructure *structure = gst_caps_get_structure (caps, 0); + gchar *ext = ges_demux_get_extension (structure); + + gst_caps_unref (caps); + if (ext) { + template = g_strdup_printf ("XXXXXX.%s", ext); + g_free (ext); + } + + f = g_file_open_tmp (template, &filename, &err); + g_free (template); if (err) { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_WRITE, @@ -480,8 +577,8 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) uri = gst_filename_to_uri (filename, NULL); GST_INFO_OBJECT (self, "Pre loading the timeline."); - ges_demux_create_timeline (self, uri, &error); - if (error) + ges_demux_create_timeline (self, uri, &err); + if (err) goto error; done: @@ -493,9 +590,9 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) error: ret = FALSE; gst_element_post_message (GST_ELEMENT (self), - gst_message_new_error (parent, error, + gst_message_new_error (parent, err, "Could not create timeline from description")); - g_clear_error (&error); + g_clear_error (&err); goto done; } else { @@ -528,7 +625,10 @@ static void ges_demux_init (GESDemux * self) { ges_init (); - self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + + self->sinkpad = + gst_pad_new_from_template (gst_element_get_pad_template (GST_ELEMENT + (self), "sink"), "sink"); gst_element_add_pad (GST_ELEMENT (self), self->sinkpad); self->input_adapter = gst_adapter_new ();