mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-07-04 05:35:53 +00:00
ges: Implement a GESGroup class, subclass of GESContainer
The GESGroup class is used to group various GESContainer together, it can contain either GESClips or GESGroup or both.
This commit is contained in:
parent
d3e3871440
commit
a933d9540d
|
@ -61,6 +61,7 @@ platform as well as Windows. It is released under the GNU Library General Public
|
|||
<xi:include href="xml/ges-text-overlay-clip.xml"/>
|
||||
<xi:include href="xml/ges-transition-clip.xml"/>
|
||||
<xi:include href="xml/ges-effect-clip.xml"/>
|
||||
<xi:include href="xml/ges-group.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
|
|
|
@ -1091,6 +1091,23 @@ GES_IS_URI_CLIP_ASSET_CLASS
|
|||
GES_URI_CLIP_ASSET_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>ges-group</FILE>
|
||||
<TITLE>GESGroup</TITLE>
|
||||
GESGroup
|
||||
ges_group_new
|
||||
<SUBSECTION Standard>
|
||||
GESGroupClass
|
||||
GESGroupPrivate
|
||||
GES_GROUP
|
||||
GES_IS_GROUP
|
||||
GES_TYPE_GROUP
|
||||
ges_group_get_type
|
||||
GES_GROUP_CLASS
|
||||
GES_IS_GROUP_CLASS
|
||||
GES_GROUP_GET_CLASS
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>ges-asset-track-file-source</FILE>
|
||||
<TITLE>GESUriSourceAsset</TITLE>
|
||||
|
|
|
@ -64,6 +64,7 @@ libges_@GST_API_VERSION@_la_SOURCES = \
|
|||
ges-smart-adder.c \
|
||||
ges-smart-video-mixer.c \
|
||||
ges-utils.c \
|
||||
ges-group.c \
|
||||
gstframepositionner.c
|
||||
|
||||
libges_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/ges/
|
||||
|
@ -125,6 +126,7 @@ libges_@GST_API_VERSION@include_HEADERS = \
|
|||
ges-smart-adder.h \
|
||||
ges-smart-video-mixer.h \
|
||||
ges-utils.h \
|
||||
ges-group.h \
|
||||
gstframepositionner.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
|
|
|
@ -686,7 +686,9 @@ ges_clip_class_init (GESClipClass * klass)
|
|||
/**
|
||||
* GESClip:layer:
|
||||
*
|
||||
* The GESLayer where this clip is being used.
|
||||
* The GESLayer where this clip is being used. If you want to connect to its
|
||||
* notify signal you should connect to it with g_signal_connect_after as the
|
||||
* signal emission can be stop in the first fase.
|
||||
*/
|
||||
properties[PROP_LAYER] = g_param_spec_object ("layer", "Layer",
|
||||
"The GESLayer where this clip is being used.",
|
||||
|
|
|
@ -325,8 +325,11 @@ _child_start_changed_cb (GESTimelineElement * child,
|
|||
map = g_hash_table_lookup (priv->mappings, child);
|
||||
g_assert (map);
|
||||
|
||||
GST_FIXME_OBJECT (container, "We should make sure that our child does not"
|
||||
"involve our start becoming < 0. In that case, undo the child move.");
|
||||
if (container->children_control_mode == GES_CHILDREN_UPDATE_OFFSETS) {
|
||||
map->start_offset = _START (container) - _START (child);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* We update all the children calling our set_start method */
|
||||
container->initiated_move = child;
|
||||
|
@ -349,6 +352,12 @@ _child_inpoint_changed_cb (GESTimelineElement * child,
|
|||
map = g_hash_table_lookup (priv->mappings, child);
|
||||
g_assert (map);
|
||||
|
||||
if (container->children_control_mode == GES_CHILDREN_UPDATE_OFFSETS) {
|
||||
map->inpoint_offset = _START (container) - _START (child);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* We update all the children calling our set_inpoint method */
|
||||
container->initiated_move = child;
|
||||
_set_inpoint0 (element, _INPOINT (child) + map->inpoint_offset);
|
||||
|
@ -370,6 +379,12 @@ _child_duration_changed_cb (GESTimelineElement * child,
|
|||
map = g_hash_table_lookup (priv->mappings, child);
|
||||
g_assert (map);
|
||||
|
||||
if (container->children_control_mode == GES_CHILDREN_UPDATE_OFFSETS) {
|
||||
map->inpoint_offset = _START (container) - _START (child);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* We update all the children calling our set_duration method */
|
||||
container->initiated_move = child;
|
||||
_set_duration0 (element, _DURATION (child) + map->duration_offset);
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef enum
|
|||
GES_CHILDREN_UPDATE,
|
||||
GES_CHILDREN_IGNORE_NOTIFIES,
|
||||
GES_CHILDREN_UPDATE_OFFSETS,
|
||||
GES_CHILDREN_LAST
|
||||
} GESChildrenControlMode;
|
||||
|
||||
/**
|
||||
|
|
550
ges/ges-group.c
Normal file
550
ges/ges-group.c
Normal file
|
@ -0,0 +1,550 @@
|
|||
/* GStreamer Editing Services
|
||||
* Copyright (C) 2013 Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:ges-group
|
||||
* @short_description: Class that permits to group GESClip-s in a timeline,
|
||||
* letting the user manage it a single GESTimelineElement
|
||||
*
|
||||
* A #GESGroup is an object which controls one or more
|
||||
* #GESClips in one or more #GESLayer(s).
|
||||
*
|
||||
* To instanciate a group, you should use the ges_container_group method,
|
||||
* this will be responsible for deciding what subclass of #GESContainer
|
||||
* should be instaciated to group the various #GESTimelineElement passed
|
||||
* in parametter.
|
||||
*/
|
||||
|
||||
#include "ges-group.h"
|
||||
#include "ges.h"
|
||||
#include "ges-internal.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define parent_class ges_group_parent_class
|
||||
G_DEFINE_TYPE (GESGroup, ges_group, GES_TYPE_CONTAINER);
|
||||
|
||||
#define GES_CHILDREN_INIBIT_SIGNAL_EMISSION (GES_CHILDREN_LAST + 1)
|
||||
|
||||
struct _GESGroupPrivate
|
||||
{
|
||||
gboolean reseting_start;
|
||||
|
||||
guint32 max_layer_prio;
|
||||
|
||||
/* This is used while were are setting ourselve a proper timing value,
|
||||
* in this case the value should always be kept */
|
||||
gboolean setting_value;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
/* static GParamSpec *properties[PROP_LAST]; */
|
||||
|
||||
/****************************************************
|
||||
* Our listening of children *
|
||||
****************************************************/
|
||||
static void
|
||||
_update_our_values (GESGroup * group)
|
||||
{
|
||||
GList *tmp;
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
guint32 min_layer_prio = G_MAXINT32, max_layer_prio = 0;
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
GESContainer *child = tmp->data;
|
||||
|
||||
if (GES_IS_CLIP (child)) {
|
||||
GESLayer *layer = ges_clip_get_layer (GES_CLIP (child));
|
||||
gint32 prio = ges_layer_get_priority (layer);
|
||||
|
||||
min_layer_prio = MIN (prio, min_layer_prio);
|
||||
max_layer_prio = MAX (prio, max_layer_prio);
|
||||
} else if (GES_IS_GROUP (child)) {
|
||||
gint32 prio = _PRIORITY (child), height = GES_CONTAINER_HEIGHT (child);
|
||||
|
||||
min_layer_prio = MIN (prio, min_layer_prio);
|
||||
max_layer_prio = MAX ((prio + height), max_layer_prio);
|
||||
}
|
||||
}
|
||||
|
||||
if (min_layer_prio != _PRIORITY (group)) {
|
||||
group->priv->setting_value = TRUE;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), min_layer_prio);
|
||||
group->priv->setting_value = FALSE;
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
guint32 child_prio = GES_IS_CLIP (child) ?
|
||||
ges_clip_get_layer_priority (GES_CLIP (child)) : _PRIORITY (child);
|
||||
|
||||
_ges_container_set_priority_offset (container,
|
||||
child, min_layer_prio - child_prio);
|
||||
}
|
||||
}
|
||||
|
||||
group->priv->max_layer_prio = max_layer_prio;
|
||||
_ges_container_set_height (GES_CONTAINER (group),
|
||||
max_layer_prio - min_layer_prio + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
_child_clip_changed_layer_cb (GESTimelineElement * clip,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
|
||||
{
|
||||
gint offset, layer_prio = ges_clip_get_layer_priority (GES_CLIP (clip));
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
|
||||
if (container->children_control_mode != GES_CHILDREN_UPDATE) {
|
||||
if (container->children_control_mode == GES_CHILDREN_INIBIT_SIGNAL_EMISSION) {
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
g_signal_stop_emission_by_name (clip, "notify::layer");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
offset = _ges_container_get_priority_offset (container, clip);
|
||||
|
||||
if (layer_prio + offset < 0 ||
|
||||
(GES_TIMELINE_ELEMENT_TIMELINE (group) &&
|
||||
layer_prio + offset + GES_CONTAINER_HEIGHT (group) - 1 >
|
||||
g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers))) {
|
||||
GESLayer *old_layer =
|
||||
g_list_nth_data (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers,
|
||||
_PRIORITY (group) - offset);
|
||||
|
||||
GST_INFO_OBJECT (container, "Trying to move to a layer outside of"
|
||||
"the timeline layers, moving back to old layer (prio %i)",
|
||||
_PRIORITY (group) - offset);
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_INIBIT_SIGNAL_EMISSION;
|
||||
ges_clip_move_to_layer (GES_CLIP (clip), old_layer);
|
||||
g_signal_stop_emission_by_name (clip, "notify::layer");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
container->initiated_move = clip;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), layer_prio + offset);
|
||||
container->initiated_move = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_child_group_priority_changed (GESTimelineElement * child,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
|
||||
{
|
||||
gint offset;
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
|
||||
if (container->children_control_mode != GES_CHILDREN_UPDATE) {
|
||||
GST_DEBUG_OBJECT (group, "Ignoring updated");
|
||||
return;
|
||||
}
|
||||
|
||||
offset = _ges_container_get_priority_offset (container, child);
|
||||
|
||||
if (_PRIORITY (group) + offset < 0 ||
|
||||
(GES_TIMELINE_ELEMENT_TIMELINE (group) &&
|
||||
_PRIORITY (group) + offset + GES_CONTAINER_HEIGHT (group) >
|
||||
g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers))) {
|
||||
|
||||
GST_WARNING_OBJECT (container, "Trying to move to a layer outside of"
|
||||
"the timeline layers");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
container->initiated_move = child;
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (group), _PRIORITY (child) + offset);
|
||||
container->initiated_move = NULL;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* GESTimelineElement vmethods *
|
||||
****************************************************/
|
||||
static gboolean
|
||||
_trim (GESTimelineElement * group, GstClockTime start)
|
||||
{
|
||||
GList *tmp;
|
||||
GstClockTime last_child_end = 0;
|
||||
GESContainer *container = GES_CONTAINER (group);
|
||||
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (group);
|
||||
gboolean ret = TRUE, expending = (start < _START (group));
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
|
||||
if (expending) {
|
||||
/* If the start if bigger, we do not touch it (in case we are expending)
|
||||
*/
|
||||
if (_START (child) > _START (group))
|
||||
continue;
|
||||
ret &= ges_timeline_element_trim (child, start);
|
||||
} else {
|
||||
if (start > _END (child))
|
||||
ret &= ges_timeline_element_trim (child, _END (child));
|
||||
else if (_START (child) < start && _DURATION (child))
|
||||
ret &= ges_timeline_element_trim (child, start);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
|
||||
if (_DURATION (tmp->data))
|
||||
last_child_end =
|
||||
MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
|
||||
}
|
||||
|
||||
GES_GROUP (group)->priv->setting_value = TRUE;
|
||||
_set_start0 (group, start);
|
||||
_set_duration0 (group, last_child_end - start);
|
||||
GES_GROUP (group)->priv->setting_value = FALSE;
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_priority (GESTimelineElement * element, guint32 priority)
|
||||
{
|
||||
GList *tmp, *layers;
|
||||
gint diff = priority - _PRIORITY (element);
|
||||
GESContainer *container = GES_CONTAINER (element);
|
||||
|
||||
if (GES_GROUP (element)->priv->setting_value == TRUE)
|
||||
return TRUE;
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
layers = GES_TIMELINE_ELEMENT_TIMELINE (element) ?
|
||||
GES_TIMELINE_ELEMENT_TIMELINE (element)->layers : NULL;
|
||||
|
||||
if (layers == NULL) {
|
||||
GST_WARNING_OBJECT (element, "Not any layer in the timeline, not doing"
|
||||
"anything, timeline: %" GST_PTR_FORMAT,
|
||||
GES_TIMELINE_ELEMENT_TIMELINE (element));
|
||||
|
||||
return FALSE;
|
||||
} else if (priority + GES_CONTAINER_HEIGHT (container) - 1 >
|
||||
g_list_length (layers)) {
|
||||
GST_WARNING_OBJECT (container, "Trying to move to a layer outside of"
|
||||
"the timeline layers");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
|
||||
if (child != container->initiated_move) {
|
||||
if (GES_IS_CLIP (child)) {
|
||||
guint32 layer_prio =
|
||||
ges_clip_get_layer_priority (GES_CLIP (child)) + diff;
|
||||
|
||||
GST_DEBUG_OBJECT (child, "moving from layer: %i to %i",
|
||||
ges_clip_get_layer_priority (GES_CLIP (child)), layer_prio);
|
||||
ges_clip_move_to_layer (GES_CLIP (child),
|
||||
g_list_nth_data (layers, layer_prio));
|
||||
} else if (GES_IS_GROUP (child)) {
|
||||
GST_DEBUG_OBJECT (child, "moving from %i to %i",
|
||||
_PRIORITY (child), diff + _PRIORITY (child));
|
||||
ges_timeline_element_set_priority (child, diff + _PRIORITY (child));
|
||||
}
|
||||
}
|
||||
}
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_start (GESTimelineElement * element, GstClockTime start)
|
||||
{
|
||||
GList *tmp;
|
||||
gint64 diff = start - _START (element);
|
||||
GESContainer *container = GES_CONTAINER (element);
|
||||
|
||||
if (GES_GROUP (element)->priv->setting_value == TRUE)
|
||||
/* Let GESContainer update itself */
|
||||
return GES_TIMELINE_ELEMENT_CLASS (parent_class)->set_start (element,
|
||||
start);
|
||||
|
||||
|
||||
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = (GESTimelineElement *) tmp->data;
|
||||
|
||||
if (child != container->initiated_move &&
|
||||
(_END (child) > _START (element) || _END (child) > start)) {
|
||||
_set_start0 (child, _START (child) + diff);
|
||||
}
|
||||
}
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_set_duration (GESTimelineElement * element, GstClockTime duration)
|
||||
{
|
||||
GList *tmp;
|
||||
GstClockTime last_child_end = 0, new_end;
|
||||
GESContainer *container = GES_CONTAINER (element);
|
||||
GESGroupPrivate *priv = GES_GROUP (element)->priv;
|
||||
|
||||
if (priv->setting_value == TRUE)
|
||||
/* Let GESContainer update itself */
|
||||
return GES_TIMELINE_ELEMENT_CLASS (parent_class)->set_duration (element,
|
||||
duration);
|
||||
|
||||
if (container->initiated_move == NULL) {
|
||||
gboolean expending = (_DURATION (element) < duration);
|
||||
|
||||
new_end = _START (element) + duration;
|
||||
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
GstClockTime n_dur;
|
||||
|
||||
if ((!expending && _END (child) > new_end) ||
|
||||
(expending && (_END (child) >= _END (element)))) {
|
||||
n_dur = MAX (0, ((gint64) (new_end - _START (child))));
|
||||
_set_duration0 (child, n_dur);
|
||||
}
|
||||
}
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
}
|
||||
|
||||
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
|
||||
if (_DURATION (tmp->data))
|
||||
last_child_end =
|
||||
MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
|
||||
}
|
||||
|
||||
priv->setting_value = TRUE;
|
||||
_set_duration0 (element, last_child_end - _START (element));
|
||||
priv->setting_value = FALSE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* *
|
||||
* GESContainer virtual methods implementation *
|
||||
* *
|
||||
****************************************************/
|
||||
|
||||
static gboolean
|
||||
_add_child (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
g_return_val_if_fail (GES_IS_CONTAINER (child), FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_child_added (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
GList *children, *tmp;
|
||||
|
||||
GESGroupPrivate *priv = GES_GROUP (group)->priv;
|
||||
GstClockTime last_child_end = 0, first_child_start = G_MAXUINT64;
|
||||
|
||||
children = GES_CONTAINER_CHILDREN (group);
|
||||
|
||||
for (tmp = children; tmp; tmp = tmp->next) {
|
||||
last_child_end = MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
|
||||
first_child_start =
|
||||
MIN (GES_TIMELINE_ELEMENT_START (tmp->data), first_child_start);
|
||||
}
|
||||
|
||||
priv->setting_value = TRUE;
|
||||
if (first_child_start != GES_TIMELINE_ELEMENT_START (group)) {
|
||||
group->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
_set_start0 (GES_TIMELINE_ELEMENT (group), first_child_start);
|
||||
}
|
||||
|
||||
if (last_child_end != GES_TIMELINE_ELEMENT_END (group)) {
|
||||
_set_duration0 (GES_TIMELINE_ELEMENT (group),
|
||||
last_child_end - first_child_start);
|
||||
}
|
||||
priv->setting_value = FALSE;
|
||||
|
||||
group->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
_update_our_values (GES_GROUP (group));
|
||||
|
||||
if (GES_IS_CLIP (child)) {
|
||||
g_signal_connect (child, "notify::layer",
|
||||
(GCallback) _child_clip_changed_layer_cb, group);
|
||||
} else if (GES_IS_GROUP (child), group) {
|
||||
g_signal_connect (child, "notify::priority",
|
||||
(GCallback) _child_group_priority_changed, group);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_child_removed (GESContainer * group, GESTimelineElement * child)
|
||||
{
|
||||
GList *children;
|
||||
GstClockTime first_child_start;
|
||||
|
||||
_ges_container_sort_children (group);
|
||||
|
||||
children = GES_CONTAINER_CHILDREN (group);
|
||||
|
||||
if (GES_IS_CLIP (child))
|
||||
g_signal_handlers_disconnect_by_func (child, _child_clip_changed_layer_cb,
|
||||
group);
|
||||
else if (GES_IS_GROUP (child), group)
|
||||
g_signal_handlers_disconnect_by_func (child, _child_group_priority_changed,
|
||||
group);
|
||||
|
||||
if (children == NULL) {
|
||||
GST_FIXME_OBJECT (group, "Auto destroy myself?");
|
||||
return;
|
||||
}
|
||||
|
||||
first_child_start = GES_TIMELINE_ELEMENT_START (children->data);
|
||||
if (first_child_start > GES_TIMELINE_ELEMENT_START (group)) {
|
||||
group->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
|
||||
_set_start0 (GES_TIMELINE_ELEMENT (group), first_child_start);
|
||||
group->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
static GList *
|
||||
_ungroup (GESContainer * group, gboolean recursive)
|
||||
{
|
||||
GList *children, *tmp, *ret = NULL;
|
||||
|
||||
children = ges_container_get_children (group);
|
||||
for (tmp = children; tmp; tmp = tmp->next) {
|
||||
GESTimelineElement *child = tmp->data;
|
||||
|
||||
gst_object_ref (child);
|
||||
ges_container_remove (group, child);
|
||||
ret = g_list_append (ret, child);
|
||||
}
|
||||
g_list_free_full (children, gst_object_unref);
|
||||
|
||||
timeline_remove_group (GES_TIMELINE_ELEMENT_TIMELINE (group),
|
||||
GES_GROUP (group));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GESContainer *
|
||||
_group (GList * containers)
|
||||
{
|
||||
GList *tmp;
|
||||
GESTimeline *timeline = NULL;
|
||||
GESContainer *ret = g_object_new (GES_TYPE_GROUP, NULL);
|
||||
|
||||
for (tmp = containers; tmp; tmp = tmp->next) {
|
||||
if (!timeline) {
|
||||
timeline = GES_TIMELINE_ELEMENT_TIMELINE (tmp->data);
|
||||
} else if (timeline != GES_TIMELINE_ELEMENT_TIMELINE (tmp->data)) {
|
||||
g_object_unref (ret);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ges_container_add (ret, tmp->data);
|
||||
}
|
||||
|
||||
timeline_add_group (timeline, GES_GROUP (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************
|
||||
* *
|
||||
* GObject virtual methods implementation *
|
||||
* *
|
||||
****************************************************/
|
||||
static void
|
||||
ges_group_get_property (GObject * object, guint property_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
switch (property_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_set_property (GObject * object, guint property_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
switch (property_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_class_init (GESGroupClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GESContainerClass *container_class = GES_CONTAINER_CLASS (klass);
|
||||
GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GESGroupPrivate));
|
||||
|
||||
object_class->get_property = ges_group_get_property;
|
||||
object_class->set_property = ges_group_set_property;
|
||||
|
||||
element_class->trim = _trim;
|
||||
element_class->set_duration = _set_duration;
|
||||
element_class->set_inpoint = _set_inpoint;
|
||||
element_class->set_start = _set_start;
|
||||
element_class->set_priority = _set_priority;
|
||||
/* TODO implement the deep_copy Virtual method */
|
||||
|
||||
container_class->add_child = _add_child;
|
||||
container_class->child_added = _child_added;
|
||||
container_class->child_removed = _child_removed;
|
||||
container_class->ungroup = _ungroup;
|
||||
container_class->group = _group;
|
||||
container_class->grouping_priority = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ges_group_init (GESGroup * self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
GES_TYPE_GROUP, GESGroupPrivate);
|
||||
|
||||
self->priv->setting_value = FALSE;
|
||||
}
|
56
ges/ges-group.h
Normal file
56
ges/ges-group.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* * Gstreamer
|
||||
*
|
||||
* Copyright (C) <2013> Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef GES_GROUP_H
|
||||
#define GES_GROUP_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <ges/ges-types.h>
|
||||
#include <ges/ges-container.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GES_TYPE_GROUP (ges_group_get_type ())
|
||||
#define GES_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GES_TYPE_GROUP, GESGroup))
|
||||
#define GES_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GES_TYPE_GROUP, GESGroupClass))
|
||||
#define GES_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GES_TYPE_GROUP))
|
||||
#define GES_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GES_TYPE_GROUP))
|
||||
#define GES_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GES_TYPE_GROUP, GESGroupClass))
|
||||
|
||||
typedef struct _GESGroupPrivate GESGroupPrivate;
|
||||
|
||||
struct _GESGroup {
|
||||
GESContainer parent;
|
||||
|
||||
/*< private >*/
|
||||
GESGroupPrivate *priv;
|
||||
|
||||
gpointer _ges_reserved[GES_PADDING];
|
||||
};
|
||||
|
||||
struct _GESGroupClass {
|
||||
GESContainerClass parent_class;
|
||||
|
||||
gpointer _ges_reserved[GES_PADDING];
|
||||
};
|
||||
|
||||
GType ges_group_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* _GES_GROUP_H */
|
|
@ -83,6 +83,14 @@ timeline_move_object (GESTimeline *timeline, GESTrackElement * object,
|
|||
G_GNUC_INTERNAL gboolean
|
||||
timeline_context_to_layer (GESTimeline *timeline, gint offset);
|
||||
|
||||
G_GNUC_INTERNAL void
|
||||
timeline_add_group (GESTimeline *timeline,
|
||||
GESGroup *group);
|
||||
G_GNUC_INTERNAL
|
||||
void
|
||||
timeline_remove_group (GESTimeline *timeline,
|
||||
GESGroup *group);
|
||||
|
||||
G_GNUC_INTERNAL void
|
||||
ges_asset_cache_init (void);
|
||||
|
||||
|
|
|
@ -384,8 +384,8 @@ ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
|
|||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
|
||||
" new start: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
|
||||
" new start: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
|
||||
|
||||
if (klass->set_start) {
|
||||
if (klass->set_start (self, start)) {
|
||||
|
@ -393,6 +393,8 @@ ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
|
|||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -489,8 +491,9 @@ ges_timeline_element_set_duration (GESTimelineElement * self,
|
|||
klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
|
||||
" new duration: %" GST_TIME_FORMAT, GST_TIME_ARGS (duration),
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)));
|
||||
" new duration: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
|
||||
GST_TIME_ARGS (duration));
|
||||
|
||||
if (klass->set_duration) {
|
||||
if (klass->set_duration (self, duration)) {
|
||||
|
|
|
@ -119,10 +119,10 @@ struct _MoveContext
|
|||
GList *moving_trackelements;
|
||||
|
||||
/* We use it as a set of Clip to move between layers */
|
||||
GHashTable *moving_clips;
|
||||
/* Min priority of the objects currently in moving_clips */
|
||||
GHashTable *toplevel_containers;
|
||||
/* Min priority of the objects currently in toplevel_containers */
|
||||
guint min_move_layer;
|
||||
/* Max priority of the objects currently in moving_clips */
|
||||
/* Max priority of the objects currently in toplevel_containers */
|
||||
guint max_layer_prio;
|
||||
|
||||
/* Never trim so duration would becomes < 0 */
|
||||
|
@ -184,6 +184,7 @@ struct _GESTimelinePrivate
|
|||
/* While we are creating and adding the TrackElements for a clip, we need to
|
||||
* ignore the child-added signal */
|
||||
GESClip *ignore_track_element_added;
|
||||
GList *groups;
|
||||
};
|
||||
|
||||
/* private structure to contain our track-related information */
|
||||
|
@ -324,9 +325,12 @@ ges_timeline_dispose (GObject * object)
|
|||
* objects aren't notified that their gnlobjects have been destroyed.
|
||||
*/
|
||||
|
||||
while (tl->tracks) {
|
||||
while (tl->tracks)
|
||||
ges_timeline_remove_track (GES_TIMELINE (object), tl->tracks->data);
|
||||
}
|
||||
|
||||
while (priv->groups)
|
||||
g_list_free_full (ges_container_ungroup (priv->groups->data, FALSE),
|
||||
gst_object_unref);
|
||||
|
||||
g_hash_table_unref (priv->by_start);
|
||||
g_hash_table_unref (priv->by_end);
|
||||
|
@ -336,7 +340,7 @@ ges_timeline_dispose (GObject * object)
|
|||
g_sequence_free (priv->starts_ends);
|
||||
g_sequence_free (priv->tracksources);
|
||||
g_list_free (priv->movecontext.moving_trackelements);
|
||||
g_hash_table_unref (priv->movecontext.moving_clips);
|
||||
g_hash_table_unref (priv->movecontext.toplevel_containers);
|
||||
|
||||
g_hash_table_unref (priv->auto_transitions);
|
||||
|
||||
|
@ -552,6 +556,18 @@ ges_timeline_init (GESTimeline * self)
|
|||
|
||||
/* Private methods */
|
||||
|
||||
static inline GESContainer *
|
||||
get_toplevel_container (GESTrackElement * element)
|
||||
{
|
||||
GESTimelineElement *ret =
|
||||
ges_timeline_element_get_toplevel_parent ((GESTimelineElement
|
||||
*) (element));
|
||||
|
||||
/* We own a ref to the elements ourself */
|
||||
gst_object_unref (ret);
|
||||
return (GESContainer *) ret;
|
||||
}
|
||||
|
||||
/* Sorting utils*/
|
||||
static gint
|
||||
sort_layers (gpointer a, gpointer b)
|
||||
|
@ -885,7 +901,8 @@ static inline void
|
|||
init_movecontext (MoveContext * mv_ctx, gboolean first_init)
|
||||
{
|
||||
if (G_UNLIKELY (first_init))
|
||||
mv_ctx->moving_clips = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
mv_ctx->toplevel_containers =
|
||||
g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
mv_ctx->moving_trackelements = NULL;
|
||||
mv_ctx->max_trim_pos = G_MAXUINT64;
|
||||
|
@ -900,7 +917,7 @@ static inline void
|
|||
clean_movecontext (MoveContext * mv_ctx)
|
||||
{
|
||||
g_list_free (mv_ctx->moving_trackelements);
|
||||
g_hash_table_remove_all (mv_ctx->moving_clips);
|
||||
g_hash_table_remove_all (mv_ctx->toplevel_containers);
|
||||
init_movecontext (mv_ctx, FALSE);
|
||||
}
|
||||
|
||||
|
@ -1060,7 +1077,7 @@ ges_timeline_snap_position (GESTimeline * timeline,
|
|||
GESTimelinePrivate *priv = timeline->priv;
|
||||
GSequenceIter *iter, *prev_iter, *nxt_iter;
|
||||
GESTrackElement *tmp_trackelement;
|
||||
GESClip *tmp_clip, *clip;
|
||||
GESContainer *tmp_container, *container;
|
||||
|
||||
GstClockTime *last_snap_ts = priv->movecontext.last_snap_ts;
|
||||
guint64 snap_distance = timeline->priv->snapping_distance;
|
||||
|
@ -1081,7 +1098,7 @@ ges_timeline_snap_position (GESTimeline * timeline,
|
|||
}
|
||||
}
|
||||
|
||||
clip = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (trackelement));
|
||||
container = get_toplevel_container (trackelement);
|
||||
|
||||
iter = g_sequence_search (priv->starts_ends, &timecode,
|
||||
(GCompareDataFunc) compare_uint64, NULL);
|
||||
|
@ -1092,10 +1109,11 @@ ges_timeline_snap_position (GESTimeline * timeline,
|
|||
while (!g_sequence_iter_is_end (nxt_iter)) {
|
||||
next_tc = g_sequence_get (iter);
|
||||
tmp_trackelement = g_hash_table_lookup (timeline->priv->by_object, next_tc);
|
||||
tmp_clip = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (tmp_trackelement));
|
||||
tmp_container = get_toplevel_container (tmp_trackelement);
|
||||
|
||||
off = timecode > *next_tc ? timecode - *next_tc : *next_tc - timecode;
|
||||
if (next_tc != current && off <= snap_distance && clip != tmp_clip) {
|
||||
if (next_tc != current && off <= snap_distance
|
||||
&& container != tmp_container) {
|
||||
|
||||
ret = next_tc;
|
||||
break;
|
||||
|
@ -1111,11 +1129,11 @@ ges_timeline_snap_position (GESTimeline * timeline,
|
|||
while (!g_sequence_iter_is_begin (prev_iter)) {
|
||||
prev_tc = g_sequence_get (prev_iter);
|
||||
tmp_trackelement = g_hash_table_lookup (timeline->priv->by_object, prev_tc);
|
||||
tmp_clip = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (tmp_trackelement));
|
||||
tmp_container = get_toplevel_container (tmp_trackelement);
|
||||
|
||||
off1 = timecode > *prev_tc ? timecode - *prev_tc : *prev_tc - timecode;
|
||||
if (prev_tc != current && off1 < off && off1 <= snap_distance &&
|
||||
clip != tmp_clip) {
|
||||
container != tmp_container) {
|
||||
ret = prev_tc;
|
||||
|
||||
break;
|
||||
|
@ -1139,35 +1157,39 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline GESClip *
|
||||
add_moving_clip (MoveContext * mv_ctx, GESTrackElement * trackelement)
|
||||
static inline GESContainer *
|
||||
add_toplevel_container (MoveContext * mv_ctx, GESTrackElement * trackelement)
|
||||
{
|
||||
GESClip *clip;
|
||||
GESLayer *layer;
|
||||
guint layer_prio;
|
||||
|
||||
clip = GES_CLIP (GES_TIMELINE_ELEMENT_PARENT (trackelement));
|
||||
GESContainer *toplevel = get_toplevel_container (trackelement);
|
||||
|
||||
/* Avoid recalculating */
|
||||
if (!g_hash_table_lookup (mv_ctx->moving_clips, clip)) {
|
||||
layer = ges_clip_get_layer (clip);
|
||||
if (layer == NULL) {
|
||||
GST_WARNING_OBJECT (clip, "Not in any layer, can not move"
|
||||
" between layers");
|
||||
if (!g_hash_table_lookup (mv_ctx->toplevel_containers, toplevel)) {
|
||||
if (GES_IS_CLIP (toplevel)) {
|
||||
|
||||
} else {
|
||||
layer_prio = ges_clip_get_layer_priority (GES_CLIP (toplevel));
|
||||
if (layer_prio == (guint32) - 1) {
|
||||
GST_WARNING_OBJECT (toplevel, "Not in any layer, can not move"
|
||||
" between layers");
|
||||
|
||||
g_hash_table_insert (mv_ctx->moving_clips, clip, clip);
|
||||
|
||||
layer_prio = ges_layer_get_priority (layer);
|
||||
return toplevel;
|
||||
}
|
||||
mv_ctx->min_move_layer = MIN (mv_ctx->min_move_layer, layer_prio);
|
||||
mv_ctx->max_layer_prio = MAX (mv_ctx->max_layer_prio, layer_prio);
|
||||
} else if GES_IS_GROUP
|
||||
(toplevel) {
|
||||
mv_ctx->min_move_layer = MIN (mv_ctx->min_move_layer,
|
||||
_PRIORITY (toplevel));
|
||||
mv_ctx->max_layer_prio = MAX (mv_ctx->max_layer_prio,
|
||||
_PRIORITY (toplevel) + GES_CONTAINER_HEIGHT (toplevel));
|
||||
} else
|
||||
g_assert_not_reached ();
|
||||
|
||||
g_hash_table_insert (mv_ctx->toplevel_containers, toplevel, toplevel);
|
||||
|
||||
gst_object_unref (layer);
|
||||
}
|
||||
}
|
||||
|
||||
return clip;
|
||||
return toplevel;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -1292,10 +1314,10 @@ ges_timeline_set_moving_context (GESTimeline * timeline, GESTrackElement * obj,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
add_moving_clip (&timeline->priv->movecontext, editor_trackelement);
|
||||
add_toplevel_container (&timeline->priv->movecontext, editor_trackelement);
|
||||
} else {
|
||||
/* We add the main object to the moving_clips set */
|
||||
add_moving_clip (&timeline->priv->movecontext, obj);
|
||||
/* We add the main object to the toplevel_containers set */
|
||||
add_toplevel_container (&timeline->priv->movecontext, obj);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1387,7 +1409,7 @@ timeline_ripple_object (GESTimeline * timeline, GESTrackElement * obj,
|
|||
{
|
||||
GList *tmp, *moved_clips = NULL;
|
||||
GESTrackElement *trackelement;
|
||||
GESClip *clip;
|
||||
GESContainer *container;
|
||||
guint64 duration, new_start, *snapped, *cur;
|
||||
gint64 offset;
|
||||
|
||||
|
@ -1415,11 +1437,11 @@ timeline_ripple_object (GESTimeline * timeline, GESTrackElement * obj,
|
|||
trackelement = GES_TRACK_ELEMENT (tmp->data);
|
||||
new_start = _START (trackelement) + offset;
|
||||
|
||||
clip = add_moving_clip (mv_ctx, trackelement);
|
||||
container = add_toplevel_container (mv_ctx, trackelement);
|
||||
/* Make sure not to move 2 times the same Clip */
|
||||
if (g_list_find (moved_clips, clip) == NULL) {
|
||||
if (g_list_find (moved_clips, container) == NULL) {
|
||||
_set_start0 (GES_TIMELINE_ELEMENT (trackelement), new_start);
|
||||
moved_clips = g_list_prepend (moved_clips, clip);
|
||||
moved_clips = g_list_prepend (moved_clips, container);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1445,12 +1467,16 @@ timeline_ripple_object (GESTimeline * timeline, GESTrackElement * obj,
|
|||
trackelement = GES_TRACK_ELEMENT (tmp->data);
|
||||
new_start = _START (trackelement) + offset;
|
||||
|
||||
clip = add_moving_clip (mv_ctx, trackelement);
|
||||
container = add_toplevel_container (mv_ctx, trackelement);
|
||||
if (GES_IS_GROUP (container))
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE_OFFSETS;
|
||||
/* Make sure not to move 2 times the same Clip */
|
||||
if (g_list_find (moved_clips, clip) == NULL) {
|
||||
if (g_list_find (moved_clips, container) == NULL) {
|
||||
_set_start0 (GES_TIMELINE_ELEMENT (trackelement), new_start);
|
||||
moved_clips = g_list_prepend (moved_clips, clip);
|
||||
moved_clips = g_list_prepend (moved_clips, container);
|
||||
}
|
||||
if (GES_IS_GROUP (container))
|
||||
container->children_control_mode = GES_CHILDREN_UPDATE;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1629,7 +1655,7 @@ gboolean
|
|||
timeline_move_object (GESTimeline * timeline, GESTrackElement * object,
|
||||
GList * layers, GESEdge edge, guint64 position)
|
||||
{
|
||||
if (!ges_timeline_set_moving_context (timeline, object, GES_EDIT_MODE_RIPPLE,
|
||||
if (!ges_timeline_set_moving_context (timeline, object, GES_EDIT_MODE_NORMAL,
|
||||
edge, layers)) {
|
||||
GST_DEBUG_OBJECT (object, "Could not move to %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (position));
|
||||
|
@ -1656,11 +1682,12 @@ ges_timeline_move_object_simple (GESTimeline * timeline,
|
|||
return FALSE;
|
||||
|
||||
track_element = GES_TRACK_ELEMENT (element);
|
||||
end = position + _DURATION (track_element);
|
||||
end = position + _DURATION (get_toplevel_container (track_element));
|
||||
cur = g_hash_table_lookup (timeline->priv->by_end, track_element);
|
||||
|
||||
GST_DEBUG_OBJECT (timeline, "Moving to %" GST_TIME_FORMAT " (end %"
|
||||
GST_TIME_FORMAT ")", GST_TIME_ARGS (position), GST_TIME_ARGS (end));
|
||||
GST_DEBUG_OBJECT (timeline, "Moving %" GST_PTR_FORMAT "to %"
|
||||
GST_TIME_FORMAT " (end %" GST_TIME_FORMAT ")", element,
|
||||
GST_TIME_ARGS (position), GST_TIME_ARGS (end));
|
||||
|
||||
snap_end = ges_timeline_snap_position (timeline, track_element, cur, end,
|
||||
FALSE);
|
||||
|
@ -1670,7 +1697,8 @@ ges_timeline_move_object_simple (GESTimeline * timeline,
|
|||
off1 = G_MAXUINT64;
|
||||
|
||||
cur = g_hash_table_lookup (timeline->priv->by_start, track_element);
|
||||
snap_st = ges_timeline_snap_position (timeline, track_element, cur, position,
|
||||
snap_st =
|
||||
ges_timeline_snap_position (timeline, track_element, cur, position,
|
||||
FALSE);
|
||||
if (snap_st)
|
||||
off2 = position > *snap_st ? position - *snap_st : *snap_st - position;
|
||||
|
@ -1704,33 +1732,37 @@ timeline_context_to_layer (GESTimeline * timeline, gint offset)
|
|||
/* Layer's priority is always positive */
|
||||
if (offset != 0 && (offset > 0 || mv_ctx->min_move_layer >= -offset)) {
|
||||
GHashTableIter iter;
|
||||
GESClip *key, *value;
|
||||
GESLayer *new_layer, *layer;
|
||||
GESContainer *key, *value;
|
||||
GESLayer *new_layer;
|
||||
guint prio;
|
||||
|
||||
mv_ctx->ignore_needs_ctx = TRUE;
|
||||
|
||||
GST_DEBUG ("Moving %d object, offset %d",
|
||||
g_hash_table_size (mv_ctx->moving_clips), offset);
|
||||
g_hash_table_size (mv_ctx->toplevel_containers), offset);
|
||||
|
||||
g_hash_table_iter_init (&iter, mv_ctx->moving_clips);
|
||||
g_hash_table_iter_init (&iter, mv_ctx->toplevel_containers);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) & key,
|
||||
(gpointer *) & value)) {
|
||||
layer = ges_clip_get_layer (value);
|
||||
prio = ges_layer_get_priority (layer);
|
||||
|
||||
/* We know that the layer exists as we created it */
|
||||
new_layer = GES_LAYER (g_list_nth_data (timeline->layers, prio + offset));
|
||||
if (GES_IS_CLIP (value)) {
|
||||
prio = ges_clip_get_layer_priority (GES_CLIP (value));
|
||||
|
||||
if (new_layer == NULL) {
|
||||
do {
|
||||
new_layer = ges_timeline_append_layer (timeline);
|
||||
} while (ges_layer_get_priority (new_layer) < prio + offset);
|
||||
/* We know that the layer exists as we created it */
|
||||
new_layer =
|
||||
GES_LAYER (g_list_nth_data (timeline->layers, prio + offset));
|
||||
|
||||
if (new_layer == NULL) {
|
||||
do {
|
||||
new_layer = ges_timeline_append_layer (timeline);
|
||||
} while (ges_layer_get_priority (new_layer) < prio + offset);
|
||||
}
|
||||
|
||||
ret &= ges_clip_move_to_layer (GES_CLIP (key), new_layer);
|
||||
} else if (GES_IS_GROUP (value)) {
|
||||
_set_priority0 (GES_TIMELINE_ELEMENT (value),
|
||||
_PRIORITY (value) + offset);
|
||||
}
|
||||
|
||||
ret &= ges_clip_move_to_layer (key, new_layer);
|
||||
|
||||
gst_object_unref (layer);
|
||||
}
|
||||
|
||||
/* Readjust min_move_layer */
|
||||
|
@ -1742,6 +1774,30 @@ timeline_context_to_layer (GESTimeline * timeline, gint offset)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
timeline_add_group (GESTimeline * timeline, GESGroup * group)
|
||||
{
|
||||
GST_DEBUG_OBJECT (timeline, "Adding group %" GST_PTR_FORMAT, group);
|
||||
|
||||
timeline->priv->movecontext.needs_move_ctx = TRUE;
|
||||
timeline->priv->groups = g_list_prepend (timeline->priv->groups,
|
||||
gst_object_ref_sink (group));
|
||||
|
||||
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), timeline);
|
||||
}
|
||||
|
||||
void
|
||||
timeline_remove_group (GESTimeline * timeline, GESGroup * group)
|
||||
{
|
||||
GST_DEBUG_OBJECT (timeline, "Removing group %" GST_PTR_FORMAT, group);
|
||||
|
||||
timeline->priv->groups = g_list_remove (timeline->priv->groups, group);
|
||||
|
||||
timeline->priv->movecontext.needs_move_ctx = TRUE;
|
||||
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (group), NULL);
|
||||
gst_object_unref (group);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
select_tracks_for_object_default (GESTimeline * timeline,
|
||||
GESClip * clip, GESTrackElement * tr_object, gpointer user_data)
|
||||
|
@ -1800,8 +1856,8 @@ layer_auto_transition_changed_cb (GESLayer * layer,
|
|||
}
|
||||
|
||||
static void
|
||||
clip_track_element_added_cb (GESClip * clip, GESTrackElement * track_element,
|
||||
GESTimeline * timeline)
|
||||
clip_track_element_added_cb (GESClip * clip,
|
||||
GESTrackElement * track_element, GESTimeline * timeline)
|
||||
{
|
||||
guint i;
|
||||
GESTrack *track;
|
||||
|
@ -1885,8 +1941,8 @@ clip_track_element_added_cb (GESClip * clip, GESTrackElement * track_element,
|
|||
}
|
||||
|
||||
static void
|
||||
clip_track_element_removed_cb (GESClip * clip, GESTrackElement * track_element,
|
||||
GESTimeline * timeline)
|
||||
clip_track_element_removed_cb (GESClip * clip,
|
||||
GESTrackElement * track_element, GESTimeline * timeline)
|
||||
{
|
||||
GESTrack *track = ges_track_element_get_track (track_element);
|
||||
|
||||
|
@ -2081,17 +2137,19 @@ track_element_added_cb (GESTrack * track, GESTrackElement * track_element,
|
|||
/* Auto transition should be updated before we receive the signal */
|
||||
g_signal_connect_after (GES_TRACK_ELEMENT (track_element), "notify::start",
|
||||
G_CALLBACK (trackelement_start_changed_cb), timeline);
|
||||
g_signal_connect_after (GES_TRACK_ELEMENT (track_element), "notify::duration",
|
||||
G_CALLBACK (trackelement_duration_changed_cb), timeline);
|
||||
g_signal_connect_after (GES_TRACK_ELEMENT (track_element), "notify::priority",
|
||||
G_CALLBACK (trackelement_priority_changed_cb), timeline);
|
||||
g_signal_connect_after (GES_TRACK_ELEMENT (track_element),
|
||||
"notify::duration", G_CALLBACK (trackelement_duration_changed_cb),
|
||||
timeline);
|
||||
g_signal_connect_after (GES_TRACK_ELEMENT (track_element),
|
||||
"notify::priority", G_CALLBACK (trackelement_priority_changed_cb),
|
||||
timeline);
|
||||
|
||||
start_tracking_track_element (timeline, track_element);
|
||||
}
|
||||
|
||||
static void
|
||||
track_element_removed_cb (GESTrack * track, GESTrackElement * track_element,
|
||||
GESTimeline * timeline)
|
||||
track_element_removed_cb (GESTrack * track,
|
||||
GESTrackElement * track_element, GESTimeline * timeline)
|
||||
{
|
||||
|
||||
if (GES_IS_SOURCE (track_element)) {
|
||||
|
|
|
@ -86,6 +86,9 @@ typedef struct _GESTextOverlayClipClass GESTextOverlayClipClass;
|
|||
typedef struct _GESEffectClip GESEffectClip;
|
||||
typedef struct _GESEffectClipClass GESEffectClipClass;
|
||||
|
||||
typedef struct _GESGroup GESGroup;
|
||||
typedef struct _GESGroupClass GESGroupClass;
|
||||
|
||||
typedef struct _GESTrack GESTrack;
|
||||
typedef struct _GESTrackClass GESTrackClass;
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@ ges_init (void)
|
|||
GES_TYPE_TRANSITION_CLIP;
|
||||
GES_TYPE_OVERLAY_CLIP;
|
||||
|
||||
GES_TYPE_GROUP;
|
||||
|
||||
/* register formatter types with the system */
|
||||
GES_TYPE_PITIVI_FORMATTER;
|
||||
GES_TYPE_XML_FORMATTER;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <ges/ges-custom-source-clip.h>
|
||||
#include <ges/ges-base-effect-clip.h>
|
||||
#include <ges/ges-uri-clip.h>
|
||||
#include <ges/ges-group.h>
|
||||
#include <ges/ges-screenshot.h>
|
||||
#include <ges/ges-asset.h>
|
||||
#include <ges/ges-clip-asset.h>
|
||||
|
|
|
@ -41,6 +41,7 @@ check_PROGRAMS = \
|
|||
ges/overlays\
|
||||
ges/text_properties\
|
||||
ges/mixers\
|
||||
ges/group\
|
||||
ges/project
|
||||
|
||||
noinst_LTLIBRARIES=$(testutils_noisnt_libraries)
|
||||
|
|
|
@ -420,6 +420,7 @@ GST_START_TEST (test_ges_timeline_remove_track)
|
|||
tmp_layer = ges_clip_get_layer (GES_CLIP (s1));
|
||||
fail_unless (tmp_layer == layer);
|
||||
gst_object_unref (tmp_layer);
|
||||
ASSERT_OBJECT_REFCOUNT (layer, "1 for the timeline", 1);
|
||||
|
||||
GST_DEBUG ("Creating a source");
|
||||
s2 = ges_custom_source_clip_new (my_fill_track_func, NULL);
|
||||
|
@ -428,6 +429,7 @@ GST_START_TEST (test_ges_timeline_remove_track)
|
|||
tmp_layer = ges_clip_get_layer (GES_CLIP (s2));
|
||||
fail_unless (tmp_layer == layer);
|
||||
gst_object_unref (tmp_layer);
|
||||
ASSERT_OBJECT_REFCOUNT (layer, "1 for the timeline", 1);
|
||||
|
||||
GST_DEBUG ("Creating a source");
|
||||
s3 = ges_custom_source_clip_new (my_fill_track_func, NULL);
|
||||
|
@ -436,6 +438,7 @@ GST_START_TEST (test_ges_timeline_remove_track)
|
|||
tmp_layer = ges_clip_get_layer (GES_CLIP (s3));
|
||||
fail_unless (tmp_layer == layer);
|
||||
gst_object_unref (tmp_layer);
|
||||
ASSERT_OBJECT_REFCOUNT (layer, "1 for the timeline", 1);
|
||||
|
||||
GST_DEBUG ("Add the layer to the timeline");
|
||||
fail_unless (ges_timeline_add_layer (timeline, layer));
|
||||
|
@ -447,6 +450,7 @@ GST_START_TEST (test_ges_timeline_remove_track)
|
|||
fail_unless (g_list_find (layers, layer) != NULL);
|
||||
g_list_foreach (layers, (GFunc) gst_object_unref, NULL);
|
||||
g_list_free (layers);
|
||||
ASSERT_OBJECT_REFCOUNT (layer, "1 for the timeline", 1);
|
||||
|
||||
GST_DEBUG ("Add the track to the timeline");
|
||||
fail_unless (ges_timeline_add_track (timeline, track));
|
||||
|
|
|
@ -287,7 +287,11 @@ GST_START_TEST (test_clip_group_ungroup)
|
|||
assert_equals_uint64 (_DURATION (clip2), 10);
|
||||
|
||||
regrouped_clip = ges_container_group (containers);
|
||||
fail_unless (regrouped_clip == NULL);
|
||||
fail_unless (GES_IS_GROUP (regrouped_clip));
|
||||
assert_equals_int (g_list_length (GES_CONTAINER_CHILDREN (regrouped_clip)),
|
||||
2);
|
||||
tmp = ges_container_ungroup (regrouped_clip, FALSE);
|
||||
g_list_free_full (tmp, gst_object_unref);
|
||||
|
||||
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (clip), 0);
|
||||
regrouped_clip = ges_container_group (containers);
|
||||
|
|
500
tests/check/ges/group.c
Normal file
500
tests/check/ges/group.c
Normal file
|
@ -0,0 +1,500 @@
|
|||
/* GStreamer Editing Services
|
||||
*
|
||||
* Copyright (C) <2013> Thibault Saunier <thibault.saunier@collabora.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "test-utils.h"
|
||||
#include <ges/ges.h>
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
GST_START_TEST (test_move_group)
|
||||
{
|
||||
GESAsset *asset;
|
||||
GESGroup *group;
|
||||
GESTimeline *timeline;
|
||||
GESLayer *layer, *layer1;
|
||||
GESClip *clip, *clip1, *clip2;
|
||||
|
||||
GList *clips = NULL;
|
||||
|
||||
ges_init ();
|
||||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
layer1 = ges_timeline_append_layer (timeline);
|
||||
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
|
||||
|
||||
/**
|
||||
* Our timeline:
|
||||
* -------------
|
||||
*
|
||||
* 0------------Group1---------------110
|
||||
* |-------- |
|
||||
* layer: | clip | |
|
||||
* |-------10 |
|
||||
* |----------------------------------|
|
||||
* | 0--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 10--------20 50----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
clip = ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
clip1 =
|
||||
ges_layer_add_asset (layer1, asset, 10, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
clip2 =
|
||||
ges_layer_add_asset (layer1, asset, 50, 0, 60, GES_TRACK_TYPE_UNKNOWN);
|
||||
clips = g_list_prepend (clips, clip);
|
||||
clips = g_list_prepend (clips, clip1);
|
||||
clips = g_list_prepend (clips, clip2);
|
||||
group = GES_GROUP (ges_container_group (clips));
|
||||
g_list_free (clips);
|
||||
|
||||
fail_unless (GES_IS_GROUP (group));
|
||||
ASSERT_OBJECT_REFCOUNT (group, "1 ref for the timeline", 1);
|
||||
fail_unless (g_list_length (GES_CONTAINER_CHILDREN (group)) == 3);
|
||||
assert_equals_int (GES_CONTAINER_HEIGHT (group), 2);
|
||||
CHECK_OBJECT_PROPS (clip, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 50, 0, 60);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 110);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------120
|
||||
* |-------- |
|
||||
* layer: | clip | |
|
||||
* |-------20 |
|
||||
* |----------------------------------|
|
||||
* | 0--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (clip), 10);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 60);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 110);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------120
|
||||
* |------ |
|
||||
* layer: |clip | |
|
||||
* |-----15 |
|
||||
* |----------------------------------|
|
||||
* | 0--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (clip), 5);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 60);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 110);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------110
|
||||
* |------ |
|
||||
* layer: |clip | |
|
||||
* |-----15 |
|
||||
* |----------------------------------|
|
||||
* | 0--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (clip2), 50);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------110
|
||||
* |------ |
|
||||
* layer: |clip | |
|
||||
* |-----15 |
|
||||
* |----------------------------------|
|
||||
* | 5--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_inpoint (GES_TIMELINE_ELEMENT (clip1), 5);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------110
|
||||
* |------ |
|
||||
* layer: |clip | |
|
||||
* |-----15 |
|
||||
* |----------------------------------|
|
||||
* | 5--------- 0-----------|
|
||||
* layer1: | | clip1 | | clip2 |
|
||||
* | 20--------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_inpoint (GES_TIMELINE_ELEMENT (clip1), 5);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 20---Group1---------------110
|
||||
* | |
|
||||
* layer: | |
|
||||
* | |
|
||||
* |--------------------------|
|
||||
* 5--------- 0------------|
|
||||
* layer1: | clip1 | | clip2 |
|
||||
* 20--------30 60----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 20);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 5, 10);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 20, 0, 90);
|
||||
|
||||
/*
|
||||
* 0 25---Group1---------------110
|
||||
* | |
|
||||
* layer: | |
|
||||
* | |
|
||||
* |--------------------------|
|
||||
* 10------ 0------------|
|
||||
* layer1: | clip1 | | clip2 |
|
||||
* 25------30 60----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 25);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 25, 10, 5);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 25, 0, 85);
|
||||
|
||||
/*
|
||||
* 0 10------------Group1---------------110
|
||||
* |------ |
|
||||
* layer: |clip | |
|
||||
* |-----15 |
|
||||
* |----------------------------------|
|
||||
* 0----------------- 0-----------|
|
||||
* layer1: | clip1 | | clip2 |
|
||||
* |-----------------30 60----------|
|
||||
* |----------------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 10);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 10, 0, 20);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 25---Group1---------------110
|
||||
* | |
|
||||
* layer: 15 | |
|
||||
* |clip | |
|
||||
* - |--------------------------|
|
||||
* 15------ 0------------|
|
||||
* layer1: | clip1 | | clip2 |
|
||||
* 25------30 60----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 25);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 25, 15, 5);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 50);
|
||||
CHECK_OBJECT_PROPS (group, 25, 0, 85);
|
||||
|
||||
/*
|
||||
* 0 25---Group1--30
|
||||
* | |
|
||||
* layer: 15 | |
|
||||
* |clip | |
|
||||
* - |------------
|
||||
* 15-----------| 60
|
||||
* layer1: | clip1 | |clip2
|
||||
* 25------------| -
|
||||
* |------------|
|
||||
*/
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (group), 10);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 25, 15, 5);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 0);
|
||||
CHECK_OBJECT_PROPS (group, 25, 0, 5);
|
||||
|
||||
/*
|
||||
* 0 25---Group1---------------125
|
||||
* | |
|
||||
* layer: 15 | |
|
||||
* |clip | |
|
||||
* - |--------------------------|
|
||||
* 15-------------------------|
|
||||
* layer1: | clip1 | clip2 |
|
||||
* 25--------------60----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_duration (GES_TIMELINE_ELEMENT (group), 100);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 25, 15, 100);
|
||||
CHECK_OBJECT_PROPS (clip2, 60, 0, 65);
|
||||
CHECK_OBJECT_PROPS (group, 25, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 20---Group1---------------120
|
||||
* | |
|
||||
* layer: 15 | |
|
||||
* |clip| |
|
||||
* - |--------------------------|
|
||||
* 15-------------------------|
|
||||
* layer1: | clip1 | clip2 |
|
||||
* 20-------------55----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (group), 20);
|
||||
CHECK_OBJECT_PROPS (clip, 15, 5, 0);
|
||||
CHECK_OBJECT_PROPS (clip1, 20, 15, 100);
|
||||
CHECK_OBJECT_PROPS (clip2, 55, 0, 65);
|
||||
CHECK_OBJECT_PROPS (group, 20, 0, 100);
|
||||
|
||||
/*
|
||||
* 0 10---Group1---------------120
|
||||
* |-----15 |
|
||||
* layer: | clip| |
|
||||
* |------ |
|
||||
* |--------------------------|
|
||||
* 5--------------------------|
|
||||
* layer1: | clip1 | clip2 |
|
||||
* 10-------------55----------|
|
||||
* |--------------------------|
|
||||
*/
|
||||
ges_timeline_element_trim (GES_TIMELINE_ELEMENT (group), 10);
|
||||
CHECK_OBJECT_PROPS (clip, 10, 0, 5);
|
||||
CHECK_OBJECT_PROPS (clip1, 10, 5, 110);
|
||||
CHECK_OBJECT_PROPS (clip2, 55, 0, 65);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 110);
|
||||
|
||||
ASSERT_OBJECT_REFCOUNT (group, "1 ref for the timeline", 1);
|
||||
check_destroyed (G_OBJECT (timeline), G_OBJECT (group), NULL);
|
||||
gst_object_unref (asset);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
|
||||
static void
|
||||
_changed_layer_cb (GESTimelineElement * clip,
|
||||
GParamSpec * arg G_GNUC_UNUSED, guint * nb_calls)
|
||||
{
|
||||
*nb_calls = *nb_calls + 1;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_group_in_group)
|
||||
{
|
||||
GESAsset *asset;
|
||||
GESTimeline *timeline;
|
||||
GESGroup *group, *group1;
|
||||
GESLayer *layer, *layer1, *layer2, *layer3;
|
||||
GESClip *c, *c1, *c2, *c3, *c4, *c5;
|
||||
|
||||
guint nb_layer_notifies = 0;
|
||||
GList *clips = NULL;
|
||||
|
||||
ges_init ();
|
||||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
|
||||
/* Our timeline
|
||||
*
|
||||
* --0------------10-Group-----20---------------30-------Group1----------70
|
||||
* | +-----------+ |+-----------50 |
|
||||
* L | | C | || C3 | |
|
||||
* | +-----------+ |+-----------+ |
|
||||
* --|-------------------------------------------|-----40----------------|
|
||||
* | +------------+ +-------------+ | +--------60 |
|
||||
* L1 | | C1 | | C2 | | | C4 | |
|
||||
* | +------------+ +-------------+ | +--------+ |
|
||||
* --|-------------------------------------------|-----------------------|
|
||||
* | | +--------+|
|
||||
* L2 | | | c5 ||
|
||||
* | | +--------+|
|
||||
* --+-------------------------------------------+-----------------------+
|
||||
*
|
||||
* L3
|
||||
*
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
layer1 = ges_timeline_append_layer (timeline);
|
||||
layer2 = ges_timeline_append_layer (timeline);
|
||||
layer3 = ges_timeline_append_layer (timeline);
|
||||
assert_equals_int (ges_layer_get_priority (layer3), 3);
|
||||
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
|
||||
|
||||
c = ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c1 = ges_layer_add_asset (layer1, asset, 10, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c2 = ges_layer_add_asset (layer1, asset, 20, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
clips = g_list_prepend (clips, c);
|
||||
clips = g_list_prepend (clips, c1);
|
||||
clips = g_list_prepend (clips, c2);
|
||||
group = GES_GROUP (ges_container_group (clips));
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
|
||||
g_list_free (clips);
|
||||
|
||||
fail_unless (GES_IS_GROUP (group));
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 30);
|
||||
|
||||
c3 = ges_layer_add_asset (layer, asset, 30, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c4 = ges_layer_add_asset (layer1, asset, 40, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c5 = ges_layer_add_asset (layer2, asset, 50, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
clips = g_list_prepend (NULL, c3);
|
||||
clips = g_list_prepend (clips, c4);
|
||||
clips = g_list_prepend (clips, c5);
|
||||
group1 = GES_GROUP (ges_container_group (clips));
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group1) == timeline);
|
||||
g_list_free (clips);
|
||||
|
||||
fail_unless (GES_IS_GROUP (group1));
|
||||
CHECK_OBJECT_PROPS (c3, 30, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (group1, 30, 0, 40);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
fail_unless (ges_container_add (GES_CONTAINER (group),
|
||||
GES_TIMELINE_ELEMENT (group1)));
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 30, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 70);
|
||||
CHECK_OBJECT_PROPS (group1, 30, 0, 40);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group1) == timeline);
|
||||
|
||||
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (c4), 50);
|
||||
CHECK_OBJECT_PROPS (c, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 30, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 60, 0, 20);
|
||||
CHECK_OBJECT_PROPS (group, 10, 0, 70);
|
||||
CHECK_OBJECT_PROPS (group1, 40, 0, 40);
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group1) == timeline);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
/* Our timeline
|
||||
*
|
||||
* L
|
||||
* -----------------------------------------------------------------------
|
||||
* 0------------10-Group-----20---------------30-------Group1----------70
|
||||
* | +-----------+ |+-----------50 |
|
||||
* L1 | | C | || C3 | |
|
||||
* | +-----------+ |+-----------+ |
|
||||
* | | |
|
||||
* --|-------------------------------------------|-----40----------------|
|
||||
* | +------------+ +-------------+ | +--------60 |
|
||||
* L2 | | C1 | | C2 | | | C4 | |
|
||||
* | +------------+ +-------------+ | +--------+ |
|
||||
* --|-------------------------------------------|-----------------------|
|
||||
* | | +--------+|
|
||||
* L3 | | | c5 ||
|
||||
* | | +--------+|
|
||||
* --+-------------------------------------------+-----------------------+
|
||||
*/
|
||||
fail_unless (ges_clip_move_to_layer (c, layer1));
|
||||
check_layer (c, 1);
|
||||
check_layer (c1, 2);
|
||||
check_layer (c2, 2);
|
||||
check_layer (c3, 1);
|
||||
check_layer (c4, 2);
|
||||
check_layer (c5, 3);
|
||||
assert_equals_int (_PRIORITY (group), 1);
|
||||
assert_equals_int (_PRIORITY (group1), 1);
|
||||
|
||||
/* We can not move so far! */
|
||||
g_signal_connect_after (c4, "notify::layer",
|
||||
(GCallback) _changed_layer_cb, &nb_layer_notifies);
|
||||
fail_if (ges_clip_move_to_layer (c4, layer));
|
||||
assert_equals_int (nb_layer_notifies, 0);
|
||||
check_layer (c, 1);
|
||||
check_layer (c1, 2);
|
||||
check_layer (c2, 2);
|
||||
check_layer (c3, 1);
|
||||
check_layer (c4, 2);
|
||||
check_layer (c5, 3);
|
||||
assert_equals_int (_PRIORITY (group), 1);
|
||||
assert_equals_int (_PRIORITY (group1), 1);
|
||||
|
||||
clips = ges_container_ungroup (GES_CONTAINER (group), FALSE);
|
||||
assert_equals_int (g_list_length (clips), 4);
|
||||
g_list_free_full (clips, gst_object_unref);
|
||||
|
||||
gst_object_unref (timeline);
|
||||
gst_object_unref (asset);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
ges_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("ges-group");
|
||||
TCase *tc_chain = tcase_create ("group");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
|
||||
tcase_add_test (tc_chain, test_move_group);
|
||||
tcase_add_test (tc_chain, test_group_in_group);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (ges);
|
|
@ -72,4 +72,16 @@ G_STMT_START { \
|
|||
#define _INPOINT(obj) GES_TIMELINE_ELEMENT_INPOINT (obj)
|
||||
#define _PRIORITY(obj) GES_TIMELINE_ELEMENT_PRIORITY (obj)
|
||||
|
||||
#define CHECK_OBJECT_PROPS(obj, start, inpoint, duration) {\
|
||||
assert_equals_uint64 (_START (obj), start);\
|
||||
assert_equals_uint64 (_INPOINT (obj), inpoint);\
|
||||
assert_equals_uint64 (_DURATION (obj), duration);\
|
||||
}
|
||||
|
||||
#define check_layer(clip, layer_prio) { \
|
||||
GESLayer *tmplayer = ges_clip_get_layer ((clip)); \
|
||||
assert_equals_int (ges_layer_get_priority (tmplayer), (layer_prio)); \
|
||||
gst_object_unref (tmplayer); \
|
||||
}
|
||||
|
||||
#endif /* _GES_TEST_UTILS */
|
||||
|
|
|
@ -22,6 +22,33 @@
|
|||
#include <ges/ges.h>
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
#define DEEP_CHECK(element, start, inpoint, duration) \
|
||||
{ \
|
||||
GList *track_elements, *tmp; \
|
||||
GstClockTime rstart, rinpoint, rduration; \
|
||||
\
|
||||
rstart = ges_timeline_element_get_start (GES_TIMELINE_ELEMENT (element)); \
|
||||
rinpoint = ges_timeline_element_get_inpoint (GES_TIMELINE_ELEMENT (element));\
|
||||
rduration = \
|
||||
ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (element)); \
|
||||
\
|
||||
assert_equals_uint64 (rstart, start); \
|
||||
assert_equals_uint64 (rinpoint, inpoint); \
|
||||
assert_equals_uint64 (rduration, duration); \
|
||||
\
|
||||
track_elements = GES_CONTAINER_CHILDREN (element); \
|
||||
for (tmp = track_elements; tmp; tmp = tmp->next) { \
|
||||
rstart = ges_timeline_element_get_start (GES_TIMELINE_ELEMENT (tmp->data));\
|
||||
rinpoint = \
|
||||
ges_timeline_element_get_inpoint (GES_TIMELINE_ELEMENT (tmp->data)); \
|
||||
rduration = \
|
||||
ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (tmp->data)); \
|
||||
assert_equals_uint64 (rstart, start); \
|
||||
assert_equals_uint64 (rinpoint, inpoint); \
|
||||
assert_equals_uint64 (rduration, duration); \
|
||||
} \
|
||||
}
|
||||
|
||||
static gboolean
|
||||
my_fill_track_func (GESClip * clip,
|
||||
GESTrackElement * track_element, GstElement * gnlobj, gpointer user_data)
|
||||
|
@ -46,12 +73,6 @@ create_custom_clip (void)
|
|||
return GES_CLIP (ges_custom_source_clip_new (my_fill_track_func, NULL));
|
||||
}
|
||||
|
||||
#define CHECK_OBJECT_PROPS(obj, start, inpoint, duration) {\
|
||||
assert_equals_uint64 (_START (obj), start);\
|
||||
assert_equals_uint64 (_INPOINT (obj), inpoint);\
|
||||
assert_equals_uint64 (_DURATION (obj), duration);\
|
||||
}
|
||||
|
||||
GST_START_TEST (test_basic_timeline_edition)
|
||||
{
|
||||
GESAsset *asset;
|
||||
|
@ -487,35 +508,6 @@ asset_added_cb (GESProject * project, GESAsset * asset, void *mainloop)
|
|||
g_main_loop_quit ((GMainLoop *) mainloop);
|
||||
}
|
||||
|
||||
static void
|
||||
deep_check (GESTimelineElement * element, GstClockTime start,
|
||||
GstClockTime inpoint, GstClockTime duration)
|
||||
{
|
||||
GList *track_elements, *tmp;
|
||||
GstClockTime rstart, rinpoint, rduration;
|
||||
|
||||
rstart = ges_timeline_element_get_start (GES_TIMELINE_ELEMENT (element));
|
||||
rinpoint = ges_timeline_element_get_inpoint (GES_TIMELINE_ELEMENT (element));
|
||||
rduration =
|
||||
ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (element));
|
||||
|
||||
assert_equals_uint64 (rstart, start);
|
||||
assert_equals_uint64 (rinpoint, inpoint);
|
||||
assert_equals_uint64 (rduration, duration);
|
||||
|
||||
track_elements = GES_CONTAINER_CHILDREN (element);
|
||||
for (tmp = track_elements; tmp; tmp = tmp->next) {
|
||||
rstart = ges_timeline_element_get_start (GES_TIMELINE_ELEMENT (tmp->data));
|
||||
rinpoint =
|
||||
ges_timeline_element_get_inpoint (GES_TIMELINE_ELEMENT (tmp->data));
|
||||
rduration =
|
||||
ges_timeline_element_get_duration (GES_TIMELINE_ELEMENT (tmp->data));
|
||||
assert_equals_uint64 (rstart, start);
|
||||
assert_equals_uint64 (rinpoint, inpoint);
|
||||
assert_equals_uint64 (rduration, duration);
|
||||
}
|
||||
}
|
||||
|
||||
GST_START_TEST (test_simple_triming)
|
||||
{
|
||||
GList *assets;
|
||||
|
@ -556,10 +548,10 @@ GST_START_TEST (test_simple_triming)
|
|||
|
||||
element = ges_layer_get_clips (layer)->data;
|
||||
|
||||
deep_check (element, 0, 0, 10);
|
||||
DEEP_CHECK (element, 0, 0, 10);
|
||||
ges_container_edit (GES_CONTAINER (element), NULL, -1, GES_EDIT_MODE_TRIM,
|
||||
GES_EDGE_START, 5);
|
||||
deep_check (element, 5, 5, 5);
|
||||
DEEP_CHECK (element, 5, 5, 5);
|
||||
|
||||
g_main_loop_unref (mainloop);
|
||||
gst_object_unref (timeline);
|
||||
|
@ -1018,6 +1010,274 @@ GST_START_TEST (test_timeline_edition_mode)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_groups)
|
||||
{
|
||||
GESAsset *asset;
|
||||
GESTimeline *timeline;
|
||||
GESGroup *group;
|
||||
GESLayer *layer, *layer1, *layer2, *layer3;
|
||||
GESClip *c, *c1, *c2, *c3, *c4, *c5;
|
||||
|
||||
GList *clips = NULL;
|
||||
|
||||
ges_init ();
|
||||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
|
||||
/* Our timeline
|
||||
*
|
||||
* --0------------10-Group-----20---------------30-----------------------70
|
||||
* | +-----------+ |+-----------50 |
|
||||
* L | | C | || C3 | |
|
||||
* | +-----------+ |+-----------+ |
|
||||
* --|-------------------------------------------|-----40----------------|
|
||||
* | +------------+ +-------------+ | +--------60 |
|
||||
* L1 | | C1 | | C2 | | | C4 | |
|
||||
* | +------------+ +-------------+ | +--------+ |
|
||||
* --|-------------------------------------------|-----------------------|
|
||||
* | | +--------+|
|
||||
* L2 | | | c5 ||
|
||||
* | | +--------+|
|
||||
* --+-------------------------------------------+-----------------------+
|
||||
*
|
||||
* L3
|
||||
*
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
layer1 = ges_timeline_append_layer (timeline);
|
||||
layer2 = ges_timeline_append_layer (timeline);
|
||||
layer3 = ges_timeline_append_layer (timeline);
|
||||
assert_equals_int (ges_layer_get_priority (layer3), 3);
|
||||
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
|
||||
|
||||
c = ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c1 = ges_layer_add_asset (layer1, asset, 10, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c2 = ges_layer_add_asset (layer1, asset, 20, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
clips = g_list_prepend (clips, c);
|
||||
clips = g_list_prepend (clips, c1);
|
||||
clips = g_list_prepend (clips, c2);
|
||||
group = GES_GROUP (ges_container_group (clips));
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
|
||||
g_list_free (clips);
|
||||
|
||||
fail_unless (GES_IS_GROUP (group));
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 30);
|
||||
|
||||
c3 = ges_layer_add_asset (layer, asset, 30, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c4 = ges_layer_add_asset (layer1, asset, 40, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c5 = ges_layer_add_asset (layer2, asset, 50, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
|
||||
CHECK_OBJECT_PROPS (c3, 30, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c), NULL, -1,
|
||||
GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 10) == TRUE);
|
||||
|
||||
CHECK_OBJECT_PROPS (c, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 30, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 60, 0, 20);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c), NULL, 1,
|
||||
GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 10) == TRUE);
|
||||
CHECK_OBJECT_PROPS (c, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 30, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 60, 0, 20);
|
||||
check_layer (c, 1);
|
||||
check_layer (c1, 2);
|
||||
check_layer (c2, 2);
|
||||
check_layer (c3, 1);
|
||||
check_layer (c4, 2);
|
||||
check_layer (c5, 3);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c1), NULL, 2,
|
||||
GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 40) == TRUE);
|
||||
CHECK_OBJECT_PROPS (c, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 20, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c2, 40, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 60, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 70, 0, 20);
|
||||
check_layer (c, 1);
|
||||
check_layer (c1, 2);
|
||||
check_layer (c2, 2);
|
||||
check_layer (c3, 1);
|
||||
check_layer (c4, 2);
|
||||
check_layer (c5, 3);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c1), NULL, 2,
|
||||
GES_EDIT_MODE_RIPPLE, GES_EDGE_END, 30) == TRUE);
|
||||
CHECK_OBJECT_PROPS (c, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 30, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 60, 0, 20);
|
||||
check_layer (c, 1);
|
||||
check_layer (c1, 2);
|
||||
check_layer (c2, 2);
|
||||
check_layer (c3, 1);
|
||||
check_layer (c4, 2);
|
||||
check_layer (c5, 3);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c), NULL, 0,
|
||||
GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, 0) == TRUE);
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c3, 30, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c2), NULL, -1,
|
||||
GES_EDIT_MODE_ROLL, GES_EDGE_END, 40) == TRUE);
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c3, 40, 10, 10);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 40);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
gst_object_unref (timeline);
|
||||
gst_object_unref (asset);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_snapping_groups)
|
||||
{
|
||||
GESAsset *asset;
|
||||
GESTimeline *timeline;
|
||||
GESGroup *group;
|
||||
GESLayer *layer, *layer1, *layer2, *layer3;
|
||||
GESClip *c, *c1, *c2, *c3, *c4, *c5;
|
||||
|
||||
GList *clips = NULL;
|
||||
|
||||
ges_init ();
|
||||
|
||||
timeline = ges_timeline_new_audio_video ();
|
||||
g_object_set (timeline, "snapping-distance", (guint64) 3, NULL);
|
||||
|
||||
/* Our timeline
|
||||
*
|
||||
* --0------------10-Group-----20---------25-----30----------------------70
|
||||
* | +-----------+ | +-----------50 |
|
||||
* L | | C | | | C3 | |
|
||||
* | +-----------+ | +-----------+ |
|
||||
* --|------------------------------------|------------40----------------|
|
||||
* | +------------+ +--------+ +--------60 |
|
||||
* L1 | | C1 | | C2 | | C4 | |
|
||||
* | +------------+ +--------+ +--------+ |
|
||||
* --|------------------------------------+------------------------------|
|
||||
* | +--------+|
|
||||
* L2 | | c5 ||
|
||||
* | +--------+|
|
||||
* --+-------------------------------------------------------------------+
|
||||
*
|
||||
* L3
|
||||
*
|
||||
* -----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
layer = ges_timeline_append_layer (timeline);
|
||||
layer1 = ges_timeline_append_layer (timeline);
|
||||
layer2 = ges_timeline_append_layer (timeline);
|
||||
layer3 = ges_timeline_append_layer (timeline);
|
||||
assert_equals_int (ges_layer_get_priority (layer3), 3);
|
||||
asset = ges_asset_request (GES_TYPE_TEST_CLIP, NULL, NULL);
|
||||
|
||||
c = ges_layer_add_asset (layer, asset, 0, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c1 = ges_layer_add_asset (layer1, asset, 10, 0, 10, GES_TRACK_TYPE_UNKNOWN);
|
||||
c2 = ges_layer_add_asset (layer1, asset, 20, 0, 5, GES_TRACK_TYPE_UNKNOWN);
|
||||
clips = g_list_prepend (clips, c);
|
||||
clips = g_list_prepend (clips, c1);
|
||||
clips = g_list_prepend (clips, c2);
|
||||
group = GES_GROUP (ges_container_group (clips));
|
||||
fail_unless (GES_TIMELINE_ELEMENT_TIMELINE (group) == timeline);
|
||||
g_list_free (clips);
|
||||
|
||||
fail_unless (GES_IS_GROUP (group));
|
||||
CHECK_OBJECT_PROPS (c, 0, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c1, 10, 0, 10);
|
||||
CHECK_OBJECT_PROPS (c2, 20, 0, 5);
|
||||
CHECK_OBJECT_PROPS (group, 0, 0, 25);
|
||||
|
||||
c3 = ges_layer_add_asset (layer, asset, 30, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c4 = ges_layer_add_asset (layer1, asset, 40, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
c5 = ges_layer_add_asset (layer2, asset, 50, 0, 20, GES_TRACK_TYPE_UNKNOWN);
|
||||
|
||||
CHECK_OBJECT_PROPS (c3, 30, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c4, 40, 0, 20);
|
||||
CHECK_OBJECT_PROPS (c5, 50, 0, 20);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
/* c2 should snap with C3 and make the group moving to 5 */
|
||||
fail_unless (ges_container_edit (GES_CONTAINER (c), NULL, -1,
|
||||
GES_EDIT_MODE_NORMAL, GES_EDGE_NONE, 3) == TRUE);
|
||||
|
||||
DEEP_CHECK (c, 5, 0, 10);
|
||||
DEEP_CHECK (c1, 15, 0, 10);
|
||||
DEEP_CHECK (c2, 25, 0, 5);
|
||||
DEEP_CHECK (c2, 25, 0, 5);
|
||||
DEEP_CHECK (c4, 40, 0, 20);
|
||||
DEEP_CHECK (c5, 50, 0, 20);
|
||||
CHECK_OBJECT_PROPS (group, 5, 0, 25);
|
||||
check_layer (c, 0);
|
||||
check_layer (c1, 1);
|
||||
check_layer (c2, 1);
|
||||
check_layer (c3, 0);
|
||||
check_layer (c4, 1);
|
||||
check_layer (c5, 2);
|
||||
|
||||
|
||||
gst_object_unref (timeline);
|
||||
gst_object_unref (asset);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
ges_suite (void)
|
||||
{
|
||||
|
@ -1030,6 +1290,8 @@ ges_suite (void)
|
|||
tcase_add_test (tc_chain, test_snapping);
|
||||
tcase_add_test (tc_chain, test_timeline_edition_mode);
|
||||
tcase_add_test (tc_chain, test_simple_triming);
|
||||
tcase_add_test (tc_chain, test_groups);
|
||||
tcase_add_test (tc_chain, test_snapping_groups);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue