Merge branch '0.10'
[platform/upstream/gstreamer.git] / ges / ges-timeline.c
index 8244e56..f9a9e52 100644 (file)
@@ -114,11 +114,7 @@ static void
 discoverer_discovered_cb (GstDiscoverer * discoverer,
     GstDiscovererInfo * info, GError * err, GESTimeline * timeline);
 
-void look_for_transition (GESTrackObject * track_object,
-    GESTimelineLayer * layer);
-void track_object_removed_cb (GESTrack * track, GESTrackObject * track_object,
-    GESTimeline * timeline);
-
+/* GObject Standard vmethods*/
 static void
 ges_timeline_get_property (GObject * object, guint property_id,
     GValue * value, GParamSpec * pspec)
@@ -298,6 +294,9 @@ ges_timeline_init (GESTimeline * self)
   gst_discoverer_start (self->priv->discoverer);
 }
 
+/* Private methods */
+
+/* Sorting utils*/
 static gint
 sort_layers (gpointer a, gpointer b)
 {
@@ -318,140 +317,21 @@ sort_layers (gpointer a, gpointer b)
   return 0;
 }
 
-/**
- * ges_timeline_new:
- *
- * Creates a new empty #GESTimeline.
- *
- * Returns: The new timeline.
- */
-
-GESTimeline *
-ges_timeline_new (void)
-{
-  return g_object_new (GES_TYPE_TIMELINE, NULL);
-}
-
-/**
- * ges_timeline_new_from_uri:
- * @uri: the URI to load from
- *
- * Creates a timeline from the given URI.
- *
- * Returns: A new timeline if the uri was loaded successfully, or NULL if the
- * uri could not be loaded
- */
-
-GESTimeline *
-ges_timeline_new_from_uri (const gchar * uri)
-{
-  GESTimeline *ret;
-
-  /* FIXME : we should have a GError** argument so the user can know why
-   * it wasn't able to load the uri
-   */
-
-  ret = ges_timeline_new ();
-
-  if (!ges_timeline_load_from_uri (ret, uri)) {
-    g_object_unref (ret);
-    return NULL;
-  }
-
-  return ret;
-}
-
-
-/**
- * ges_timeline_load_from_uri:
- * @timeline: an empty #GESTimeline into which to load the formatter
- * @uri: The URI to load from
- *
- * Loads the contents of URI into the given timeline.
- *
- * Returns: TRUE if the timeline was loaded successfully, or FALSE if the uri
- * could not be loaded.
- */
-
-gboolean
-ges_timeline_load_from_uri (GESTimeline * timeline, const gchar * uri)
-{
-  GESFormatter *p = NULL;
-  gboolean ret = FALSE;
-
-  /* FIXME : we should have a GError** argument so the user can know why
-   * it wasn't able to load the uri
-   */
-
-  if (!(p = ges_formatter_new_for_uri (uri))) {
-    GST_ERROR ("unsupported uri '%s'", uri);
-    goto fail;
-  }
-
-  if (!ges_formatter_load_from_uri (p, timeline, uri)) {
-    GST_ERROR ("error deserializing formatter");
-    goto fail;
-  }
-
-  ret = TRUE;
-
-fail:
-  if (p)
-    g_object_unref (p);
-  return ret;
-}
-
-/**
- * ges_timeline_save_to_uri:
- * @timeline: a #GESTimeline
- * @uri: The location to save to
- *
- * Saves the timeline to the given location
- *
- * Returns: TRUE if the timeline was successfully saved to the given location,
- * else FALSE.
- */
-
-gboolean
-ges_timeline_save_to_uri (GESTimeline * timeline, const gchar * uri)
+static gint
+custom_find_track (TrackPrivate * tr_priv, GESTrack * track)
 {
-  GESFormatter *p = NULL;
-  gboolean ret = FALSE;
-
-  /* FIXME : How will the user be able to chose the format he
-   * wishes to store to ? */
-
-  /* FIXME : How will we ensure a timeline loaded with a certain format
-   * will be saved with the same one by default ? We need to make this
-   * easy from an API perspective */
-
-  /* FIXME : we should have a GError** argument so the user can know why
-   * it wasn't able to save
-   */
-
-  if (!(p = ges_formatter_new_for_uri (uri))) {
-    GST_ERROR ("unsupported uri '%s'", uri);
-    goto fail;
-  }
-
-  if (!ges_formatter_save_to_uri (p, timeline, uri)) {
-    GST_ERROR ("error serializing formatter");
-    goto fail;
-  }
-
-  ret = TRUE;
-
-fail:
-  if (p)
-    g_object_unref (p);
-  return ret;
+  if (tr_priv->track == track)
+    return 0;
+  return -1;
 }
 
 static void
 add_object_to_track (GESTimelineObject * object, GESTrack * track)
 {
   if (!ges_timeline_object_create_track_objects (object, track)) {
-    GST_WARNING ("error creating track objects");
+    if ((track->type & ges_timeline_object_get_supported_formats (object))) {
+      GST_WARNING ("Error creating track objects");
+    }
   }
 }
 
@@ -510,6 +390,7 @@ do_async_done (GESTimeline * timeline)
   }
 }
 
+/* Callbacks  */
 static void
 discoverer_finished_cb (GstDiscoverer * discoverer, GESTimeline * timeline)
 {
@@ -623,49 +504,6 @@ check_image:
   g_object_unref (tfs);
 }
 
-static GstStateChangeReturn
-ges_timeline_change_state (GstElement * element, GstStateChange transition)
-{
-  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
-  GESTimeline *timeline = GES_TIMELINE (element);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_PAUSED:
-      GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
-      if (timeline->priv->pendingobjects) {
-        GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
-        do_async_start (timeline);
-        ret = GST_STATE_CHANGE_ASYNC;
-      } else {
-        GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
-      }
-      break;
-    default:
-      break;
-  }
-
-  {
-    GstStateChangeReturn bret;
-
-    bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-    if (G_UNLIKELY (bret == GST_STATE_CHANGE_NO_PREROLL)) {
-      do_async_done (timeline);
-      ret = bret;
-    }
-  }
-
-  switch (transition) {
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      do_async_done (timeline);
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-
-}
-
 static void
 layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object,
     GESTimeline * timeline)
@@ -767,29 +605,231 @@ layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
   GST_DEBUG ("Done");
 }
 
+static void
+track_duration_cb (GstElement * track,
+    GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
+{
+  guint64 duration, max_duration = 0;
+  GList *tmp;
+
+  for (tmp = timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
+    TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
+    g_object_get (tr_priv->track, "duration", &duration, NULL);
+    GST_DEBUG ("track duration : %" GST_TIME_FORMAT, GST_TIME_ARGS (duration));
+    max_duration = MAX (duration, max_duration);
+  }
+
+  if (timeline->priv->duration != max_duration) {
+    GST_DEBUG ("track duration : %" GST_TIME_FORMAT " current : %"
+        GST_TIME_FORMAT, GST_TIME_ARGS (max_duration),
+        GST_TIME_ARGS (timeline->priv->duration));
+
+    timeline->priv->duration = max_duration;
+
+#if GLIB_CHECK_VERSION(2,26,0)
+    g_object_notify_by_pspec (G_OBJECT (timeline), properties[PROP_DURATION]);
+#else
+    g_object_notify (G_OBJECT (timeline), "duration");
+#endif
+  }
+}
+
+static GstStateChangeReturn
+ges_timeline_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GESTimeline *timeline = GES_TIMELINE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      GES_TIMELINE_PENDINGOBJS_LOCK (timeline);
+      if (timeline->priv->pendingobjects) {
+        GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
+        do_async_start (timeline);
+        ret = GST_STATE_CHANGE_ASYNC;
+      } else {
+        GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline);
+      }
+      break;
+    default:
+      break;
+  }
+
+  {
+    GstStateChangeReturn bret;
+
+    bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+    if (G_UNLIKELY (bret == GST_STATE_CHANGE_NO_PREROLL)) {
+      do_async_done (timeline);
+      ret = bret;
+    }
+  }
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      do_async_done (timeline);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+}
+
 /**
- * ges_timeline_append_layer:
+ * ges_timeline_new:
+ *
+ * Creates a new empty #GESTimeline.
+ *
+ * Returns: The new timeline.
+ */
+
+GESTimeline *
+ges_timeline_new (void)
+{
+  return g_object_new (GES_TYPE_TIMELINE, NULL);
+}
+
+/**
+ * ges_timeline_new_from_uri:
+ * @uri: the URI to load from
+ *
+ * Creates a timeline from the given URI.
+ *
+ * Returns: A new timeline if the uri was loaded successfully, or NULL if the
+ * uri could not be loaded
+ */
+
+GESTimeline *
+ges_timeline_new_from_uri (const gchar * uri)
+{
+  GESTimeline *ret;
+
+  /* FIXME : we should have a GError** argument so the user can know why
+   * it wasn't able to load the uri
+   */
+
+  ret = ges_timeline_new ();
+
+  if (!ges_timeline_load_from_uri (ret, uri)) {
+    g_object_unref (ret);
+    return NULL;
+  }
+
+  return ret;
+}
+
+
+/**
+ * ges_timeline_load_from_uri:
+ * @timeline: an empty #GESTimeline into which to load the formatter
+ * @uri: The URI to load from
+ *
+ * Loads the contents of URI into the given timeline.
+ *
+ * Returns: TRUE if the timeline was loaded successfully, or FALSE if the uri
+ * could not be loaded.
+ */
+
+gboolean
+ges_timeline_load_from_uri (GESTimeline * timeline, const gchar * uri)
+{
+  GESFormatter *p = NULL;
+  gboolean ret = FALSE;
+
+  /* FIXME : we should have a GError** argument so the user can know why
+   * it wasn't able to load the uri
+   */
+
+  if (!(p = ges_formatter_new_for_uri (uri))) {
+    GST_ERROR ("unsupported uri '%s'", uri);
+    goto fail;
+  }
+
+  if (!ges_formatter_load_from_uri (p, timeline, uri)) {
+    GST_ERROR ("error deserializing formatter");
+    goto fail;
+  }
+
+  ret = TRUE;
+
+fail:
+  if (p)
+    g_object_unref (p);
+  return ret;
+}
+
+/**
+ * ges_timeline_save_to_uri:
  * @timeline: a #GESTimeline
- * @layer: the #GESTimelineLayer to add
+ * @uri: The location to save to
  *
- * Convenience method to append @layer to @timeline which means that the
- * priority of @layer is changed to correspond to the last layer of @timeline.
- * The reference to the @layer will be stolen by @timeline.
+ * Saves the timeline to the given location
  *
- * Returns: TRUE if the layer was properly added, else FALSE.
+ * Returns: TRUE if the timeline was successfully saved to the given location,
+ * else FALSE.
  */
+
 gboolean
-ges_timeline_append_layer (GESTimeline * timeline, GESTimelineLayer * layer)
+ges_timeline_save_to_uri (GESTimeline * timeline, const gchar * uri)
+{
+  GESFormatter *p = NULL;
+  gboolean ret = FALSE;
+
+  /* FIXME : How will the user be able to chose the format he
+   * wishes to store to ? */
+
+  /* FIXME : How will we ensure a timeline loaded with a certain format
+   * will be saved with the same one by default ? We need to make this
+   * easy from an API perspective */
+
+  /* FIXME : we should have a GError** argument so the user can know why
+   * it wasn't able to save
+   */
+
+  if (!(p = ges_formatter_new_for_uri (uri))) {
+    GST_ERROR ("unsupported uri '%s'", uri);
+    goto fail;
+  }
+
+  if (!ges_formatter_save_to_uri (p, timeline, uri)) {
+    GST_ERROR ("error serializing formatter");
+    goto fail;
+  }
+
+  ret = TRUE;
+
+fail:
+  if (p)
+    g_object_unref (p);
+  return ret;
+}
+
+/**
+ * ges_timeline_append_layer:
+ * @timeline: a #GESTimeline
+ *
+ * Append a newly creater #GESTimelineLayer to @timeline
+ * Note that you do not own any reference to the returned layer.
+ *
+ * Returns: (transfer none): The newly created #GESTimelineLayer, or the last (empty)
+ * #GESTimelineLayer of @timeline.
+ */
+GESTimelineLayer *
+ges_timeline_append_layer (GESTimeline * timeline)
 {
   guint32 priority;
   GESTimelinePrivate *priv = timeline->priv;
+  GESTimelineLayer *layer;
 
-  GST_DEBUG ("Appending layer to layer:%p, timeline:%p", timeline, layer);
+  layer = ges_timeline_layer_new ();
   priority = g_list_length (priv->layers);
-
   ges_timeline_layer_set_priority (layer, priority);
 
-  return ges_timeline_add_layer (timeline, layer);
+  ges_timeline_add_layer (timeline, layer);
+
+  return layer;
 }
 
 /**
@@ -969,14 +1009,6 @@ pad_removed_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
   tr_priv->pad = NULL;
 }
 
-static gint
-custom_find_track (TrackPrivate * tr_priv, GESTrack * track)
-{
-  if (tr_priv->track == track)
-    return 0;
-  return -1;
-}
-
 /**
  * ges_timeline_add_track:
  * @timeline: a #GESTimeline
@@ -1240,49 +1272,15 @@ ges_timeline_is_updating (GESTimeline * timeline)
 gboolean
 ges_timeline_enable_update (GESTimeline * timeline, gboolean enabled)
 {
-  GList *tmp, *tracks;
+  GList *tmp;
   gboolean res = TRUE;
 
   GST_DEBUG_OBJECT (timeline, "%s updates", enabled ? "Enabling" : "Disabling");
 
-  tracks = ges_timeline_get_tracks (timeline);
-
-  for (tmp = tracks; tmp; tmp = tmp->next) {
-    if (!ges_track_enable_update (tmp->data, enabled)) {
+  for (tmp = timeline->priv->tracks; tmp; tmp = tmp->next) {
+    if (!ges_track_enable_update (((TrackPrivate *) tmp->data)->track, enabled))
       res = FALSE;
-    }
   }
 
-  g_list_free (tracks);
-
   return res;
 }
-
-static void
-track_duration_cb (GstElement * track,
-    GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
-{
-  guint64 duration, max_duration = 0;
-  GList *tmp;
-
-  for (tmp = timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
-    TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
-    g_object_get (tr_priv->track, "duration", &duration, NULL);
-    GST_DEBUG ("track duration : %" GST_TIME_FORMAT, GST_TIME_ARGS (duration));
-    max_duration = MAX (duration, max_duration);
-  }
-
-  if (timeline->priv->duration != max_duration) {
-    GST_DEBUG ("track duration : %" GST_TIME_FORMAT " current : %"
-        GST_TIME_FORMAT, GST_TIME_ARGS (max_duration),
-        GST_TIME_ARGS (timeline->priv->duration));
-
-    timeline->priv->duration = max_duration;
-
-#if GLIB_CHECK_VERSION(2,26,0)
-    g_object_notify_by_pspec (G_OBJECT (timeline), properties[PROP_DURATION]);
-#else
-    g_object_notify (G_OBJECT (timeline), "duration");
-#endif
-  }
-}