From abb4f005e3826baa1e0e90b442efdabb83972ff8 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Thu, 11 Jul 2019 16:23:47 -0400 Subject: [PATCH] Mark nested timeline assets as such Adding a property to let the application know Also make sure that the duration of nested timeline assets is reported as CLOCK_TIME_NONE as those are extended as necessary. And make a difference between asset duration and their max duration As nested timelines can be extended 'infinitely' those max duration is GST_CLOCK_TIME_NONE, but their duration is the real duration of the timeline. --- ges/ges-uri-asset.c | 54 +++++++++++++++++++++++++++++++++++++++--- ges/ges-uri-asset.h | 2 ++ ges/ges-uri-clip.c | 2 +- plugins/ges/gesdemux.c | 7 ++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/ges/ges-uri-asset.c b/ges/ges-uri-asset.c index 5e21f5de6d..edca8cdab1 100644 --- a/ges/ges-uri-asset.c +++ b/ges/ges-uri-asset.c @@ -94,6 +94,7 @@ enum { PROP_0, PROP_DURATION, + PROP_IS_NESTED_TIMELINE, PROP_LAST }; static GParamSpec *properties[PROP_LAST]; @@ -102,7 +103,9 @@ struct _GESUriClipAssetPrivate { GstDiscovererInfo *info; GstClockTime duration; + GstClockTime max_duration; gboolean is_image; + gboolean is_nested_timeline; GList *asset_trackfilesources; }; @@ -136,6 +139,9 @@ ges_uri_clip_asset_get_property (GObject * object, guint property_id, case PROP_DURATION: g_value_set_uint64 (value, priv->duration); break; + case PROP_IS_NESTED_TIMELINE: + g_value_set_boolean (value, priv->is_nested_timeline); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -272,6 +278,17 @@ ges_uri_clip_asset_class_init (GESUriClipAssetClass * klass) g_object_class_install_property (object_class, PROP_DURATION, properties[PROP_DURATION]); + /** + * GESUriClipAsset:is-nested-timeline: + * + * The duration (in nanoseconds) of the media file + */ + properties[PROP_IS_NESTED_TIMELINE] = + g_param_spec_boolean ("is-nested-timeline", "Is nested timeline", + "Whether this is a nested timeline", FALSE, G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_IS_NESTED_TIMELINE, + properties[PROP_IS_NESTED_TIMELINE]); + _ges_uri_asset_ensure_setup (klass); } @@ -283,7 +300,7 @@ ges_uri_clip_asset_init (GESUriClipAsset * self) priv = self->priv = ges_uri_clip_asset_get_instance_private (self); priv->info = NULL; - priv->duration = GST_CLOCK_TIME_NONE; + priv->max_duration = priv->duration = GST_CLOCK_TIME_NONE; priv->is_image = FALSE; } @@ -329,6 +346,7 @@ ges_uri_clip_asset_set_info (GESUriClipAsset * self, GstDiscovererInfo * info) GESTrackType supportedformats = GES_TRACK_TYPE_UNKNOWN; GESUriClipAssetPrivate *priv = GES_URI_CLIP_ASSET (self)->priv; + const GstTagList *tlist = gst_discoverer_info_get_tags (info); /* Extract infos from the GstDiscovererInfo */ stream_list = gst_discoverer_info_get_stream_list (info); @@ -364,8 +382,16 @@ ges_uri_clip_asset_set_info (GESUriClipAsset * self, GstDiscovererInfo * info) if (stream_list) gst_discoverer_stream_info_list_free (stream_list); - if (priv->is_image == FALSE) - priv->duration = gst_discoverer_info_get_duration (info); + if (tlist) + gst_tag_list_get_boolean (tlist, "is-ges-timeline", + &priv->is_nested_timeline); + + if (priv->is_image == FALSE) { + priv->max_duration = priv->duration = + gst_discoverer_info_get_duration (info); + if (priv->is_nested_timeline) + priv->max_duration = GST_CLOCK_TIME_NONE; + } /* else we keep #GST_CLOCK_TIME_NONE */ priv->info = gst_object_ref (info); @@ -500,6 +526,28 @@ ges_uri_clip_asset_get_duration (GESUriClipAsset * self) return self->priv->duration; } + +/** + * ges_uri_clip_asset_get_max_duration: + * @self: a #GESUriClipAsset + * + * Gets maximum duration of the file represented by @self, + * it is usually the same as GESUriClipAsset::duration, + * but in the case of nested timelines, for example, they + * are different as those can be extended 'infinitely'. + * + * Returns: The maximum duration of @self + * + * Since: 1.18 + */ +GstClockTime +ges_uri_clip_asset_get_max_duration (GESUriClipAsset * self) +{ + g_return_val_if_fail (GES_IS_URI_CLIP_ASSET (self), GST_CLOCK_TIME_NONE); + + return self->priv->max_duration; +} + /** * ges_uri_clip_asset_is_image: * @self: a #GESUriClipAsset diff --git a/ges/ges-uri-asset.h b/ges/ges-uri-asset.h index c24a08f175..6b739c2b5a 100644 --- a/ges/ges-uri-asset.h +++ b/ges/ges-uri-asset.h @@ -78,6 +78,8 @@ GstDiscovererInfo *ges_uri_clip_asset_get_info (const GESUriClipAsset * sel GES_API GstClockTime ges_uri_clip_asset_get_duration (GESUriClipAsset *self); GES_API +GstClockTime ges_uri_clip_asset_get_max_duration (GESUriClipAsset *self); +GES_API gboolean ges_uri_clip_asset_is_image (GESUriClipAsset *self); GES_API void ges_uri_clip_asset_new (const gchar *uri, diff --git a/ges/ges-uri-clip.c b/ges/ges-uri-clip.c index 91ef527442..d7d44eb4d0 100644 --- a/ges/ges-uri-clip.c +++ b/ges/ges-uri-clip.c @@ -299,7 +299,7 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset) ges_uri_clip_asset_get_duration (uri_clip_asset)); ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (uriclip), - ges_uri_clip_asset_get_duration (uri_clip_asset)); + ges_uri_clip_asset_get_max_duration (uri_clip_asset)); ges_uri_clip_set_is_image (uriclip, ges_uri_clip_asset_is_image (uri_clip_asset)); diff --git a/plugins/ges/gesdemux.c b/plugins/ges/gesdemux.c index e674d3a284..cfa850805c 100644 --- a/plugins/ges/gesdemux.c +++ b/plugins/ges/gesdemux.c @@ -113,6 +113,8 @@ ges_demux_class_init (GESDemuxClass * self_class) GST_DEBUG_CATEGORY_INIT (gesdemux, "gesdemux", 0, "ges demux element"); + gst_tag_register ("is-ges-timeline", GST_TAG_FLAG_META, G_TYPE_BOOLEAN, + "is-ges-timeline", "The stream is a ges timeline.", NULL); gclass->get_property = ges_demux_get_property; gclass->set_property = ges_demux_set_property; @@ -259,9 +261,14 @@ static gboolean ges_demux_set_srcpad_probe (GstElement * element, GstPad * pad, gpointer user_data) { + GstTagList *tlist = gst_tag_list_new ("is-ges-timeline", TRUE, NULL); + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM, (GstPadProbeCallback) ges_demux_src_probe, element, NULL); + + gst_tag_list_set_scope (tlist, GST_TAG_SCOPE_GLOBAL); + gst_pad_push_event (pad, gst_event_new_tag (tlist)); return TRUE; }