Mark nested timeline assets as such
authorThibault Saunier <tsaunier@igalia.com>
Thu, 11 Jul 2019 20:23:47 +0000 (16:23 -0400)
committerThibault Saunier <tsaunier@igalia.com>
Fri, 26 Jul 2019 17:48:51 +0000 (13:48 -0400)
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
ges/ges-uri-asset.h
ges/ges-uri-clip.c
plugins/ges/gesdemux.c

index 5e21f5d..edca8cd 100644 (file)
@@ -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
index c24a08f..6b739c2 100644 (file)
@@ -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,
index 91ef527..d7d44eb 100644 (file)
@@ -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));
 
index e674d3a..cfa8508 100644 (file)
@@ -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;
 }