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.
This commit is contained in:
Thibault Saunier 2019-07-11 16:23:47 -04:00
parent 6f9e6d3586
commit abb4f005e3
4 changed files with 61 additions and 4 deletions

View file

@ -94,6 +94,7 @@ enum
{ {
PROP_0, PROP_0,
PROP_DURATION, PROP_DURATION,
PROP_IS_NESTED_TIMELINE,
PROP_LAST PROP_LAST
}; };
static GParamSpec *properties[PROP_LAST]; static GParamSpec *properties[PROP_LAST];
@ -102,7 +103,9 @@ struct _GESUriClipAssetPrivate
{ {
GstDiscovererInfo *info; GstDiscovererInfo *info;
GstClockTime duration; GstClockTime duration;
GstClockTime max_duration;
gboolean is_image; gboolean is_image;
gboolean is_nested_timeline;
GList *asset_trackfilesources; GList *asset_trackfilesources;
}; };
@ -136,6 +139,9 @@ ges_uri_clip_asset_get_property (GObject * object, guint property_id,
case PROP_DURATION: case PROP_DURATION:
g_value_set_uint64 (value, priv->duration); g_value_set_uint64 (value, priv->duration);
break; break;
case PROP_IS_NESTED_TIMELINE:
g_value_set_boolean (value, priv->is_nested_timeline);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 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, g_object_class_install_property (object_class, PROP_DURATION,
properties[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); _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 = self->priv = ges_uri_clip_asset_get_instance_private (self);
priv->info = NULL; priv->info = NULL;
priv->duration = GST_CLOCK_TIME_NONE; priv->max_duration = priv->duration = GST_CLOCK_TIME_NONE;
priv->is_image = FALSE; priv->is_image = FALSE;
} }
@ -329,6 +346,7 @@ ges_uri_clip_asset_set_info (GESUriClipAsset * self, GstDiscovererInfo * info)
GESTrackType supportedformats = GES_TRACK_TYPE_UNKNOWN; GESTrackType supportedformats = GES_TRACK_TYPE_UNKNOWN;
GESUriClipAssetPrivate *priv = GES_URI_CLIP_ASSET (self)->priv; GESUriClipAssetPrivate *priv = GES_URI_CLIP_ASSET (self)->priv;
const GstTagList *tlist = gst_discoverer_info_get_tags (info);
/* Extract infos from the GstDiscovererInfo */ /* Extract infos from the GstDiscovererInfo */
stream_list = gst_discoverer_info_get_stream_list (info); 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) if (stream_list)
gst_discoverer_stream_info_list_free (stream_list); gst_discoverer_stream_info_list_free (stream_list);
if (priv->is_image == FALSE) if (tlist)
priv->duration = gst_discoverer_info_get_duration (info); 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 */ /* else we keep #GST_CLOCK_TIME_NONE */
priv->info = gst_object_ref (info); priv->info = gst_object_ref (info);
@ -500,6 +526,28 @@ ges_uri_clip_asset_get_duration (GESUriClipAsset * self)
return self->priv->duration; 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: * ges_uri_clip_asset_is_image:
* @self: a #GESUriClipAsset * @self: a #GESUriClipAsset

View file

@ -78,6 +78,8 @@ GstDiscovererInfo *ges_uri_clip_asset_get_info (const GESUriClipAsset * sel
GES_API GES_API
GstClockTime ges_uri_clip_asset_get_duration (GESUriClipAsset *self); GstClockTime ges_uri_clip_asset_get_duration (GESUriClipAsset *self);
GES_API GES_API
GstClockTime ges_uri_clip_asset_get_max_duration (GESUriClipAsset *self);
GES_API
gboolean ges_uri_clip_asset_is_image (GESUriClipAsset *self); gboolean ges_uri_clip_asset_is_image (GESUriClipAsset *self);
GES_API GES_API
void ges_uri_clip_asset_new (const gchar *uri, void ges_uri_clip_asset_new (const gchar *uri,

View file

@ -299,7 +299,7 @@ extractable_set_asset (GESExtractable * self, GESAsset * asset)
ges_uri_clip_asset_get_duration (uri_clip_asset)); ges_uri_clip_asset_get_duration (uri_clip_asset));
ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (uriclip), 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_set_is_image (uriclip,
ges_uri_clip_asset_is_image (uri_clip_asset)); ges_uri_clip_asset_is_image (uri_clip_asset));

View file

@ -113,6 +113,8 @@ ges_demux_class_init (GESDemuxClass * self_class)
GST_DEBUG_CATEGORY_INIT (gesdemux, "gesdemux", 0, "ges demux element"); 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->get_property = ges_demux_get_property;
gclass->set_property = ges_demux_set_property; gclass->set_property = ges_demux_set_property;
@ -259,9 +261,14 @@ static gboolean
ges_demux_set_srcpad_probe (GstElement * element, GstPad * pad, ges_demux_set_srcpad_probe (GstElement * element, GstPad * pad,
gpointer user_data) gpointer user_data)
{ {
GstTagList *tlist = gst_tag_list_new ("is-ges-timeline", TRUE, NULL);
gst_pad_add_probe (pad, gst_pad_add_probe (pad,
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
(GstPadProbeCallback) ges_demux_src_probe, element, NULL); (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; return TRUE;
} }