gstreamer/ges/ges-clip.c

2368 lines
80 KiB
C
Raw Normal View History

2009-08-04 15:13:11 +00:00
/* GStreamer Editing Services
2009-11-30 14:14:25 +00:00
* Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
* 2009 Nokia Corporation
* 2012 Collabora Ltd.
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
2009-08-04 15:13:11 +00:00
*
* 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
2012-11-04 00:25:20 +00:00
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
2009-08-04 15:13:11 +00:00
*/
/**
* SECTION:gesclip
* @title: GESClip
2020-01-09 12:11:35 +00:00
* @short_description: Base class for elements that occupy a single
* #GESLayer and maintain equal timings of their children
2009-08-04 15:13:11 +00:00
*
2020-01-09 12:11:35 +00:00
* #GESClip-s are the core objects of a #GESLayer. Each clip may exist in
* a single layer but may control several #GESTrackElement-s that span
* several #GESTrack-s. A clip will ensure that all its children share the
* same #GESTimelineElement:start and #GESTimelineElement:duration in
* their tracks, which will match the #GESTimelineElement:start and
* #GESTimelineElement:duration of the clip itself. Therefore, changing
* the timing of the clip will change the timing of the children, and a
* change in the timing of a child will change the timing of the clip and
* subsequently all its siblings. As such, a clip can be treated as a
* singular object in its layer.
2009-08-04 15:13:11 +00:00
*
2020-01-09 12:11:35 +00:00
* For most uses of a #GESTimeline, it is often sufficient to only
* interact with #GESClip-s directly, which will take care of creating and
* organising the elements of the timeline's tracks.
*
* Most subclassed clips will be associated with some *core*
* #GESTrackElement-s. When such a clip is added to a layer in a timeline,
* it will create these children and they will be added to the timeline's
* tracks. You can connect to the #GESContainer::child-added signal to be
* notified of their creation. If a clip will produce several core
* elements of the same #GESTrackElement:track-type but they are destined
* for separate tracks, you should connect to the timeline's
* #GESTimeline::select-tracks-for-object signal to coordinate which
* tracks each element should land in.
*
* The #GESTimelineElement:in-point of the clip will control the
* #GESTimelineElement:in-point of these core elements to be the same
* value if their #GESTrackElement:has-internal-source is set to %TRUE.
*
* The #GESTimelineElement:max-duration of the clip is the minimum
* #GESTimelineElement:max-duration of its children. If you set its value
* to anything other than its current value, this will also set the
* #GESTimelineElement:max-duration of all its core children to the same
* value if their #GESTrackElement:has-internal-source is set to %TRUE.
* As a special case, whilst a clip does not yet have any core children,
* its #GESTimelineElement:max-duration may be set to indicate what its
* value will be once they are created.
2020-01-09 12:11:35 +00:00
*
* ## Effects
*
* Some subclasses (#GESSourceClip and #GESBaseEffect) may also allow
* their objects to have additional non-core #GESBaseEffect-s elements as
* children. These are additional effects that are applied to the output
* data of the core elements. They can be added to the clip using
* ges_container_add(), which will take care of adding the effect to the
* timeline's tracks. The new effect will be placed between the clip's
* core track elements and its other effects. As such, the newly added
* effect will be applied to any source data **before** the other existing
* effects. You can change the ordering of effects using
2020-01-09 12:11:35 +00:00
* ges_clip_set_top_effect_index().
2009-08-04 15:13:11 +00:00
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2009-08-04 15:13:11 +00:00
2013-01-20 15:42:29 +00:00
#include "ges-clip.h"
#include "ges.h"
#include "ges-internal.h"
#include <string.h>
static GList *ges_clip_create_track_elements_func (GESClip * clip,
GESTrackType type);
static gboolean _ripple (GESTimelineElement * element, GstClockTime start);
static gboolean _ripple_end (GESTimelineElement * element, GstClockTime end);
static gboolean _roll_start (GESTimelineElement * element, GstClockTime start);
static gboolean _roll_end (GESTimelineElement * element, GstClockTime end);
static gboolean _trim (GESTimelineElement * element, GstClockTime start);
static void _compute_height (GESContainer * container);
2013-01-20 15:42:29 +00:00
struct _GESClipPrivate
{
/*< public > */
2013-04-23 23:04:04 +00:00
GESLayer *layer;
/*< private > */
guint nb_effects;
GList *copied_track_elements;
GESLayer *copied_layer;
GESTimeline *copied_timeline;
gboolean prevent_priority_offset_update;
gboolean prevent_resort;
gboolean updating_max_duration;
gboolean prevent_max_duration_update;
gboolean setting_inpoint;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
gboolean allow_any_track;
2013-01-20 15:42:29 +00:00
/* The formats supported by this Clip */
GESTrackType supportedformats;
};
enum
{
PROP_0,
PROP_LAYER,
PROP_SUPPORTED_FORMATS,
PROP_LAST
};
static GParamSpec *properties[PROP_LAST];
static void
ges_extractable_interface_init (GESExtractableInterface * iface)
{
iface->asset_type = GES_TYPE_CLIP_ASSET;
}
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GESClip, ges_clip,
GES_TYPE_CONTAINER, G_ADD_PRIVATE (GESClip)
G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE,
ges_extractable_interface_init));
/****************************************************
* Listen to our children *
****************************************************/
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
#define _IS_CORE_CHILD(child) GES_TRACK_ELEMENT_IS_CORE(child)
#define _IS_TOP_EFFECT(child) \
(!_IS_CORE_CHILD (child) && GES_IS_BASE_EFFECT (child))
#define _IS_CORE_INTERNAL_SOURCE_CHILD(child) \
(_IS_CORE_CHILD (child) \
&& ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child)))
/* @min_priority: The absolute minimum priority a child of @container should have
* @max_priority: The absolute maximum priority a child of @container should have
*/
static void
_get_priority_range_full (GESContainer * container, guint32 * min_priority,
guint32 * max_priority, guint32 priority_base)
{
GESLayer *layer = GES_CLIP (container)->priv->layer;
if (layer) {
*min_priority = priority_base + layer->min_nle_priority;
Cleanup import of GNL and rename gnl to nle for Non Linear Engine Conflicts: ges/ges-track-element.c gnl/Makefile.am gnl/common Conflicts: ges/ges-internal.h ges/ges-track.c ges/ges-utils.c ges/nle/.gitignore ges/nle/gnlmarshal.list ges/nle/nle.h ges/nle/nlecomposition.c ges/nle/nlecomposition.h ges/nle/nleghostpad.c ges/nle/nleghostpad.h ges/nle/nleobject.c ges/nle/nleoperation.c ges/nle/nleoperation.h ges/nle/nlesource.c ges/nle/nlesource.h ges/nle/nletypes.h ges/nle/nleurisource.c ges/nle/nleurisource.h gnl/Makefile.am gnl/gnl.c gnl/gnl.h gnl/gnl/gnl.h gnl/gnl/gnlcomposition.c gnl/gnl/gnlcomposition.h gnl/gnl/gnlghostpad.c gnl/gnl/gnlghostpad.h gnl/gnl/gnlmarshal.list gnl/gnl/gnlobject.c gnl/gnl/gnloperation.c gnl/gnl/gnloperation.h gnl/gnl/gnlsource.c gnl/gnl/gnlsource.h gnl/gnl/gnltypes.h gnl/gnl/gnlurisource.c gnl/gnl/gnlurisource.h gnl/gnlcomposition.c gnl/gnlcomposition.h gnl/gnlghostpad.c gnl/gnlghostpad.h gnl/gnlmarshal.list gnl/gnlobject.c gnl/gnlobject.h gnl/gnloperation.c gnl/gnloperation.h gnl/gnlsource.c gnl/gnlsource.h gnl/gnltypes.h gnl/gnlurisource.c gnl/gnlurisource.h gnl/tests/check/gnl/common.c gnl/tests/check/gnl/common.h gnl/tests/check/gnl/complex.c gnl/tests/check/gnl/gnlcomposition.c gnl/tests/check/gnl/gnloperation.c gnl/tests/check/gnl/gnlsource.c gnl/tests/check/gnl/seek.c gnl/tests/check/gnl/simple.c tests/check/gnl/common.c tests/check/gnl/common.h tests/check/gnl/complex.c tests/check/gnl/gnlcomposition.c tests/check/gnl/gnloperation.c tests/check/gnl/gnlsource.c tests/check/gnl/seek.c tests/check/gnl/simple.c tests/check/nle/common.c tests/check/nle/common.h tests/check/nle/complex.c tests/check/nle/nlecomposition.c tests/check/nle/nleoperation.c tests/check/nle/nlesource.c tests/check/nle/seek.c tests/check/nle/simple.c
2014-08-15 13:48:14 +00:00
*max_priority = layer->max_nle_priority;
} else {
*min_priority = priority_base + MIN_NLE_PRIO;
*max_priority = G_MAXUINT32;
}
}
static void
_get_priority_range (GESContainer * container, guint32 * min_priority,
guint32 * max_priority)
{
_get_priority_range_full (container, min_priority, max_priority,
_PRIORITY (container));
}
static void
_child_priority_changed_cb (GESTimelineElement * child,
GParamSpec * arg G_GNUC_UNUSED, GESContainer * container)
{
/* we do not change the rest of the clip in response to a change in
* the child priority */
guint32 min_prio, max_prio;
GESClipPrivate *priv = GES_CLIP (container)->priv;
GST_DEBUG_OBJECT (container, "TimelineElement %" GES_FORMAT
" priority changed to %u", GES_ARGS (child), _PRIORITY (child));
if (!priv->prevent_priority_offset_update) {
/* Update mapping */
_get_priority_range (container, &min_prio, &max_prio);
_ges_container_set_priority_offset (container, child,
min_prio - _PRIORITY (child));
}
if (!priv->prevent_resort) {
_ges_container_sort_children (container);
_compute_height (container);
}
}
static void
_child_inpoint_changed_cb (GESTimelineElement * child, GParamSpec * pspec,
GESContainer * container)
{
if (GES_CLIP (container)->priv->setting_inpoint)
return;
/* ignore non-core */
/* if the track element has no internal content, then this means its
* in-point has been set (back) to 0, we can ignore this update */
if (!_IS_CORE_INTERNAL_SOURCE_CHILD (child))
return;
/* If the child->inpoint is the same as our own, set_inpoint will do
* nothing. For example, when we set them in add_child (the notifies for
* this are released after child_added is called because
* ges_container_add freezes them) */
_set_inpoint0 (GES_TIMELINE_ELEMENT (container), child->inpoint);
}
/* called when a child is added, removed or their max-duration changes */
static void
_update_max_duration (GESContainer * container)
{
GList *tmp;
GstClockTime min = GST_CLOCK_TIME_NONE;
GESClipPrivate *priv = GES_CLIP (container)->priv;
if (priv->prevent_max_duration_update)
return;
for (tmp = container->children; tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
if (_IS_CORE_CHILD (child)
&& GST_CLOCK_TIME_IS_VALID (child->maxduration))
min = GST_CLOCK_TIME_IS_VALID (min) ? MIN (min, child->maxduration) :
child->maxduration;
}
priv->updating_max_duration = TRUE;
ges_timeline_element_set_max_duration (GES_TIMELINE_ELEMENT (container), min);
priv->updating_max_duration = FALSE;
}
static void
_child_max_duration_changed_cb (GESTimelineElement * child,
GParamSpec * pspec, GESContainer * container)
{
/* ignore non-core */
if (!_IS_CORE_CHILD (child))
return;
_update_max_duration (container);
}
static void
_child_has_internal_source_changed_cb (GESTimelineElement * child,
GParamSpec * pspec, GESContainer * container)
{
/* ignore non-core */
/* if the track element is now registered to have no internal content,
* we don't have to do anything */
if (!_IS_CORE_INTERNAL_SOURCE_CHILD (child))
return;
/* otherwise, we need to make its in-point match ours */
_set_inpoint0 (child, _INPOINT (container));
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/****************************************************
* Restrict our children *
****************************************************/
static gboolean
_track_contains_core (GESClip * clip, GESTrack * track, gboolean core)
{
GList *tmp;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTrackElement *child = tmp->data;
if (_IS_CORE_CHILD (child) == core
&& ges_track_element_get_track (child) == track)
return TRUE;
}
return FALSE;
}
gboolean
ges_clip_can_set_track_of_child (GESClip * clip, GESTrackElement * child,
GESTrack * track)
{
GESTrack *current_track = ges_track_element_get_track (child);
if (clip->priv->allow_any_track)
return TRUE;
if (current_track == track)
return TRUE;
if (current_track) {
/* can not remove a core element from a track if a non-core one sits
* above it */
if (_IS_CORE_CHILD (child)
&& _track_contains_core (clip, current_track, FALSE)) {
GST_INFO_OBJECT (clip, "Cannot move the core child %" GES_FORMAT
" to the track %" GST_PTR_FORMAT " because it has non-core "
"siblings above it in its current track %" GST_PTR_FORMAT,
GES_ARGS (child), track, current_track);
return FALSE;
}
/* otherwise can remove */
}
if (track) {
GESTimeline *clip_timeline = GES_TIMELINE_ELEMENT_TIMELINE (clip);
const GESTimeline *track_timeline = ges_track_get_timeline (track);
if (track_timeline == NULL) {
GST_INFO_OBJECT (clip, "Cannot move the child %" GES_FORMAT
" to the track %" GST_PTR_FORMAT " because it is not part "
"of a timeline", GES_ARGS (child), track);
return FALSE;
}
if (track_timeline != clip_timeline) {
GST_INFO_OBJECT (clip, "Cannot move the child %" GES_FORMAT
" to the track %" GST_PTR_FORMAT " because its timeline %"
GST_PTR_FORMAT " does not match the clip's timeline %"
GST_PTR_FORMAT, GES_ARGS (child), track, track_timeline,
clip_timeline);
return FALSE;
}
/* one core child per track, and other children (effects) can only be
* placed in a track that already has a core child */
if (_IS_CORE_CHILD (child)) {
if (_track_contains_core (clip, track, TRUE)) {
GST_INFO_OBJECT (clip, "Cannot move the core child %" GES_FORMAT
" to the track %" GST_PTR_FORMAT " because it contains a "
"core sibling", GES_ARGS (child), track);
return FALSE;
}
} else {
if (!_track_contains_core (clip, track, TRUE)) {
GST_INFO_OBJECT (clip, "Cannot move the non-core child %"
GES_FORMAT " to the track %" GST_PTR_FORMAT " because it "
" does not contain a core sibling", GES_ARGS (child), track);
return FALSE;
}
}
}
return TRUE;
}
/*****************************************************
* *
* GESTimelineElement virtual methods implementation *
* *
*****************************************************/
static gboolean
_set_start (GESTimelineElement * element, GstClockTime start)
{
GList *tmp, *children;
GESContainer *container = GES_CONTAINER (element);
GST_DEBUG_OBJECT (element, "Setting children start, (initiated_move: %"
GST_PTR_FORMAT ")", container->initiated_move);
/* get copy of children, since GESContainer may resort the clip */
children = ges_container_get_children (container, FALSE);
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
for (tmp = children; tmp; tmp = g_list_next (tmp)) {
GESTimelineElement *child = (GESTimelineElement *) tmp->data;
if (child != container->initiated_move)
_set_start0 (GES_TIMELINE_ELEMENT (child), start);
}
container->children_control_mode = GES_CHILDREN_UPDATE;
g_list_free_full (children, gst_object_unref);
return TRUE;
}
/* Whether @clip can have its in-point set to @inpoint because none of
* its children have a max-duration below it */
gboolean
ges_clip_can_set_inpoint_of_child (GESClip * clip, GESTimelineElement * child,
GstClockTime inpoint)
{
GList *tmp;
/* don't bother checking if we are setting the value */
if (clip->priv->setting_inpoint)
return TRUE;
/* non-core children do not effect our in-point */
if (!_IS_CORE_CHILD (child))
return TRUE;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
if (_IS_CORE_INTERNAL_SOURCE_CHILD (child)
&& GST_CLOCK_TIME_IS_VALID (child->maxduration)
&& child->maxduration < inpoint)
return FALSE;
}
return TRUE;
}
/* returns TRUE if we did not break early */
static gboolean
_set_childrens_inpoint (GESTimelineElement * element, GstClockTime inpoint,
gboolean break_on_failure)
{
GList *tmp;
GESClipPrivate *priv = GES_CLIP (element)->priv;
priv->setting_inpoint = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
if (_IS_CORE_INTERNAL_SOURCE_CHILD (child)) {
if (!_set_inpoint0 (child, inpoint)) {
GST_ERROR_OBJECT ("Could not set the in-point of child %"
GES_FORMAT " to %" GST_TIME_FORMAT, GES_ARGS (child),
GST_TIME_ARGS (inpoint));
if (break_on_failure)
return FALSE;
}
}
}
priv->setting_inpoint = FALSE;
return TRUE;
}
static gboolean
_set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
{
if (!_set_childrens_inpoint (element, inpoint, TRUE)) {
_set_childrens_inpoint (element, element->inpoint, FALSE);
return FALSE;
}
return TRUE;
}
static gboolean
_set_duration (GESTimelineElement * element, GstClockTime duration)
{
GList *tmp, *children;
GESContainer *container = GES_CONTAINER (element);
/* get copy of children, since GESContainer may resort the clip */
children = ges_container_get_children (container, FALSE);
container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
for (tmp = container->children; tmp; tmp = g_list_next (tmp)) {
GESTimelineElement *child = (GESTimelineElement *) tmp->data;
if (child != container->initiated_move) {
ELEMENT_SET_FLAG (child, GES_TIMELINE_ELEMENT_SET_SIMPLE);
_set_duration0 (GES_TIMELINE_ELEMENT (child), duration);
ELEMENT_UNSET_FLAG (child, GES_TIMELINE_ELEMENT_SET_SIMPLE);
}
}
container->children_control_mode = GES_CHILDREN_UPDATE;
g_list_free_full (children, gst_object_unref);
return TRUE;
}
static gboolean
_set_max_duration (GESTimelineElement * element, GstClockTime maxduration)
{
GList *tmp;
GESClipPrivate *priv = GES_CLIP (element)->priv;
GstClockTime new_min = GST_CLOCK_TIME_NONE;
gboolean has_core = FALSE;
/* if we are setting based on a change in the minimum */
if (priv->updating_max_duration)
return TRUE;
/* else, we set every core child to have the same max duration */
priv->prevent_max_duration_update = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
GESTimelineElement *child = tmp->data;
if (_IS_CORE_CHILD (child)) {
has_core = TRUE;
if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT (child))) {
if (!ges_timeline_element_set_max_duration (child, maxduration))
GST_ERROR_OBJECT ("Could not set the max-duration of child %"
GES_FORMAT " to %" GST_TIME_FORMAT, GES_ARGS (child),
GST_TIME_ARGS (maxduration));
if (GST_CLOCK_TIME_IS_VALID (child->maxduration))
new_min = GST_CLOCK_TIME_IS_VALID (new_min) ?
MIN (new_min, child->maxduration) : child->maxduration;
}
}
}
priv->prevent_max_duration_update = FALSE;
if (!has_core) {
/* allow max-duration to be set arbitrarily when we have no
* core children, even though there is no actual minimum max-duration
* when it has no core children */
if (GST_CLOCK_TIME_IS_VALID (maxduration))
GST_INFO_OBJECT (element,
"Allowing max-duration of the clip to be set to %" GST_TIME_FORMAT
" because it has no core children", GST_TIME_ARGS (maxduration));
return TRUE;
}
if (new_min != maxduration) {
if (GST_CLOCK_TIME_IS_VALID (new_min))
GST_WARNING_OBJECT (element, "Failed to set the max-duration of the "
"clip to %" GST_TIME_FORMAT " because it was not possible to "
"match this with the actual minimum of %" GST_TIME_FORMAT,
GST_TIME_ARGS (maxduration), GST_TIME_ARGS (new_min));
else
GST_WARNING_OBJECT (element, "Failed to set the max-duration of the "
"clip to %" GST_TIME_FORMAT " because it has no core children "
"whose max-duration could be set to anything other than "
"GST_CLOCK_TIME_NONE", GST_TIME_ARGS (maxduration));
priv->updating_max_duration = TRUE;
ges_timeline_element_set_max_duration (element, new_min);
priv->updating_max_duration = FALSE;
return FALSE;
}
return TRUE;
}
static gboolean
_set_priority (GESTimelineElement * element, guint32 priority)
{
GESClipPrivate *priv = GES_CLIP (element)->priv;
GList *tmp;
guint32 min_prio, max_prio;
GESContainer *container = GES_CONTAINER (element);
/* send the new 'priority' to determine what the new 'min_prio' should
* be for the clip */
_get_priority_range_full (container, &min_prio, &max_prio, priority);
/* offsets will remain constant for the children */
priv->prevent_resort = TRUE;
priv->prevent_priority_offset_update = TRUE;
for (tmp = container->children; tmp; tmp = g_list_next (tmp)) {
guint32 track_element_prio;
GESTimelineElement *child = (GESTimelineElement *) tmp->data;
gint off = _ges_container_get_priority_offset (container, child);
if (off >= LAYER_HEIGHT) {
GST_ERROR ("%s child %s as a priority offset %d >= LAYER_HEIGHT %d"
" ==> clamping it to 0", GES_TIMELINE_ELEMENT_NAME (element),
GES_TIMELINE_ELEMENT_NAME (child), off, LAYER_HEIGHT);
off = 0;
}
/* Want the priority offset 'off' of each child to stay the same with
* the new priority. The offset is calculated from
* offset = min_priority - child_priority
*/
track_element_prio = min_prio - off;
if (track_element_prio > max_prio) {
GST_WARNING ("%p priority of %i, is outside of the its containing "
"layer space. (%d/%d) setting it to the maximum it can be",
container, priority, min_prio, max_prio);
track_element_prio = max_prio;
}
_set_priority0 (child, track_element_prio);
}
/* no need to re-sort the container since we maintained the relative
* offsets. As such, the height remains the same as well. */
priv->prevent_resort = FALSE;
priv->prevent_priority_offset_update = FALSE;
return TRUE;
}
static guint32
_get_layer_priority (GESTimelineElement * element)
{
GESClip *clip = GES_CLIP (element);
if (clip->priv->layer == NULL)
return GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY;
return ges_layer_get_priority (clip->priv->layer);
}
static gboolean
_get_natural_framerate (GESTimelineElement * self, gint * framerate_n,
gint * framerate_d)
{
GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
if (!asset) {
GST_WARNING_OBJECT (self, "No asset set?");
return FALSE;
}
return ges_clip_asset_get_natural_framerate (GES_CLIP_ASSET (asset),
framerate_n, framerate_d);
}
/****************************************************
* *
* GESContainer virtual methods implementation *
* *
****************************************************/
static void
_compute_height (GESContainer * container)
{
GList *tmp;
guint32 min_prio = G_MAXUINT32, max_prio = 0;
if (container->children == NULL) {
/* FIXME Why not 0! */
_ges_container_set_height (container, 1);
return;
}
/* Go over all childs and check if height has changed */
for (tmp = container->children; tmp; tmp = tmp->next) {
guint tck_priority = _PRIORITY (tmp->data);
if (tck_priority < min_prio)
min_prio = tck_priority;
if (tck_priority > max_prio)
max_prio = tck_priority;
}
_ges_container_set_height (container, max_prio - min_prio + 1);
}
static gboolean
_add_child (GESContainer * container, GESTimelineElement * element)
{
GESClipClass *klass = GES_CLIP_GET_CLASS (GES_CLIP (container));
guint max_prio, min_prio;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
GESTrack *track;
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (container);
GESClipPrivate *priv = GES_CLIP (container)->priv;
GESAsset *asset, *creator_asset;
g_return_val_if_fail (GES_IS_TRACK_ELEMENT (element), FALSE);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (element->timeline && element->timeline != timeline) {
GST_WARNING_OBJECT (container, "Cannot add %" GES_FORMAT " as a child "
"because its timeline is %" GST_PTR_FORMAT " rather than the "
"clip's timeline %" GST_PTR_FORMAT, GES_ARGS (element),
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
element->timeline, timeline);
return FALSE;
}
asset = ges_extractable_get_asset (GES_EXTRACTABLE (container));
creator_asset =
ges_track_element_get_creator_asset (GES_TRACK_ELEMENT (element));
if (creator_asset && asset != creator_asset) {
GST_WARNING_OBJECT (container,
"Cannot add the track element %" GES_FORMAT " as a child "
"because it is a core element created by another clip with a "
"different asset to the current clip's asset", GES_ARGS (element));
return FALSE;
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
track = ges_track_element_get_track (GES_TRACK_ELEMENT (element));
if (track && ges_track_get_timeline (track) != timeline) {
/* really, an element in a track should have the same timeline as
* the track, so we would have checked this with the
* element->timeline check. But technically a user could get around
* this, so we double check here. */
GST_WARNING_OBJECT (container, "Cannot add %" GES_FORMAT " as a child "
"because its track %" GST_PTR_FORMAT " is part of the timeline %"
GST_PTR_FORMAT " rather than the clip's timeline %" GST_PTR_FORMAT,
GES_ARGS (element), track, ges_track_get_timeline (track), timeline);
return FALSE;
}
/* NOTE: notifies are currently frozen by ges_container_add */
_get_priority_range (container, &min_prio, &max_prio);
if (creator_asset) {
/* NOTE: Core track elements that are base effects are added like any
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
* other core elements. In particular, they are *not* added to the
* list of added effects, so we do not increase nb_effects. */
if (track && !priv->allow_any_track
&& _track_contains_core (GES_CLIP (container), track, TRUE)) {
GST_WARNING_OBJECT (container, "Cannot add the core child %" GES_FORMAT
" because it is in the same track %" GST_PTR_FORMAT " as an "
"existing core child", GES_ARGS (element), track);
return FALSE;
}
/* Set the core element to have the same in-point, which we don't
* apply to effects */
if (ges_track_element_has_internal_source (GES_TRACK_ELEMENT (element))) {
/* adding can fail if the max-duration of the element is smaller
* than the current in-point of the clip */
if (!_set_inpoint0 (element, _INPOINT (container))) {
GST_ERROR_OBJECT (element, "Could not set the in-point of the "
"element %" GES_FORMAT " to %" GST_TIME_FORMAT ". Not adding "
"as a child", GES_ARGS (element),
GST_TIME_ARGS (_INPOINT (container)));
return FALSE;
}
}
/* Always add at the same priority, on top of existing effects */
_set_priority0 (element, min_prio + priv->nb_effects);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
} else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass) && _IS_TOP_EFFECT (element)) {
GList *tmp;
/* Add the effect at the lowest priority among effects (just after
* the core elements). Need to shift the core elements up by 1
* to make room. */
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (track && !priv->allow_any_track
&& !_track_contains_core (GES_CLIP (container), track, TRUE)) {
GST_WARNING_OBJECT (container, "Cannot add the effect %" GES_FORMAT
" because its track %" GST_PTR_FORMAT " does not contain one "
"of the clip's core children", GES_ARGS (element), track);
return FALSE;
}
GST_DEBUG_OBJECT (container, "Adding %ith effect: %" GES_FORMAT
" Priority %i", priv->nb_effects + 1, GES_ARGS (element),
min_prio + priv->nb_effects);
/* changing priorities, and updating their offset */
priv->prevent_resort = TRUE;
tmp = g_list_nth (GES_CONTAINER_CHILDREN (container), priv->nb_effects);
for (; tmp; tmp = tmp->next)
ges_timeline_element_set_priority (GES_TIMELINE_ELEMENT (tmp->data),
GES_TIMELINE_ELEMENT_PRIORITY (tmp->data) + 1);
_set_priority0 (element, min_prio + priv->nb_effects);
priv->nb_effects++;
priv->prevent_resort = FALSE;
/* no need to call _ges_container_sort_children (container) since
* there is no change to the ordering yet (this happens after the
* child is actually added) */
/* The height has already changed (increased by 1) */
_compute_height (container);
} else {
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (_IS_TOP_EFFECT (element))
GST_WARNING_OBJECT (container, "Cannot add the effect %" GES_FORMAT
" because it is not a core element created by the clip itself "
"and the %s class does not allow for adding extra effects",
GES_ARGS (element), G_OBJECT_CLASS_NAME (klass));
else if (GES_CLIP_CLASS_CAN_ADD_EFFECTS (klass))
GST_WARNING_OBJECT (container, "Cannot add the track element %"
GES_FORMAT " because it is neither a core element created by "
"the clip itself, nor a GESBaseEffect", GES_ARGS (element));
else
GST_WARNING_OBJECT (container, "Cannot add the track element %"
GES_FORMAT " because it is not a core element created by the "
"clip itself", GES_ARGS (element));
return FALSE;
}
_set_start0 (element, GES_TIMELINE_ELEMENT_START (container));
_set_duration0 (element, GES_TIMELINE_ELEMENT_DURATION (container));
return TRUE;
}
static gboolean
_remove_child (GESContainer * container, GESTimelineElement * element)
{
GESClipPrivate *priv = GES_CLIP (container)->priv;
/* NOTE: notifies are currently frozen by ges_container_add */
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (_IS_TOP_EFFECT (element)) {
GList *tmp;
GST_DEBUG_OBJECT (container, "Resyncing effects priority.");
/* changing priorities, so preventing a re-sort */
priv->prevent_resort = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (container); tmp; tmp = tmp->next) {
guint32 sibling_prio = GES_TIMELINE_ELEMENT_PRIORITY (tmp->data);
if (sibling_prio > element->priority)
ges_timeline_element_set_priority (GES_TIMELINE_ELEMENT (tmp->data),
sibling_prio - 1);
}
priv->nb_effects--;
priv->prevent_resort = FALSE;
/* no need to re-sort the children since the rest keep the same
* relative priorities */
/* height may have changed */
_compute_height (container);
}
return TRUE;
}
static void
_child_added (GESContainer * container, GESTimelineElement * element)
{
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_signal_connect (element, "notify::priority",
G_CALLBACK (_child_priority_changed_cb), container);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_signal_connect (element, "notify::in-point",
G_CALLBACK (_child_inpoint_changed_cb), container);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_signal_connect (element, "notify::max-duration",
G_CALLBACK (_child_max_duration_changed_cb), container);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_signal_connect (element, "notify::has-internal-source",
G_CALLBACK (_child_has_internal_source_changed_cb), container);
_child_priority_changed_cb (element, NULL, container);
if (_IS_CORE_CHILD (element))
_update_max_duration (container);
}
static void
_child_removed (GESContainer * container, GESTimelineElement * element)
{
g_signal_handlers_disconnect_by_func (element, _child_priority_changed_cb,
container);
g_signal_handlers_disconnect_by_func (element, _child_inpoint_changed_cb,
container);
g_signal_handlers_disconnect_by_func (element,
_child_max_duration_changed_cb, container);
g_signal_handlers_disconnect_by_func (element,
_child_has_internal_source_changed_cb, container);
if (_IS_CORE_CHILD (element))
_update_max_duration (container);
}
static void
add_clip_to_list (gpointer key, gpointer clip, GList ** list)
{
*list = g_list_prepend (*list, gst_object_ref (clip));
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* NOTE: Since this does not change the track of @child, this should
* only be called if it is guaranteed that neither @from_clip nor @to_clip
* will not break the track rules:
* + no more than one core child per track
* + every non-core child must be in the same track as a core child
* NOTE: Since this does not change the creator asset of the child, this
* should only be called for transferring children between clips with the
* same asset.
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
*/
static void
_transfer_child (GESClip * from_clip, GESClip * to_clip,
GESTrackElement * child)
{
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (to_clip);
/* We need to bump the refcount to avoid the object to be destroyed */
gst_object_ref (child);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* don't want to change tracks */
ges_timeline_set_moving_track_elements (timeline, TRUE);
ges_container_remove (GES_CONTAINER (from_clip),
GES_TIMELINE_ELEMENT (child));
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
to_clip->priv->allow_any_track = TRUE;
if (!ges_container_add (GES_CONTAINER (to_clip),
GES_TIMELINE_ELEMENT (child)))
GST_ERROR ("%" GES_FORMAT " could not add child %p while"
" transfering, this should never happen", GES_ARGS (to_clip), child);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
to_clip->priv->allow_any_track = FALSE;
ges_timeline_set_moving_track_elements (timeline, FALSE);
gst_object_unref (child);
}
static GList *
_ungroup (GESContainer * container, gboolean recursive)
{
GESClip *tmpclip;
GESTrackType track_type;
GESTrackElement *track_element;
gboolean first_obj = TRUE;
GList *tmp, *children, *ret = NULL;
GESClip *clip = GES_CLIP (container);
GESTimelineElement *element = GES_TIMELINE_ELEMENT (container);
2013-04-23 23:04:04 +00:00
GESLayer *layer = clip->priv->layer;
GHashTable *_tracktype_clip = g_hash_table_new (g_int_hash, g_int_equal);
/* If there is no TrackElement, just return @container in a list */
if (GES_CONTAINER_CHILDREN (container) == NULL) {
GST_DEBUG ("No TrackElement, simply returning");
return g_list_prepend (ret, container);
}
children = ges_container_get_children (container, FALSE);
/* _add_child will add core elements at the lowest priority and new
* non-core effects at the lowest effect priority, so we need to add
* the highest priority children first to preserve the effect order.
* @children is already ordered by highest priority first */
for (tmp = children; tmp; tmp = tmp->next) {
track_element = GES_TRACK_ELEMENT (tmp->data);
track_type = ges_track_element_get_track_type (track_element);
tmpclip = g_hash_table_lookup (_tracktype_clip, &track_type);
if (tmpclip == NULL) {
if (G_UNLIKELY (first_obj == TRUE)) {
tmpclip = clip;
first_obj = FALSE;
} else {
tmpclip = GES_CLIP (ges_timeline_element_copy (element, FALSE));
if (layer) {
/* Add new container to the same layer as @container */
ges_clip_set_moving_from_layer (tmpclip, TRUE);
/* adding to the same layer should not fail when moving */
2013-04-23 23:04:04 +00:00
ges_layer_add_clip (layer, tmpclip);
ges_clip_set_moving_from_layer (tmpclip, FALSE);
}
}
g_hash_table_insert (_tracktype_clip, &track_type, tmpclip);
ges_clip_set_supported_formats (tmpclip, track_type);
}
/* Move trackelement to the container it is supposed to land into */
/* Note: it is safe to transfer the element whilst not changing tracks
* because all track elements in the same track will stay in the
* same clip */
if (tmpclip != clip)
_transfer_child (clip, tmpclip, track_element);
}
g_list_free_full (children, gst_object_unref);
g_hash_table_foreach (_tracktype_clip, (GHFunc) add_clip_to_list, &ret);
g_hash_table_unref (_tracktype_clip);
return ret;
}
static gboolean
_group_test_share_track (GESClip * clip1, GESClip * clip2)
{
GList *tmp1, *tmp2;
GESTrackElement *child1, *child2;
for (tmp1 = GES_CONTAINER_CHILDREN (clip1); tmp1; tmp1 = tmp1->next) {
child1 = tmp1->data;
for (tmp2 = GES_CONTAINER_CHILDREN (clip2); tmp2; tmp2 = tmp2->next) {
child2 = tmp2->data;
if (ges_track_element_get_track (child1)
== ges_track_element_get_track (child2)) {
GST_INFO_OBJECT (clip1, "Cannot group with clip %" GES_FORMAT
" because its child %" GES_FORMAT " shares the same "
"track with our child %" GES_FORMAT, GES_ARGS (clip2),
GES_ARGS (child2), GES_ARGS (child1));
return TRUE;
}
}
}
return FALSE;
}
#define _GROUP_TEST_EQUAL(val, expect, format) \
if (val != expect) { \
GST_INFO_OBJECT (clip, "Cannot group with other clip %" GES_FORMAT \
" because the clip's " #expect " is %" format " rather than the " \
#expect " of the other clip %" format, GES_ARGS (first_clip), val, \
expect); \
return NULL; \
}
static GESContainer *
_group (GList * containers)
{
GESClip *first_clip = NULL;
GESTimeline *timeline;
GESTrackType supported_formats;
GESLayer *layer;
GList *tmp, *tmp2, *tmpclip;
GstClockTime start, inpoint, duration;
GESTimelineElement *element;
GESAsset *asset;
GESContainer *ret = NULL;
if (!containers)
return NULL;
for (tmp = containers; tmp; tmp = tmp->next) {
if (GES_IS_CLIP (tmp->data) == FALSE) {
GST_DEBUG ("Can only work with clips");
return NULL;
}
if (!first_clip) {
first_clip = tmp->data;
element = GES_TIMELINE_ELEMENT (first_clip);
start = element->start;
inpoint = element->inpoint;
duration = element->duration;
timeline = element->timeline;
layer = first_clip->priv->layer;
asset = ges_extractable_get_asset (GES_EXTRACTABLE (first_clip));
}
}
for (tmp = containers; tmp; tmp = tmp->next) {
GESClip *clip;
GESAsset *cmp_asset;
element = GES_TIMELINE_ELEMENT (tmp->data);
clip = GES_CLIP (element);
_GROUP_TEST_EQUAL (element->start, start, G_GUINT64_FORMAT);
_GROUP_TEST_EQUAL (element->duration, duration, G_GUINT64_FORMAT);
_GROUP_TEST_EQUAL (element->inpoint, inpoint, G_GUINT64_FORMAT);
_GROUP_TEST_EQUAL (element->timeline, timeline, GST_PTR_FORMAT);
_GROUP_TEST_EQUAL (clip->priv->layer, layer, GST_PTR_FORMAT);
cmp_asset = ges_extractable_get_asset (GES_EXTRACTABLE (clip));
if (cmp_asset != asset) {
GST_INFO_OBJECT (clip, "Cannot group with other clip %"
GES_FORMAT " because the clip's asset is %s rather than "
" the asset of the other clip %s", GES_ARGS (first_clip),
cmp_asset ? ges_asset_get_id (cmp_asset) : NULL,
asset ? ges_asset_get_id (asset) : NULL);
return NULL;
}
/* make sure we don't share the same track */
for (tmp2 = tmp->next; tmp2; tmp2 = tmp2->next) {
if (_group_test_share_track (clip, tmp2->data))
return NULL;
}
}
/* And now pass all TrackElements to the first clip,
* and remove others from the layer (updating the supported formats) */
ret = containers->data;
supported_formats = GES_CLIP (ret)->priv->supportedformats;
for (tmpclip = containers->next; tmpclip; tmpclip = tmpclip->next) {
GESClip *cclip = tmpclip->data;
GList *children = ges_container_get_children (GES_CONTAINER (cclip), FALSE);
/* _add_child will add core elements at the lowest priority and new
* non-core effects at the lowest effect priority, so we need to add
* the highest priority children first to preserve the effect order.
* @children is already ordered by highest priority first.
* Priorities between children in different tracks (as tmpclips are)
* is not important */
for (tmp = children; tmp; tmp = tmp->next) {
GESTrackElement *celement = GES_TRACK_ELEMENT (tmp->data);
/* Note: it is safe to transfer the element whilst not changing
* tracks because the elements from different clips will have
* children in separate tracks. So it should not be possible for
* two core children to appear in the same track */
_transfer_child (cclip, GES_CLIP (ret), celement);
supported_formats |= ges_track_element_get_track_type (celement);
}
g_list_free_full (children, gst_object_unref);
ges_layer_remove_clip (layer, cclip);
}
ges_clip_set_supported_formats (GES_CLIP (ret), supported_formats);
return ret;
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
void
ges_clip_empty_from_track (GESClip * clip, GESTrack * track)
{
GList *tmp;
if (track == NULL)
return;
/* allow us to remove in any order */
clip->priv->allow_any_track = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTrackElement *child = tmp->data;
if (ges_track_element_get_track (child) == track) {
if (!ges_track_remove_element (track, child))
GST_ERROR_OBJECT (clip, "Failed to remove child %" GES_FORMAT
" from the track %" GST_PTR_FORMAT, GES_ARGS (child), track);
}
}
clip->priv->allow_any_track = FALSE;
}
static GESTrackElement *
_copy_track_element_to (GESTrackElement * orig, GESClip * to_clip,
GstClockTime position)
{
GESTrackElement *copy;
GESTimelineElement *el_copy, *el_orig;
/* NOTE: we do not deep copy the track element, we instead call
* ges_track_element_copy_properties explicitly, which is the
* deep_copy for the GESTrackElementClass. */
el_orig = GES_TIMELINE_ELEMENT (orig);
el_copy = ges_timeline_element_copy (el_orig, FALSE);
if (el_copy == NULL)
return NULL;
copy = GES_TRACK_ELEMENT (el_copy);
ges_track_element_copy_properties (el_orig, el_copy);
/* NOTE: control bindings that are not registered in GES are not
* handled */
ges_track_element_copy_bindings (orig, copy, position);
ges_track_element_set_creator_asset (copy,
ges_track_element_get_creator_asset (orig));
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
return copy;
}
static GESTrackElement *
ges_clip_copy_track_element_into (GESClip * clip, GESTrackElement * orig,
GstClockTime position)
{
GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (clip);
GESTrackElement *copy;
copy = _copy_track_element_to (orig, clip, position);
if (copy == NULL) {
GST_ERROR_OBJECT (clip, "Failed to create a copy of the "
"element %" GES_FORMAT " for the clip", GES_ARGS (orig));
return NULL;
}
gst_object_ref (copy);
ges_timeline_set_moving_track_elements (timeline, TRUE);
if (!ges_container_add (GES_CONTAINER (clip), GES_TIMELINE_ELEMENT (copy))) {
GST_ERROR_OBJECT (clip, "Failed to add the copied child track "
"element %" GES_FORMAT " to the clip", GES_ARGS (copy));
ges_timeline_set_moving_track_elements (timeline, FALSE);
gst_object_unref (copy);
return NULL;
}
ges_timeline_set_moving_track_elements (timeline, FALSE);
/* now owned by the clip */
gst_object_unref (copy);
return copy;
}
static void
_deep_copy (GESTimelineElement * element, GESTimelineElement * copy)
{
GList *tmp;
GESClip *self = GES_CLIP (element), *ccopy = GES_CLIP (copy);
GESTrackElement *el, *el_copy;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* NOTE: this should only be called on a newly created @copy, so
* its copied_track_elements, and copied_layer, should be free to set
* without disposing of the previous values */
for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
el = GES_TRACK_ELEMENT (tmp->data);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
el_copy = _copy_track_element_to (el, ccopy, GST_CLOCK_TIME_NONE);
if (!el_copy) {
GST_ERROR_OBJECT (element, "Failed to copy the track element %"
GES_FORMAT " for pasting", GES_ARGS (el));
continue;
}
/* owned by copied_track_elements */
gst_object_ref_sink (el_copy);
/* _add_child will add core elements at the lowest priority and new
* non-core effects at the lowest effect priority, so we need to add
* the highest priority children first to preserve the effect order.
* The clip's children are already ordered by highest priority first.
* So we order copied_track_elements in the same way */
ccopy->priv->copied_track_elements =
g_list_append (ccopy->priv->copied_track_elements, el_copy);
}
ccopy->priv->copied_layer = g_object_ref (self->priv->layer);
ccopy->priv->copied_timeline = self->priv->layer->timeline;
}
static GESTimelineElement *
_paste (GESTimelineElement * element, GESTimelineElement * ref,
GstClockTime paste_position)
{
GList *tmp;
GESClip *self = GES_CLIP (element);
GESLayer *layer = self->priv->copied_layer;
GESClip *nclip = GES_CLIP (ges_timeline_element_copy (element, FALSE));
ges_timeline_element_set_start (GES_TIMELINE_ELEMENT (nclip), paste_position);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* paste in order of priority (highest first) */
for (tmp = self->priv->copied_track_elements; tmp; tmp = tmp->next)
ges_clip_copy_track_element_into (nclip, tmp->data, GST_CLOCK_TIME_NONE);
if (layer) {
if (layer->timeline != self->priv->copied_timeline) {
GST_WARNING_OBJECT (self, "Cannot be pasted into the layer %"
GST_PTR_FORMAT " because its timeline has changed", layer);
gst_object_ref_sink (nclip);
gst_object_unref (nclip);
return NULL;
}
/* adding the clip to the layer will add it to the tracks, but not
* necessarily the same ones depending on select-tracks-for-object */
if (!ges_layer_add_clip (layer, nclip)) {
GST_INFO ("%" GES_FORMAT " could not be pasted to %" GST_TIME_FORMAT,
GES_ARGS (element), GST_TIME_ARGS (paste_position));
return NULL;
}
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* NOTE: self should not be used and be freed after this call, so we can
* leave the freeing of copied_layer and copied_track_elements to the
* dispose method */
return GES_TIMELINE_ELEMENT (nclip);
}
static gboolean
_lookup_child (GESTimelineElement * self, const gchar * prop_name,
GObject ** child, GParamSpec ** pspec)
{
GList *tmp;
if (GES_TIMELINE_ELEMENT_CLASS (ges_clip_parent_class)->lookup_child (self,
prop_name, child, pspec))
return TRUE;
for (tmp = GES_CONTAINER_CHILDREN (self); tmp; tmp = tmp->next) {
if (ges_timeline_element_lookup_child (tmp->data, prop_name, child, pspec))
return TRUE;
}
return FALSE;
}
/****************************************************
* *
* GObject virtual methods implementation *
* *
****************************************************/
static void
2013-01-20 15:42:29 +00:00
ges_clip_get_property (GObject * object, guint property_id,
2009-08-04 15:16:31 +00:00
GValue * value, GParamSpec * pspec)
2009-08-04 15:13:11 +00:00
{
GESClip *clip = GES_CLIP (object);
2009-08-04 15:13:11 +00:00
switch (property_id) {
case PROP_LAYER:
g_value_set_object (value, clip->priv->layer);
break;
case PROP_SUPPORTED_FORMATS:
g_value_set_flags (value, clip->priv->supportedformats);
break;
2009-08-04 15:16:31 +00:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2009-08-04 15:13:11 +00:00
}
}
static void
2013-01-20 15:42:29 +00:00
ges_clip_set_property (GObject * object, guint property_id,
2009-08-04 15:16:31 +00:00
const GValue * value, GParamSpec * pspec)
2009-08-04 15:13:11 +00:00
{
GESClip *clip = GES_CLIP (object);
2009-08-04 15:13:11 +00:00
switch (property_id) {
case PROP_SUPPORTED_FORMATS:
ges_clip_set_supported_formats (clip, g_value_get_flags (value));
break;
2009-08-04 15:16:31 +00:00
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
2009-08-04 15:13:11 +00:00
}
}
static void
ges_clip_dispose (GObject * object)
{
GESClip *self = GES_CLIP (object);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_list_free_full (self->priv->copied_track_elements, gst_object_unref);
self->priv->copied_track_elements = NULL;
g_clear_object (&self->priv->copied_layer);
G_OBJECT_CLASS (ges_clip_parent_class)->dispose (object);
}
2009-08-04 15:13:11 +00:00
static void
2013-01-20 15:42:29 +00:00
ges_clip_class_init (GESClipClass * klass)
2009-08-04 15:13:11 +00:00
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GESContainerClass *container_class = GES_CONTAINER_CLASS (klass);
GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
2009-08-04 15:13:11 +00:00
2013-01-20 15:42:29 +00:00
object_class->get_property = ges_clip_get_property;
object_class->set_property = ges_clip_set_property;
object_class->dispose = ges_clip_dispose;
klass->create_track_elements = ges_clip_create_track_elements_func;
klass->create_track_element = NULL;
2010-07-09 09:51:21 +00:00
/**
2013-01-20 15:42:29 +00:00
* GESClip:supported-formats:
*
2020-01-09 12:11:35 +00:00
* The #GESTrackType-s that the clip supports, which it can create
* #GESTrackElement-s for. Note that this can be a combination of
* #GESTrackType flags to indicate support for several
* #GESTrackElement:track-type elements.
*/
properties[PROP_SUPPORTED_FORMATS] = g_param_spec_flags ("supported-formats",
2020-01-09 12:11:35 +00:00
"Supported formats", "Formats supported by the clip",
GES_TYPE_TRACK_TYPE, GES_TRACK_TYPE_AUDIO | GES_TRACK_TYPE_VIDEO,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
g_object_class_install_property (object_class, PROP_SUPPORTED_FORMATS,
properties[PROP_SUPPORTED_FORMATS]);
/**
2013-01-20 15:42:29 +00:00
* GESClip:layer:
*
2020-01-09 12:11:35 +00:00
* The layer this clip lies in.
*
* If you want to connect to this property's #GObject::notify signal,
* you should connect to it with g_signal_connect_after() since the
* signal emission may be stopped internally.
*/
properties[PROP_LAYER] = g_param_spec_object ("layer", "Layer",
2013-04-23 23:04:04 +00:00
"The GESLayer where this clip is being used.",
GES_TYPE_LAYER, G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_property (object_class, PROP_LAYER,
properties[PROP_LAYER]);
element_class->ripple = _ripple;
element_class->ripple_end = _ripple_end;
element_class->roll_start = _roll_start;
element_class->roll_end = _roll_end;
element_class->trim = _trim;
element_class->set_start = _set_start;
element_class->set_duration = _set_duration;
element_class->set_inpoint = _set_inpoint;
element_class->set_priority = _set_priority;
element_class->set_max_duration = _set_max_duration;
element_class->paste = _paste;
element_class->deep_copy = _deep_copy;
element_class->lookup_child = _lookup_child;
element_class->get_layer_priority = _get_layer_priority;
element_class->get_natural_framerate = _get_natural_framerate;
container_class->add_child = _add_child;
container_class->remove_child = _remove_child;
container_class->child_removed = _child_removed;
container_class->child_added = _child_added;
container_class->ungroup = _ungroup;
container_class->group = _group;
container_class->grouping_priority = G_MAXUINT;
2009-08-04 15:13:11 +00:00
}
static void
2013-01-20 15:42:29 +00:00
ges_clip_init (GESClip * self)
2009-08-04 15:13:11 +00:00
{
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
self->priv = ges_clip_get_instance_private (self);
}
2009-08-06 09:23:01 +00:00
/**
* ges_clip_create_track_element:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @type: The track to create an element for
2009-08-06 09:23:01 +00:00
*
2020-01-09 12:11:35 +00:00
* Creates the core #GESTrackElement of the clip, of the given track type.
2009-08-06 09:23:01 +00:00
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer floating) (nullable): The element created
* by @clip, or %NULL if @clip can not provide a track element for the
* given @type or an error occurred.
2009-08-06 09:23:01 +00:00
*/
GESTrackElement *
ges_clip_create_track_element (GESClip * clip, GESTrackType type)
2009-08-06 09:23:01 +00:00
{
2013-01-20 15:42:29 +00:00
GESClipClass *class;
GESTrackElement *res;
2009-08-06 09:23:01 +00:00
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
GST_DEBUG_OBJECT (clip, "Creating track element for %s",
ges_track_type_name (type));
if (!(type & clip->priv->supportedformats)) {
GST_DEBUG_OBJECT (clip, "We don't support this track type %i", type);
return NULL;
}
class = GES_CLIP_GET_CLASS (clip);
2009-08-06 09:23:01 +00:00
if (G_UNLIKELY (class->create_track_element == NULL)) {
GST_ERROR ("No 'create_track_element' implementation available fo type %s",
G_OBJECT_TYPE_NAME (clip));
return NULL;
}
res = class->create_track_element (clip, type);
return res;
}
2010-07-07 14:51:39 +00:00
/**
* ges_clip_create_track_elements:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @type: The track-type to create elements for
2010-07-07 14:51:39 +00:00
*
2020-01-09 12:11:35 +00:00
* Creates the core #GESTrackElement-s of the clip, of the given track
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
* type.
2010-07-07 14:51:39 +00:00
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer container) (element-type GESTrackElement): A list of
* the #GESTrackElement-s created by @clip for the given @type, or %NULL
* if no track elements are created or an error occurred.
2010-07-07 14:51:39 +00:00
*/
GList *
ges_clip_create_track_elements (GESClip * clip, GESTrackType type)
2010-07-07 14:51:39 +00:00
{
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
GList *tmp, *ret;
2013-01-20 15:42:29 +00:00
GESClipClass *klass;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
gboolean already_created = FALSE;
GESAsset *asset;
2010-07-07 14:51:39 +00:00
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if ((clip->priv->supportedformats & type) == 0)
return NULL;
klass = GES_CLIP_GET_CLASS (clip);
2010-07-07 14:51:39 +00:00
if (!(klass->create_track_elements)) {
GST_WARNING ("no GESClip::create_track_elements implentation");
return NULL;
2010-07-07 14:51:39 +00:00
}
2012-04-20 23:02:19 +00:00
GST_DEBUG_OBJECT (clip, "Creating TrackElements for type: %s",
ges_track_type_name (type));
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTrackElement *child = GES_TRACK_ELEMENT (tmp->data);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (_IS_CORE_CHILD (child)
&& ges_track_element_get_track_type (child) & type) {
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* assume the core track elements have all been created if we find
* at least one core child with the same type */
already_created = TRUE;
break;
}
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (already_created)
return NULL;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
ret = klass->create_track_elements (clip, type);
asset = ges_extractable_get_asset (GES_EXTRACTABLE (clip));
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
for (tmp = ret; tmp; tmp = tmp->next)
ges_track_element_set_creator_asset (tmp->data, asset);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
return ret;
}
/*
* default implementation of GESClipClass::create_track_elements
*/
GList *
ges_clip_create_track_elements_func (GESClip * clip, GESTrackType type)
2010-07-07 14:51:39 +00:00
{
GESTrackElement *result;
2010-07-07 14:51:39 +00:00
GST_DEBUG_OBJECT (clip, "Creating trackelement for track: %s",
ges_track_type_name (type));
result = ges_clip_create_track_element (clip, type);
2010-07-07 14:51:39 +00:00
if (!result) {
GST_DEBUG ("Did not create track element");
return NULL;
2010-07-07 14:51:39 +00:00
}
return g_list_append (NULL, result);
2010-07-07 14:51:39 +00:00
}
void
2013-04-23 23:04:04 +00:00
ges_clip_set_layer (GESClip * clip, GESLayer * layer)
{
if (layer == clip->priv->layer)
return;
clip->priv->layer = layer;
GST_DEBUG ("clip:%p, layer:%p", clip, layer);
/* We do not want to notify the setting of layer = NULL when
* it is actually the result of a move between layer (as we know
* that it will be added to another layer right after, and this
* is what imports here.) */
if (!ELEMENT_FLAG_IS_SET (clip, GES_CLIP_IS_MOVING))
g_object_notify_by_pspec (G_OBJECT (clip), properties[PROP_LAYER]);
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_set_moving_from_layer:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @is_moving: %TRUE if you want to start moving @clip to another layer
2020-01-09 12:11:35 +00:00
* %FALSE when you finished moving it
*
* Sets the clip in a moving to layer state. You might rather use the
2013-01-20 15:42:29 +00:00
* ges_clip_move_to_layer function to move #GESClip-s
* from a layer to another.
**/
void
ges_clip_set_moving_from_layer (GESClip * clip, gboolean is_moving)
{
g_return_if_fail (GES_IS_CLIP (clip));
if (is_moving)
ELEMENT_SET_FLAG (clip, GES_CLIP_IS_MOVING);
else
ELEMENT_UNSET_FLAG (clip, GES_CLIP_IS_MOVING);
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_is_moving_from_layer:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
*
* Tells you if the clip is currently moving from a layer to another.
2013-01-20 15:42:29 +00:00
* You might rather use the ges_clip_move_to_layer function to
* move #GESClip-s from a layer to another.
*
* Returns: %TRUE if @clip is currently moving from its current layer
2020-01-09 12:11:35 +00:00
* %FALSE otherwize.
**/
gboolean
ges_clip_is_moving_from_layer (GESClip * clip)
{
g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
2012-04-20 23:02:19 +00:00
return ELEMENT_FLAG_IS_SET (clip, GES_CLIP_IS_MOVING);
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_move_to_layer:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @layer: The new layer
*
2020-01-09 12:11:35 +00:00
* Moves a clip to a new layer. If the clip already exists in a layer, it
* is first removed from its current layer before being added to the new
* layer.
*
2020-01-09 12:11:35 +00:00
* Returns: %TRUE if @clip was successfully moved to @layer.
*/
gboolean
2013-04-23 23:04:04 +00:00
ges_clip_move_to_layer (GESClip * clip, GESLayer * layer)
{
gboolean ret = FALSE;
2013-04-23 23:04:04 +00:00
GESLayer *current_layer;
GESTimeline *current_timeline = GES_TIMELINE_ELEMENT_TIMELINE (clip);
g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
2013-04-23 23:04:04 +00:00
g_return_val_if_fail (GES_IS_LAYER (layer), FALSE);
current_layer = clip->priv->layer;
if (current_layer == layer) {
GST_INFO_OBJECT (clip, "Already in the layer %" GST_PTR_FORMAT, layer);
return TRUE;
}
gst_object_ref (clip);
if (current_layer == NULL) {
GST_DEBUG ("Not moving %p, only adding it to %p", clip, layer);
ret = ges_layer_add_clip (layer, clip);
goto done;
}
ELEMENT_SET_FLAG (clip, GES_CLIP_IS_MOVING);
if (current_timeline != layer->timeline) {
/* make sure we can perform the can_move_element_check in the timeline
* of the layer */
GST_WARNING_OBJECT (layer, "Cannot move clip %" GES_FORMAT " into "
"the layer because its timeline %" GST_PTR_FORMAT " does not "
"match the timeline of the layer %" GST_PTR_FORMAT,
GES_ARGS (clip), current_timeline, layer->timeline);
ret = FALSE;
goto done;
}
if (layer->timeline
&& !timeline_tree_can_move_element (timeline_get_tree (layer->timeline),
GES_TIMELINE_ELEMENT (clip),
ges_layer_get_priority (layer),
GES_TIMELINE_ELEMENT_START (clip),
GES_TIMELINE_ELEMENT_DURATION (clip), NULL)) {
GST_INFO_OBJECT (layer, "Clip %" GES_FORMAT " can't move to layer %d",
GES_ARGS (clip), ges_layer_get_priority (layer));
goto done;
}
GST_DEBUG_OBJECT (clip, "moving to layer %p, priority: %d", layer,
2013-04-23 23:04:04 +00:00
ges_layer_get_priority (layer));
2012-01-20 20:03:58 +00:00
2013-04-23 23:04:04 +00:00
ret = ges_layer_remove_clip (current_layer, clip);
if (!ret) {
goto done;
}
2013-04-23 23:04:04 +00:00
ret = ges_layer_add_clip (layer, clip);
if (ret) {
g_object_notify_by_pspec (G_OBJECT (clip), properties[PROP_LAYER]);
} else {
/* try and move back into the original layer */
ges_layer_add_clip (current_layer, clip);
}
done:
ELEMENT_UNSET_FLAG (clip, GES_CLIP_IS_MOVING);
gst_object_unref (clip);
return ret && (clip->priv->layer == layer);
}
/**
* ges_clip_find_track_element:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @track: (allow-none): The track to search in, or %NULL to search in
* all tracks
* @type: The type of track element to search for, or `G_TYPE_NONE` to
* match any type
*
2020-01-09 12:11:35 +00:00
* Finds an element controlled by the clip. If @track is given,
* then only the track elements in @track are searched for. If @type is
* given, then this function searches for a track element of the given
* @type.
*
2020-01-09 12:11:35 +00:00
* Note, if multiple track elements in the clip match the given criteria,
* this will return the element amongst them with the highest
* #GESTimelineElement:priority (numerically, the smallest). See
* ges_clip_find_track_elements() if you wish to find all such elements.
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer full) (nullable): The element controlled by
* @clip, in @track, and of the given @type, or %NULL if no such element
* could be found.
*/
GESTrackElement *
ges_clip_find_track_element (GESClip * clip, GESTrack * track, GType type)
{
GList *tmp;
GESTrackElement *otmp;
GESTrackElement *ret = NULL;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
g_return_val_if_fail (!(track == NULL && type == G_TYPE_NONE), NULL);
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = g_list_next (tmp)) {
otmp = (GESTrackElement *) tmp->data;
if ((type != G_TYPE_NONE) && !G_TYPE_CHECK_INSTANCE_TYPE (tmp->data, type))
continue;
if ((track == NULL) || (ges_track_element_get_track (otmp) == track)) {
ret = GES_TRACK_ELEMENT (tmp->data);
gst_object_ref (ret);
break;
}
}
return ret;
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_get_layer:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
*
2020-01-09 12:11:35 +00:00
* Gets the #GESClip:layer of the clip.
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer full) (nullable): The layer @clip is in, or %NULL if
* @clip is not in any layer.
*/
2013-04-23 23:04:04 +00:00
GESLayer *
ges_clip_get_layer (GESClip * clip)
{
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
if (clip->priv->layer != NULL)
gst_object_ref (G_OBJECT (clip->priv->layer));
return clip->priv->layer;
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_get_top_effects:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
*
2020-01-09 12:11:35 +00:00
* Gets the #GESBaseEffect-s that have been added to the clip. The
* returned list is ordered by their internal index in the clip. See
* ges_clip_get_top_effect_index().
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer full) (element-type GESTrackElement): A list of all
* #GESBaseEffect-s that have been added to @clip.
*/
GList *
ges_clip_get_top_effects (GESClip * clip)
{
GList *tmp, *ret;
GESTimelineElement *child;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
GST_DEBUG_OBJECT (clip, "Getting the %i top effects", clip->priv->nb_effects);
ret = NULL;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
child = tmp->data;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (_IS_TOP_EFFECT (child))
ret = g_list_append (ret, gst_object_ref (child));
}
/* list is already sorted by index because the list of children is
* sorted by priority */
return ret;
}
static gboolean
_is_added_effect (GESClip * clip, GESBaseEffect * effect)
{
if (GES_TIMELINE_ELEMENT_PARENT (effect) != GES_TIMELINE_ELEMENT (clip)) {
GST_WARNING_OBJECT (clip, "The effect %" GES_FORMAT
" doe not belong to this clip", GES_ARGS (effect));
return FALSE;
}
if (_IS_CORE_CHILD (effect)) {
GST_WARNING_OBJECT (clip, "The effect %" GES_FORMAT " is not a top "
"effect of this clip (it is a core element of the clip)",
GES_ARGS (effect));
return FALSE;
}
return TRUE;
}
/**
* ges_clip_get_top_effect_index:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @effect: The effect we want to get the index of
*
2020-01-09 12:11:35 +00:00
* Gets the internal index of an effect in the clip. The index of effects
* in a clip will run from 0 to n-1, where n is the total number of
* effects. If two effects share the same #GESTrackElement:track, the
* effect with the numerically lower index will be applied to the source
* data **after** the other effect, i.e. output data will always flow from
* a higher index effect to a lower index effect.
*
2020-01-09 12:11:35 +00:00
* Returns: The index of @effect in @clip, or -1 if something went wrong.
*/
gint
ges_clip_get_top_effect_index (GESClip * clip, GESBaseEffect * effect)
{
guint max_prio, min_prio;
g_return_val_if_fail (GES_IS_CLIP (clip), -1);
g_return_val_if_fail (GES_IS_BASE_EFFECT (effect), -1);
if (!_is_added_effect (clip, effect))
return -1;
_get_priority_range (GES_CONTAINER (clip), &min_prio, &max_prio);
return GES_TIMELINE_ELEMENT_PRIORITY (effect) - min_prio;
}
/* TODO 2.0 remove as it is Deprecated */
gint
ges_clip_get_top_effect_position (GESClip * clip, GESBaseEffect * effect)
{
return ges_clip_get_top_effect_index (clip, effect);
}
/* TODO 2.0 remove as it is Deprecated */
gboolean
ges_clip_set_top_effect_priority (GESClip * clip,
GESBaseEffect * effect, guint newpriority)
{
return ges_clip_set_top_effect_index (clip, effect, newpriority);
}
/**
* ges_clip_set_top_effect_index:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @effect: An effect within @clip to move
* @newindex: The index for @effect in @clip
*
2020-01-09 12:11:35 +00:00
* Set the index of an effect within the clip. See
* ges_clip_get_top_effect_index(). The new index must be an existing
* index of the clip. The effect is moved to the new index, and the other
* effects may be shifted in index accordingly to otherwise maintain the
* ordering.
*
2020-01-09 12:11:35 +00:00
* Returns: %TRUE if @effect was successfully moved to @newindex.
*/
gboolean
ges_clip_set_top_effect_index (GESClip * clip, GESBaseEffect * effect,
guint newindex)
{
gint inc;
GList *tmp;
guint current_prio, min_prio, max_prio;
GESTrackElement *track_element;
g_return_val_if_fail (GES_IS_CLIP (clip), FALSE);
g_return_val_if_fail (GES_IS_BASE_EFFECT (effect), FALSE);
if (!_is_added_effect (clip, effect))
return FALSE;
track_element = GES_TRACK_ELEMENT (effect);
current_prio = _PRIORITY (track_element);
_get_priority_range (GES_CONTAINER (clip), &min_prio, &max_prio);
newindex = newindex + min_prio;
/* We don't change the priority */
if (current_prio == newindex)
return TRUE;
if (newindex > (clip->priv->nb_effects - 1 + min_prio)) {
GST_DEBUG ("You are trying to make %p not a top effect", effect);
return FALSE;
}
if (current_prio > clip->priv->nb_effects + min_prio) {
GST_ERROR ("%p is not a top effect", effect);
return FALSE;
}
GST_DEBUG_OBJECT (clip, "Setting top effect %" GST_PTR_FORMAT "priority: %i",
effect, newindex);
if (current_prio < newindex)
inc = -1;
else
inc = +1;
/* prevent a re-sort of the list whilst we are traversing it! */
clip->priv->prevent_resort = TRUE;
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
GESTrackElement *tmpo = GES_TRACK_ELEMENT (tmp->data);
guint tck_priority = _PRIORITY (tmpo);
if (tmpo == track_element)
continue;
/* only need to change the priority for those between the new and old
* index */
if ((inc == +1 && tck_priority >= newindex && tck_priority < current_prio)
|| (inc == -1 && tck_priority <= newindex
&& tck_priority > current_prio)) {
_set_priority0 (GES_TIMELINE_ELEMENT (tmpo), tck_priority + inc);
}
}
_set_priority0 (GES_TIMELINE_ELEMENT (track_element), newindex);
clip->priv->prevent_resort = FALSE;
_ges_container_sort_children (GES_CONTAINER (clip));
/* height should have stayed the same */
return TRUE;
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_split:
2020-01-09 12:11:35 +00:00
* @clip: The #GESClip to split
* @position: The timeline position at which to perform the split
*
2020-01-09 12:11:35 +00:00
* Splits a clip at the given timeline position into two clips. The clip
* must already have a #GESClip:layer.
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
*
2020-01-09 12:11:35 +00:00
* The original clip's #GESTimelineElement:duration is reduced such that
* its end point matches the split position. Then a new clip is created in
* the same layer, whose #GESTimelineElement:start matches the split
* position and #GESTimelineElement:duration will be set such that its end
* point matches the old end point of the original clip. Thus, the two
* clips together will occupy the same positions in the timeline as the
* original clip did.
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
*
2020-01-09 12:11:35 +00:00
* The children of the new clip will be new copies of the original clip's
* children, so it will share the same sources and use the same
* operations.
*
2020-01-09 12:11:35 +00:00
* The new clip will also have its #GESTimelineElement:in-point set so
* that any internal data will appear in the timeline at the same time.
* Thus, when the timeline is played, the playback of data should
* appear the same. This may be complicated by any additional
* #GESEffect-s that have been placed on the original clip that depend on
* the playback time or change the data consumption rate of sources. This
* method will attempt to translate these effects such that the playback
* appears the same. In such complex situations, you may get a better
* result if you place the clip in a separate sub #GESProject, which only
* contains this clip (and its effects), and in the original layer
* create two neighbouring #GESUriClip-s that reference this sub-project,
* but at a different #GESTimelineElement:in-point.
*
* Returns: (transfer none) (nullable): The newly created clip resulting
* from the splitting @clip, or %NULL if @clip can't be split.
*/
2013-01-20 15:42:29 +00:00
GESClip *
ges_clip_split (GESClip * clip, guint64 position)
{
GList *tmp;
2013-01-20 15:42:29 +00:00
GESClip *new_object;
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
GstClockTime start, inpoint, duration, old_duration, new_duration;
gdouble media_duration_factor;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
GESTimelineElement *element;
GESTimeline *timeline;
GHashTable *track_for_copy;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
g_return_val_if_fail (clip->priv->layer, NULL);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), NULL);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
element = GES_TIMELINE_ELEMENT (clip);
timeline = element->timeline;
duration = element->duration;
start = element->start;
inpoint = element->inpoint;
if (position >= start + duration || position <= start) {
GST_WARNING_OBJECT (clip, "Can not split %" GST_TIME_FORMAT
" out of boundaries", GST_TIME_ARGS (position));
return NULL;
}
old_duration = position - start;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (timeline && !timeline_tree_can_move_element (timeline_get_tree
(timeline), element,
ges_timeline_element_get_layer_priority (element),
start, old_duration, NULL)) {
GST_WARNING_OBJECT (clip,
"Can not split %" GES_FORMAT " at %" GST_TIME_FORMAT
" as timeline would be in an illegal" " state.", GES_ARGS (clip),
GST_TIME_ARGS (position));
return NULL;
}
new_duration = duration + start - position;
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (timeline && !timeline_tree_can_move_element (timeline_get_tree
(timeline), element,
ges_timeline_element_get_layer_priority (element),
position, new_duration, NULL)) {
GST_WARNING_OBJECT (clip,
"Can not split %" GES_FORMAT " at %" GST_TIME_FORMAT
" as timeline would end up in an illegal" " state.", GES_ARGS (clip),
GST_TIME_ARGS (position));
return NULL;
}
GST_DEBUG_OBJECT (clip, "Spliting at %" GST_TIME_FORMAT,
GST_TIME_ARGS (position));
2013-01-20 15:42:29 +00:00
/* Create the new Clip */
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
new_object = GES_CLIP (ges_timeline_element_copy (element, FALSE));
GST_DEBUG_OBJECT (new_object, "New 'splitted' clip");
2013-01-20 15:42:29 +00:00
/* Set new timing properties on the Clip */
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
media_duration_factor =
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
ges_timeline_element_get_media_duration_factor (element);
_set_start0 (GES_TIMELINE_ELEMENT (new_object), position);
_set_inpoint0 (GES_TIMELINE_ELEMENT (new_object),
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
inpoint + old_duration * media_duration_factor);
_set_duration0 (GES_TIMELINE_ELEMENT (new_object), new_duration);
/* We do not want the timeline to create again TrackElement-s */
ges_clip_set_moving_from_layer (new_object, TRUE);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* adding to the same layer should not fail when moving */
2013-04-23 23:04:04 +00:00
ges_layer_add_clip (clip->priv->layer, new_object);
ges_clip_set_moving_from_layer (new_object, FALSE);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/* split binding before duration changes */
track_for_copy = g_hash_table_new_full (NULL, NULL,
gst_object_unref, gst_object_unref);
/* _add_child will add core elements at the lowest priority and new
* non-core effects at the lowest effect priority, so we need to add the
* highest priority children first to preserve the effect order. The
* clip's children are already ordered by highest priority first. */
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = tmp->next) {
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
GESTrackElement *copy, *orig = tmp->data;
GESTrack *track = ges_track_element_get_track (orig);
2020-01-09 12:11:35 +00:00
/* FIXME: is position - start + inpoint always the correct splitting
* point for control bindings? What coordinate system are control
* bindings given in? */
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
copy = ges_clip_copy_track_element_into (new_object, orig,
position - start + inpoint);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
if (copy && track)
g_hash_table_insert (track_for_copy, gst_object_ref (copy),
gst_object_ref (track));
}
ELEMENT_SET_FLAG (clip, GES_TIMELINE_ELEMENT_SET_SIMPLE);
Handle changing playback rate Before this patch, NLE and GES did not support NleOperations (respectively GESEffects) that changed the speed/tempo/rate at which the source plays. For example, the 'pitch' element can make audio play faster or slower. In GES 1.5.90 and before, an NleOperation containing the pitch element to change the rate (or tempo) would cause a pipeline state change to PAUSED after that stack; that has been fixed in 1.5.91 (see #755012 [0]). But even then, in 1.5.91 and later, NleComposition would send segment events to its NleSources assuming that one source second is equal to one pipeline second. The resulting early EOS event (in the case of a source rate higher than 1.0) would cause it to switch stacks too early, causing confusion in the timeline and spectacularly messed up output. This patch fixes that by searching for rate-changing elements in GESTrackElements such as GESEffects. If such rate-changing elements are found, their final effect on the playing rate is stored in the corresponding NleObject as the 'media duration factor', named like this because the 'media duration', or source duration, of an NleObject can be computed by multiplying the duration with the media duration factor of that object and its parents (this is called the 'recursive media duration factor'). For example, a 4-second NleSource with an NleOperation with a media duration factor of 2.0 will have an 8-second media duration, which means that for playing 4 seconds in the pipeline, the seek event sent to it must span 8 seconds of media. (So, the 'duration' of an NleObject or GES object always refers to its duration in the timeline, not the media duration.) To summarize: * Rate-changing elements are registered in the GESEffectClass (pitch::tempo and pitch::rate are registered by default); * GESTimelineElement is responsible for detecting rate-changing elements and computing the media_duration_factor; * GESTrackElement is responsible for storing the media_duration_factor in NleObject; * NleComposition is responsible for the recursive_media_duration_factor; * The latter property finally fixes media time computations in NleObject. NLE and GES tests are included. [0] https://bugzilla.gnome.org/show_bug.cgi?id=755012 Differential Revision: https://phabricator.freedesktop.org/D276
2015-12-20 13:03:57 +00:00
_set_duration0 (GES_TIMELINE_ELEMENT (clip), old_duration);
ELEMENT_UNSET_FLAG (clip, GES_TIMELINE_ELEMENT_SET_SIMPLE);
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
g_object_notify (G_OBJECT (clip), "duration");
/* add to the track after the duration change so we don't overlap! */
for (tmp = GES_CONTAINER_CHILDREN (new_object); tmp; tmp = tmp->next) {
GESTrackElement *copy = tmp->data;
GESTrack *track = g_hash_table_lookup (track_for_copy, copy);
if (track) {
new_object->priv->allow_any_track = TRUE;
ges_track_add_element (track, copy);
new_object->priv->allow_any_track = FALSE;
}
}
g_hash_table_unref (track_for_copy);
return new_object;
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_set_supported_formats:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @supportedformats: The #GESTrackType-s supported by @clip
*
2020-01-09 12:11:35 +00:00
* Sets the #GESClip:supported-formats of the clip. This should normally
* only be called by subclasses, which should be responsible for updating
* its value, rather than the user.
*/
void
ges_clip_set_supported_formats (GESClip * clip, GESTrackType supportedformats)
{
g_return_if_fail (GES_IS_CLIP (clip));
clip->priv->supportedformats = supportedformats;
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_get_supported_formats:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
*
2020-01-09 12:11:35 +00:00
* Gets the #GESClip:supported-formats of the clip.
*
2020-01-09 12:11:35 +00:00
* Returns: The #GESTrackType-s supported by @clip.
*/
GESTrackType
ges_clip_get_supported_formats (GESClip * clip)
{
g_return_val_if_fail (GES_IS_CLIP (clip), GES_TRACK_TYPE_UNKNOWN);
return clip->priv->supportedformats;
}
gboolean
_ripple (GESTimelineElement * element, GstClockTime start)
{
return ges_container_edit (GES_CONTAINER (element), NULL,
ges_timeline_element_get_layer_priority (element),
GES_EDIT_MODE_RIPPLE, GES_EDGE_NONE, start);
}
static gboolean
_ripple_end (GESTimelineElement * element, GstClockTime end)
{
return ges_container_edit (GES_CONTAINER (element), NULL,
ges_timeline_element_get_layer_priority (element),
GES_EDIT_MODE_RIPPLE, GES_EDGE_END, end);
}
gboolean
_roll_start (GESTimelineElement * element, GstClockTime start)
{
return ges_container_edit (GES_CONTAINER (element), NULL,
ges_timeline_element_get_layer_priority (element),
GES_EDIT_MODE_ROLL, GES_EDGE_START, start);
}
gboolean
_roll_end (GESTimelineElement * element, GstClockTime end)
{
return ges_container_edit (GES_CONTAINER (element), NULL,
ges_timeline_element_get_layer_priority (element),
GES_EDIT_MODE_ROLL, GES_EDGE_END, end);
}
gboolean
_trim (GESTimelineElement * element, GstClockTime start)
{
return ges_container_edit (GES_CONTAINER (element), NULL, -1,
GES_EDIT_MODE_TRIM, GES_EDGE_START, start);
}
/**
2013-01-20 15:42:29 +00:00
* ges_clip_add_asset:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @asset: An asset with #GES_TYPE_TRACK_ELEMENT as its
* #GESAsset:extractable-type
*
2020-01-09 12:11:35 +00:00
* Extracts a #GESTrackElement from an asset and adds it to the clip.
* This can be used to add effects that derive from the asset to the
* clip, but this method is not intended to be used to create the core
* elements of the clip.
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer none)(allow-none): The newly created element, or
* %NULL if an error occurred.
*/
2020-01-09 12:11:35 +00:00
/* FIXME: this is not used elsewhere in the GES library */
GESTrackElement *
ges_clip_add_asset (GESClip * clip, GESAsset * asset)
{
GESTrackElement *element;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
g_return_val_if_fail (GES_IS_ASSET (asset), NULL);
g_return_val_if_fail (g_type_is_a (ges_asset_get_extractable_type
(asset), GES_TYPE_TRACK_ELEMENT), NULL);
element = GES_TRACK_ELEMENT (ges_asset_extract (asset, NULL));
if (!ges_container_add (GES_CONTAINER (clip), GES_TIMELINE_ELEMENT (element)))
return NULL;
return element;
}
/**
* ges_clip_find_track_elements:
2020-01-09 12:11:35 +00:00
* @clip: A #GESClip
* @track: (allow-none): The track to search in, or %NULL to search in
* all tracks
* @track_type: The track-type of the track element to search for, or
* #GES_TRACK_TYPE_UNKNOWN to match any track type
* @type: The type of track element to search for, or %G_TYPE_NONE to
* match any type
2020-01-09 12:11:35 +00:00
*
* Finds the #GESTrackElement-s controlled by the clip that match the
* given criteria. If @track is given as %NULL and @track_type is given as
* #GES_TRACK_TYPE_UNKNOWN, then the search will match all elements in any
* track, including those with no track, and of any
* #GESTrackElement:track-type. Otherwise, if @track is not %NULL, but
* @track_type is #GES_TRACK_TYPE_UNKNOWN, then only the track elements in
* @track are searched for. Otherwise, if @track_type is not
* #GES_TRACK_TYPE_UNKNOWN, but @track is %NULL, then only the track
* elements whose #GESTrackElement:track-type matches @track_type are
* searched for. Otherwise, when both are given, the track elements that
* match **either** criteria are searched for. Therefore, if you wish to
* only find elements in a specific track, you should give the track as
* @track, but you should not give the track's #GESTrack:track-type as
* @track_type because this would also select elements from other tracks
* of the same type.
*
* You may also give @type to _further_ restrict the search to track
2020-01-09 12:11:35 +00:00
* elements of the given @type.
*
2020-01-09 12:11:35 +00:00
* Returns: (transfer full) (element-type GESTrackElement): A list of all
* the #GESTrackElement-s controlled by @clip, in @track or of the given
* @track_type, and of the given @type.
*/
GList *
ges_clip_find_track_elements (GESClip * clip, GESTrack * track,
GESTrackType track_type, GType type)
{
GList *tmp;
GESTrackElement *otmp;
GList *ret = NULL;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
g_return_val_if_fail (!(track == NULL && type == G_TYPE_NONE &&
track_type == GES_TRACK_TYPE_UNKNOWN), NULL);
for (tmp = GES_CONTAINER_CHILDREN (clip); tmp; tmp = g_list_next (tmp)) {
otmp = (GESTrackElement *) tmp->data;
if ((type != G_TYPE_NONE) && !G_TYPE_CHECK_INSTANCE_TYPE (tmp->data, type))
continue;
/* TODO 2.0: an AND condition, using a condition like the above type
* check would have made more sense here. Especially when both
* track != NULL and track_type != GES_TRACK_TYPE_UNKNOWN are given */
if ((track == NULL && track_type == GES_TRACK_TYPE_UNKNOWN) ||
(track != NULL && ges_track_element_get_track (otmp) == track) ||
(track_type != GES_TRACK_TYPE_UNKNOWN
&& ges_track_element_get_track_type (otmp) == track_type))
ret = g_list_append (ret, gst_object_ref (otmp));
}
return ret;
}
/**
* ges_clip_get_timeline_time_from_source_frame:
* @clip: A #GESClip
* @frame_number: The frame number to get the corresponding timestamp in the
* timeline coordinates
* @err: A #GError set on errors
*
* This method allows you to convert a frame number into a #GstClockTime, this
* can be used to either seek to a particular frame in the timeline or to later
* on edit @self with that timestamp.
*
* This method should be use specifically in the case where you want to trim the
* clip to a particular frame.
*
* The returned timestamp is in the global #GESTimeline time coordinates of @self, not
* in the internal time coordinates. In practice, this means that you can not use
* that time to set the clip #GESTimelineElement:in-point but it can be used in
* the timeline editing API, for example as the @position argument of the
* #ges_timeline_element_edit method.
*
* Note that you can get the frame timestamp of a particular clip asset with
* #ges_clip_asset_get_frame_time.
*
* Returns: The timestamp corresponding to @frame_number in the element source
* in the timeline coordinates.
*/
GstClockTime
ges_clip_get_timeline_time_from_source_frame (GESClip * clip,
GESFrameNumber frame_number, GError ** err)
{
GstClockTime frame_ts;
GESClipAsset *asset;
GstClockTimeDiff inpoint_diff;
g_return_val_if_fail (GES_IS_CLIP (clip), GST_CLOCK_TIME_NONE);
g_return_val_if_fail (!err || !*err, GST_CLOCK_TIME_NONE);
if (!GES_FRAME_NUMBER_IS_VALID (frame_number))
return GST_CLOCK_TIME_NONE;
asset = GES_CLIP_ASSET (ges_extractable_get_asset (GES_EXTRACTABLE (clip)));
frame_ts = ges_clip_asset_get_frame_time (asset, frame_number);
if (!GST_CLOCK_TIME_IS_VALID (frame_ts))
return GST_CLOCK_TIME_NONE;
inpoint_diff = GST_CLOCK_DIFF (frame_ts, GES_TIMELINE_ELEMENT_INPOINT (clip));
if (GST_CLOCK_DIFF (inpoint_diff, _START (clip)) < 0) {
g_set_error (err, GES_ERROR, GES_ERROR_INVALID_FRAME_NUMBER,
"Requested frame %" G_GINT64_FORMAT
" would be outside the timeline.", frame_number);
return GST_CLOCK_TIME_NONE;
}
return GST_CLOCK_DIFF (inpoint_diff, _START (clip));
}
timeline: re-handle clip children track selection The way a clip's track elements are added to tracks was re-handled. This doesn't affect the normal usage of a simple audio-video timeline, where the tracks are added before any clips, but usage for multi-track timelines has improved. The main changes are: + We can now handle a track being selected for more than one track, including a full copy of their children properties and bindings. (Previously broken.) + When a clip is split, we copy the new elements directly into the same track, avoiding select-tracks-for-object. + When a clip is grouped or ungrouped, we avoid moving the elements to or from tracks. + Added API to allow users to copy the core elements of a clip directly into a track, complementing select-tracks-for-object. + Enforced the rule that a clip can only contain one core child in a track, and all the non-core children must be added to tracks that already contains a core child. This extends the previous condition that two sources from the same clip should not be added to the same track. + Made ges_track_add_element check that the newly added track element does not break the configuration rules of the timeline. + When adding a track to a timeline, we only use select-tracks-for-object to check whether track elements should be added to the new track, not existing ones. + When removing a track from a timeline, we empty it of all the track elements that are controlled by a clip. Thus, we ensure that a clip only contains elements that are in the tracks of the same timeline, or no track. Similarly, when removing a clip from a timeline. + We can now avoid unsupported timeline configurations when a layer is added to a timeline, and already contains clips. + We can now avoid unsupported timeline configurations when a track is added to a timeline, and the timeline already contains clips. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/84
2020-04-06 11:09:54 +00:00
/**
* ges_clip_add_child_to_track:
* @clip: A #GESClip
* @child: A child of @clip
* @track: The track to add @child to
* @err: Return location for an error
*
* Adds the track element child of the clip to a specific track.
*
* If the given child is already in another track, this will create a copy
* of the child, add it to the clip, and add this copy to the track.
*
* You should only call this whilst a clip is part of a #GESTimeline, and
* for tracks that are in the same timeline.
*
* This method is an alternative to using the
* #GESTimeline::select-tracks-for-object signal, but can be used to
* complement it when, say, you wish to copy a clip's children from one
* track into a new one.
*
* When the child is a core child, it must be added to a track that does
* not already contain another core child of the same clip. If it is not a
* core child (an additional effect), then it must be added to a track
* that already contains one of the core children of the same clip.
*
* This method can also fail if the adding the track element to the track
* would break a configuration rule of the corresponding #GESTimeline,
* such as causing three sources to overlap at a single time, or causing
* a source to completely overlap another in the same track.
*
* Note that @err will not always be set upon failure.
*
* Returns: (transfer none): The element that was added to @track, either
* @child or a copy of child, or %NULL if the element could not be added.
*/
GESTrackElement *
ges_clip_add_child_to_track (GESClip * clip, GESTrackElement * child,
GESTrack * track, GError ** err)
{
GESTimeline *timeline;
GESTrackElement *el;
GESTrack *current_track;
g_return_val_if_fail (GES_IS_CLIP (clip), NULL);
g_return_val_if_fail (GES_IS_TRACK_ELEMENT (child), NULL);
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
g_return_val_if_fail (!err || !*err, NULL);
timeline = GES_TIMELINE_ELEMENT_TIMELINE (clip);
if (!g_list_find (GES_CONTAINER_CHILDREN (clip), child)) {
GST_WARNING_OBJECT (clip, "The track element %" GES_FORMAT " is not "
"a child of the clip", GES_ARGS (child));
return NULL;
}
if (!timeline) {
GST_WARNING_OBJECT (clip, "Cannot add children to tracks unless "
"the clip is part of a timeline");
return NULL;
}
if (timeline != ges_track_get_timeline (track)) {
GST_WARNING_OBJECT (clip, "Cannot add the children to the track %"
GST_PTR_FORMAT " because its timeline is %" GST_PTR_FORMAT
" rather than that of the clip %" GST_PTR_FORMAT,
track, ges_track_get_timeline (track), timeline);
return NULL;
}
current_track = ges_track_element_get_track (child);
if (current_track == track) {
GST_WARNING_OBJECT (clip, "Child %s" GES_FORMAT " is already in the "
"track %" GST_PTR_FORMAT, GES_ARGS (child), track);
return NULL;
}
/* copy if the element is already in a track */
if (current_track) {
el = ges_clip_copy_track_element_into (clip, child, GST_CLOCK_TIME_NONE);
if (!el) {
GST_ERROR_OBJECT (clip, "Could not add a copy of the track element %"
GES_FORMAT " to the clip so cannot add it to the track %"
GST_PTR_FORMAT, GES_ARGS (child), track);
return NULL;
}
if (_IS_TOP_EFFECT (child)) {
/* add at next lowest priority */
ges_clip_set_top_effect_index (clip, GES_BASE_EFFECT (el),
ges_clip_get_top_effect_index (clip, GES_BASE_EFFECT (child)) + 1);
}
} else {
el = child;
}
/* FIXME: set error if can not be added to track:
* Either breaks the track rules for the clip, or the timeline
* configuration rules */
if (!ges_track_add_element (track, el)) {
GST_WARNING_OBJECT (clip, "Could not add the track element %"
GES_FORMAT " to the track %" GST_PTR_FORMAT, GES_ARGS (el), track);
if (el != child)
ges_container_remove (GES_CONTAINER (clip), GES_TIMELINE_ELEMENT (el));
return NULL;
}
if (GES_IS_SOURCE (el))
timeline_tree_create_transitions (timeline_get_tree (timeline),
ges_timeline_find_auto_transition);
return el;
}