/**
* SECTION: gesbaseeffectclip
* @title: GESBaseEffectClip
- * @short_description: An effect in a GESLayer
+ * @short_description: An effect in a #GESLayer
*
- * The effect will be applied on the sources that have lower priorities
- * (higher number) between the inpoint and the end of it.
+ * #GESBaseEffectClip-s are clips whose core elements are
+ * #GESBaseEffect-s.
+ *
+ * ## Effects
+ *
+ * #GESBaseEffectClip-s can have **additional** #GESBaseEffect-s added as
+ * non-core elements. These additional effects are applied to the output
+ * of the core effects of the clip that they share a #GESTrack with. See
+ * #GESClip for how to add and move these effects from the clip.
*/
+
+/* FIXME: properly handle the priority of the children. How should we sort
+ * the priority of effects when two #GESBaseEffectClip's overlap? */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
static void
ges_base_effect_clip_class_init (GESBaseEffectClipClass * klass)
{
+ GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass) = TRUE;
}
static void
*
* ## Effects
*
- * For #GESSourceClip-s, you may wish to add additional track elements to
- * the clip in the form of #GESEffect-s. These can be added to the source
- * clip using ges_container_add(), which will take care of adding the
- * effect to the timeline's tracks. The new effect will be placed between
- * the clip's core track elements and its other effects. As such, the
- * newly added effect will be applied to any source data **before** the
- * other existing effects. You can change the ordering of effects using
+ * Some subclasses (#GESSourceClip and #GESBaseEffect) may also allow
+ * their objects to have additional non-core #GESBaseEffect-s elements as
+ * children. These are additional effects that are applied to the output
+ * data of the core elements. They can be added to the clip using
+ * ges_container_add(), which will take care of adding the effect to the
+ * timeline's tracks. The new effect will be placed between the clip's
+ * core track elements and its other effects. As such, the newly added
+ * effect will be applied to any source data **before** the other existing
+ * effects. You can change the ordering of effects using
* ges_clip_set_top_effect_index().
*/
#ifdef HAVE_CONFIG_H
static gboolean
_add_child (GESContainer * container, GESTimelineElement * element)
{
- GList *tmp;
+ GESClipClass *klass = GES_CLIP_GET_CLASS (GES_CLIP (container));
guint max_prio, min_prio;
+ GESChildrenControlMode mode = container->children_control_mode;
GESClipPrivate *priv = GES_CLIP (container)->priv;
g_return_val_if_fail (GES_IS_TRACK_ELEMENT (element), FALSE);
/* First make sure we work with a sorted list of GESTimelineElement-s */
_ges_container_sort_children (container);
-
- /* If the TrackElement is an effect:
- * - We add it on top of the list of TrackEffect
- * - We put all TrackElements present in the Clip
- * which are not BaseEffect on top of them
- * FIXME: Let the full control over priorities to the user
- */
_get_priority_range (container, &min_prio, &max_prio);
- if (GES_IS_BASE_EFFECT (element)) {
- GESChildrenControlMode mode = container->children_control_mode;
+ if (ELEMENT_FLAG_IS_SET (element, GES_TRACK_ELEMENT_IS_CORE)) {
+ /* NOTE: we are assuming that the core element is **our** core element
+ * and not from another clip. */
+ /* NOTE: Core track elements that are base effects are added like any
+ * other core clip. In particular, they are *not* added to the list of
+ * added effects, so we don not increase nb_effects. */
+
+ /* Always add at the same priority, on top of existing effects */
+ _set_priority0 (element, min_prio + priv->nb_effects);
- GST_DEBUG_OBJECT (container, "Adding %ith effect: %" GST_PTR_FORMAT
- " Priority %i", priv->nb_effects + 1, element,
+ /* Set the core element to have the same in-point, which we don't
+ * apply to effects */
+ container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
+ _set_inpoint0 (element, GES_TIMELINE_ELEMENT_INPOINT (container));
+ } else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass)
+ && GES_IS_BASE_EFFECT (element)) {
+ GList *tmp;
+ /* Add the effect at the lowest priority among effects (just after
+ * the core elements). Need to shift the core elements up by 1
+ * to make room. */
+ GST_DEBUG_OBJECT (container, "Adding %ith effect: %" GES_FORMAT
+ " Priority %i", priv->nb_effects + 1, GES_ARGS (element),
min_prio + priv->nb_effects);
+ /* changing priorities, and updating their offset */
tmp = g_list_nth (GES_CONTAINER_CHILDREN (container), priv->nb_effects);
- container->children_control_mode = GES_CHILDREN_UPDATE_OFFSETS;
- for (; tmp; tmp = tmp->next) {
+ for (; tmp; tmp = tmp->next)
ges_timeline_element_set_priority (GES_TIMELINE_ELEMENT (tmp->data),
GES_TIMELINE_ELEMENT_PRIORITY (tmp->data) + 1);
- }
_set_priority0 (element, min_prio + priv->nb_effects);
- container->children_control_mode = mode;
priv->nb_effects++;
+ /* no need to call _ges_container_sort_children (container) since
+ * there is no change to the ordering yet (this happens after the
+ * child is actually added) */
+ /* The height has already changed (increased by 1) */
+ _compute_height (container);
} else {
- /* We add the track element on top of the effect list */
- _set_priority0 (element, min_prio + priv->nb_effects);
+ if (GES_IS_BASE_EFFECT (element))
+ GST_WARNING_OBJECT (container, "Can not add the effect %" GES_FORMAT
+ " because it is not a core element created by the clip itself "
+ "and the %s class does not allow for the adding extra effects",
+ GES_ARGS (element), G_OBJECT_CLASS_NAME (klass));
+ else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass))
+ GST_WARNING_OBJECT (container, "Can not add the track element %"
+ GES_FORMAT " because it is neither a core element created by "
+ "the clip itself, nor a GESBaseEffect", GES_ARGS (element));
+ else
+ GST_WARNING_OBJECT (container, "Can not add the track element %"
+ GES_FORMAT " because it is not a core element created by the "
+ "clip itself", GES_ARGS (element));
+ return FALSE;
}
/* We set the timing value of the child to ours, we avoid infinite loop
* making sure the container ignore notifies from the child */
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
_set_start0 (element, GES_TIMELINE_ELEMENT_START (container));
- /* FIXME: we should allow the inpoint to be different for children
- * that are *not* the core track elements of the clip. E.g. if we
- * add a GESEffect to a clip, we should not be editing its inpoint */
- _set_inpoint0 (element, GES_TIMELINE_ELEMENT_INPOINT (container));
_set_duration0 (element, GES_TIMELINE_ELEMENT_DURATION (container));
- container->children_control_mode = GES_CHILDREN_UPDATE;
+ container->children_control_mode = mode;
return TRUE;
}
static gboolean
_remove_child (GESContainer * container, GESTimelineElement * element)
{
- if (GES_IS_BASE_EFFECT (element)) {
+ if (!ELEMENT_FLAG_IS_SET (element, GES_TRACK_ELEMENT_IS_CORE)
+ && GES_IS_BASE_EFFECT (element)) {
GES_CLIP (container)->priv->nb_effects--;
}
GST_FIXME_OBJECT (container, "We should set other children prios");
+ if (ELEMENT_FLAG_IS_SET (element, GES_TRACK_ELEMENT_IS_CORE)) {
+ /* When removed, the child is no longer considered a core element.
+ * This prevents the user from being able to add the removed track
+ * element to an arbitrary clip */
+ ELEMENT_UNSET_FLAG (element, GES_TRACK_ELEMENT_IS_CORE);
+ }
return TRUE;
}
static void
_child_added (GESContainer * container, GESTimelineElement * element)
{
+ /* FIXME: adjust the max-duration according to the new child */
g_signal_connect (G_OBJECT (element), "notify::priority",
G_CALLBACK (_child_priority_changed_cb), container);
g_signal_handlers_disconnect_by_func (element, _child_priority_changed_cb,
container);
- if (GES_IS_BASE_EFFECT (element)) {
+ if (!ELEMENT_FLAG_IS_SET (element, GES_TRACK_ELEMENT_IS_CORE)
+ && GES_IS_BASE_EFFECT (element)) {
GList *tmp;
guint32 priority;
GESChildrenControlMode mode = container->children_control_mode;
*list = g_list_prepend (*list, gst_object_ref (clip));
}
+static void
+_transfer_child (GESClip * from_clip, GESClip * to_clip,
+ GESTrackElement * child)
+{
+ gboolean is_core;
+ /* We need to bump the refcount to avoid the object to be destroyed */
+ gst_object_ref (child);
+ /* IS_CORE flag is removed when an element is removed from its clip */
+ is_core = ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE);
+ ges_container_remove (GES_CONTAINER (from_clip),
+ GES_TIMELINE_ELEMENT (child));
+ if (is_core)
+ ELEMENT_SET_FLAG (child, GES_TRACK_ELEMENT_IS_CORE);
+ ges_container_add (GES_CONTAINER (to_clip), GES_TIMELINE_ELEMENT (child));
+ gst_object_unref (child);
+}
+
static GList *
_ungroup (GESContainer * container, gboolean recursive)
{
}
/* Move trackelement to the container it is supposed to land into */
- if (tmpclip != clip) {
- /* We need to bump the refcount to avoid the object to be destroyed */
- gst_object_ref (track_element);
- ges_container_remove (container, GES_TIMELINE_ELEMENT (track_element));
- ges_container_add (GES_CONTAINER (tmpclip),
- GES_TIMELINE_ELEMENT (track_element));
- gst_object_unref (track_element);
- }
+ if (tmpclip != clip)
+ _transfer_child (clip, tmpclip, track_element);
}
g_list_free_full (children, gst_object_unref);
g_hash_table_foreach (_tracktype_clip, (GHFunc) add_clip_to_list, &ret);
GList *children = ges_container_get_children (GES_CONTAINER (cclip), FALSE);
for (tmpelement = children; tmpelement; tmpelement = tmpelement->next) {
- GESTimelineElement *celement = GES_TIMELINE_ELEMENT (tmpelement->data);
-
- ges_container_remove (GES_CONTAINER (cclip), celement);
- ges_container_add (ret, celement);
-
- supported_formats = supported_formats |
- ges_track_element_get_track_type (GES_TRACK_ELEMENT (celement));
+ GESTrackElement *celement = GES_TRACK_ELEMENT (tmpelement->data);
+ _transfer_child (cclip, GES_CLIP (ret), celement);
+ supported_formats |= ges_track_element_get_track_type (celement);
}
g_list_free_full (children, gst_object_unref);
{
GList *tmp;
GESClip *self = GES_CLIP (element), *ccopy = GES_CLIP (copy);
+ GESTrackElement *el, *el_copy;
if (!self->priv->layer)
return;
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
+ el = GES_TRACK_ELEMENT (tmp->data);
+ el_copy = ges_track_element_copy_core (el, TRUE);
ccopy->priv->copied_track_elements =
- g_list_append (ccopy->priv->copied_track_elements,
- ges_timeline_element_copy (tmp->data, TRUE));
+ g_list_append (ccopy->priv->copied_track_elements, el_copy);
}
ccopy->priv->copied_layer = g_object_ref (self->priv->layer);
GESTrackElement *new_trackelement, *trackelement =
GES_TRACK_ELEMENT (tmp->data);
+ /* NOTE: we do not deep copy the track element, we instead call
+ * ges_track_element_copy_properties explicitly, which is the
+ * deep_copy for the GESTrackElementClass. */
new_trackelement =
- GES_TRACK_ELEMENT (ges_timeline_element_copy (GES_TIMELINE_ELEMENT
- (trackelement), FALSE));
+ GES_TRACK_ELEMENT (ges_track_element_copy_core (trackelement, FALSE));
if (new_trackelement == NULL) {
GST_WARNING_OBJECT (trackelement, "Could not create a copy");
continue;
{
GList *result = NULL, *tmp, *children;
GESClipClass *klass;
- guint max_prio, min_prio;
gboolean readding_effects_only = TRUE;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
if (!ges_track_element_get_track (child)
&& ges_track_element_get_track_type (child) & type) {
+ gboolean is_core = ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE);
GST_DEBUG_OBJECT (clip, "Removing for reusage: %" GST_PTR_FORMAT, child);
result = g_list_append (result, g_object_ref (child));
ges_container_remove (GES_CONTAINER (clip), tmp->data);
- if (!GES_IS_BASE_EFFECT (child))
+ if (is_core) {
+ /* set on child since the flag is removed when removed from the clip */
+ ELEMENT_SET_FLAG (child, GES_TRACK_ELEMENT_IS_CORE);
readding_effects_only = FALSE;
+ }
}
}
g_list_free_full (children, gst_object_unref);
* recreated.
*/
if (readding_effects_only) {
- result = g_list_concat (result, klass->create_track_elements (clip, type));
+ GList *track_elements = klass->create_track_elements (clip, type);
+ for (tmp = track_elements; tmp; tmp = tmp->next) {
+ GESTimelineElement *elem = tmp->data;
+ ELEMENT_SET_FLAG (elem, GES_TRACK_ELEMENT_IS_CORE);
+
+ /* FIXME: we should set the max duration of the clip based on the
+ * max duration of the child. Not the other way around. */
+ if (GST_CLOCK_TIME_IS_VALID (GES_TIMELINE_ELEMENT_MAX_DURATION (clip)))
+ ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (elem),
+ GES_TIMELINE_ELEMENT_MAX_DURATION (clip));
+ }
+ result = g_list_concat (track_elements, result);
}
- _get_priority_range (GES_CONTAINER (clip), &min_prio, &max_prio);
for (tmp = result; tmp; tmp = tmp->next) {
- GESTimelineElement *elem = tmp->data;
-
- _set_start0 (elem, GES_TIMELINE_ELEMENT_START (clip));
- /* FIXME: only set the in-point and max-duration for non-core
- * elements */
- _set_inpoint0 (elem, GES_TIMELINE_ELEMENT_INPOINT (clip));
- _set_duration0 (elem, GES_TIMELINE_ELEMENT_DURATION (clip));
-
- if (GST_CLOCK_TIME_IS_VALID (GES_TIMELINE_ELEMENT_MAX_DURATION (clip)))
- ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (elem),
- GES_TIMELINE_ELEMENT_MAX_DURATION (clip));
-
- _set_priority0 (elem, min_prio + clip->priv->nb_effects);
-
- ges_container_add (GES_CONTAINER (clip), elem);
+ ges_container_add (GES_CONTAINER (clip), GES_TIMELINE_ELEMENT (tmp->data));
}
return result;
ges_clip_get_top_effects (GESClip * clip)
{
GList *tmp, *ret;
- guint i;
+ GESTimelineElement *child;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
GST_DEBUG_OBJECT (clip, "Getting the %i top effects", clip->priv->nb_effects);
ret = NULL;
- for (tmp = GES_CONTAINER_CHILDREN (clip), i = 0;
- i < clip->priv->nb_effects; tmp = tmp->next, i++) {
- ret = g_list_append (ret, gst_object_ref (tmp->data));
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
+ child = tmp->data;
+ if (GES_IS_BASE_EFFECT (child)
+ && !ELEMENT_FLAG_IS_SET (child, GES_TRACK_ELEMENT_IS_CORE))
+ ret = g_list_append (ret, gst_object_ref (child));
}
return g_list_sort (ret, (GCompareFunc) element_start_compare);
}
+static gboolean
+_is_added_effect (GESClip * clip, GESBaseEffect * effect)
+{
+ if (GES_TIMELINE_ELEMENT_PARENT (effect) != GES_TIMELINE_ELEMENT (clip)) {
+ GST_WARNING_OBJECT (clip, "The effect %" GES_FORMAT
+ " doe not belong to this clip", GES_ARGS (effect));
+ return FALSE;
+ }
+ if (ELEMENT_FLAG_IS_SET (effect, GES_TRACK_ELEMENT_IS_CORE)) {
+ GST_WARNING_OBJECT (clip, "The effect %" GES_FORMAT " is not a top "
+ "effect of this clip (it is a core element of the clip)",
+ GES_ARGS (effect));
+ return FALSE;
+ }
+ return TRUE;
+}
+
/**
* ges_clip_get_top_effect_index:
* @clip: A #GESClip
g_return_val_if_fail (GES_IS_CLIP (clip), -1);
g_return_val_if_fail (GES_IS_BASE_EFFECT (effect), -1);
+ if (!_is_added_effect (clip, effect))
+ return -1;
_get_priority_range (GES_CONTAINER (clip), &min_prio, &max_prio);
GESTrackElement *track_element;
g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
+ g_return_val_if_fail (GES_IS_BASE_EFFECT (effect), FALSE);
- track_element = GES_TRACK_ELEMENT (effect);
- if (G_UNLIKELY (GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (track_element)) !=
- clip))
+ if (!_is_added_effect (clip, effect))
return FALSE;
+ track_element = GES_TRACK_ELEMENT (effect);
current_prio = _PRIORITY (track_element);
_get_priority_range (GES_CONTAINER (clip), &min_prio, &max_prio);
inpoint + old_duration * media_duration_factor);
_set_duration0 (GES_TIMELINE_ELEMENT (new_object), new_duration);
- /* FIXME: this does not check that the new duration of the clip does
- * not break the allowed configurations of a timeline!
- * E.g., consider a layer with two clips:
- *
- * [ clip0 ]
- * [ clip1 ]
- * 0 1 2 3 4 5 6 7 - timeline time
- *
- * If we split clip1 at time 4 then we would have
- *
- * [ clip0 ]
- * [ clip1 ]
- * [ new-clip]
- * 0 1 2 3 4 5 6 7 - timeline time
- *
- * This means that clip1 is entirely covered by clip0! This is allowed
- * to occur using ges_clip_split()!
- *
- * Note this early setting of the duration does not perform such a
- * check. Moreover, the later setting of the duration at the end of this
- * function also does not perform this check because we set the
- * GES_TIMELINE_ELEMENT_SET_SIMPLE flag!
- */
_DURATION (clip) = old_duration;
g_object_notify (G_OBJECT (clip), "duration");
GESTrackElement *new_trackelement, *trackelement =
GES_TRACK_ELEMENT (tmp->data);
- new_trackelement =
- GES_TRACK_ELEMENT (ges_timeline_element_copy (GES_TIMELINE_ELEMENT
- (trackelement), FALSE));
+ new_trackelement = ges_track_element_copy_core (trackelement, FALSE);
if (new_trackelement == NULL) {
GST_WARNING_OBJECT (trackelement, "Could not create a copy");
continue;
}
- /* Set 'new' track element timing propeties */
- _set_start0 (GES_TIMELINE_ELEMENT (new_trackelement), position);
- /* FIXME: not all track elements should have their inpoint set,
- * e.g. transitions or most effects. But how can we determine
- * whether a transition should *always* have a 0 inpoint, or
- * whether a transition actually uses the inpoint, but it just so
- * happens to be set to 0? */
- _set_inpoint0 (GES_TIMELINE_ELEMENT (new_trackelement),
- inpoint + old_duration * media_duration_factor);
- _set_duration0 (GES_TIMELINE_ELEMENT (new_trackelement), new_duration);
-
ges_container_add (GES_CONTAINER (new_object),
GES_TIMELINE_ELEMENT (new_trackelement));
ges_track_element_copy_properties (GES_TIMELINE_ELEMENT (trackelement),
typedef struct _GESClipPrivate GESClipPrivate;
+/**
+ * GES_CLIP_CLASS_CAN_ADD_EFFECTS:
+ * @klass: A #GESClipClass
+ *
+ * Whether the class allows for the user to add additional non-core
+ * #GESBaseEffect-s to clips from this class.
+ */
+#define GES_CLIP_CLASS_CAN_ADD_EFFECTS(klass) ((GES_CLIP_CLASS (klass))->ABI.abi.can_add_effects)
+
/**
* GESFillTrackElementFunc:
* @clip: The #GESClip controlling the track elements
* @create_track_elements: Method to create the (multiple) core
* #GESTrackElement-s of a clip of this class. If create_track_element()
* is implemented, this should be kept as the default implementation
+ * @can_add_effects: Whether the user can add additional non-core
+ * #GESBaseEffect-s to clips from this class, to be applied to the output
+ * data of the core elements.
*/
struct _GESClipClass
{
/*< private >*/
/* Padding for API extension */
- gpointer _ges_reserved[GES_PADDING_LARGE];
+ union {
+ gpointer _ges_reserved[GES_PADDING_LARGE];
+ struct {
+ gboolean can_add_effects;
+ } abi;
+ } ABI;
};
/****************************************************
if (class->add_child) {
if (class->add_child (container, child) == FALSE) {
container->children_control_mode = GES_CHILDREN_UPDATE;
- GST_WARNING_OBJECT (container, "Erreur adding child %p", child);
+ GST_WARNING_OBJECT (container, "Error adding child %p", child);
return FALSE;
}
}
GESTimelineElement * elementcopy);
G_GNUC_INTERNAL void ges_track_element_copy_bindings (GESTrackElement *element,
- GESTrackElement *new_element,
- guint64 position);
+ GESTrackElement *new_element,
+ guint64 position);
+G_GNUC_INTERNAL GESTrackElement * ges_track_element_copy_core (GESTrackElement * self,
+ gboolean deep);
G_GNUC_INTERNAL GstElement* ges_source_create_topbin(const gchar* bin_name, GstElement* sub_element, GPtrArray* elements);
G_GNUC_INTERNAL void ges_track_set_caps(GESTrack* track,
{
GES_CLIP_IS_MOVING = (1 << 0),
GES_TIMELINE_ELEMENT_SET_SIMPLE = (1 << 1),
+ GES_TRACK_ELEMENT_IS_CORE = (1 << 2),
} GESTimelineElementFlags;
G_GNUC_INTERNAL gdouble ges_timeline_element_get_media_duration_factor(GESTimelineElement *self);
/**
* SECTION:gessourceclip
* @title: GESSourceClip
- * @short_description: Base Class for sources of a GESLayer
+ * @short_description: Base Class for sources of a #GESLayer
+ *
+ * #GESSourceClip-s are clips whose core elements are #GESSource-s.
+ *
+ * ## Effects
+ *
+ * #GESSourceClip-s can also have #GESBaseEffect-s added as non-core
+ * elements. These effects are applied to the core sources of the clip
+ * that they share a #GESTrack with. See #GESClip for how to add and move
+ * these effects from the clip.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
object_class->get_property = ges_source_clip_get_property;
object_class->set_property = ges_source_clip_set_property;
object_class->finalize = ges_source_clip_finalize;
+
+ GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass) = TRUE;
}
static void
GESTimelineElement *ret = NULL;
- g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
+ g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
/* FIXME: in both cases track_element is removed from the clip! */
g_clear_object (&existing_src);
- track_element_copy =
- GES_TRACK_ELEMENT (ges_timeline_element_copy (GES_TIMELINE_ELEMENT
- (track_element), TRUE));
+ track_element_copy = ges_track_element_copy_core (track_element, TRUE);
GST_LOG_OBJECT (timeline, "Trying to add %p to track %p",
track_element_copy, track);
g_free (specs);
}
+/* copy an element, as well as its GES_TRACK_ELEMENT_IS_CORE flag */
+GESTrackElement *
+ges_track_element_copy_core (GESTrackElement * self, gboolean deep)
+{
+ GESTimelineElement *copy =
+ ges_timeline_element_copy (GES_TIMELINE_ELEMENT (self), deep);
+ if (!copy)
+ return NULL;
+ if (ELEMENT_FLAG_IS_SET (self, GES_TRACK_ELEMENT_IS_CORE))
+ ELEMENT_SET_FLAG (copy, GES_TRACK_ELEMENT_IS_CORE);
+ return GES_TRACK_ELEMENT (copy);
+}
+
static void
_split_binding (GESTrackElement * element, GESTrackElement * new_element,
guint64 position, GstTimedValueControlSource * source,
#include <ges/ges.h>
#include <gst/check/gstcheck.h>
-void count_cb (GObject * obj, GParamSpec * pspec, gint * count);
-void test_children_time_val (GESClip * clip, const gchar * prop,
- GstClockTime val);
-void test_children_time_setter (GESClip * clip, GESTimelineElement * child,
- const gchar * prop, gboolean (*setter) (GESTimelineElement *, GstClockTime),
- GstClockTime val1, GstClockTime val2);
-void test_children_time_setting_on_clip (GESClip * clip,
- GESTimelineElement * child);
-
GST_START_TEST (test_object_properties)
{
GESClip *clip;
GST_END_TEST;
-void
-count_cb (GObject * obj, GParamSpec * pspec, gint * count)
+static void
+_count_cb (GObject * obj, GParamSpec * pspec, gint * count)
{
*count = *count + 1;
}
-void
-test_children_time_val (GESClip * clip, const gchar * prop, GstClockTime val)
-{
- GList *tmp;
- GstClockTime read_val;
-
- g_object_get (clip, prop, &read_val, NULL);
- assert_equals_uint64 (read_val, val);
- for (tmp = GES_CONTAINER_CHILDREN (clip); tmp != NULL; tmp = tmp->next) {
- g_object_get (tmp->data, prop, &read_val, NULL);
- assert_equals_uint64 (read_val, val);
- }
-}
-
-void
-test_children_time_setter (GESClip * clip, GESTimelineElement * child,
- const gchar * prop, gboolean (*setter) (GESTimelineElement *, GstClockTime),
- GstClockTime val1, GstClockTime val2)
-{
- gint clip_count = 0;
- gint child_count = 0;
- gchar *notify_name = g_strconcat ("notify::", prop, NULL);
-
- g_signal_connect (clip, notify_name, G_CALLBACK (count_cb), &clip_count);
- g_signal_connect (child, notify_name, G_CALLBACK (count_cb), &child_count);
- fail_unless (setter (GES_TIMELINE_ELEMENT (clip), val1));
- test_children_time_val (clip, prop, val1);
- assert_equals_int (clip_count, 1);
- assert_equals_int (child_count, 1);
- clip_count = 0;
- child_count = 0;
- fail_unless (setter (child, val2));
- test_children_time_val (clip, prop, val2);
- assert_equals_int (clip_count, 1);
- assert_equals_int (child_count, 1);
- assert_equals_int (g_signal_handlers_disconnect_by_func (clip,
- G_CALLBACK (count_cb), &clip_count), 1);
- assert_equals_int (g_signal_handlers_disconnect_by_func (child,
- G_CALLBACK (count_cb), &child_count), 1);
- g_free (notify_name);
+#define _assert_children_time_setter(clip, child, prop, setter, val1, val2) \
+{ \
+ gint clip_count = 0; \
+ gint child_count = 0; \
+ gchar *notify_name = g_strconcat ("notify::", prop, NULL); \
+ gchar *clip_name = GES_TIMELINE_ELEMENT_NAME (clip); \
+ gchar *child_name = NULL; \
+ g_signal_connect (clip, notify_name, G_CALLBACK (_count_cb), \
+ &clip_count); \
+ if (child) { \
+ child_name = GES_TIMELINE_ELEMENT_NAME (child); \
+ g_signal_connect (child, notify_name, G_CALLBACK (_count_cb), \
+ &child_count); \
+ } \
+ \
+ fail_unless (setter (GES_TIMELINE_ELEMENT (clip), val1), \
+ "Failed to set the %s property for clip %s", prop, clip_name); \
+ assert_clip_children_time_val (clip, prop, val1); \
+ \
+ fail_unless (clip_count == 1, "The callback for the %s property was " \
+ "called %i times for clip %s, rather than once", \
+ prop, clip_count, clip_name); \
+ if (child) { \
+ fail_unless (child_count == 1, "The callback for the %s property " \
+ "was called %i times for the child %s of clip %s, rather than " \
+ "once", prop, child_count, child_name, clip_name); \
+ } \
+ \
+ clip_count = 0; \
+ if (child) { \
+ child_count = 0; \
+ fail_unless (setter (GES_TIMELINE_ELEMENT (child), val2), \
+ "Failed to set the %s property for the child %s of clip %s", \
+ prop, child_name, clip_name); \
+ fail_unless (child_count == 1, "The callback for the %s property " \
+ "was called %i more times for the child %s of clip %s, rather " \
+ "than once more", prop, child_count, child_name, clip_name); \
+ } else { \
+ fail_unless (setter (GES_TIMELINE_ELEMENT (clip), val2), \
+ "Failed to set the %s property for clip %s", prop, clip_name); \
+ } \
+ assert_clip_children_time_val (clip, prop, val2); \
+ \
+ fail_unless (clip_count == 1, "The callback for the %s property " \
+ "was called %i more times for clip %s, rather than once more", \
+ prop, clip_count, clip_name); \
+ assert_equals_int (g_signal_handlers_disconnect_by_func (clip, \
+ G_CALLBACK (_count_cb), &clip_count), 1); \
+ if (child) { \
+ assert_equals_int (g_signal_handlers_disconnect_by_func (child, \
+ G_CALLBACK (_count_cb), &child_count), 1); \
+ } \
+ \
+ g_free (notify_name); \
}
-void
-test_children_time_setting_on_clip (GESClip * clip, GESTimelineElement * child)
+static void
+_test_children_time_setting_on_clip (GESClip * clip, GESTimelineElement * child)
{
/* FIXME: Don't necessarily want to change the inpoint of all the
* children if the clip inpoint changes. Really, we would only expect
* test should be changed to only check that source elements have
* their inpoint changed, and operation elements have their inpoint
* unchanged */
- test_children_time_setter (clip, child, "in-point",
- ges_timeline_element_set_inpoint, 23, 52);
- test_children_time_setter (clip, child, "start",
- ges_timeline_element_set_start, 43, 72);
- test_children_time_setter (clip, child, "duration",
- ges_timeline_element_set_duration, 53, 12);
+ _assert_children_time_setter (clip, child, "in-point",
+ ges_timeline_element_set_inpoint, 11, 101);
+ _assert_children_time_setter (clip, child, "in-point",
+ ges_timeline_element_set_inpoint, 51, 1);
+ _assert_children_time_setter (clip, child, "start",
+ ges_timeline_element_set_start, 12, 102);
+ _assert_children_time_setter (clip, child, "start",
+ ges_timeline_element_set_start, 52, 2);
+ _assert_children_time_setter (clip, child, "duration",
+ ges_timeline_element_set_duration, 13, 103);
+ _assert_children_time_setter (clip, child, "duration",
+ ges_timeline_element_set_duration, 53, 3);
}
GST_START_TEST (test_children_time_setters)
{
GESTimeline *timeline;
- GESTrack *audio_track, *video_track;
GESLayer *layer;
-
- GESTimelineElement *effect;
- GESClip *clips[] = {
- GES_CLIP (ges_transition_clip_new (GES_VIDEO_STANDARD_TRANSITION_TYPE_CROSSFADE)), /* operation clip */
- GES_CLIP (ges_test_clip_new ()), /* source clip */
- };
+ GESClip *clips[] = { NULL, NULL };
gint i;
ges_init ();
- audio_track = GES_TRACK (ges_audio_track_new ());
- video_track = GES_TRACK (ges_video_track_new ());
-
- timeline = ges_timeline_new ();
- fail_unless (ges_timeline_add_track (timeline, audio_track));
- fail_unless (ges_timeline_add_track (timeline, video_track));
+ timeline = ges_timeline_new_audio_video ();
+ fail_unless (timeline);
layer = ges_timeline_append_layer (timeline);
- effect = GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv"));
+ clips[0] =
+ GES_CLIP (ges_transition_clip_new
+ (GES_VIDEO_STANDARD_TRANSITION_TYPE_CROSSFADE));
+ clips[1] = GES_CLIP (ges_test_clip_new ());
for (i = 0; i < G_N_ELEMENTS (clips); i++) {
GESClip *clip = clips[i];
- fail_unless (ges_container_add (GES_CONTAINER (clip), effect));
- test_children_time_setting_on_clip (clip, effect);
+ GESContainer *group = GES_CONTAINER (ges_group_new ());
+ GList *children;
+ GESTimelineElement *child;
+ /* no children */
+ _test_children_time_setting_on_clip (clip, NULL);
+ /* child in timeline */
fail_unless (ges_layer_add_clip (layer, clip));
- test_children_time_setting_on_clip (clip, effect);
- fail_unless (ges_container_remove (GES_CONTAINER (clip), effect));
+ children = GES_CONTAINER_CHILDREN (clip);
+ fail_unless (children);
+ child = GES_TIMELINE_ELEMENT (children->data);
+ _test_children_time_setting_on_clip (clip, child);
+ /* clip in a group */
+ ges_container_add (group, GES_TIMELINE_ELEMENT (clip));
+ _test_children_time_setting_on_clip (clip, child);
+ /* group is removed from the timeline and destroyed when empty */
+ ges_container_remove (group, GES_TIMELINE_ELEMENT (clip));
+ /* child not in timeline */
+ gst_object_ref (clip);
fail_unless (ges_layer_remove_clip (layer, clip));
+ children = GES_CONTAINER_CHILDREN (clip);
+ fail_unless (children);
+ child = GES_TIMELINE_ELEMENT (children->data);
+ _test_children_time_setting_on_clip (clip, child);
+ gst_object_unref (clip);
}
- gst_object_unref (effect);
gst_object_unref (timeline);
ges_deinit ();
GST_END_TEST;
+GST_START_TEST (test_can_add_effect)
+{
+ struct CanAddEffectData
+ {
+ GESClip *clip;
+ gboolean can_add_effect;
+ } clips[6];
+ guint i;
+ gchar *uri;
+
+ ges_init ();
+
+ uri = ges_test_get_audio_video_uri ();
+
+ clips[0] = (struct CanAddEffectData) {
+ GES_CLIP (ges_test_clip_new ()), TRUE};
+ clips[1] = (struct CanAddEffectData) {
+ GES_CLIP (ges_uri_clip_new (uri)), TRUE};
+ clips[2] = (struct CanAddEffectData) {
+ GES_CLIP (ges_title_clip_new ()), TRUE};
+ clips[3] = (struct CanAddEffectData) {
+ GES_CLIP (ges_effect_clip_new ("agingtv", "audioecho")), TRUE};
+ clips[4] = (struct CanAddEffectData) {
+ GES_CLIP (ges_transition_clip_new
+ (GES_VIDEO_STANDARD_TRANSITION_TYPE_CROSSFADE)), FALSE};
+ clips[5] = (struct CanAddEffectData) {
+ GES_CLIP (ges_text_overlay_clip_new ()), FALSE};
+
+ g_free (uri);
+
+ for (i = 0; i < G_N_ELEMENTS (clips); i++) {
+ GESClip *clip = clips[i].clip;
+ GESTimelineElement *effect =
+ GES_TIMELINE_ELEMENT (ges_effect_new ("agingtv"));
+ gst_object_ref_sink (effect);
+ gst_object_ref_sink (clip);
+ fail_unless (clip);
+ if (clips[i].can_add_effect)
+ fail_unless (ges_container_add (GES_CONTAINER (clip), effect),
+ "Could not add an effect to clip %s",
+ GES_TIMELINE_ELEMENT_NAME (clip));
+ else
+ fail_if (ges_container_add (GES_CONTAINER (clip), effect),
+ "Could add an effect to clip %s, but we expect this to fail",
+ GES_TIMELINE_ELEMENT_NAME (clip));
+ gst_object_unref (effect);
+ gst_object_unref (clip);
+ }
+
+ ges_deinit ();
+}
+
+GST_END_TEST;
static Suite *
ges_suite (void)
tcase_add_test (tc_chain, test_clip_find_track_element);
tcase_add_test (tc_chain, test_effects_priorities);
tcase_add_test (tc_chain, test_children_time_setters);
+ tcase_add_test (tc_chain, test_can_add_effect);
return s;
}
GESLayer *layer;
GESTrack *track_audio, *track_video;
GESEffectClip *effect_clip;
- GESEffect *effect, *effect1;
- GList *effects, *tmp;
- gint i, clip_height;
- gint effect_prio = -1;
- /* FIXME the order of track type is not well defined */
- guint track_type[4] = { GES_TRACK_TYPE_AUDIO,
- GES_TRACK_TYPE_VIDEO, GES_TRACK_TYPE_VIDEO,
- GES_TRACK_TYPE_AUDIO
- };
+ GESEffect *effect, *effect1, *core_effect, *core_effect1;
+ GList *children, *top_effects, *tmp;
+ gint clip_height;
+ gint core_effect_prio;
+ gint effect_index, effect1_index;
ges_init ();
ges_timeline_add_layer (timeline, layer);
GST_DEBUG ("Create effect");
- effect_clip = ges_effect_clip_new ("agingtv", "audiopanorama");
+ /* these are the core video and audio effects for the clip */
+ effect_clip = ges_effect_clip_new ("videobalance", "audioecho");
g_object_set (effect_clip, "duration", 25 * GST_SECOND, NULL);
ges_layer_add_clip (layer, (GESClip *) effect_clip);
+ /* core elements should now be created */
+ fail_unless (children = GES_CONTAINER_CHILDREN (effect_clip));
+ core_effect = GES_EFFECT (children->data);
+ fail_unless (children = children->next);
+ core_effect1 = GES_EFFECT (children->data);
+ fail_unless (children->next == NULL);
+
+ /* both effects are placed at the same priority since they are core
+ * children of the clip, destined for different tracks */
+ core_effect_prio = _PRIORITY (core_effect);
+ assert_equals_int (core_effect_prio, _PRIORITY (core_effect1));
+ g_object_get (effect_clip, "height", &clip_height, NULL);
+ assert_equals_int (clip_height, 1);
+
+ /* add additional non-core effects */
effect = ges_effect_new ("agingtv");
fail_unless (ges_container_add (GES_CONTAINER (effect_clip),
GES_TIMELINE_ELEMENT (effect)));
fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (effect)) ==
track_video);
+ /* placed at a higher priority than the effects */
+ core_effect_prio = _PRIORITY (core_effect);
+ assert_equals_int (core_effect_prio, _PRIORITY (core_effect1));
+ fail_unless (_PRIORITY (effect) < core_effect_prio);
g_object_get (effect_clip, "height", &clip_height, NULL);
- assert_equals_int (clip_height, 3);
+ assert_equals_int (clip_height, 2);
+
+ effect_index =
+ ges_clip_get_top_effect_index (GES_CLIP (effect_clip),
+ GES_BASE_EFFECT (effect));
+ assert_equals_int (effect_index, 0);
+ /* 'effect1' is placed in between the core children and 'effect' */
effect1 = ges_effect_new ("audiopanorama");
fail_unless (ges_container_add (GES_CONTAINER (effect_clip),
GES_TIMELINE_ELEMENT (effect1)));
fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (effect1)) ==
track_audio);
+ /* 'effect' is still the highest priority effect, and the core
+ * elements are at the lowest priority */
+ core_effect_prio = _PRIORITY (core_effect);
+ assert_equals_int (core_effect_prio, _PRIORITY (core_effect1));
+ fail_unless (_PRIORITY (effect1) < core_effect_prio);
+ fail_unless (_PRIORITY (effect1) > _PRIORITY (effect));
g_object_get (effect_clip, "height", &clip_height, NULL);
- assert_equals_int (clip_height, 4);
-
- effects = ges_clip_get_top_effects (GES_CLIP (effect_clip));
- for (tmp = effects, i = 0; tmp; tmp = tmp->next, i++) {
- gint priority = ges_clip_get_top_effect_position (GES_CLIP (effect_clip),
- GES_BASE_EFFECT (tmp->data));
- fail_unless (priority > effect_prio);
- fail_unless (GES_IS_EFFECT (tmp->data));
- fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (tmp->data))->
- type == track_type[i]);
- effect_prio = priority;
-
- gst_object_unref (tmp->data);
- }
- g_list_free (effects);
+ assert_equals_int (clip_height, 3);
- ges_layer_remove_clip (layer, (GESClip *) effect_clip);
+ effect_index =
+ ges_clip_get_top_effect_index (GES_CLIP (effect_clip),
+ GES_BASE_EFFECT (effect));
+ effect1_index =
+ ges_clip_get_top_effect_index (GES_CLIP (effect_clip),
+ GES_BASE_EFFECT (effect1));
+ assert_equals_int (effect_index, 0);
+ assert_equals_int (effect1_index, 1);
+
+ /* all effects are children of the effect_clip, ordered by priority */
+ fail_unless (children = GES_CONTAINER_CHILDREN (effect_clip));
+ fail_unless (children->data == effect);
+ fail_unless (children = children->next);
+ fail_unless (children->data == effect1);
+ fail_unless (children = children->next);
+ fail_unless (children->data == core_effect);
+ fail_unless (children = children->next);
+ fail_unless (children->data == core_effect1);
+ fail_unless (children->next == NULL);
+
+ /* but only the additional effects are part of the top effects */
+ top_effects = ges_clip_get_top_effects (GES_CLIP (effect_clip));
+ fail_unless (tmp = top_effects);
+ fail_unless (tmp->data == effect);
+ fail_unless (tmp = tmp->next);
+ fail_unless (tmp->data == effect1);
+ fail_unless (tmp->next == NULL);
+
+ g_list_free_full (top_effects, gst_object_unref);
gst_object_unref (timeline);
GST_START_TEST (test_priorities_clip)
{
- GList *effects, *tmp;
+ GList *top_effects, *tmp;
GESTimeline *timeline;
GESLayer *layer;
- GESEffectClip *effect_clip;
- GESTrack *track_audio, *track_video;
- GESEffect *effect, *effect1, *audio_effect = NULL, *video_effect = NULL;
-
- gint effect_prio = -1;
+ GESClip *effect_clip;
+ GESTrack *track_audio, *track_video, *track;
+ GESBaseEffect *effects[6], *audio_effect = NULL, *video_effect = NULL;
+ gint prev_index, i, num_effects = G_N_ELEMENTS (effects);
+ guint32 base_prio = MIN_NLE_PRIO + TRANSITIONS_HEIGHT;
ges_init ();
ges_timeline_add_layer (timeline, layer);
GST_DEBUG ("Create effect");
- effect_clip = ges_effect_clip_new ("agingtv", "audiopanorama");
+ effect_clip = GES_CLIP (ges_effect_clip_new ("videobalance", "audioecho"));
g_object_set (effect_clip, "duration", 25 * GST_SECOND, NULL);
}
fail_unless (GES_IS_EFFECT (audio_effect));
fail_unless (GES_IS_EFFECT (video_effect));
+ fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (audio_effect)) ==
+ track_audio);
+ fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (video_effect)) ==
+ track_video);
- /* FIXME This is ridiculus, both effects should have the same priority */
- assert_equals_int (_PRIORITY (audio_effect),
- MIN_NLE_PRIO + TRANSITIONS_HEIGHT);
- assert_equals_int (_PRIORITY (video_effect),
- MIN_NLE_PRIO + TRANSITIONS_HEIGHT + 1);
- assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 2);
+ /* both the core effects have the same priority */
+ assert_equals_int (_PRIORITY (audio_effect), base_prio);
+ assert_equals_int (_PRIORITY (video_effect), base_prio);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 1);
+
+ /* can not change their priority using the top effect methods since
+ * they are not top effects */
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, audio_effect, 1)
+ == FALSE);
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, video_effect, 0)
+ == FALSE);
+
+ /* adding non-core effects */
+ GST_DEBUG ("Adding effects to the effect clip ");
+ for (i = 0; i < num_effects; i++) {
+ if (i % 2)
+ effects[i] = GES_BASE_EFFECT (ges_effect_new ("agingtv"));
+ else
+ effects[i] = GES_BASE_EFFECT (ges_effect_new ("audiopanorama"));
+ fail_unless (ges_container_add (GES_CONTAINER (effect_clip),
+ GES_TIMELINE_ELEMENT (effects[i])));
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 2 + i);
+ track = ges_track_element_get_track (GES_TRACK_ELEMENT (effects[i]));
+ if (i % 2)
+ fail_unless (track == track_video);
+ else
+ fail_unless (track == track_audio);
+ }
- effect = ges_effect_new ("agingtv");
- GST_DEBUG ("Adding effect to the effect clip %" GST_PTR_FORMAT, effect);
- fail_unless (ges_container_add (GES_CONTAINER (effect_clip),
- GES_TIMELINE_ELEMENT (effect)));
- fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (effect)) ==
- track_video);
- assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 3);
+ /* change top effect index */
+ for (i = 0; i < num_effects; i++) {
+ assert_equals_int (ges_clip_get_top_effect_index (effect_clip, effects[i]),
+ i);
+ assert_equals_int (_PRIORITY (effects[i]), i + base_prio);
+ }
- effect1 = ges_effect_new ("audiopanorama");
- GST_DEBUG ("Adding effect1 to the effect clip %" GST_PTR_FORMAT, effect1);
- fail_unless (ges_container_add (GES_CONTAINER (effect_clip),
- GES_TIMELINE_ELEMENT (effect1)));
- fail_unless (ges_track_element_get_track (GES_TRACK_ELEMENT (effect1)) ==
- track_audio);
+ assert_equals_int (_PRIORITY (video_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (audio_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (effect_clip), 1);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), num_effects + 1);
+
+ /* moving 4th effect to index 1 should only change the priority of
+ * effects 1, 2, 3, and 4 because these lie between the new index (1)
+ * and the old index (4). */
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, effects[4], 1));
+
+ assert_equals_int (_PRIORITY (effects[0]), 0 + base_prio);
+ assert_equals_int (_PRIORITY (effects[1]), 2 + base_prio);
+ assert_equals_int (_PRIORITY (effects[2]), 3 + base_prio);
+ assert_equals_int (_PRIORITY (effects[3]), 4 + base_prio);
+ assert_equals_int (_PRIORITY (effects[4]), 1 + base_prio);
+ assert_equals_int (_PRIORITY (effects[5]), 5 + base_prio);
+
+ /* everything else stays the same */
+ assert_equals_int (_PRIORITY (video_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (audio_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (effect_clip), 1);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), num_effects + 1);
- fail_unless (ges_clip_set_top_effect_priority (GES_CLIP (effect_clip),
- GES_BASE_EFFECT (effect1), 0));
+ /* move back */
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, effects[4], 4));
+
+ for (i = 0; i < num_effects; i++) {
+ assert_equals_int (ges_clip_get_top_effect_index (effect_clip, effects[i]),
+ i);
+ assert_equals_int (_PRIORITY (effects[i]), i + base_prio);
+ }
+
+ assert_equals_int (_PRIORITY (video_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (audio_effect), num_effects + base_prio);
assert_equals_int (_PRIORITY (effect_clip), 1);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), num_effects + 1);
- assert_equals_int (_PRIORITY (effect), 3 + MIN_NLE_PRIO + TRANSITIONS_HEIGHT);
- assert_equals_int (_PRIORITY (effect1),
- 0 + MIN_NLE_PRIO + TRANSITIONS_HEIGHT);
+ /* moving 2nd effect to index 4 should only change the priority of
+ * effects 2, 3 and 4 because these lie between the new index (4) and
+ * the old index (2). */
- assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 4);
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, effects[2], 4));
- fail_unless (ges_clip_set_top_effect_priority (GES_CLIP (effect_clip),
- GES_BASE_EFFECT (effect1), 3));
- assert_equals_int (_PRIORITY (effect), 2 + MIN_NLE_PRIO + TRANSITIONS_HEIGHT);
- assert_equals_int (_PRIORITY (effect1),
- 3 + MIN_NLE_PRIO + TRANSITIONS_HEIGHT);
- assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 4);
+ assert_equals_int (_PRIORITY (effects[0]), 0 + base_prio);
+ assert_equals_int (_PRIORITY (effects[1]), 1 + base_prio);
+ assert_equals_int (_PRIORITY (effects[2]), 4 + base_prio);
+ assert_equals_int (_PRIORITY (effects[3]), 2 + base_prio);
+ assert_equals_int (_PRIORITY (effects[4]), 3 + base_prio);
+ assert_equals_int (_PRIORITY (effects[5]), 5 + base_prio);
- effects = ges_clip_get_top_effects (GES_CLIP (effect_clip));
- for (tmp = effects; tmp; tmp = tmp->next) {
- gint priority = ges_clip_get_top_effect_position (GES_CLIP (effect_clip),
- GES_BASE_EFFECT (tmp->data));
- fail_unless (priority > effect_prio);
- fail_unless (GES_IS_EFFECT (tmp->data));
- effect_prio = priority;
+ /* everything else stays the same */
+ assert_equals_int (_PRIORITY (video_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (audio_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (effect_clip), 1);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), num_effects + 1);
- gst_object_unref (tmp->data);
- }
- g_list_free (effects);
+ /* move 4th effect to index 0 should only change the priority of
+ * effects 0, 1, 3 and 4 because these lie between the new index (0) and
+ * the old index (3) */
- assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), 4);
- effects = ges_clip_get_top_effects (GES_CLIP (effect_clip));
- effect_prio = 0;
- for (tmp = effects; tmp; tmp = tmp->next) {
- gint priority = ges_clip_get_top_effect_position (GES_CLIP (effect_clip),
+ fail_unless (ges_clip_set_top_effect_index (effect_clip, effects[4], 0));
+
+ assert_equals_int (_PRIORITY (effects[0]), 1 + base_prio);
+ assert_equals_int (_PRIORITY (effects[1]), 2 + base_prio);
+ assert_equals_int (_PRIORITY (effects[2]), 4 + base_prio);
+ assert_equals_int (_PRIORITY (effects[3]), 3 + base_prio);
+ assert_equals_int (_PRIORITY (effects[4]), 0 + base_prio);
+ assert_equals_int (_PRIORITY (effects[5]), 5 + base_prio);
+
+ /* everything else stays the same */
+ assert_equals_int (_PRIORITY (video_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (audio_effect), num_effects + base_prio);
+ assert_equals_int (_PRIORITY (effect_clip), 1);
+ assert_equals_int (GES_CONTAINER_HEIGHT (effect_clip), num_effects + 1);
+
+ /* make sure top effects are ordered by index */
+ top_effects = ges_clip_get_top_effects (effect_clip);
+ prev_index = -1;
+ for (tmp = top_effects; tmp; tmp = tmp->next) {
+ gint index = ges_clip_get_top_effect_index (effect_clip,
GES_BASE_EFFECT (tmp->data));
- fail_unless (priority >= effect_prio, "%d >= %d", priority, effect_prio);
+ fail_unless (index >= 0);
+ fail_unless (index > prev_index);
fail_unless (GES_IS_EFFECT (tmp->data));
- effect_prio = priority;
-
- gst_object_unref (tmp->data);
+ prev_index = index;
}
- g_list_free (effects);
-
- ges_layer_remove_clip (layer, (GESClip *) effect_clip);
+ g_list_free_full (top_effects, gst_object_unref);
gst_object_unref (timeline);
ges_init ();
timeline = ges_timeline_new ();
- layer = ges_layer_new ();
+ layer = ges_timeline_append_layer (timeline);
track_video = GES_TRACK (ges_video_track_new ());
g_object_set (timeline, "auto-transition", TRUE, NULL);
assert_equals_uint64 (GES_TIMELINE_ELEMENT_PRIORITY (source), 4);
nclip = ges_clip_split (clip, GST_SECOND);
+ fail_unless (nclip);
neffect = ges_clip_find_track_element (nclip, NULL, GES_TYPE_EFFECT);
nsource = ges_clip_find_track_element (nclip, NULL, GES_TYPE_VIDEO_SOURCE);
fail_unless (_DURATION (obj) == duration, "%s duration is %" GST_TIME_FORMAT " != %" GST_TIME_FORMAT, GES_TIMELINE_ELEMENT_NAME(obj), GST_TIME_ARGS (_DURATION(obj)), GST_TIME_ARGS (duration));\
}
+/* assert that the time property (start, duration or in-point) is the
+ * same as @cmp for the clip and all its children */
+#define assert_clip_children_time_val(clip, property, cmp) \
+{ \
+ GList *tmp; \
+ GstClockTime read_val; \
+ gchar *name = GES_TIMELINE_ELEMENT (clip)->name; \
+ g_object_get (clip, property, &read_val, NULL); \
+ fail_unless (read_val == cmp, "The %s property for clip %s is %" \
+ GST_TIME_FORMAT ", rather than the expected value of %" \
+ GST_TIME_FORMAT, property, name, GST_TIME_ARGS (read_val), \
+ GST_TIME_ARGS (cmp)); \
+ for (tmp = GES_CONTAINER_CHILDREN (clip); tmp != NULL; \
+ tmp = tmp->next) { \
+ GESTimelineElement *child = tmp->data; \
+ g_object_get (child, property, &read_val, NULL); \
+ fail_unless (read_val == cmp, "The %s property for the child %s " \
+ "of clip %s is %" GST_TIME_FORMAT ", rather than the expected " \
+ "value of %" GST_TIME_FORMAT, property, child->name, name, \
+ GST_TIME_ARGS (read_val), GST_TIME_ARGS (cmp)); \
+ } \
+}
+
#define check_layer(clip, layer_prio) { \
fail_unless (GES_TIMELINE_ELEMENT_LAYER_PRIORITY (clip) == (layer_prio), \
"%s in layer %d instead of %d", GES_TIMELINE_ELEMENT_NAME (clip), \