Merge branch '0.10'

Conflicts:
	bindings/python/ges.defs
This commit is contained in:
Thibault Saunier 2012-04-07 22:31:23 -04:00
commit 672a162062
13 changed files with 1011 additions and 835 deletions

View file

@ -79,6 +79,7 @@ GES_TYPE_TRACK
GESTrackObject
GESTrackObjectClass
ges_track_object_set_duration
ges_track_object_set_max_duration
ges_track_object_set_inpoint
ges_track_object_set_priority
ges_track_object_set_start
@ -92,6 +93,7 @@ ges_track_object_get_element
ges_track_object_get_start
ges_track_object_get_inpoint
ges_track_object_get_duration
ges_track_object_get_max_duration
ges_track_object_get_priority
ges_track_object_is_active
ges_track_object_lookup_child
@ -283,6 +285,7 @@ ges_timeline_layer_get_objects
ges_timeline_layer_get_timeline
ges_timeline_layer_get_auto_transition
ges_timeline_layer_set_auto_transition
ges_timeline_layer_is_empty
<SUBSECTION Standard>
GESTimelineLayerPrivate
ges_timeline_layer_set_timeline
@ -310,6 +313,7 @@ ges_timeline_object_set_duration
ges_timeline_object_get_layer
ges_timeline_object_find_track_object
ges_timeline_object_add_track_object
ges_timeline_object_release_track_object
ges_timeline_object_get_top_effects
ges_timeline_object_get_top_effect_position
ges_timeline_object_move_to_layer

View file

@ -42,15 +42,12 @@ struct _GESTimelineFileSourcePrivate
gboolean mute;
gboolean is_image;
guint64 maxduration;
};
enum
{
PROP_0,
PROP_URI,
PROP_MAX_DURATION,
PROP_MUTE,
PROP_IS_IMAGE,
};
@ -62,6 +59,9 @@ static GESTrackObject
void
ges_timeline_filesource_set_uri (GESTimelineFileSource * self, gchar * uri);
static void
filesource_set_max_duration (GESTimelineObject * object, guint64 maxduration);
static void
ges_timeline_filesource_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
@ -75,9 +75,6 @@ ges_timeline_filesource_get_property (GObject * object, guint property_id,
case PROP_MUTE:
g_value_set_boolean (value, priv->mute);
break;
case PROP_MAX_DURATION:
g_value_set_uint64 (value, priv->maxduration);
break;
case PROP_IS_IMAGE:
g_value_set_boolean (value, priv->is_image);
break;
@ -99,10 +96,6 @@ ges_timeline_filesource_set_property (GObject * object, guint property_id,
case PROP_MUTE:
ges_timeline_filesource_set_mute (tfs, g_value_get_boolean (value));
break;
case PROP_MAX_DURATION:
ges_timeline_filesource_set_max_duration (tfs,
g_value_get_uint64 (value));
break;
case PROP_IS_IMAGE:
ges_timeline_filesource_set_is_image (tfs, g_value_get_boolean (value));
break;
@ -143,19 +136,6 @@ ges_timeline_filesource_class_init (GESTimelineFileSourceClass * klass)
g_param_spec_string ("uri", "URI", "uri of the resource",
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/**
* GESTimelineFileSource:max-duration:
*
* The maximum duration (in nanoseconds) of the file.
*
* If not set before adding the object to a layer, it will be discovered
* asynchronously. Connect to 'notify::max-duration' to be notified of it.
*/
g_object_class_install_property (object_class, PROP_MAX_DURATION,
g_param_spec_uint64 ("max-duration", "Maximum duration",
"The duration of the file", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/**
* GESTimelineFileSource:mute:
*
@ -178,6 +158,7 @@ ges_timeline_filesource_class_init (GESTimelineFileSourceClass * klass)
timobj_class->create_track_object =
ges_timeline_filesource_create_track_object;
timobj_class->set_max_duration = filesource_set_max_duration;
timobj_class->need_fill_track = FALSE;
}
@ -234,24 +215,26 @@ void
ges_timeline_filesource_set_max_duration (GESTimelineFileSource * self,
guint64 maxduration)
{
GESTimelineObject *object = GES_TIMELINE_OBJECT (self);
ges_timeline_object_set_max_duration (GES_TIMELINE_OBJECT (self),
maxduration);
}
void
filesource_set_max_duration (GESTimelineObject * object, guint64 maxduration)
{
GList *tmp, *tckobjs;
self->priv->maxduration = maxduration;
if (object->duration == GST_CLOCK_TIME_NONE || object->duration == 0) {
/* If we don't have a valid duration, use the max duration */
g_object_set (self, "duration", self->priv->maxduration - object->inpoint,
NULL);
g_object_set (object, "duration", maxduration - object->inpoint, NULL);
}
tckobjs = ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (self));
tckobjs = ges_timeline_object_get_track_objects (object);
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
g_object_set (tmp->data, "max-duration", maxduration, NULL);
/* We free the list in the same loop */
g_object_unref (tmp->data);
g_list_free_1 (tmp);
}
g_list_free_full (tckobjs, g_object_unref);
}
/**
@ -309,7 +292,7 @@ ges_timeline_filesource_is_muted (GESTimelineFileSource * self)
guint64
ges_timeline_filesource_get_max_duration (GESTimelineFileSource * self)
{
return self->priv->maxduration;
return ges_timeline_object_get_max_duration (GES_TIMELINE_OBJECT (self));
}
/**

View file

@ -36,17 +36,6 @@
#define LAYER_HEIGHT 1000
static void
track_object_removed_cb (GESTimelineObject * object,
GESTrackObject * track_object);
static void track_object_added_cb (GESTimelineObject * object,
GESTrackObject * track_object, GHashTable * signal_table);
static void track_object_changed_cb (GESTrackObject * track_object,
GParamSpec * arg G_GNUC_UNUSED);
static void calculate_transitions (GESTrackObject * track_object);
static void calculate_next_transition (GESTrackObject * track_object,
GESTimelineLayer * layer);
static void
timeline_object_height_changed_cb (GESTimelineObject * obj,
GESTrackEffect * tr_eff, GESTimelineObject * second_obj);
@ -59,13 +48,9 @@ struct _GESTimelineLayerPrivate
GList *objects_start; /* The TimelineObjects sorted by start and
* priority */
guint32 priority; /* The priority of the layer within the
guint32 priority; /* The priority of the layer within the
* containing timeline */
gboolean auto_transition;
GHashTable *signal_table;
};
enum
@ -85,13 +70,7 @@ enum
static guint ges_timeline_layer_signals[LAST_SIGNAL] = { 0 };
static gboolean ges_timeline_layer_resync_priorities (GESTimelineLayer * layer);
static GList *track_get_by_layer (GESTimelineLayer * layer, GESTrack * track);
static void compare (GList * compared, GESTrackObject * track_object,
gboolean ahead);
/* GObject standard vmethods */
static void
ges_timeline_layer_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
@ -213,50 +192,9 @@ ges_timeline_layer_init (GESTimelineLayer * self)
self->priv->auto_transition = FALSE;
self->min_gnl_priority = 0;
self->max_gnl_priority = LAYER_HEIGHT;
self->priv->signal_table =
g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref,
NULL);
}
/**
* ges_timeline_layer_new:
*
* Creates a new #GESTimelineLayer.
*
* Returns: A new #GESTimelineLayer
*/
GESTimelineLayer *
ges_timeline_layer_new (void)
{
return g_object_new (GES_TYPE_TIMELINE_LAYER, NULL);
}
/**
* ges_timeline_layer_get_timeline:
* @layer: The #GESTimelineLayer to get the parent #GESTimeline from
*
* Get the #GESTimeline in which #GESTimelineLayer currently is.
*
* Returns: (transfer none): the #GESTimeline in which #GESTimelineLayer
* currently is or %NULL if not in any timeline yet.
*/
GESTimeline *
ges_timeline_layer_get_timeline (GESTimelineLayer * layer)
{
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), NULL);
return layer->timeline;
}
void
ges_timeline_layer_set_timeline (GESTimelineLayer * layer,
GESTimeline * timeline)
{
GST_DEBUG ("layer:%p, timeline:%p", layer, timeline);
layer->timeline = timeline;
}
/* Private methods and utils */
static gint
objects_start_compare (GESTimelineObject * a, GESTimelineObject * b)
{
@ -295,268 +233,6 @@ track_get_by_layer (GESTimelineLayer * layer, GESTrack * track)
return return_list;
}
/**
* ges_timeline_layer_add_object:
* @layer: a #GESTimelineLayer
* @object: (transfer full): the #GESTimelineObject to add.
*
* Adds the given object to the layer. Sets the object's parent, and thus
* takes ownership of the object.
*
* An object can only be added to one layer.
*
* Returns: TRUE if the object was properly added to the layer, or FALSE
* if the @layer refuses to add the object.
*/
gboolean
ges_timeline_layer_add_object (GESTimelineLayer * layer,
GESTimelineObject * object)
{
GESTimelineLayer *tl_obj_layer;
guint32 maxprio, minprio, prio;
GST_DEBUG ("layer:%p, object:%p", layer, object);
tl_obj_layer = ges_timeline_object_get_layer (object);
if (G_UNLIKELY (tl_obj_layer)) {
GST_WARNING ("TimelineObject %p already belongs to another layer", object);
g_object_unref (tl_obj_layer);
return FALSE;
}
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,
(GCompareFunc) objects_start_compare);
/* We have to wait for the track objects to be created to calculate transitions */
if (layer->priv->auto_transition) {
if (GES_IS_TIMELINE_SOURCE (object)) {
g_signal_connect (G_OBJECT (object), "track-object-added",
G_CALLBACK (track_object_added_cb), layer->priv->signal_table);
g_signal_connect (G_OBJECT (object), "track-object-removed",
G_CALLBACK (track_object_removed_cb), NULL);
}
}
/* Inform the object it's now in this layer */
ges_timeline_object_set_layer (object, layer);
GST_DEBUG ("current object priority : %d, layer min/max : %d/%d",
GES_TIMELINE_OBJECT_PRIORITY (object),
layer->min_gnl_priority, layer->max_gnl_priority);
/* Set the priority. */
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);
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' */
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_ADDED], 0, object);
return TRUE;
}
static void
track_object_duration_cb (GESTrackObject * track_object,
GParamSpec * arg G_GNUC_UNUSED)
{
GESTimelineLayer *layer;
GESTimelineObject *tlobj;
tlobj = ges_track_object_get_timeline_object (track_object);
layer = ges_timeline_object_get_layer (tlobj);
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
GST_DEBUG ("Here we should recalculate");
calculate_next_transition (track_object, layer);
}
static void
track_object_deleted_cb (GESTrack * track, GESTrackObject * track_object)
{
GList *track_objects, *tmp, *cur;
GESTimelineLayer *layer;
track_objects = ges_track_get_objects (track);
cur = g_list_find (track_objects, track_object);
for (tmp = cur->next; tmp; tmp = tmp->next) {
if (GES_IS_TRACK_SOURCE (tmp->data)) {
break;
}
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
layer =
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
(tmp->data));
if (ges_timeline_layer_get_auto_transition (layer)) {
ges_track_enable_update (track, FALSE);
ges_timeline_layer_remove_object (layer,
ges_track_object_get_timeline_object (tmp->data));
ges_track_enable_update (track, TRUE);
}
g_object_unref (layer);
}
}
for (tmp = cur->prev; tmp; tmp = tmp->prev) {
if (GES_IS_TRACK_SOURCE (tmp->data)) {
break;
}
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
layer =
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
(tmp->data));
if (ges_timeline_layer_get_auto_transition (layer)) {
ges_track_enable_update (track, FALSE);
ges_timeline_layer_remove_object (layer,
ges_track_object_get_timeline_object (tmp->data));
ges_track_enable_update (track, TRUE);
}
g_object_unref (layer);
}
}
g_object_unref (track_object);
}
static void
track_object_added_cb (GESTimelineObject * object,
GESTrackObject * track_object, GHashTable * signal_table)
{
GESTrack *track;
gint ptr;
if (GES_IS_TRACK_SOURCE (track_object)) {
g_signal_connect (G_OBJECT (track_object), "notify::start",
G_CALLBACK (track_object_changed_cb), NULL);
g_signal_connect (G_OBJECT (track_object), "notify::duration",
G_CALLBACK (track_object_duration_cb), NULL);
calculate_transitions (track_object);
}
track = ges_track_object_get_track (track_object);
if (!g_hash_table_lookup (signal_table, track)) {
ptr = g_signal_connect (track, "track-object-removed",
(GCallback) track_object_deleted_cb, NULL);
g_hash_table_insert (signal_table, track, GINT_TO_POINTER (ptr));
}
return;
}
static void
track_object_removed_cb (GESTimelineObject * object,
GESTrackObject * track_object)
{
return;
if (GES_IS_TRACK_SOURCE (track_object)) {
g_signal_handlers_disconnect_by_func (track_object, track_object_changed_cb,
object);
}
return;
}
static void
timeline_object_height_changed_cb (GESTimelineObject * obj,
GESTrackEffect * tr_eff, GESTimelineObject * second_obj)
{
gint priority, height;
g_object_get (obj, "height", &height, "priority", &priority, NULL);
g_object_set (second_obj, "priority", priority + height, NULL);
}
static void
track_object_changed_cb (GESTrackObject * track_object,
GParamSpec * arg G_GNUC_UNUSED)
{
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
calculate_transitions (track_object);
}
static void
calculate_next_transition_with_list (GESTrackObject * track_object,
GList * tckobjs_in_layer, GESTimelineLayer * layer)
{
GList *compared;
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
return;
if (compared == NULL)
/* This is the last TrackObject of the Track */
return;
do {
compared = compared->next;
if (compared == NULL)
return;
} while (!GES_IS_TRACK_SOURCE (compared->data));
compare (compared, track_object, FALSE);
}
static void
calculate_next_transition (GESTrackObject * track_object,
GESTimelineLayer * layer)
{
GESTrack *track = ges_track_object_get_track (track_object);
GList *tckobjs_in_layer = track_get_by_layer (layer, track);
if (ges_track_object_get_track (track_object)) {
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
}
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
g_list_free (tckobjs_in_layer);
}
static void
calculate_transitions (GESTrackObject * track_object)
{
GList *tckobjs_in_layer, *compared;
GESTrack *track = ges_track_object_get_track (track_object);
GESTimelineLayer *layer;
GESTimelineObject *tlobj;
tlobj = ges_track_object_get_timeline_object (track_object);
layer = ges_timeline_object_get_layer (tlobj);
tckobjs_in_layer = track_get_by_layer (layer, track);
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
return;
do {
compared = compared->prev;
if (compared == NULL) {
/* Nothing before, let's check after */
calculate_next_transition_with_list (track_object, tckobjs_in_layer,
layer);
goto done;
}
} while (!GES_IS_TRACK_SOURCE (compared->data));
compare (compared, track_object, TRUE);
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
done:
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
g_list_free (tckobjs_in_layer);
}
/* Compare:
* @compared: The #GList of #GESTrackObjects that we compare with @track_object
* @track_object: The #GESTrackObject that serves as a reference
@ -731,6 +407,84 @@ clean:
g_object_unref (layer);
}
static void
calculate_next_transition_with_list (GESTrackObject * track_object,
GList * tckobjs_in_layer, GESTimelineLayer * layer)
{
GList *compared;
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
return;
if (compared == NULL)
/* This is the last TrackObject of the Track */
return;
do {
compared = compared->next;
if (compared == NULL)
return;
} while (!GES_IS_TRACK_SOURCE (compared->data));
compare (compared, track_object, FALSE);
}
static void
calculate_next_transition (GESTrackObject * track_object,
GESTimelineLayer * layer)
{
GESTrack *track;
GList *tckobjs_in_layer;
if ((track = ges_track_object_get_track (track_object))) {
tckobjs_in_layer = track_get_by_layer (layer, track);
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
g_list_free (tckobjs_in_layer);
}
}
static void
calculate_transitions (GESTrackObject * track_object)
{
GList *tckobjs_in_layer, *compared;
GESTimelineLayer *layer;
GESTimelineObject *tlobj;
GESTrack *track = ges_track_object_get_track (track_object);
if (track == NULL)
return;
tlobj = ges_track_object_get_timeline_object (track_object);
layer = ges_timeline_object_get_layer (tlobj);
tckobjs_in_layer = track_get_by_layer (layer, track);
if (!(compared = g_list_find (tckobjs_in_layer, track_object)))
return;
do {
compared = compared->prev;
if (compared == NULL) {
/* Nothing before, let's check after */
calculate_next_transition_with_list (track_object, tckobjs_in_layer,
layer);
goto done;
}
} while (!GES_IS_TRACK_SOURCE (compared->data));
compare (compared, track_object, TRUE);
calculate_next_transition_with_list (track_object, tckobjs_in_layer, layer);
done:
g_list_foreach (tckobjs_in_layer, (GFunc) g_object_unref, NULL);
g_list_free (tckobjs_in_layer);
}
static void
look_for_transition (GESTrackObject * track_object, GESTimelineLayer * layer)
{
@ -738,7 +492,6 @@ look_for_transition (GESTrackObject * track_object, GESTimelineLayer * layer)
GList *track_objects, *tmp, *cur;
track = ges_track_object_get_track (track_object);
track_objects = ges_track_get_objects (track);
cur = g_list_find (track_objects, track_object);
@ -768,14 +521,169 @@ look_for_transition (GESTrackObject * track_object, GESTimelineLayer * layer)
g_list_free (track_objects);
}
/**
* ges_timeline_layer_resync_priorities:
* @layer: a #GESTimelineLayer
*
* Resyncs the priorities of the objects controlled by @layer.
* This method
*/
static gboolean
disconnect_handlers (GESTrack * track, gpointer * ptr)
ges_timeline_layer_resync_priorities (GESTimelineLayer * layer)
{
g_signal_handler_disconnect (track, GPOINTER_TO_INT (ptr));
GList *tmp;
GESTimelineObject *obj;
GST_DEBUG ("Resync priorities of %p", layer);
/* TODO : Inhibit composition updates while doing this.
* Ideally we want to do it from an even higher level, but here will
* do in the meantime. */
for (tmp = layer->priv->objects_start; tmp; tmp = tmp->next) {
obj = GES_TIMELINE_OBJECT (tmp->data);
ges_timeline_object_set_priority (obj, GES_TIMELINE_OBJECT_PRIORITY (obj));
}
return TRUE;
}
/* Callbacks */
static void
track_object_duration_cb (GESTrackObject * track_object,
GParamSpec * arg G_GNUC_UNUSED)
{
GESTimelineLayer *layer;
GESTimelineObject *tlobj;
tlobj = ges_track_object_get_timeline_object (track_object);
layer = ges_timeline_object_get_layer (tlobj);
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
calculate_next_transition (track_object, layer);
}
static void
track_object_removed_cb (GESTrack * track, GESTrackObject * track_object)
{
GList *track_objects, *tmp, *cur;
GESTimelineLayer *layer;
track_objects = ges_track_get_objects (track);
cur = g_list_find (track_objects, track_object);
for (tmp = cur->next; tmp; tmp = tmp->next) {
if (GES_IS_TRACK_SOURCE (tmp->data)) {
break;
}
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
layer =
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
(tmp->data));
if (ges_timeline_layer_get_auto_transition (layer)) {
ges_track_enable_update (track, FALSE);
ges_timeline_layer_remove_object (layer,
ges_track_object_get_timeline_object (tmp->data));
ges_track_enable_update (track, TRUE);
}
g_object_unref (layer);
}
}
for (tmp = cur->prev; tmp; tmp = tmp->prev) {
if (GES_IS_TRACK_SOURCE (tmp->data)) {
break;
}
if (GES_IS_TRACK_AUDIO_TRANSITION (tmp->data)
|| GES_IS_TRACK_VIDEO_TRANSITION (tmp->data)) {
layer =
ges_timeline_object_get_layer (ges_track_object_get_timeline_object
(tmp->data));
if (ges_timeline_layer_get_auto_transition (layer)) {
ges_track_enable_update (track, FALSE);
ges_timeline_layer_remove_object (layer,
ges_track_object_get_timeline_object (tmp->data));
ges_track_enable_update (track, TRUE);
}
g_object_unref (layer);
}
}
g_object_unref (track_object);
}
static void
track_object_changed_cb (GESTrackObject * track_object,
GParamSpec * arg G_GNUC_UNUSED)
{
if (G_LIKELY (GES_IS_TRACK_SOURCE (track_object)))
calculate_transitions (track_object);
}
static void
track_object_added_cb (GESTrack * track, GESTrackObject * track_object,
GESTimelineLayer * layer)
{
GST_ERROR ("TRACKOBJECTADDED %i", GES_IS_TRACK_SOURCE (track_object));
if (GES_IS_TRACK_SOURCE (track_object)) {
g_signal_connect (G_OBJECT (track_object), "notify::start",
G_CALLBACK (track_object_changed_cb), NULL);
g_signal_connect (G_OBJECT (track_object), "notify::duration",
G_CALLBACK (track_object_duration_cb), NULL);
calculate_transitions (track_object);
}
}
static void
track_removed_cb (GESTrack * track, GESTrackObject * track_object,
GESTimelineLayer * layer)
{
g_signal_handlers_disconnect_by_func (track, track_object_added_cb, layer);
g_signal_handlers_disconnect_by_func (track, track_object_removed_cb, NULL);
}
static void
track_added_cb (GESTrack * track, GESTrackObject * track_object,
GESTimelineLayer * layer)
{
g_signal_connect (track, "track-object-removed",
(GCallback) track_object_removed_cb, NULL);
g_signal_connect (track, "track-object-added",
(GCallback) track_object_added_cb, NULL);
}
static void
timeline_object_height_changed_cb (GESTimelineObject * obj,
GESTrackEffect * tr_eff, GESTimelineObject * second_obj)
{
gint priority, height;
g_object_get (obj, "height", &height, "priority", &priority, NULL);
g_object_set (second_obj, "priority", priority + height, NULL);
}
static void
start_calculating_transitions (GESTimelineLayer * layer)
{
GList *tmp, *tracks = ges_timeline_get_tracks (layer->timeline);
g_signal_connect (layer->timeline, "track-added", G_CALLBACK (track_added_cb),
layer);
g_signal_connect (layer->timeline, "track-removed",
G_CALLBACK (track_removed_cb), layer);
for (tmp = tracks; tmp; tmp = tmp->next) {
g_signal_connect (G_OBJECT (tmp->data), "track-object-added",
G_CALLBACK (track_object_added_cb), layer);
g_signal_connect (G_OBJECT (tmp->data), "track-object-removed",
G_CALLBACK (track_object_removed_cb), NULL);
}
g_list_free_full (tracks, g_object_unref);
/* FIXME calculate all the transitions at that time */
}
/* Public methods */
/**
* ges_timeline_layer_remove_object:
* @layer: a #GESTimelineLayer
@ -804,13 +712,15 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
tl_obj_layer = ges_timeline_object_get_layer (object);
if (G_UNLIKELY (tl_obj_layer != layer)) {
GST_WARNING ("TimelineObject doesn't belong to this layer");
if (tl_obj_layer != NULL)
g_object_unref (tl_obj_layer);
return FALSE;
}
g_object_unref (tl_obj_layer);
if (layer->priv->auto_transition) {
if (layer->priv->auto_transition && GES_IS_TIMELINE_SOURCE (object)) {
trackobjects = ges_timeline_object_get_track_objects (object);
for (tmp = trackobjects; tmp; tmp = tmp->next) {
@ -821,9 +731,6 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
g_list_free (trackobjects);
}
g_hash_table_foreach_remove (layer->priv->signal_table,
(GHRFunc) disconnect_handlers, NULL);
/* emit 'object-removed' */
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_REMOVED], 0, object);
@ -840,33 +747,6 @@ ges_timeline_layer_remove_object (GESTimelineLayer * layer,
return TRUE;
}
/**
* ges_timeline_layer_resync_priorities:
* @layer: a #GESTimelineLayer
*
* Resyncs the priorities of the objects controlled by @layer.
* This method
*/
gboolean
ges_timeline_layer_resync_priorities (GESTimelineLayer * layer)
{
GList *tmp;
GESTimelineObject *obj;
GST_DEBUG ("Resync priorities of %p", layer);
/* TODO : Inhibit composition updates while doing this.
* Ideally we want to do it from an even higher level, but here will
* do in the meantime. */
for (tmp = layer->priv->objects_start; tmp; tmp = tmp->next) {
obj = GES_TIMELINE_OBJECT (tmp->data);
ges_timeline_object_set_priority (obj, GES_TIMELINE_OBJECT_PRIORITY (obj));
}
return TRUE;
}
/**
* ges_timeline_layer_set_priority:
* @layer: a #GESTimelineLayer
@ -921,20 +801,11 @@ ges_timeline_layer_set_auto_transition (GESTimelineLayer * layer,
gboolean auto_transition)
{
GList *tmp;
g_return_if_fail (GES_IS_TIMELINE_LAYER (layer));
if (auto_transition) {
for (tmp = layer->priv->objects_start; tmp; tmp = tmp->next) {
if (GES_IS_TIMELINE_SOURCE (tmp->data)) {
g_signal_connect (G_OBJECT (tmp->data), "track-object-added",
G_CALLBACK (track_object_added_cb), layer);
g_signal_connect (G_OBJECT (tmp->data), "track-object-removed",
G_CALLBACK (track_object_removed_cb), layer);
}
}
/* FIXME calculate all the transitions at that time */
}
if (auto_transition && layer->timeline)
start_calculating_transitions (layer);
layer->priv->auto_transition = auto_transition;
}
@ -988,3 +859,143 @@ ges_timeline_layer_get_objects (GESTimelineLayer * layer)
ret = g_list_reverse (ret);
return ret;
}
/**
* ges_timeline_layer_is_empty:
* @layer: The #GESTimelineLayer to check
*
* Convenience method to check if @layer is empty (doesn't contain any object),
* or not.
*
* Returns: %TRUE if @layer is empty, %FALSE if it already contains at least
* one #GESTimelineObject
*/
gboolean
ges_timeline_layer_is_empty (GESTimelineLayer * layer)
{
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), FALSE);
return (layer->priv->objects_start == NULL);
}
/**
* ges_timeline_layer_add_object:
* @layer: a #GESTimelineLayer
* @object: (transfer full): the #GESTimelineObject to add.
*
* Adds the given object to the layer. Sets the object's parent, and thus
* takes ownership of the object.
*
* An object can only be added to one layer.
*
* Calling this method will construct and properly set all the media related
* elements on @object. If you need to know when those objects (actually #GESTrackObject)
* are constructed, you should connect to the object::track-object-added signal which
* is emited right after those elements are ready to be used.
*
* Returns: TRUE if the object was properly added to the layer, or FALSE
* if the @layer refuses to add the object.
*/
gboolean
ges_timeline_layer_add_object (GESTimelineLayer * layer,
GESTimelineObject * object)
{
GESTimelineLayer *tl_obj_layer;
guint32 maxprio, minprio, prio;
GST_DEBUG ("layer:%p, object:%p", layer, object);
tl_obj_layer = ges_timeline_object_get_layer (object);
if (G_UNLIKELY (tl_obj_layer)) {
GST_WARNING ("TimelineObject %p already belongs to another layer", object);
g_object_unref (tl_obj_layer);
return FALSE;
}
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,
(GCompareFunc) objects_start_compare);
/* Inform the object it's now in this layer */
ges_timeline_object_set_layer (object, layer);
GST_DEBUG ("current object priority : %d, layer min/max : %d/%d",
GES_TIMELINE_OBJECT_PRIORITY (object),
layer->min_gnl_priority, layer->max_gnl_priority);
/* Set the priority. */
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);
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' */
g_signal_emit (layer, ges_timeline_layer_signals[OBJECT_ADDED], 0, object);
return TRUE;
}
/**
* ges_timeline_layer_new:
*
* Creates a new #GESTimelineLayer.
*
* Returns: A new #GESTimelineLayer
*/
GESTimelineLayer *
ges_timeline_layer_new (void)
{
return g_object_new (GES_TYPE_TIMELINE_LAYER, NULL);
}
/**
* ges_timeline_layer_get_timeline:
* @layer: The #GESTimelineLayer to get the parent #GESTimeline from
*
* Get the #GESTimeline in which #GESTimelineLayer currently is.
*
* Returns: (transfer none): the #GESTimeline in which #GESTimelineLayer
* currently is or %NULL if not in any timeline yet.
*/
GESTimeline *
ges_timeline_layer_get_timeline (GESTimelineLayer * layer)
{
g_return_val_if_fail (GES_IS_TIMELINE_LAYER (layer), NULL);
return layer->timeline;
}
void
ges_timeline_layer_set_timeline (GESTimelineLayer * layer,
GESTimeline * timeline)
{
GST_DEBUG ("layer:%p, timeline:%p", layer, timeline);
if (layer->priv->auto_transition == TRUE) {
if (layer->timeline != NULL) {
g_signal_handlers_disconnect_by_func (layer->timeline, track_added_cb,
layer);
g_signal_handlers_disconnect_by_func (layer->timeline, track_removed_cb,
layer);
}
layer->timeline = timeline;
if (timeline != NULL)
start_calculating_transitions (layer);
} else
layer->timeline = timeline;
}

View file

@ -108,6 +108,8 @@ gboolean ges_timeline_layer_remove_object (GESTimelineLayer * layer,
void ges_timeline_layer_set_priority (GESTimelineLayer * layer,
guint priority);
gboolean ges_timeline_layer_is_empty (GESTimelineLayer * layer);
guint ges_timeline_layer_get_priority (GESTimelineLayer * layer);
gboolean ges_timeline_layer_get_auto_transition (GESTimelineLayer * layer);

View file

@ -43,6 +43,8 @@ gboolean
ges_timeline_object_create_track_objects_func (GESTimelineObject
* object, GESTrack * track);
void default_set_max_duration (GESTimelineObject * object, guint64 maxduration);
static void
track_object_start_changed_cb (GESTrackObject * child,
GParamSpec * arg G_GNUC_UNUSED, GESTimelineObject * object);
@ -131,6 +133,8 @@ struct _GESTimelineObjectPrivate
gboolean ignore_notifies;
gboolean is_moving;
guint64 maxduration;
GList *mappings;
guint nb_effects;
@ -151,6 +155,7 @@ enum
PROP_HEIGHT,
PROP_LAYER,
PROP_SUPPORTED_FORMATS,
PROP_MAX_DURATION,
PROP_LAST
};
@ -184,6 +189,9 @@ ges_timeline_object_get_property (GObject * object, guint property_id,
case PROP_SUPPORTED_FORMATS:
g_value_set_flags (value, tobj->priv->supportedformats);
break;
case PROP_MAX_DURATION:
g_value_set_uint64 (value, tobj->priv->maxduration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -215,6 +223,9 @@ ges_timeline_object_set_property (GObject * object, guint property_id,
ges_timeline_object_set_supported_formats (tobj,
g_value_get_flags (value));
break;
case PROP_MAX_DURATION:
ges_timeline_object_set_max_duration (tobj, g_value_get_uint64 (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -230,6 +241,7 @@ ges_timeline_object_class_init (GESTimelineObjectClass * klass)
object_class->get_property = ges_timeline_object_get_property;
object_class->set_property = ges_timeline_object_set_property;
klass->create_track_objects = ges_timeline_object_create_track_objects_func;
klass->set_max_duration = default_set_max_duration;
klass->track_object_added = NULL;
klass->track_object_released = NULL;
@ -373,6 +385,18 @@ ges_timeline_object_class_init (GESTimelineObjectClass * klass)
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 1, GES_TYPE_TRACK_OBJECT);
/**
* GESTimelineObject:max-duration:
*
* The maximum duration (in nanoseconds) of the #GESTimelineObject.
*
* Since: 0.10.XX
*/
g_object_class_install_property (object_class, PROP_MAX_DURATION,
g_param_spec_uint64 ("max-duration", "Maximum duration",
"The duration of the object", 0, G_MAXUINT64, G_MAXUINT64,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
klass->need_fill_track = TRUE;
}
@ -387,6 +411,7 @@ ges_timeline_object_init (GESTimelineObject * self)
self->priv->layer = NULL;
self->priv->nb_effects = 0;
self->priv->is_moving = FALSE;
self->priv->maxduration = G_MAXUINT64;
}
/**
@ -456,6 +481,15 @@ ges_timeline_object_create_track_objects (GESTimelineObject * object,
return klass->create_track_objects (object, track);
}
/* Default implementation of default_set_max_duration */
void
default_set_max_duration (GESTimelineObject * object, guint64 maxduration)
{
GList *tmp;
for (tmp = object->priv->trackobjects; tmp; tmp = g_list_next (tmp))
g_object_set (tmp->data, "max-duration", maxduration, NULL);
}
/*
* default implementation of GESTimelineObjectClass::create_track_objects
*/
@ -464,7 +498,6 @@ ges_timeline_object_create_track_objects_func (GESTimelineObject * object,
GESTrack * track)
{
GESTrackObject *result;
gboolean ret;
result = ges_timeline_object_create_track_object (object, track);
if (!result) {
@ -472,10 +505,10 @@ ges_timeline_object_create_track_objects_func (GESTimelineObject * object,
return FALSE;
}
ret = ges_track_add_object (track, result);
ges_timeline_object_add_track_object (object, result);
if (ges_timeline_object_add_track_object (object, result) == FALSE)
return FALSE;
return ret;
return ges_track_add_object (track, result);
}
/**
@ -558,6 +591,7 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
ges_track_object_set_start (trobj, object->start);
ges_track_object_set_duration (trobj, object->duration);
ges_track_object_set_inpoint (trobj, object->inpoint);
ges_track_object_set_max_duration (trobj, object->priv->maxduration);
if (klass->track_object_added) {
GST_DEBUG ("Calling track_object_added subclass method");
@ -586,7 +620,7 @@ ges_timeline_object_add_track_object (GESTimelineObject * object, GESTrackObject
+ mapping->priority_offset);
GST_DEBUG ("Returning trobj:%p", trobj);
if (!GES_IS_TRACK_PARSE_LAUNCH_EFFECT (trobj)) {
if (!GES_IS_TRACK_EFFECT (trobj)) {
g_signal_emit (object, ges_timeline_object_signals[TRACK_OBJECT_ADDED], 0,
GES_TRACK_OBJECT (trobj));
} else {
@ -995,6 +1029,9 @@ ges_timeline_object_move_to_layer (GESTimelineObject * object, GESTimelineLayer
return ges_timeline_layer_add_object (layer, object);
}
GST_DEBUG_OBJECT (object, "moving to layer %p, priority: %d", layer,
ges_timeline_layer_get_priority (layer));
object->priv->is_moving = TRUE;
g_object_ref (object);
ret = ges_timeline_layer_remove_object (current_layer, object);
@ -1455,6 +1492,45 @@ ges_timeline_object_objects_set_locked (GESTimelineObject * object,
}
}
/**
* ges_timeline_object_get_max_duration:
* @object: The #GESTimelineObject to retrieve max duration from
*
* Get the max duration of @object.
*
* Returns: The max duration of @object
*
* Since: 0.10.XX
*/
guint64
ges_timeline_object_get_max_duration (GESTimelineObject * object)
{
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), 0);
return object->priv->maxduration;
}
/**
* ges_timeline_object_set_max_duration:
* @object: The #GESTimelineObject to retrieve max duration from
* @maxduration: The maximum duration of @object
*
* Returns: Set the max duration of @object
*
* Since: 0.10.XX
*/
void
ges_timeline_object_set_max_duration (GESTimelineObject * object,
guint64 maxduration)
{
GESTimelineObjectClass *klass = GES_TIMELINE_OBJECT_GET_CLASS (object);
g_return_if_fail (GES_IS_TIMELINE_OBJECT (object));
object->priv->maxduration = maxduration;
klass->set_max_duration (object, maxduration);
}
static void
update_height (GESTimelineObject * object)
{
@ -1517,18 +1593,54 @@ static void
track_object_inpoint_changed_cb (GESTrackObject * child,
GParamSpec * arg G_GNUC_UNUSED, GESTimelineObject * object)
{
ObjectMapping *map;
if (object->priv->ignore_notifies)
return;
map = find_object_mapping (object, child);
if (G_UNLIKELY (map == NULL))
/* something massively screwed up if we get this */
return;
if (!ges_track_object_is_locked (child)) {
/* Update the internal start_offset */
map->inpoint_offset = object->inpoint - child->inpoint;
} else {
/* Or update the parent start */
object->priv->initiated_move = child;
ges_timeline_object_set_inpoint (object,
child->inpoint + map->inpoint_offset);
object->priv->initiated_move = NULL;
}
}
static void
track_object_duration_changed_cb (GESTrackObject * child,
GParamSpec * arg G_GNUC_UNUSED, GESTimelineObject * object)
{
ObjectMapping *map;
if (object->priv->ignore_notifies)
return;
map = find_object_mapping (object, child);
if (G_UNLIKELY (map == NULL))
/* something massively screwed up if we get this */
return;
if (!ges_track_object_is_locked (child)) {
/* Update the internal start_offset */
map->duration_offset = object->duration - child->duration;
} else {
/* Or update the parent start */
object->priv->initiated_move = child;
ges_timeline_object_set_duration (object,
child->duration + map->duration_offset);
object->priv->initiated_move = NULL;
}
}
static void

View file

@ -184,8 +184,10 @@ struct _GESTimelineObject {
* @need_fill_track: Set to TRUE if @fill_track_object needs to be called.
* @track_object_added: Should be overridden by subclasses if they need to perform an
* operation when a #GESTrackObject is added. Since: 0.10.2
* @track_object_released: Should be overridden by subclassed if they need to perform
* @track_object_released: Should be overridden by subclasses if they need to perform
* action when a #GESTrackObject is released. Since: 0.10.2
* @set_max_duration: Should be overridden by subclasses if they need to perform
* action when a changing the maximum duration. Since: 0.10.XX
*
* Subclasses can override the @create_track_object and @fill_track_object methods.
*/
@ -205,10 +207,12 @@ struct _GESTimelineObjectClass {
GESTrackObject *tck_object);
void (*track_object_released) (GESTimelineObject *object,
GESTrackObject *tck_object);
void (*set_max_duration ) (GESTimelineObject *object,
guint64 maxduration);
/*< private >*/
/* Padding for API extension */
gpointer _ges_reserved[GES_PADDING - 2];
gpointer _ges_reserved[GES_PADDING - 3];
};
GType ges_timeline_object_get_type (void);
@ -220,9 +224,13 @@ void ges_timeline_object_set_inpoint (GESTimelineObject * object,
guint64 inpoint);
void ges_timeline_object_set_duration (GESTimelineObject * object,
guint64 duration);
void ges_timeline_object_set_max_duration (GESTimelineObject * object,
guint64 maxduration);
void ges_timeline_object_set_priority (GESTimelineObject * object,
guint priority);
guint64 ges_timeline_object_get_max_duration (GESTimelineObject * object);
void ges_timeline_object_set_layer (GESTimelineObject * object,
GESTimelineLayer * layer);

View file

@ -191,29 +191,37 @@ ges_tl_transition_create_track_object (GESTimelineObject * obj,
{
GESTimelineStandardTransition *transition =
(GESTimelineStandardTransition *) obj;
GESTrackObject *res;
GESTrackObject *res = NULL;
GESTrackType supportedformats;
GST_DEBUG ("Creating a GESTrackTransition");
supportedformats = ges_timeline_object_get_supported_formats (obj);
if (track->type == GES_TRACK_TYPE_VIDEO &&
(supportedformats == GES_TRACK_TYPE_UNKNOWN ||
supportedformats & GES_TRACK_TYPE_VIDEO)) {
res = GES_TRACK_OBJECT (ges_track_video_transition_new ());
ges_track_video_transition_set_transition_type ((GESTrackVideoTransition *)
res, transition->vtype);
if (track->type == GES_TRACK_TYPE_VIDEO) {
if (supportedformats == GES_TRACK_TYPE_UNKNOWN ||
supportedformats & GES_TRACK_TYPE_VIDEO) {
GESTrackVideoTransition *trans;
} else if (track->type == GES_TRACK_TYPE_AUDIO &&
(supportedformats == GES_TRACK_TYPE_UNKNOWN ||
supportedformats & GES_TRACK_TYPE_AUDIO)) {
res = GES_TRACK_OBJECT (ges_track_audio_transition_new ());
}
trans = ges_track_video_transition_new ();
ges_track_video_transition_set_transition_type (trans, transition->vtype);
else {
res = GES_TRACK_OBJECT (trans);
} else {
GST_DEBUG ("Not creating transition as video track not on"
" supportedformats");
}
} else if (track->type == GES_TRACK_TYPE_AUDIO) {
if (supportedformats == GES_TRACK_TYPE_UNKNOWN ||
supportedformats & GES_TRACK_TYPE_AUDIO)
res = GES_TRACK_OBJECT (ges_track_audio_transition_new ());
else
GST_DEBUG ("Not creating transition as audio track"
" not on supportedformats");
} else
GST_WARNING ("Transitions don't handle this track type");
return NULL;
}
return res;
}

View 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,6 +317,366 @@ sort_layers (gpointer a, gpointer b)
return 0;
}
static gint
custom_find_track (TrackPrivate * tr_priv, GESTrack * track)
{
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)) {
if ((track->type & ges_timeline_object_get_supported_formats (object))) {
GST_WARNING ("Error creating track objects");
}
}
}
static void
add_object_to_tracks (GESTimeline * timeline, GESTimelineObject * object)
{
GList *tmp;
for (tmp = timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
GESTrack *track = tr_priv->track;
GST_LOG ("Trying with track %p", track);
add_object_to_track (object, track);
}
}
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;
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:
if (is_image) {
/* don't set max-duration on still images */
g_object_set (tfs, "is_image", (gboolean) TRUE, NULL);
}
/* Continue the processing on tfs */
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
if (!is_image) {
g_object_set (tfs, "max-duration",
gst_discoverer_info_get_duration (info), NULL);
}
/* 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)
{
if (ges_timeline_object_is_moving_from_layer (object)) {
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
" anything on it", object);
return;
}
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");
}
static void
layer_priority_changed_cb (GESTimelineLayer * layer,
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
{
timeline->priv->layers = g_list_sort (timeline->priv->layers, (GCompareFunc)
sort_layers);
}
static void
layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
GESTimeline * timeline)
{
GList *trackobjects, *tmp;
if (ges_timeline_object_is_moving_from_layer (object)) {
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
" anything on it", object);
return;
}
GST_DEBUG ("TimelineObject %p removed from layer %p", object, layer);
/* Go over the object's track objects and figure out which one belongs to
* the list of tracks we control */
trackobjects = ges_timeline_object_get_track_objects (object);
for (tmp = trackobjects; tmp; tmp = tmp->next) {
GESTrackObject *trobj = (GESTrackObject *) tmp->data;
GST_DEBUG ("Trying to remove TrackObject %p", trobj);
if (G_LIKELY (g_list_find_custom (timeline->priv->tracks,
ges_track_object_get_track (trobj),
(GCompareFunc) custom_find_track))) {
GST_DEBUG ("Belongs to one of the tracks we control");
ges_track_remove_object (ges_track_object_get_track (trobj), trobj);
ges_timeline_object_release_track_object (object, trobj);
}
/* removing the reference added by _get_track_objects() */
g_object_unref (trobj);
}
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");
}
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_new:
*
@ -447,349 +806,30 @@ fail:
return ret;
}
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");
}
}
static void
add_object_to_tracks (GESTimeline * timeline, GESTimelineObject * object)
{
GList *tmp;
for (tmp = timeline->priv->tracks; tmp; tmp = g_list_next (tmp)) {
TrackPrivate *tr_priv = (TrackPrivate *) tmp->data;
GESTrack *track = tr_priv->track;
GST_LOG ("Trying with track %p", track);
add_object_to_track (object, track);
}
}
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;
}
}
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;
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:
if (is_image) {
/* don't set max-duration on still images */
g_object_set (tfs, "is_image", (gboolean) TRUE, NULL);
}
/* Continue the processing on tfs */
add_object_to_tracks (timeline, GES_TIMELINE_OBJECT (tfs));
if (!is_image) {
g_object_set (tfs, "max-duration",
gst_discoverer_info_get_duration (info), NULL);
}
/* Remove the ref as the timeline file source is no longer needed here */
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)
{
if (ges_timeline_object_is_moving_from_layer (object)) {
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
" anything on it", object);
return;
}
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");
}
static void
layer_priority_changed_cb (GESTimelineLayer * layer,
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
{
timeline->priv->layers = g_list_sort (timeline->priv->layers, (GCompareFunc)
sort_layers);
}
static void
layer_object_removed_cb (GESTimelineLayer * layer, GESTimelineObject * object,
GESTimeline * timeline)
{
GList *trackobjects, *tmp;
if (ges_timeline_object_is_moving_from_layer (object)) {
GST_DEBUG ("TimelineObject %p is moving from a layer to another, not doing"
" anything on it", object);
return;
}
GST_DEBUG ("TimelineObject %p removed from layer %p", object, layer);
/* Go over the object's track objects and figure out which one belongs to
* the list of tracks we control */
trackobjects = ges_timeline_object_get_track_objects (object);
for (tmp = trackobjects; tmp; tmp = tmp->next) {
GESTrackObject *trobj = (GESTrackObject *) tmp->data;
GST_DEBUG ("Trying to remove TrackObject %p", trobj);
if (G_LIKELY (g_list_find_custom (timeline->priv->tracks,
ges_track_object_get_track (trobj),
(GCompareFunc) custom_find_track))) {
GST_DEBUG ("Belongs to one of the tracks we control");
ges_track_remove_object (ges_track_object_get_track (trobj), trobj);
ges_timeline_object_release_track_object (object, trobj);
}
/* removing the reference added by _get_track_objects() */
g_object_unref (trobj);
}
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");
}
/**
* ges_timeline_append_layer:
* @timeline: a #GESTimeline
* @layer: the #GESTimelineLayer to add
*
* 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.
* Append a newly creater #GESTimelineLayer to @timeline
* Note that you do not own any reference to the returned layer.
*
* Returns: TRUE if the layer was properly added, else FALSE.
* Returns: (transfer none): The newly created #GESTimelineLayer, or the last (empty)
* #GESTimelineLayer of @timeline.
*/
gboolean
ges_timeline_append_layer (GESTimeline * timeline, GESTimelineLayer * layer)
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
}
}

View file

@ -89,7 +89,7 @@ gboolean ges_timeline_load_from_uri (GESTimeline *timeline, const gchar *uri);
gboolean ges_timeline_save_to_uri (GESTimeline *timeline, const gchar *uri);
gboolean ges_timeline_add_layer (GESTimeline *timeline, GESTimelineLayer *layer);
gboolean ges_timeline_append_layer (GESTimeline * timeline, GESTimelineLayer * layer);
GESTimelineLayer * ges_timeline_append_layer (GESTimeline * timeline);
gboolean ges_timeline_remove_layer (GESTimeline *timeline, GESTimelineLayer *layer);
GList* ges_timeline_get_layers (GESTimeline *timeline);

View file

@ -34,14 +34,13 @@ G_DEFINE_TYPE (GESTrackFileSource, ges_track_filesource, GES_TYPE_TRACK_SOURCE);
struct _GESTrackFileSourcePrivate
{
guint64 maxduration;
void *dummy;
};
enum
{
PROP_0,
PROP_URI,
PROP_MAX_DURATION
PROP_URI
};
static void
@ -54,9 +53,6 @@ ges_track_filesource_get_property (GObject * object, guint property_id,
case PROP_URI:
g_value_set_string (value, tfs->uri);
break;
case PROP_MAX_DURATION:
g_value_set_uint64 (value, tfs->priv->maxduration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -72,9 +68,6 @@ ges_track_filesource_set_property (GObject * object, guint property_id,
case PROP_URI:
tfs->uri = g_value_dup_string (value);
break;
case PROP_MAX_DURATION:
tfs->priv->maxduration = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -114,19 +107,6 @@ ges_track_filesource_class_init (GESTrackFileSourceClass * klass)
object_class->set_property = ges_track_filesource_set_property;
object_class->dispose = ges_track_filesource_dispose;
/**
* GESTrackFileSource:max-duration:
*
* The maximum duration (in nanoseconds) of the file.
*
* If not set before adding the object to a layer, it will be discovered
* asynchronously. Connect to 'notify::max-duration' to be notified of it.
*/
g_object_class_install_property (object_class, PROP_MAX_DURATION,
g_param_spec_uint64 ("max-duration", "Maximum duration",
"The duration of the file", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/**
* GESTrackFileSource:uri
*

View file

@ -60,6 +60,8 @@ struct _GESTrackObjectPrivate
gboolean valid;
guint64 maxduration;
gboolean locked; /* If TRUE, then moves in sync with its controlling
* GESTimelineObject */
};
@ -73,6 +75,7 @@ enum
PROP_PRIORITY,
PROP_ACTIVE,
PROP_LOCKED,
PROP_MAX_DURATION,
PROP_LAST
};
@ -149,6 +152,9 @@ ges_track_object_get_property (GObject * object, guint property_id,
case PROP_LOCKED:
g_value_set_boolean (value, ges_track_object_is_locked (tobj));
break;
case PROP_MAX_DURATION:
g_value_set_uint64 (value, tobj->priv->maxduration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -179,6 +185,9 @@ ges_track_object_set_property (GObject * object, guint property_id,
case PROP_LOCKED:
ges_track_object_set_locked_internal (tobj, g_value_get_boolean (value));
break;
case PROP_MAX_DURATION:
ges_track_object_set_max_duration (tobj, g_value_get_uint64 (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@ -290,6 +299,18 @@ ges_track_object_class_init (GESTrackObjectClass * klass)
g_object_class_install_property (object_class, PROP_LOCKED,
properties[PROP_LOCKED]);
/**
* GESTrackObject:max-duration:
*
* The maximum duration (in nanoseconds) of the #GESTrackObject.
*
* Since: 0.10.XX
*/
g_object_class_install_property (object_class, PROP_MAX_DURATION,
g_param_spec_uint64 ("max-duration", "Maximum duration",
"The duration of the object", 0, G_MAXUINT64, G_MAXUINT64,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/**
* GESTrackObject::deep-notify:
* @track_object: a #GESTrackObject
@ -843,14 +864,20 @@ ges_track_object_get_track (GESTrackObject * object)
return object->priv->track;
}
/**
* ges_track_object_set_timeline_object:
* @object: The #GESTrackObject to set the parent to
* @tlobject: The #GESTimelineObject, parent of @tlobj or %NULL
*
* Set the #GESTimelineObject to which @object belongs.
*/
void
ges_track_object_set_timeline_object (GESTrackObject * object,
GESTimelineObject * tlobj)
GESTimelineObject * tlobject)
{
GST_DEBUG ("object:%p, timeline-object:%p", object, tlobj);
GST_DEBUG ("object:%p, timeline-object:%p", object, tlobject);
object->priv->timelineobj = tlobj;
object->priv->timelineobj = tlobject;
}
/**
@ -1423,3 +1450,38 @@ prop_hash_not_set:
return NULL;
}
}
/**
* ges_track_object_get_max_duration:
* @object: The #GESTrackObject to retrieve max duration from
*
* Get the max duration of @object.
*
* Returns: The max duration of @object
*
* Since: 0.10.XX
*/
guint64
ges_track_object_get_max_duration (GESTrackObject * object)
{
g_return_val_if_fail (GES_IS_TRACK_OBJECT (object), 0);
return object->priv->maxduration;
}
/**
* ges_track_object_set_max_duration:
* @object: The #GESTrackObject to retrieve max duration from
* @maxduration: The maximum duration of @object
*
* Returns: Set the max duration of @object
*
* Since: 0.10.XX
*/
void
ges_track_object_set_max_duration (GESTrackObject * object, guint64 maxduration)
{
g_return_if_fail (GES_IS_TRACK_OBJECT (object));
object->priv->maxduration = maxduration;
}

View file

@ -173,6 +173,9 @@ void ges_track_object_set_inpoint (GESTrackObject * object,
void ges_track_object_set_duration (GESTrackObject * object,
guint64 duration);
void ges_track_object_set_max_duration (GESTrackObject * object,
guint64 maxduration);
void ges_track_object_set_priority (GESTrackObject * object,
guint32 priority);
@ -182,6 +185,7 @@ gboolean ges_track_object_set_active (GESTrackObject * object,
guint64 ges_track_object_get_start (GESTrackObject * object);
guint64 ges_track_object_get_inpoint (GESTrackObject * object);
guint64 ges_track_object_get_duration (GESTrackObject * object);
guint64 ges_track_object_get_max_duration (GESTrackObject * object);
guint32 ges_track_object_get_priority (GESTrackObject * object);
gboolean ges_track_object_is_active (GESTrackObject * object);

View file

@ -124,6 +124,7 @@ GST_START_TEST (test_keyfile_save)
KEY ("Object0", "duration", "2000000000");
KEY ("Object0", "priority", "2");
KEY ("Object0", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object0", "max-duration", "18446744073709551615");
KEY ("Object0", "mute", "false");
KEY ("Object0", "vpattern", "100% Black");
KEY ("Object0", "freq", "440");
@ -144,6 +145,7 @@ GST_START_TEST (test_keyfile_save)
KEY ("Object1", "duration", "500000000");
KEY ("Object1", "priority", "1");
KEY ("Object1", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object1", "max-duration", "18446744073709551615");
KEY ("Object1", "vtype", "A bar moves from left to right");
COMPARE;
@ -159,6 +161,7 @@ GST_START_TEST (test_keyfile_save)
KEY ("Object2", "duration", "2000000000");
KEY ("Object2", "priority", "3");
KEY ("Object2", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object2", "max-duration", "18446744073709551615");
KEY ("Object2", "mute", "false");
KEY ("Object2", "vpattern", "100% Black");
KEY ("Object2", "freq", "440");
@ -190,6 +193,7 @@ GST_START_TEST (test_keyfile_save)
KEY ("Object3", "duration", "1000000000");
KEY ("Object3", "priority", "0");
KEY ("Object3", "supported-formats", "GES_TRACK_TYPE_UNKNOWN");
KEY ("Object3", "max-duration", "18446744073709551615");
KEY ("Object3", "mute", "false");
KEY ("Object3", "text", "\"the\\\\ quick\\\\ brown\\\\ fox\"");
KEY ("Object3", "font-desc", "\"Serif\\\\ 36\"");