mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
Merge branch '0.10'
Conflicts: bindings/python/ges.defs
This commit is contained in:
commit
672a162062
13 changed files with 1011 additions and 835 deletions
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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\"");
|
||||
|
|
Loading…
Reference in a new issue