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:
*
* {
* 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,
}
}
+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);
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);
}
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
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;
}
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,
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;
#include "ges-formatter.h"
#include "ges-internal.h"
#include "ges.h"
+#ifndef DISABLE_XPTV
+#include "ges-pitivi-formatter.h"
+#endif
+
#ifdef HAS_PYTHON
#include <Python.h>
#include "ges-resources.h"
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);
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 */
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
/* 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,
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;
}
gst_object_unref (nlecomposition_factory);
-
-
/* register clip classes with the system */
g_type_class_ref (GES_TYPE_TEST_CLIP);
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);
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));
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 = []
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
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)
{
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");
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 <tsaunier@igalia.com");
+
+ gst_element_class_add_pad_template (gstelement_klass,
+ gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ sinkpad_caps));
+ gst_caps_unref (sinkpad_caps);
}
typedef struct
xges_buffer = gst_adapter_take_buffer (self->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,
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:
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 {
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 ();