mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 23:28:16 +00:00
ges: Add a timeline edition mode API
+ timeline: Add a snapping-distance property + Bump the GLib dependency to 2.28 in the mean time as we need some functions from GSequence that only landed + Update the testsuite accordingly API: GESTimeline:snapping-distance property API: ges_timeline_object_edit API: ges_timeline_object_ripple API: ges_timeline_object_ripple_end API: ges_timeline_object_roll_start API: ges_timeline_object_roll_end API: ges_timeline_object_trim_start API: ges_track_object_edit API: GESEdge enum API: GESEditMode enum
This commit is contained in:
parent
7cced397b6
commit
2fd5364927
11 changed files with 1694 additions and 53 deletions
|
@ -195,7 +195,7 @@ dnl *** checks for headers ***
|
|||
dnl *** checks for dependency libraries ***
|
||||
|
||||
dnl GLib is required
|
||||
AG_GST_GLIB_CHECK([2.22])
|
||||
AG_GST_GLIB_CHECK([2.28])
|
||||
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.16, HAVE_GIO=yes, HAVE_GIO=no)
|
||||
AC_SUBST(GIO_CFLAGS)
|
||||
|
|
|
@ -30,6 +30,8 @@ GESTextVAlign
|
|||
DEFAULT_VALIGNMENT
|
||||
GESVideoTestPattern
|
||||
GESPipelineFlags
|
||||
GESEdge
|
||||
GESEditMode
|
||||
<SUBSECTION Standard>
|
||||
GES_TYPE_TRACK_TYPE
|
||||
ges_track_type_get_type
|
||||
|
@ -104,6 +106,7 @@ ges_track_object_set_child_property_by_pspec
|
|||
ges_track_object_get_child_property
|
||||
ges_track_object_get_child_property_valist
|
||||
ges_track_object_get_child_property_by_pspec
|
||||
ges_track_object_edit
|
||||
<SUBSECTION Standard>
|
||||
GES_TRACK_OBJECT_DURATION
|
||||
GES_TRACK_OBJECT_INPOINT
|
||||
|
@ -321,6 +324,12 @@ ges_timeline_object_set_top_effect_priority
|
|||
ges_timeline_object_set_supported_formats
|
||||
ges_timeline_object_get_supported_formats
|
||||
ges_timeline_object_split
|
||||
ges_timeline_object_edit
|
||||
ges_timeline_object_ripple
|
||||
ges_timeline_object_ripple_end
|
||||
ges_timeline_object_roll_start
|
||||
ges_timeline_object_roll_end
|
||||
ges_timeline_object_trim_start
|
||||
<SUBSECTION Standard>
|
||||
GES_TIMELINE_OBJECT_DURATION
|
||||
GES_TIMELINE_OBJECT_INPOINT
|
||||
|
|
|
@ -50,11 +50,14 @@ static void
|
|||
register_ges_pipeline_flags (GType * id)
|
||||
{
|
||||
static const GFlagsValue values[] = {
|
||||
{C_ENUM (TIMELINE_MODE_PREVIEW_AUDIO), "TIMELINE_MODE_PREVIEW_AUDIO", "audio_preview"},
|
||||
{C_ENUM (TIMELINE_MODE_PREVIEW_VIDEO), "TIMELINE_MODE_PREVIEW_VIDEO", "video_preview"},
|
||||
{C_ENUM (TIMELINE_MODE_PREVIEW_AUDIO), "TIMELINE_MODE_PREVIEW_AUDIO",
|
||||
"audio_preview"},
|
||||
{C_ENUM (TIMELINE_MODE_PREVIEW_VIDEO), "TIMELINE_MODE_PREVIEW_VIDEO",
|
||||
"video_preview"},
|
||||
{C_ENUM (TIMELINE_MODE_PREVIEW), "TIMELINE_MODE_PREVIEW", "full_preview"},
|
||||
{C_ENUM (TIMELINE_MODE_RENDER), "TIMELINE_MODE_RENDER", "render"},
|
||||
{C_ENUM (TIMELINE_MODE_SMART_RENDER), "TIMELINE_MODE_SMART_RENDER", "smart_render"},
|
||||
{C_ENUM (TIMELINE_MODE_SMART_RENDER), "TIMELINE_MODE_SMART_RENDER",
|
||||
"smart_render"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -71,6 +74,64 @@ ges_pipeline_flags_get_type (void)
|
|||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
register_ges_edit_mode (GType * id)
|
||||
{
|
||||
static const GEnumValue edit_mode[] = {
|
||||
{C_ENUM (GES_EDIT_MODE_NORMAL), "GES_EDIT_MODE_NORMAL",
|
||||
"edit_normal"},
|
||||
|
||||
{C_ENUM (GES_EDIT_MODE_RIPPLE), "GES_EDIT_MODE_RIPPLE",
|
||||
"edit_ripple"},
|
||||
|
||||
{C_ENUM (GES_EDIT_MODE_ROLL), "GES_EDIT_MODE_ROLL",
|
||||
"edit_roll"},
|
||||
|
||||
{C_ENUM (GES_EDIT_MODE_TRIM), "GES_EDIT_MODE_TRIM",
|
||||
"edit_trim"},
|
||||
|
||||
{C_ENUM (GES_EDIT_MODE_SLIDE), "GES_EDIT_MODE_SLIDE",
|
||||
"edit_slide"},
|
||||
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
*id = g_enum_register_static ("GESEditMode", edit_mode);
|
||||
}
|
||||
|
||||
GType
|
||||
ges_edit_mode_get_type (void)
|
||||
{
|
||||
static GType id;
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
g_once (&once, (GThreadFunc) register_ges_edit_mode, &id);
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
register_ges_edge (GType * id)
|
||||
{
|
||||
static const GEnumValue edges[] = {
|
||||
{C_ENUM (GES_EDGE_START), "GES_EDGE_START", "edge_start"},
|
||||
{C_ENUM (GES_EDGE_END), "GES_EDGE_END", "edge_end"},
|
||||
{C_ENUM (GES_EDGE_NONE), "GES_EDGE_NONE", "edge_none"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
*id = g_enum_register_static ("GESEdge", edges);
|
||||
}
|
||||
|
||||
GType
|
||||
ges_edge_get_type (void)
|
||||
{
|
||||
static GType id;
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
g_once (&once, (GThreadFunc) register_ges_edge, &id);
|
||||
return id;
|
||||
}
|
||||
|
||||
static GEnumValue transition_types[] = {
|
||||
{
|
||||
0,
|
||||
|
|
|
@ -323,6 +323,60 @@ typedef enum {
|
|||
|
||||
GType ges_pipeline_flags_get_type (void);
|
||||
|
||||
/**
|
||||
* GESEditMode:
|
||||
* @GES_EDIT_MODE_NORMAL: The object is edited the normal way (default).
|
||||
* @GES_EDIT_MODE_RIPPLE: The objects are edited in ripple mode.
|
||||
* The Ripple mode allows you to modify the beginning/end of a clip
|
||||
* and move the neighbours accordingly. This will change the overall
|
||||
* timeline duration.
|
||||
* @GES_EDIT_MODE_ROLL: The object is edited in roll mode.
|
||||
* The Roll mode allows you to modify the position of an editing point
|
||||
* between two clips without modifying the inpoint of the first clip
|
||||
* nor the out-point of the second clip. This will not change the
|
||||
* overall timeline duration.
|
||||
* @GES_EDIT_MODE_TRIM: The object is edited in trim mode.
|
||||
* The Trim mode allows you to modify the in-point/out-point of a clip without
|
||||
* modifying it's duration or position in the timeline.
|
||||
* @GES_EDIT_MODE_SLIDE: The object is edited in slide mode.
|
||||
* The Slide mode allows you to modify the position of a clip in a
|
||||
* timeline without modifying it's duration or it's in-point, but will
|
||||
* modify the out-point of the previous clip and in-point of the
|
||||
* following clip so as not to modify the overall timeline duration.
|
||||
*
|
||||
* The various edition modes the a clip can be edited with.
|
||||
*/
|
||||
typedef enum {
|
||||
GES_EDIT_MODE_NORMAL,
|
||||
GES_EDIT_MODE_RIPPLE,
|
||||
GES_EDIT_MODE_ROLL,
|
||||
GES_EDIT_MODE_TRIM,
|
||||
GES_EDIT_MODE_SLIDE
|
||||
} GESEditMode;
|
||||
|
||||
#define GES_TYPE_EDIT_MODE ges_edit_mode_get_type()
|
||||
|
||||
GType ges_edit_mode_get_type (void);
|
||||
|
||||
/**
|
||||
* GESEdge:
|
||||
* @GES_EDGE_START: Represents the start of an object.
|
||||
* @GES_EDGE_END: Represents the end of an object.
|
||||
* @GES_EDGE_NONE: Represent the fact we are not workin with any edge of an
|
||||
* object.
|
||||
*
|
||||
* The edges of an object contain in a #GESTimeline or #GESTrack
|
||||
*/
|
||||
typedef enum {
|
||||
GES_EDGE_START,
|
||||
GES_EDGE_END,
|
||||
GES_EDGE_NONE
|
||||
} GESEdge;
|
||||
|
||||
#define GES_TYPE_EDGE ges_edge_get_type()
|
||||
|
||||
GType ges_edge_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GES_ENUMS_H__ */
|
||||
|
|
|
@ -22,12 +22,45 @@
|
|||
#define __GES_INTERNAL_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "ges-timeline.h"
|
||||
#include "ges-track-object.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (_ges_debug);
|
||||
#define GST_CAT_DEFAULT _ges_debug
|
||||
|
||||
|
||||
GESTrackObject *
|
||||
ges_track_object_copy (GESTrackObject * object, gboolean deep);
|
||||
|
||||
gboolean
|
||||
timeline_ripple_object (GESTimeline *timeline, GESTrackObject *obj,
|
||||
GList * layers, GESEdge edge,
|
||||
guint64 position);
|
||||
|
||||
gboolean
|
||||
timeline_slide_object (GESTimeline *timeline, GESTrackObject *obj,
|
||||
GList * layers, GESEdge edge, guint64 position);
|
||||
|
||||
gboolean
|
||||
timeline_roll_object (GESTimeline *timeline, GESTrackObject *obj,
|
||||
GList * layers, GESEdge edge, guint64 position);
|
||||
|
||||
gboolean
|
||||
timeline_trim_object (GESTimeline *timeline, GESTrackObject * object,
|
||||
GList * layers, GESEdge edge, guint64 position);
|
||||
gboolean
|
||||
ges_timeline_trim_object_simple (GESTimeline * timeline, GESTrackObject * obj,
|
||||
GList * layers, GESEdge edge, guint64 position, gboolean snapping);
|
||||
|
||||
gboolean
|
||||
ges_timeline_move_object_simple (GESTimeline * timeline, GESTrackObject * object,
|
||||
GList * layers, GESEdge edge, guint64 position);
|
||||
|
||||
gboolean
|
||||
timeline_move_object (GESTimeline *timeline, GESTrackObject * object,
|
||||
GList * layers, GESEdge edge, guint64 position);
|
||||
|
||||
gboolean
|
||||
timeline_context_to_layer (GESTimeline *timeline, gint offset);
|
||||
|
||||
#endif /* __GES_INTERNAL_H__ */
|
||||
|
|
|
@ -1304,6 +1304,73 @@ ges_timeline_object_set_top_effect_priority (GESTimelineObject * object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_edit:
|
||||
* @object: the #GESTimelineObject to edit
|
||||
* @layers: (element-type GESTimelineLayer): The layers you want the edit to
|
||||
* happen in, %NULL means that the edition is done in all the
|
||||
* #GESTimelineLayers contained in the current timeline.
|
||||
* @new_layer_priority: The priority of the layer @object should land in.
|
||||
* If the layer you're trying to move the object to doesn't exist, it will
|
||||
* be created automatically. -1 means no move.
|
||||
* @mode: The #GESEditMode in which the editition will happen.
|
||||
* @edge: The #GESEdge the edit should happen on.
|
||||
* @position: The position at which to edit @object (in nanosecond)
|
||||
*
|
||||
* Edit @object in the different exisiting #GESEditMode modes. In the case of
|
||||
* slide, and roll, you need to specify a #GESEdge
|
||||
*
|
||||
* Returns: %TRUE if the object as been edited properly, %FALSE if an error
|
||||
* occured
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_edit (GESTimelineObject * object, GList * layers,
|
||||
gint new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position)
|
||||
{
|
||||
GList *tmp;
|
||||
gboolean ret = TRUE;
|
||||
GESTimelineLayer *layer;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
if (!G_UNLIKELY (object->priv->trackobjects)) {
|
||||
GST_WARNING_OBJECT (object, "Trying to edit, but not containing"
|
||||
"any TrackObject yet.");
|
||||
return FALSE;
|
||||
} else if (position < 0) {
|
||||
GST_DEBUG_OBJECT (object, "Trying to move before 0, not moving");
|
||||
}
|
||||
|
||||
for (tmp = object->priv->trackobjects; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret &= ges_track_object_edit (tmp->data, layers, mode, edge, position);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Moving to layer */
|
||||
if (new_layer_priority == -1) {
|
||||
GST_DEBUG_OBJECT (object, "Not moving new prio %d", new_layer_priority);
|
||||
} else {
|
||||
gint priority_offset;
|
||||
|
||||
layer = object->priv->layer;
|
||||
if (layer == NULL) {
|
||||
GST_WARNING_OBJECT (object, "Not in any layer yet, not moving");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
priority_offset = new_layer_priority -
|
||||
ges_timeline_layer_get_priority (layer);
|
||||
|
||||
ret &= timeline_context_to_layer (layer->timeline, object, priority_offset);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_split:
|
||||
* @object: the #GESTimelineObject to split
|
||||
|
@ -1554,6 +1621,264 @@ ges_timeline_object_set_max_duration (GESTimelineObject * object,
|
|||
klass->set_max_duration (object, maxduration);
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_ripple:
|
||||
* @object: The #GESTimeline to ripple.
|
||||
* @start: The new start of @object in ripple mode.
|
||||
*
|
||||
* Edits @object in ripple mode. It allows you to modify the
|
||||
* start of @object and move the following neighbours accordingly.
|
||||
* This will change the overall timeline duration.
|
||||
*
|
||||
* You could also use:
|
||||
*
|
||||
* #ges_timeline_object_edit (@object, @layers,
|
||||
* new_layer_priority=-1, GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE,
|
||||
* @position);
|
||||
*
|
||||
* Which lets you more control over layer management.
|
||||
*
|
||||
* Returns: %TRUE if the object as been rippled properly, %FALSE if an error
|
||||
* occured
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_ripple (GESTimelineObject * object, guint64 start)
|
||||
{
|
||||
GList *tmp, *tckobjs;
|
||||
gboolean ret = TRUE;
|
||||
GESTimeline *timeline;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
timeline = ges_timeline_layer_get_timeline (object->priv->layer);
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (object);
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret = timeline_ripple_object (timeline, GES_TRACK_OBJECT (tmp->data),
|
||||
NULL, GES_EDGE_NONE, start);
|
||||
/* As we work only with locked objects, the changes will be reflected
|
||||
* to others controlled TrackObjects */
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free_full (tckobjs, g_object_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_ripple_end:
|
||||
* @object: The #GESTimeline to ripple.
|
||||
* @end: The new end (start + duration) of @object in ripple mode. It will
|
||||
* basically only change the duration of @object.
|
||||
*
|
||||
* Edits @object in ripple mode. It allows you to modify the
|
||||
* duration of a @object and move the following neighbours accordingly.
|
||||
* This will change the overall timeline duration.
|
||||
*
|
||||
* You could also use:
|
||||
*
|
||||
* #ges_timeline_object_edit (@object, @layers,
|
||||
* new_layer_priority=-1, GES_EDIT_MODE_RIPPLE, GES_EDGE_END, @end);
|
||||
*
|
||||
* Which lets you more control over layer management.
|
||||
*
|
||||
* Returns: %TRUE if the object as been rippled properly, %FALSE if an error
|
||||
* occured
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_ripple_end (GESTimelineObject * object, guint64 end)
|
||||
{
|
||||
GList *tmp, *tckobjs;
|
||||
gboolean ret = TRUE;
|
||||
GESTimeline *timeline;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
timeline = ges_timeline_layer_get_timeline (object->priv->layer);
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (object);
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret = timeline_ripple_object (timeline, GES_TRACK_OBJECT (tmp->data),
|
||||
NULL, GES_EDGE_END, end);
|
||||
/* As we work only with locked objects, the changes will be reflected
|
||||
* to others controlled TrackObjects */
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free_full (tckobjs, g_object_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_roll_start:
|
||||
* @start: The new start of @object in roll mode, it will also adapat
|
||||
* the in-point of @object according
|
||||
*
|
||||
* Edits @object in roll mode. It allows you to modify the
|
||||
* start and inpoint of a @object and "resize" (basicly change the duration
|
||||
* in this case) of the previous neighbours accordingly.
|
||||
* This will not change the overall timeline duration.
|
||||
*
|
||||
* You could also use:
|
||||
*
|
||||
* #ges_timeline_object_edit (@object, @layers,
|
||||
* new_layer_priority=-1, GES_EDIT_MODE_ROLL, GES_EDGE_START, @start);
|
||||
*
|
||||
* Which lets you more control over layer management.
|
||||
*
|
||||
* Returns: %TRUE if the object as been roll properly, %FALSE if an error
|
||||
* occured
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_roll_start (GESTimelineObject * object, guint64 start)
|
||||
{
|
||||
GList *tmp, *tckobjs;
|
||||
gboolean ret = TRUE;
|
||||
GESTimeline *timeline;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
timeline = ges_timeline_layer_get_timeline (object->priv->layer);
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (object);
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret = timeline_roll_object (timeline, GES_TRACK_OBJECT (tmp->data),
|
||||
NULL, GES_EDGE_START, start);
|
||||
/* As we work only with locked objects, the changes will be reflected
|
||||
* to others controlled TrackObjects */
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free_full (tckobjs, g_object_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_roll_end:
|
||||
* @object: The #GESTimeline to roll.
|
||||
* @end: The new end (start + duration) of @object in roll mode
|
||||
*
|
||||
* Edits @object in roll mode. It allows you to modify the
|
||||
* duration of a @object and trim (basicly change the start + inpoint
|
||||
* in this case) the following neighbours accordingly.
|
||||
* This will not change the overall timeline duration.
|
||||
*
|
||||
* You could also use:
|
||||
*
|
||||
* #ges_timeline_object_edit (@object, @layers,
|
||||
* new_layer_priority=-1, GES_EDIT_MODE_ROLL, GES_EDGE_END, @end);
|
||||
*
|
||||
* Which lets you more control over layer management.
|
||||
*
|
||||
* Returns: %TRUE if the object as been rolled properly, %FALSE if an error
|
||||
* occured
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_roll_end (GESTimelineObject * object, guint64 end)
|
||||
{
|
||||
GList *tmp, *tckobjs;
|
||||
gboolean ret = TRUE;
|
||||
GESTimeline *timeline;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
timeline = ges_timeline_layer_get_timeline (object->priv->layer);
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (object);
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret = timeline_roll_object (timeline, GES_TRACK_OBJECT (tmp->data),
|
||||
NULL, GES_EDGE_END, end);
|
||||
/* As we work only with locked objects, the changes will be reflected
|
||||
* to others controlled TrackObjects */
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free_full (tckobjs, g_object_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_timeline_object_trim_start:
|
||||
* @object: The #GESTimeline to trim.
|
||||
* @start: The new start of @object in trim mode, will adapt the inpoint
|
||||
* of @object accordingly
|
||||
*
|
||||
* Edits @object in trim mode. It allows you to modify the
|
||||
* inpoint and start of @object.
|
||||
* This will not change the overall timeline duration.
|
||||
*
|
||||
* You could also use:
|
||||
*
|
||||
* #ges_timeline_object_edit (@object, @layers,
|
||||
* new_layer_priority=-1, GES_EDIT_MODE_TRIM, GES_EDGE_START, @start);
|
||||
*
|
||||
* Which lets you more control over layer management.
|
||||
*
|
||||
* Note that to trim the end of an object you can just set its duration. The same way
|
||||
* as this method, it will take into account the snapping-distance property of the
|
||||
* timeline in which @object is.
|
||||
*
|
||||
* Returns: %TRUE if the object as been trimmed properly, %FALSE if an error
|
||||
* occured
|
||||
*/
|
||||
gboolean
|
||||
ges_timeline_object_trim_start (GESTimelineObject * object, guint64 start)
|
||||
{
|
||||
GList *tmp, *tckobjs;
|
||||
gboolean ret = TRUE;
|
||||
GESTimeline *timeline;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE_OBJECT (object), FALSE);
|
||||
|
||||
timeline = ges_timeline_layer_get_timeline (object->priv->layer);
|
||||
|
||||
if (timeline == NULL) {
|
||||
GST_DEBUG ("Not in a timeline yet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tckobjs = ges_timeline_object_get_track_objects (object);
|
||||
for (tmp = tckobjs; tmp; tmp = g_list_next (tmp)) {
|
||||
if (ges_track_object_is_locked (tmp->data)) {
|
||||
ret = timeline_trim_object (timeline, GES_TRACK_OBJECT (tmp->data),
|
||||
NULL, GES_EDGE_START, start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_list_free_full (tckobjs, g_object_unref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
update_height (GESTimelineObject * object)
|
||||
{
|
||||
|
|
|
@ -300,8 +300,29 @@ ges_timeline_object_set_supported_formats (GESTimelineObject * object,
|
|||
GESTimelineObject *
|
||||
ges_timeline_object_split (GESTimelineObject * object, guint64 position);
|
||||
|
||||
gboolean
|
||||
ges_timeline_object_edit (GESTimelineObject * object,
|
||||
GList *layers, gint new_layer_priority,
|
||||
GESEditMode mode, GESEdge edge,
|
||||
guint64 position);
|
||||
|
||||
void
|
||||
ges_timeline_object_objects_set_locked (GESTimelineObject * object, gboolean locked);
|
||||
|
||||
gboolean ges_timeline_object_ripple (GESTimelineObject *object,
|
||||
guint64 start);
|
||||
|
||||
gboolean ges_timeline_object_ripple_end (GESTimelineObject *object,
|
||||
guint64 end);
|
||||
|
||||
gboolean ges_timeline_object_roll_start (GESTimelineObject *object,
|
||||
guint64 start);
|
||||
|
||||
gboolean ges_timeline_object_roll_end (GESTimelineObject *object,
|
||||
guint64 end);
|
||||
|
||||
gboolean ges_timeline_object_trim_start (GESTimelineObject *object,
|
||||
guint64 start);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _GES_TIMELINE_OBJECT */
|
||||
|
|
1084
ges/ges-timeline.c
1084
ges/ges-timeline.c
File diff suppressed because it is too large
Load diff
|
@ -1544,3 +1544,70 @@ ges_track_object_copy (GESTrackObject * object, gboolean deep)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ges_track_object_edit:
|
||||
* @object: the #GESTrackObject to edit
|
||||
* @layers: (element-type GESTimelineLayer): The layers you want the edit to
|
||||
* happen in, %NULL means that the edition is done in all the
|
||||
* #GESTimelineLayers contained in the current timeline.
|
||||
* FIXME: This is not implemented yet.
|
||||
* @mode: The #GESEditMode in which the editition will happen.
|
||||
* @edge: The #GESEdge the edit should happen on.
|
||||
* @position: The position at which to edit @object (in nanosecond)
|
||||
*
|
||||
* Edit @object in the different exisiting #GESEditMode modes. In the case of
|
||||
* slide, and roll, you need to specify a #GESEdge
|
||||
*
|
||||
* Returns: %TRUE if the object as been edited properly, %FALSE if an error
|
||||
* occured
|
||||
*
|
||||
* Since: 0.10.XX
|
||||
*/
|
||||
gboolean
|
||||
ges_track_object_edit (GESTrackObject * object,
|
||||
GList * layers, GESEditMode mode, GESEdge edge, guint64 position)
|
||||
{
|
||||
GESTrack *track = ges_track_object_get_track (object);
|
||||
GESTimeline *timeline;
|
||||
|
||||
if (G_UNLIKELY (!track)) {
|
||||
GST_WARNING_OBJECT (object, "Trying to edit in %d mode but not in"
|
||||
"any Track yet.", mode);
|
||||
return FALSE;
|
||||
} else if (position < 0) {
|
||||
GST_DEBUG_OBJECT (object, "Trying to move before 0, not moving");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
timeline = GES_TIMELINE (ges_track_get_timeline (track));
|
||||
|
||||
if (G_UNLIKELY (!timeline)) {
|
||||
GST_WARNING_OBJECT (object, "Trying to edit in %d mode but not in"
|
||||
"track %p no in any timeline yet.", mode, track);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case GES_EDIT_MODE_NORMAL:
|
||||
timeline_move_object (timeline, object, layers, edge, position);
|
||||
break;
|
||||
case GES_EDIT_MODE_TRIM:
|
||||
timeline_trim_object (timeline, object, layers, edge, position);
|
||||
break;
|
||||
case GES_EDIT_MODE_RIPPLE:
|
||||
timeline_ripple_object (timeline, object, layers, edge, position);
|
||||
break;
|
||||
case GES_EDIT_MODE_ROLL:
|
||||
timeline_roll_object (timeline, object, layers, edge, position);
|
||||
break;
|
||||
case GES_EDIT_MODE_SLIDE:
|
||||
timeline_slide_object (timeline, object, layers, edge, position);
|
||||
break;
|
||||
default:
|
||||
GST_ERROR ("Unkown edit mode: %d", mode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -226,6 +226,10 @@ void ges_track_object_set_child_property (GESTrackObject * object,
|
|||
const gchar * first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
gboolean
|
||||
ges_track_object_edit (GESTrackObject * object,
|
||||
GList *layers, GESEditMode mode,
|
||||
GESEdge edge, guint64 position);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* _GES_TRACK_OBJECT */
|
||||
|
|
|
@ -115,19 +115,21 @@ GST_START_TEST (test_ges_scenario)
|
|||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (source));
|
||||
fail_unless (trackobjects != NULL);
|
||||
trackobject = GES_TRACK_OBJECT (trackobjects->data);
|
||||
/* There are 3 references:
|
||||
/* There are 4 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by the call to _get_track_objects() above */
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 4);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
/* There are 2 references:
|
||||
/* There are 3 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the timeline
|
||||
* 1 by the track */
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 3);
|
||||
|
||||
GST_DEBUG ("Remove the TimelineObject from the layer");
|
||||
|
||||
|
@ -252,19 +254,21 @@ GST_START_TEST (test_ges_timeline_add_layer)
|
|||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s1));
|
||||
fail_unless (trackobjects != NULL);
|
||||
trackobject = GES_TRACK_OBJECT (trackobjects->data);
|
||||
/* There are 3 references:
|
||||
/* There are 4 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the trackobject
|
||||
* 1 by the timeline
|
||||
* 1 added by the call to _get_track_objects() above */
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 4);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
/* There are 2 references:
|
||||
/* There are 3 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the timeline
|
||||
* 1 by the trackobject */
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 3);
|
||||
|
||||
trackobjects =
|
||||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s2));
|
||||
|
@ -274,10 +278,11 @@ GST_START_TEST (test_ges_timeline_add_layer)
|
|||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
/* There are 2 references:
|
||||
/* There are 3 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the timeline
|
||||
* 1 by the trackobject */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (trackobject), "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (trackobject), "trackobject", 3);
|
||||
|
||||
trackobjects =
|
||||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s3));
|
||||
|
@ -287,10 +292,11 @@ GST_START_TEST (test_ges_timeline_add_layer)
|
|||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
/* There are 2 references:
|
||||
/* There are 3 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the timeline
|
||||
* 1 by the trackobject */
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (trackobject, "trackobject", 3);
|
||||
|
||||
/* theoretically this is all we need to do to ensure cleanup */
|
||||
g_object_unref (timeline);
|
||||
|
@ -369,11 +375,12 @@ GST_START_TEST (test_ges_timeline_add_layer_first)
|
|||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s1));
|
||||
fail_unless (trackobjects != NULL);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* Each object has 3 references:
|
||||
/* Each object has 4 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by _get_track_object() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
|
@ -382,11 +389,12 @@ GST_START_TEST (test_ges_timeline_add_layer_first)
|
|||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s2));
|
||||
fail_unless (trackobjects != NULL);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* Each object has 3 references:
|
||||
/* Each object has 4 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by _get_track_object() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
|
@ -395,11 +403,12 @@ GST_START_TEST (test_ges_timeline_add_layer_first)
|
|||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s3));
|
||||
fail_unless (trackobjects != NULL);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* Each object has 3 references:
|
||||
/* Each object has 4 references:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by _get_track_object() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_list_free (trackobjects);
|
||||
|
@ -482,67 +491,73 @@ GST_START_TEST (test_ges_timeline_remove_track)
|
|||
fail_unless (trackobjects != NULL);
|
||||
t1 = GES_TRACK_OBJECT ((trackobjects)->data);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by the call to _get_track_objects() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_object_ref (t1);
|
||||
g_list_free (trackobjects);
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelinobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by ourselves above (g_object_ref (t1)) */
|
||||
ASSERT_OBJECT_REFCOUNT (t1, "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (t1, "trackobject", 4);
|
||||
|
||||
trackobjects =
|
||||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s2));
|
||||
fail_unless (trackobjects != NULL);
|
||||
t2 = GES_TRACK_OBJECT (trackobjects->data);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by the call to _get_track_objects() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_object_ref (t2);
|
||||
g_list_free (trackobjects);
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelinobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by ourselves above (g_object_ref (t1)) */
|
||||
ASSERT_OBJECT_REFCOUNT (t2, "t2", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (t2, "t2", 4);
|
||||
|
||||
trackobjects =
|
||||
ges_timeline_object_get_track_objects (GES_TIMELINE_OBJECT (s3));
|
||||
fail_unless (trackobjects != NULL);
|
||||
t3 = GES_TRACK_OBJECT (trackobjects->data);
|
||||
for (tmp = trackobjects; tmp; tmp = tmp->next) {
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelineobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by the call to _get_track_objects() above */
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (GES_TRACK_OBJECT (tmp->data), "trackobject", 4);
|
||||
g_object_unref (GES_TRACK_OBJECT (tmp->data));
|
||||
}
|
||||
g_object_ref (t3);
|
||||
g_list_free (trackobjects);
|
||||
/* There are 3 references held:
|
||||
/* There are 4 references held:
|
||||
* 1 by the timelinobject
|
||||
* 1 by the track
|
||||
* 1 by the timeline
|
||||
* 1 added by ourselves above (g_object_ref (t1)) */
|
||||
ASSERT_OBJECT_REFCOUNT (t3, "t3", 3);
|
||||
ASSERT_OBJECT_REFCOUNT (t3, "t3", 4);
|
||||
|
||||
/* remove the track and check that the track objects have been released */
|
||||
fail_unless (ges_timeline_remove_track (timeline, track));
|
||||
|
||||
ASSERT_OBJECT_REFCOUNT (t1, "trackobject", 1);
|
||||
ASSERT_OBJECT_REFCOUNT (t2, "trackobject", 1);
|
||||
ASSERT_OBJECT_REFCOUNT (t3, "trackobject", 1);
|
||||
ASSERT_OBJECT_REFCOUNT (t1, "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (t2, "trackobject", 2);
|
||||
ASSERT_OBJECT_REFCOUNT (t3, "trackobject", 2);
|
||||
|
||||
g_object_unref (t1);
|
||||
g_object_unref (t2);
|
||||
|
|
Loading…
Reference in a new issue