mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
gesdemux: Compute sinkpad caps based on formatter mimetypes
Implement lazy loading asset cache so gesdemux use the formatters assets while GES hasn't been initialized. And set extensions to temporary files as some formatters require the information (otio)
This commit is contained in:
parent
7caa424aaf
commit
f51f2f70de
6 changed files with 199 additions and 54 deletions
|
@ -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;
|
||||
|
|
|
@ -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 <Python.h>
|
||||
#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
|
||||
|
|
|
@ -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,
|
||||
|
|
19
ges/ges.c
19
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));
|
||||
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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 <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
|
||||
|
@ -455,10 +540,22 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
|
||||
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,
|
||||
|
@ -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 ();
|
||||
|
|
Loading…
Reference in a new issue