From a7280fb59dd6b58d05b4780df244eaf1dc96db86 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 17 Dec 2012 17:05:56 -0300 Subject: [PATCH] ges: Implement the ges_timeline_layer_add_asset method + Remove GstDiscoverer related code in GESTimeline as we do not need it anymore + Refactor the ges_timeline_layer_add_object method to make sure it is still working as intended API: ges_timeline_layer_add_asset --- ges/ges-timeline-layer.c | 146 +++++++++++++++++++++--- ges/ges-timeline-layer.h | 10 +- ges/ges-timeline.c | 290 +---------------------------------------------- 3 files changed, 140 insertions(+), 306 deletions(-) diff --git a/ges/ges-timeline-layer.c b/ges/ges-timeline-layer.c index d2f248b..53e7b8e 100644 --- a/ges/ges-timeline-layer.c +++ b/ges/ges-timeline-layer.c @@ -59,6 +59,12 @@ struct _GESTimelineLayerPrivate gboolean auto_transition; }; +typedef struct +{ + GESTimelineObject *object; + GESTimelineLayer *layer; +} NewAssetUData; + enum { PROP_0, @@ -695,6 +701,26 @@ start_calculating_transitions (GESTimelineLayer * layer) /* FIXME calculate all the transitions at that time */ } +static void +new_asset_cb (GESAsset * source, GAsyncResult * res, NewAssetUData * udata) +{ + GError *error = NULL; + + GESAsset *asset = ges_asset_request_finish (res, &error); + + GST_DEBUG_OBJECT (udata->layer, "%" GST_PTR_FORMAT " Asset loaded, " + "setting its asset", udata->object); + + if (error) { + GST_ERROR ("Asset could not be created for uri"); + } else { + ges_timeline_layer_add_object (udata->layer, udata->object); + } + + g_object_unref (asset); + g_slice_free (NewAssetUData, udata); +} + /* Public methods */ /** * ges_timeline_layer_remove_object: @@ -713,7 +739,7 @@ gboolean ges_timeline_layer_remove_object (GESTimelineLayer * layer, GESTimelineObject * object) { - GESTimelineLayer *tl_obj_layer; + GESTimelineLayer *current_layer; GList *trackobjects, *tmp; g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE); @@ -721,16 +747,16 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer, GST_DEBUG ("layer:%p, object:%p", layer, object); - tl_obj_layer = ges_timeline_object_get_layer (object); - if (G_UNLIKELY (tl_obj_layer != layer)) { + current_layer = ges_timeline_object_get_layer (object); + if (G_UNLIKELY (current_layer != layer)) { GST_WARNING ("TimelineObject doesn't belong to this layer"); - if (tl_obj_layer != NULL) - g_object_unref (tl_obj_layer); + if (current_layer != NULL) + g_object_unref (current_layer); return FALSE; } - g_object_unref (tl_obj_layer); + g_object_unref (current_layer); if (layer->priv->auto_transition && GES_IS_TIMELINE_SOURCE (object)) { trackobjects = ges_timeline_object_get_track_objects (object); @@ -912,24 +938,60 @@ gboolean ges_timeline_layer_add_object (GESTimelineLayer * layer, GESTimelineObject * object) { - GESTimelineLayer *tl_obj_layer; + GESAsset *asset; + GESTimelineLayer *current_layer; guint32 maxprio, minprio, prio; - GST_DEBUG ("layer:%p, object:%p", layer, object); + GESTimelineLayerPrivate *priv; + + g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE); + g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE); - tl_obj_layer = ges_timeline_object_get_layer (object); + GST_DEBUG_OBJECT (layer, "adding object:%p", object); - if (G_UNLIKELY (tl_obj_layer)) { + priv = layer->priv; + current_layer = ges_timeline_object_get_layer (object); + + if (G_UNLIKELY (current_layer)) { GST_WARNING ("TimelineObject %p already belongs to another layer", object); - g_object_unref (tl_obj_layer); + g_object_unref (current_layer); + return FALSE; } + asset = ges_extractable_get_asset (GES_EXTRACTABLE (object)); + if (asset == NULL) { + gchar *id; + NewAssetUData *mudata = g_slice_new (NewAssetUData); + + mudata->object = object; + mudata->layer = layer; + + GST_DEBUG_OBJECT (layer, "%" GST_PTR_FORMAT " as no reference to any " + "assets creating a asset... trying sync", object); + + id = ges_extractable_get_id (GES_EXTRACTABLE (object)); + asset = ges_asset_request (G_OBJECT_TYPE (object), id, NULL); + if (asset == NULL) { + ges_asset_request_async (G_OBJECT_TYPE (object), + id, NULL, (GAsyncReadyCallback) new_asset_cb, mudata); + g_free (id); + + GST_LOG_OBJECT (layer, "Object added async"); + return TRUE; + } + g_free (id); + + ges_extractable_set_asset (GES_EXTRACTABLE (object), asset); + + g_slice_free (NewAssetUData, mudata); + } + + g_object_ref_sink (object); /* Take a reference to the object and store it stored by start/priority */ - layer->priv->objects_start = - g_list_insert_sorted (layer->priv->objects_start, object, + priv->objects_start = g_list_insert_sorted (priv->objects_start, object, (GCompareFunc) objects_start_compare); /* Inform the object it's now in this layer */ @@ -943,15 +1005,17 @@ ges_timeline_layer_add_object (GESTimelineLayer * layer, maxprio = layer->max_gnl_priority; minprio = layer->min_gnl_priority; prio = GES_TIMELINE_OBJECT_PRIORITY (object); + if (minprio + prio > (maxprio)) { - GST_WARNING ("%p is out of the layer %p space, setting its priority to " - "setting its priority %d to failthe maximum priority of the layer %d", - object, layer, prio, maxprio - minprio); + GST_WARNING_OBJECT (layer, + "%p is out of the layer space, setting its priority to " + "%d, setting it to the maximum priority of the layer: %d", object, prio, + maxprio - minprio); ges_timeline_object_set_priority (object, LAYER_HEIGHT - 1); } + /* If the object has an acceptable priority, we just let it with its current * priority */ - ges_timeline_layer_resync_priorities (layer); /* emit 'object-added' */ @@ -961,6 +1025,54 @@ ges_timeline_layer_add_object (GESTimelineLayer * layer, } /** + * ges_timeline_layer_add_asset: + * @layer: a #GESTimelineLayer + * @asset: The asset to add to + * @start: The start value to set on the new #GESTimelineObject + * @inpoint: The inpoint value to set on the new #GESTimelineObject + * @duration: The duration value to set on the new #GESTimelineObject + * @rate: The rate value to set on the new #GESTimelineObject + * @track_types: The #GESTrackType to set on the the new #GESTimelineObject + * + * Creates TimelineObject from asset, adds it to layer and + * returns a reference to it. + * + * Returns: (transfer floating): Created #GESTimelineObject +*/ +GESTimelineObject * +ges_timeline_layer_add_asset (GESTimelineLayer * layer, + GESAsset * asset, GstClockTime start, GstClockTime inpoint, + GstClockTime duration, gdouble rate, GESTrackType track_types) +{ + GESTimelineObject *tlobj; + + g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), NULL); + g_return_val_if_fail (GES_IS_ASSET (asset), NULL); + g_return_val_if_fail (g_type_is_a (ges_asset_get_extractable_type + (asset), GES_TYPE_TIMELINE_OBJECT), NULL); + + + GST_DEBUG_OBJECT (layer, "Adding asset: %s", ges_asset_get_id (asset)); + tlobj = GES_TIMELINE_OBJECT (ges_asset_extract (asset, NULL)); + ges_timeline_object_set_start (tlobj, start); + ges_timeline_object_set_inpoint (tlobj, inpoint); + if (track_types != GES_TRACK_TYPE_UNKNOWN) + ges_timeline_object_set_supported_formats (tlobj, track_types); + + if (GST_CLOCK_TIME_IS_VALID (duration)) { + ges_timeline_object_set_duration (tlobj, duration); + } + + if (!ges_timeline_layer_add_object (layer, tlobj)) { + gst_object_unref (tlobj); + + return NULL; + } + + return tlobj; +} + +/** * ges_timeline_layer_new: * * Creates a new #GESTimelineLayer. diff --git a/ges/ges-timeline-layer.h b/ges/ges-timeline-layer.h index 990bf3e..abd73e7 100644 --- a/ges/ges-timeline-layer.h +++ b/ges/ges-timeline-layer.h @@ -50,7 +50,7 @@ typedef struct _GESTimelineLayerPrivate GESTimelineLayerPrivate; * @timeline: the #GESTimeline where this layer is being used. */ struct _GESTimelineLayer { - GInitiallyUnowned parent; + GInitiallyUnowned parent; /*< public >*/ @@ -102,6 +102,14 @@ ges_timeline_layer_get_timeline (GESTimelineLayer * layer); gboolean ges_timeline_layer_add_object (GESTimelineLayer * layer, GESTimelineObject * object); +GESTimelineObject * ges_timeline_layer_add_asset (GESTimelineLayer *layer, + GESAsset *asset, + GstClockTime start, + GstClockTime inpoint, + GstClockTime duration, + gdouble rate, + GESTrackType track_types); + gboolean ges_timeline_layer_remove_object (GESTimelineLayer * layer, GESTimelineObject * object); diff --git a/ges/ges-timeline.c b/ges/ges-timeline.c index fbdcbae..debe65e 100644 --- a/ges/ges-timeline.c +++ b/ges/ges-timeline.c @@ -117,15 +117,6 @@ struct _GESTimelinePrivate /* The duration of the timeline */ gint64 duration; - /* discoverer used for virgin sources */ - GstDiscoverer *discoverer; - GList *pendingobjects; - /* lock to avoid discovery of objects that will be removed */ - GMutex pendingobjects_lock; - - /* Whether we are changing state asynchronously or not */ - gboolean async_pending; - /* Timeline edition modes and snapping management */ guint64 snapping_distance; @@ -183,13 +174,6 @@ static GstBinClass *parent_class; static guint ges_timeline_signals[LAST_SIGNAL] = { 0 }; static gint custom_find_track (TrackPrivate * tr_priv, GESTrack * track); -static GstStateChangeReturn -ges_timeline_change_state (GstElement * element, GstStateChange transition); -static void -discoverer_finished_cb (GstDiscoverer * discoverer, GESTimeline * timeline); -static void -discoverer_discovered_cb (GstDiscoverer * discoverer, - GstDiscovererInfo * info, GError * err, GESTimeline * timeline); /* Internal methods */ static gboolean @@ -257,12 +241,6 @@ ges_timeline_dispose (GObject * object) { GESTimelinePrivate *priv = GES_TIMELINE (object)->priv; - if (priv->discoverer) { - gst_discoverer_stop (priv->discoverer); - g_object_unref (priv->discoverer); - priv->discoverer = NULL; - } - while (priv->layers) { GESTimelineLayer *layer = (GESTimelineLayer *) priv->layers->data; ges_timeline_remove_layer (GES_TIMELINE (object), layer); @@ -293,10 +271,6 @@ ges_timeline_dispose (GObject * object) static void ges_timeline_finalize (GObject * object) { - GESTimeline *timeline = GES_TIMELINE (object); - - g_mutex_clear (&timeline->priv->pendingobjects_lock); - G_OBJECT_CLASS (ges_timeline_parent_class)->finalize (object); } @@ -304,14 +278,11 @@ static void ges_timeline_class_init (GESTimelineClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); g_type_class_add_private (klass, sizeof (GESTimelinePrivate)); parent_class = g_type_class_peek_parent (klass); - element_class->change_state = ges_timeline_change_state; - object_class->get_property = ges_timeline_get_property; object_class->set_property = ges_timeline_set_property; object_class->dispose = ges_timeline_dispose; @@ -489,15 +460,6 @@ ges_timeline_init (GESTimeline * self) (GDestroyNotify) _destroy_obj_iters); priv->starts_ends = g_sequence_new (g_free); priv->tracksources = g_sequence_new (g_object_unref); - - g_mutex_init (&priv->pendingobjects_lock); - /* New discoverer with a 15s timeout */ - priv->discoverer = gst_discoverer_new (15 * GST_SECOND, NULL); - g_signal_connect (priv->discoverer, "finished", - G_CALLBACK (discoverer_finished_cb), self); - g_signal_connect (priv->discoverer, "discovered", - G_CALLBACK (discoverer_discovered_cb), self); - gst_discoverer_start (priv->discoverer); } /* Private methods */ @@ -1442,169 +1404,6 @@ add_object_to_tracks (GESTimeline * timeline, GESTimelineObject * object) } static void -do_async_start (GESTimeline * timeline) -{ - GstMessage *message; - GList *tmp; - - timeline->priv->async_pending = TRUE; - - /* Freeze state of tracks */ - for (tmp = timeline->priv->tracks; tmp; tmp = tmp->next) { - TrackPrivate *tr_priv = (TrackPrivate *) tmp->data; - gst_element_set_locked_state ((GstElement *) tr_priv->track, TRUE); - } - - message = gst_message_new_async_start (GST_OBJECT_CAST (timeline)); - parent_class->handle_message (GST_BIN_CAST (timeline), message); -} - -static void -do_async_done (GESTimeline * timeline) -{ - GstMessage *message; - - if (timeline->priv->async_pending) { - GList *tmp; - /* Unfreeze state of tracks */ - for (tmp = timeline->priv->tracks; tmp; tmp = tmp->next) { - TrackPrivate *tr_priv = (TrackPrivate *) tmp->data; - gst_element_set_locked_state ((GstElement *) tr_priv->track, FALSE); - gst_element_sync_state_with_parent ((GstElement *) tr_priv->track); - } - - GST_DEBUG_OBJECT (timeline, "Emitting async-done"); - message = gst_message_new_async_done (GST_OBJECT_CAST (timeline), FALSE); - parent_class->handle_message (GST_BIN_CAST (timeline), message); - - timeline->priv->async_pending = FALSE; - } -} - -/* Callbacks */ -static void -discoverer_finished_cb (GstDiscoverer * discoverer, GESTimeline * timeline) -{ - do_async_done (timeline); -} - -static void -discoverer_discovered_cb (GstDiscoverer * discoverer, - GstDiscovererInfo * info, GError * err, GESTimeline * timeline) -{ - GList *tmp; - GList *stream_list; - GESTimelineObject *tlobj; - GESTrackType tfs_supportedformats; - - gboolean found = FALSE; - gboolean is_image = FALSE; - GESTimelineFileSource *tfs = NULL; - GESTimelinePrivate *priv = timeline->priv; - const gchar *uri = gst_discoverer_info_get_uri (info); - - GES_TIMELINE_PENDINGOBJS_LOCK (timeline); - - /* Find corresponding TimelineFileSource in the sources */ - for (tmp = priv->pendingobjects; tmp; tmp = tmp->next) { - tfs = (GESTimelineFileSource *) tmp->data; - - if (!g_strcmp0 (ges_timeline_filesource_get_uri (tfs), uri)) { - found = TRUE; - break; - } - } - - if (!found) { - GST_WARNING ("Discovered %s, that seems not to be in the list of sources" - "to discover", uri); - GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline); - return; - } - - if (err) { - GError *propagate_error = NULL; - - priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp); - GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline); - GST_WARNING ("Error while discovering %s: %s", uri, err->message); - - g_propagate_error (&propagate_error, err); - g_signal_emit (timeline, ges_timeline_signals[DISCOVERY_ERROR], 0, tfs, - propagate_error); - - return; - } - - /* Everything went fine... let's do our job! */ - GST_DEBUG ("Discovered uri %s", uri); - - /* The timeline file source will be updated with discovered information - * so it needs to not be finalized during this process */ - g_object_ref (tfs); - - /* Remove object from list */ - priv->pendingobjects = g_list_delete_link (priv->pendingobjects, tmp); - GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline); - - /* FIXME : Handle errors in discovery */ - stream_list = gst_discoverer_info_get_stream_list (info); - - tfs_supportedformats = ges_timeline_filesource_get_supported_formats (tfs); - if (tfs_supportedformats != GES_TRACK_TYPE_UNKNOWN) - goto check_image; - - /* Update timelinefilesource properties based on info */ - for (tmp = stream_list; tmp; tmp = tmp->next) { - GstDiscovererStreamInfo *sinf = (GstDiscovererStreamInfo *) tmp->data; - - if (GST_IS_DISCOVERER_AUDIO_INFO (sinf)) { - tfs_supportedformats |= GES_TRACK_TYPE_AUDIO; - ges_timeline_filesource_set_supported_formats (tfs, tfs_supportedformats); - } else if (GST_IS_DISCOVERER_VIDEO_INFO (sinf)) { - tfs_supportedformats |= GES_TRACK_TYPE_VIDEO; - ges_timeline_filesource_set_supported_formats (tfs, tfs_supportedformats); - if (gst_discoverer_video_info_is_image ((GstDiscovererVideoInfo *) - sinf)) { - tfs_supportedformats |= GES_TRACK_TYPE_AUDIO; - ges_timeline_filesource_set_supported_formats (tfs, - tfs_supportedformats); - is_image = TRUE; - } - } - } - - if (stream_list) - gst_discoverer_stream_info_list_free (stream_list); - -check_image: - - tlobj = GES_TIMELINE_OBJECT (tfs); - if (is_image) { - /* don't set max-duration on still images */ - g_object_set (tfs, "is_image", (gboolean) TRUE, NULL); - } else { - GstClockTime file_duration, tlobj_max_duration; - - /* Properly set duration informations from the discovery */ - file_duration = gst_discoverer_info_get_duration (info); - tlobj_max_duration = ges_timeline_object_get_max_duration (tlobj); - - if (tlobj_max_duration == G_MAXUINT64) - ges_timeline_object_set_max_duration (tlobj, file_duration); - - if (GST_CLOCK_TIME_IS_VALID (tlobj->duration) == FALSE) - ges_timeline_object_set_duration (tlobj, file_duration); - } - - /* Continue the processing on tfs */ - add_object_to_tracks (timeline, tlobj); - - /* Remove the ref as the timeline file source is no longer needed here */ - g_object_unref (tfs); -} - -static void layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object, GESTimeline * timeline) { @@ -1616,37 +1415,8 @@ layer_object_added_cb (GESTimelineLayer * layer, GESTimelineObject * object, } GST_DEBUG ("New TimelineObject %p added to layer %p", object, layer); - - if (GES_IS_TIMELINE_FILE_SOURCE (object)) { - GESTimelineFileSource *tfs = GES_TIMELINE_FILE_SOURCE (object); - GESTrackType tfs_supportedformats = - ges_timeline_filesource_get_supported_formats (tfs); - guint64 tfs_maxdur = ges_timeline_filesource_get_max_duration (tfs); - const gchar *tfs_uri; - - /* Send the filesource to the discoverer if: - * * it doesn't have specified supported formats - * * OR it doesn't have a specified max-duration - * * OR it doesn't have a valid duration */ - - if (tfs_supportedformats == GES_TRACK_TYPE_UNKNOWN || - tfs_maxdur == GST_CLOCK_TIME_NONE || object->duration == 0) { - GST_LOG ("Incomplete TimelineFileSource, discovering it"); - tfs_uri = ges_timeline_filesource_get_uri (tfs); - - GES_TIMELINE_PENDINGOBJS_LOCK (timeline); - timeline->priv->pendingobjects = - g_list_append (timeline->priv->pendingobjects, object); - GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline); - - gst_discoverer_discover_uri_async (timeline->priv->discoverer, tfs_uri); - } else - add_object_to_tracks (timeline, object); - } else { - add_object_to_tracks (timeline, object); - } - - GST_DEBUG ("done"); + add_object_to_tracks (timeline, object); + GST_DEBUG ("Done"); } static void @@ -1693,16 +1463,6 @@ layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object, g_list_free (trackobjects); - /* if the object is a timeline file source that has not yet been discovered, - * it no longer needs to be discovered so remove it from the pendingobjects - * list if it belongs to this layer */ - if (GES_IS_TIMELINE_FILE_SOURCE (object)) { - GES_TIMELINE_PENDINGOBJS_LOCK (timeline); - timeline->priv->pendingobjects = - g_list_remove_all (timeline->priv->pendingobjects, object); - GES_TIMELINE_PENDINGOBJS_UNLOCK (timeline); - } - GST_DEBUG ("Done"); } @@ -1835,51 +1595,6 @@ pad_removed_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv) tr_priv->pad = NULL; } - -/* GstElement Virtual methods */ -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; - -} - /**** API *****/ /** * ges_timeline_new: @@ -2247,7 +1962,6 @@ ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track) } /* set track state to NULL */ - gst_element_set_state (GST_ELEMENT (track), GST_STATE_NULL); gst_object_unref (track); -- 2.7.4