gboolean auto_transition;
};
+typedef struct
+{
+ GESTimelineObject *object;
+ GESTimelineLayer *layer;
+} NewAssetUData;
+
enum
{
PROP_0,
/* 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:
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);
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);
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 */
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' */
}
/**
+ * 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.
/* 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;
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
{
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);
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);
}
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;
(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 */
}
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)
{
}
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
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");
}
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:
}
/* set track state to NULL */
-
gst_element_set_state (GST_ELEMENT (track), GST_STATE_NULL);
gst_object_unref (track);