gstreamer/subprojects/gst-editing-services/ges/ges-track.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1495 lines
44 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
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:gestrack
* @title: GESTrack
2020-01-15 14:44:38 +00:00
* @short_description: The output source of a #GESTimeline
*
2020-01-15 14:44:38 +00:00
* A #GESTrack acts an output source for a #GESTimeline. Each one
* essentially provides an additional #GstPad for the timeline, with
* #GESTrack:restriction-caps capabilities. Internally, a track
* wraps an #nlecomposition filtered by a #capsfilter.
2009-08-04 15:13:11 +00:00
*
2020-01-15 14:44:38 +00:00
* A track will contain a number of #GESTrackElement-s, and its role is
* to select and activate these elements according to their timings when
* the timeline in played. For example, a track would activate a
* #GESSource when its #GESTimelineElement:start is reached by outputting
* its data for its #GESTimelineElement:duration. Similarly, a
* #GESOperation would be activated by applying its effect to the source
* data, starting from its #GESTimelineElement:start time and lasting for
* its #GESTimelineElement:duration.
*
* For most users, it will usually be sufficient to add newly created
* tracks to a timeline, but never directly add an element to a track.
* Whenever a #GESClip is added to a timeline, the clip adds its
* elements to the timeline's tracks and assumes responsibility for
* updating them.
2009-08-04 15:13:11 +00:00
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2009-08-04 15:13:11 +00:00
#include "ges-internal.h"
#include "ges-track.h"
#include "ges-track-element.h"
#include "ges-meta-container.h"
#include "ges-video-track.h"
#include "ges-audio-track.h"
#define CHECK_THREAD(track) g_assert(track->priv->valid_thread == g_thread_self())
static GstStaticPadTemplate ges_track_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
/* Structure that represents gaps and keep knowledge
* of the gaps filled in the track */
typedef struct
{
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
GstElement *nleobj;
GstClockTime start;
GstClockTime duration;
GESTrack *track;
} Gap;
2010-12-04 18:54:13 +00:00
struct _GESTrackPrivate
{
/*< private > */
GESTimeline *timeline;
GSequence *trackelements_by_start;
GHashTable *trackelements_iter;
GList *gaps;
gboolean last_gap_disabled;
guint64 duration;
GstCaps *caps;
GstCaps *restriction_caps;
GstElement *composition; /* The composition associated with this track */
GstPad *srcpad; /* The source GhostPad */
gboolean updating;
gboolean mixing;
GstElement *mixing_operation;
GstElement *capsfilter;
/* Virtual method to create GstElement that fill gaps */
GESCreateElementForGapFunc create_element_for_gaps;
GThread *valid_thread;
2010-12-04 18:54:13 +00:00
};
2009-08-07 16:18:42 +00:00
enum
{
ARG_0,
ARG_CAPS,
ARG_RESTRICTION_CAPS,
ARG_TYPE,
ARG_DURATION,
ARG_MIXING,
2019-06-06 21:21:01 +00:00
ARG_ID,
ARG_LAST,
TRACK_ELEMENT_ADDED,
TRACK_ELEMENT_REMOVED,
COMMITED,
LAST_SIGNAL
2009-08-07 16:18:42 +00:00
};
static guint ges_track_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *properties[ARG_LAST];
2009-08-07 18:32:47 +00:00
G_DEFINE_TYPE_WITH_CODE (GESTrack, ges_track, GST_TYPE_BIN,
G_ADD_PRIVATE (GESTrack)
G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
static void composition_duration_cb (GstElement * composition, GParamSpec * arg
G_GNUC_UNUSED, GESTrack * obj);
static void ges_track_set_caps (GESTrack * track, const GstCaps * caps);
/* Private methods/functions/callbacks */
static void
add_trackelement_to_list_foreach (GESTrackElement * trackelement, GList ** list)
{
gst_object_ref (trackelement);
*list = g_list_prepend (*list, trackelement);
}
static Gap *
gap_new (GESTrack * track, GstClockTime start, GstClockTime duration)
{
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
GstElement *nlesrc, *elem;
Gap *new_gap;
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
nlesrc = gst_element_factory_make ("nlesource", NULL);
elem = track->priv->create_element_for_gaps (track);
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
if (G_UNLIKELY (gst_bin_add (GST_BIN (nlesrc), elem) == FALSE)) {
GST_WARNING_OBJECT (track, "Could not create gap filler");
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
if (nlesrc)
gst_object_unref (nlesrc);
if (elem)
gst_object_unref (elem);
return NULL;
}
if (G_UNLIKELY (ges_nle_composition_add_object (track->priv->composition,
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
nlesrc) == FALSE)) {
GST_WARNING_OBJECT (track, "Could not add gap to the composition");
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
if (nlesrc)
gst_object_unref (nlesrc);
if (elem)
gst_object_unref (elem);
return NULL;
}
new_gap = g_new (Gap, 1);
new_gap->start = start;
new_gap->duration = duration;
new_gap->track = track;
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
new_gap->nleobj = nlesrc;
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
g_object_set (nlesrc, "start", new_gap->start, "duration", new_gap->duration,
"priority", 1, NULL);
GST_DEBUG_OBJECT (track,
"Created gap with start %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT,
GST_TIME_ARGS (new_gap->start), GST_TIME_ARGS (new_gap->duration));
return new_gap;
}
static void
free_gap (Gap * gap)
{
GESTrack *track = gap->track;
GST_DEBUG_OBJECT (track, "Removed gap with start %" GST_TIME_FORMAT
" duration %" GST_TIME_FORMAT, GST_TIME_ARGS (gap->start),
GST_TIME_ARGS (gap->duration));
ges_nle_composition_remove_object (track->priv->composition, gap->nleobj);
g_free (gap);
}
static inline void
update_gaps (GESTrack * track)
{
Gap *gap;
GList *gaps;
GSequenceIter *it;
GESTrackElement *trackelement;
GstClockTime start, end, duration = 0, timeline_duration = 0;
GESTrackPrivate *priv = track->priv;
if (priv->create_element_for_gaps == NULL) {
GST_INFO ("Not filling the gaps as no create_element_for_gaps vmethod"
" provided");
return;
}
gaps = priv->gaps;
priv->gaps = NULL;
/* 1- And recalculate gaps */
for (it = g_sequence_get_begin_iter (priv->trackelements_by_start);
g_sequence_iter_is_end (it) == FALSE; it = g_sequence_iter_next (it)) {
trackelement = g_sequence_get (it);
2014-10-26 20:36:22 +00:00
if (!ges_track_element_is_active (trackelement))
continue;
if (priv->timeline) {
guint32 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (trackelement);
if (layer_prio != GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY) {
GESLayer *layer = g_list_nth_data (priv->timeline->layers, layer_prio);
if (!ges_layer_get_active_for_track (layer, track))
continue;
}
}
start = _START (trackelement);
end = start + _DURATION (trackelement);
if (start > duration) {
/* 2- Fill gap */
gap = gap_new (track, duration, start - duration);
if (G_LIKELY (gap != NULL))
priv->gaps = g_list_prepend (priv->gaps, gap);
}
duration = MAX (duration, end);
}
/* 3- Add a gap at the end of the timeline if needed */
if (priv->timeline) {
g_object_get (priv->timeline, "duration", &timeline_duration, NULL);
if (duration < timeline_duration) {
gap = gap_new (track, duration, timeline_duration - duration);
if (G_LIKELY (gap != NULL)) {
priv->gaps = g_list_prepend (priv->gaps, gap);
}
2020-01-15 14:44:38 +00:00
/* FIXME: here the duration is set to the duration of the timeline,
* but elsewhere it is set to the duration of the composition. Are
* these always the same? */
priv->duration = timeline_duration;
}
}
if (!track->priv->last_gap_disabled) {
GST_DEBUG_OBJECT (track, "Adding a one second gap at the end");
gap = gap_new (track, timeline_duration, 1);
priv->gaps = g_list_prepend (priv->gaps, gap);
}
/* 4- Remove old gaps */
g_list_free_full (gaps, (GDestroyNotify) free_gap);
}
void
track_disable_last_gap (GESTrack * track, gboolean disabled)
{
track->priv->last_gap_disabled = disabled;
update_gaps (track);
}
void
track_resort_and_fill_gaps (GESTrack * track)
{
g_sequence_sort (track->priv->trackelements_by_start,
(GCompareDataFunc) element_start_compare, NULL);
if (track->priv->updating == TRUE) {
update_gaps (track);
}
}
static gboolean
update_field (GQuark field_id, const GValue * value, GstStructure * original)
{
gst_structure_id_set_value (original, field_id, value);
return TRUE;
}
/* callbacks */
static void
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
_ghost_nlecomposition_srcpad (GESTrack * track)
2009-08-04 15:13:11 +00:00
{
GstPad *capsfilter_sink;
GstPad *capsfilter_src;
GESTrackPrivate *priv = track->priv;
GstPad *pad = gst_element_get_static_pad (priv->composition, "src");
capsfilter_sink = gst_element_get_static_pad (priv->capsfilter, "sink");
2009-08-07 16:18:42 +00:00
GST_DEBUG ("track:%p, pad %s:%s", track, GST_DEBUG_PAD_NAME (pad));
gst_pad_link (pad, capsfilter_sink);
gst_object_unref (capsfilter_sink);
gst_object_unref (pad);
capsfilter_src = gst_element_get_static_pad (priv->capsfilter, "src");
/* ghost the pad */
priv->srcpad = gst_ghost_pad_new ("src", capsfilter_src);
gst_object_unref (capsfilter_src);
gst_pad_set_active (priv->srcpad, TRUE);
gst_element_add_pad (GST_ELEMENT (track), priv->srcpad);
GST_DEBUG ("done");
2009-08-04 15:13:11 +00:00
}
2009-08-07 18:32:47 +00:00
static void
composition_duration_cb (GstElement * composition,
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track)
{
guint64 duration;
g_object_get (composition, "duration", &duration, NULL);
if (track->priv->duration != duration) {
GST_DEBUG_OBJECT (track,
"composition duration : %" GST_TIME_FORMAT " current : %"
GST_TIME_FORMAT, GST_TIME_ARGS (duration),
GST_TIME_ARGS (track->priv->duration));
2020-01-15 14:44:38 +00:00
/* FIXME: here the duration is set to the duration of the composition,
* but elsewhere it is set to the duration of the timeline. Are these
* always the same? */
track->priv->duration = duration;
g_object_notify_by_pspec (G_OBJECT (track), properties[ARG_DURATION]);
}
}
static void
composition_commited_cb (GstElement * composition, gboolean changed,
GESTrack * self)
{
g_signal_emit (self, ges_track_signals[COMMITED], 0);
}
/* Internal */
GstElement *
ges_track_get_composition (GESTrack * track)
{
return track->priv->composition;
}
void
ges_track_set_smart_rendering (GESTrack * track, gboolean rendering_smartly)
{
GESTrackPrivate *priv = track->priv;
g_object_set (priv->capsfilter, "caps",
rendering_smartly ? NULL : priv->restriction_caps, NULL);
}
2013-03-15 14:32:48 +00:00
/* FIXME: Find out how to avoid doing this "hack" using the GDestroyNotify
* function pointer in the trackelements_by_start GSequence
*
* Remove @object from @track, but keeps it in the sequence this is needed
* when finalizing as we can not change a GSequence at the same time we are
* accessing it
*/
static gboolean
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
remove_object_internal (GESTrack * track, GESTrackElement * object,
gboolean emit, GError ** error)
{
GESTrackPrivate *priv;
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
GstElement *nleobject;
GST_DEBUG_OBJECT (track, "object:%p", object);
priv = track->priv;
if (G_UNLIKELY (ges_track_element_get_track (object) != 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
GST_WARNING_OBJECT (track, "Object belongs to another track");
return FALSE;
}
if (!ges_track_element_set_track (object, NULL, error)) {
GST_INFO_OBJECT (track, "Failed to unset the track for %" GES_FORMAT,
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_ARGS (object));
return FALSE;
}
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (object), NULL);
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
if ((nleobject = ges_track_element_get_nleobject (object))) {
GST_DEBUG ("Removing NleObject '%s' from composition '%s'",
GST_ELEMENT_NAME (nleobject), GST_ELEMENT_NAME (priv->composition));
if (!ges_nle_composition_remove_object (priv->composition, nleobject)) {
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
GST_WARNING_OBJECT (track, "Failed to remove nleobject from composition");
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
if (emit)
g_signal_emit (track, ges_track_signals[TRACK_ELEMENT_REMOVED], 0,
GES_TRACK_ELEMENT (object));
gst_object_unref (object);
return TRUE;
}
static void
dispose_trackelements_foreach (GESTrackElement * trackelement, GESTrack * track)
{
remove_object_internal (track, trackelement, TRUE, NULL);
}
/* GstElement virtual methods */
static GstStateChangeReturn
ges_track_change_state (GstElement * element, GstStateChange transition)
{
GESTrack *track = GES_TRACK (element);
if (transition == GST_STATE_CHANGE_READY_TO_PAUSED &&
track->priv->valid_thread == g_thread_self ())
track_resort_and_fill_gaps (GES_TRACK (element));
return GST_ELEMENT_CLASS (ges_track_parent_class)->change_state (element,
transition);
}
void
ges_track_select_subtimeline_streams (GESTrack * track,
GstStreamCollection * collection, GstElement * subtimeline)
{
GList *selected_streams = NULL;
for (gint i = 0; i < gst_stream_collection_get_size (collection); i++) {
GstStream *stream = gst_stream_collection_get_stream (collection, i);
GstStreamType stype = gst_stream_get_stream_type (stream);
if ((track->type == GES_TRACK_TYPE_VIDEO && stype == GST_STREAM_TYPE_VIDEO)
|| (track->type == GES_TRACK_TYPE_AUDIO
&& stype == GST_STREAM_TYPE_AUDIO)
|| (stype == GST_STREAM_TYPE_UNKNOWN)) {
selected_streams =
g_list_append (selected_streams,
g_strdup (gst_stream_get_stream_id (stream)));
}
}
if (selected_streams) {
gst_element_send_event (subtimeline,
gst_event_new_select_streams (selected_streams));
g_list_free_full (selected_streams, g_free);
}
}
2019-06-07 03:19:38 +00:00
static void
ges_track_handle_message (GstBin * bin, GstMessage * message)
{
GESTrack *track = GES_TRACK (bin);
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_STREAM_COLLECTION:
g_error ("Internal stream collection messages should be kept internal");
break;
case GST_MESSAGE_ELEMENT:
{
const GstStructure *s = gst_message_get_structure (message);
if (gst_structure_has_name (s, "ges-timeline-collection")) {
GstStreamCollection *collection;
gst_structure_get (s, "collection", GST_TYPE_STREAM_COLLECTION,
&collection, NULL);
ges_track_select_subtimeline_streams (track, collection,
GST_ELEMENT (GST_MESSAGE_SRC (message)));
GST_INFO_OBJECT (bin,
"Handled ges-timeline-collection message, dropping");
2019-06-07 03:19:38 +00:00
gst_message_unref (message);
return;
}
break;
2019-06-07 03:19:38 +00:00
}
default:
break;
2019-06-07 03:19:38 +00:00
}
GST_BIN_CLASS (ges_track_parent_class)->handle_message (bin, message);
2019-06-07 03:19:38 +00:00
}
/* GObject virtual methods */
static void
ges_track_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
{
2009-08-07 16:18:42 +00:00
GESTrack *track = GES_TRACK (object);
2009-08-04 15:13:11 +00:00
switch (property_id) {
2009-08-07 16:18:42 +00:00
case ARG_CAPS:
gst_value_set_caps (value, track->priv->caps);
2009-08-07 16:18:42 +00:00
break;
case ARG_TYPE:
g_value_set_flags (value, track->type);
break;
case ARG_DURATION:
g_value_set_uint64 (value, track->priv->duration);
break;
case ARG_RESTRICTION_CAPS:
gst_value_set_caps (value, track->priv->restriction_caps);
break;
case ARG_MIXING:
g_value_set_boolean (value, track->priv->mixing);
break;
2019-06-06 21:21:01 +00:00
case ARG_ID:
g_object_get_property (G_OBJECT (track->priv->composition), "id", 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
2009-08-04 15:16:31 +00:00
ges_track_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
2009-08-04 15:13:11 +00:00
{
2009-08-07 16:18:42 +00:00
GESTrack *track = GES_TRACK (object);
2009-08-04 15:13:11 +00:00
switch (property_id) {
2009-08-07 16:18:42 +00:00
case ARG_CAPS:
ges_track_set_caps (track, gst_value_get_caps (value));
break;
case ARG_TYPE:
track->type = g_value_get_flags (value);
break;
case ARG_RESTRICTION_CAPS:
ges_track_set_restriction_caps (track, gst_value_get_caps (value));
break;
case ARG_MIXING:
ges_track_set_mixing (track, g_value_get_boolean (value));
break;
2019-06-06 21:21:01 +00:00
case ARG_ID:
g_object_set_property (G_OBJECT (track->priv->composition), "id", 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
2009-08-04 15:16:31 +00:00
ges_track_dispose (GObject * object)
2009-08-04 15:13:11 +00:00
{
2009-08-07 14:43:49 +00:00
GESTrack *track = (GESTrack *) object;
GESTrackPrivate *priv = track->priv;
2009-08-07 14:43:49 +00:00
/* Remove all TrackElements and drop our reference */
g_hash_table_unref (priv->trackelements_iter);
g_sequence_foreach (track->priv->trackelements_by_start,
(GFunc) dispose_trackelements_foreach, track);
g_sequence_free (priv->trackelements_by_start);
g_list_free_full (priv->gaps, (GDestroyNotify) free_gap);
ges_nle_object_commit (track->priv->composition, TRUE);
2009-08-07 14:43:49 +00:00
gst_clear_object (&track->priv->mixing_operation);
if (priv->composition) {
gst_element_remove_pad (GST_ELEMENT (track), priv->srcpad);
gst_bin_remove (GST_BIN (object), priv->composition);
priv->composition = NULL;
2009-08-07 14:43:49 +00:00
}
if (priv->caps) {
gst_caps_unref (priv->caps);
priv->caps = NULL;
}
2014-10-26 20:30:29 +00:00
if (priv->restriction_caps) {
gst_caps_unref (priv->restriction_caps);
priv->restriction_caps = NULL;
}
2009-08-04 15:13:11 +00:00
G_OBJECT_CLASS (ges_track_parent_class)->dispose (object);
}
static void
2009-08-04 15:16:31 +00:00
ges_track_finalize (GObject * object)
2009-08-04 15:13:11 +00:00
{
G_OBJECT_CLASS (ges_track_parent_class)->finalize (object);
}
static void
ges_track_constructed (GObject * object)
{
GESTrack *self = GES_TRACK (object);
gchar *componame = NULL;
gchar *capsfiltername = NULL;
if (self->type == GES_TRACK_TYPE_VIDEO) {
componame =
g_strdup_printf ("video_%s", GST_OBJECT_NAME (self->priv->composition));
capsfiltername =
g_strdup_printf ("video_restriction_%s",
GST_OBJECT_NAME (self->priv->capsfilter));
} else if (self->type == GES_TRACK_TYPE_AUDIO) {
componame =
g_strdup_printf ("audio_%s", GST_OBJECT_NAME (self->priv->composition));
capsfiltername =
g_strdup_printf ("audio_restriction_%s",
GST_OBJECT_NAME (self->priv->capsfilter));
}
if (componame) {
gst_object_set_name (GST_OBJECT (self->priv->composition), componame);
gst_object_set_name (GST_OBJECT (self->priv->capsfilter), capsfiltername);
g_free (componame);
g_free (capsfiltername);
}
if (!gst_bin_add (GST_BIN (self), self->priv->composition))
GST_ERROR ("Couldn't add composition to bin !");
if (!gst_bin_add (GST_BIN (self), self->priv->capsfilter))
GST_ERROR ("Couldn't add capsfilter to bin !");
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
_ghost_nlecomposition_srcpad (self);
if (GES_TRACK_GET_CLASS (self)->get_mixing_element) {
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
GstElement *nleobject;
GstElement *mixer = GES_TRACK_GET_CLASS (self)->get_mixing_element (self);
if (mixer == NULL) {
GST_WARNING_OBJECT (self, "Got no element fron get_mixing_element");
return;
}
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
nleobject = gst_element_factory_make ("nleoperation", "mixing-operation");
if (!gst_bin_add (GST_BIN (nleobject), mixer)) {
GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
gst_object_unref (mixer);
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
gst_object_unref (nleobject);
return;
}
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
g_object_set (nleobject, "expandable", TRUE, NULL);
if (self->priv->mixing) {
if (!ges_nle_composition_add_object (self->priv->composition, nleobject)) {
GST_WARNING_OBJECT (self, "Could not add the mixer to our composition");
gst_object_unref (nleobject);
return;
}
}
self->priv->mixing_operation = gst_object_ref (nleobject);
} else {
GST_INFO_OBJECT (self, "No way to create a main mixer");
}
}
2009-08-04 15:13:11 +00:00
static void
2009-08-04 15:16:31 +00:00
ges_track_class_init (GESTrackClass * klass)
2009-08-04 15:13:11 +00:00
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = (GstElementClass *) klass;
2019-06-07 03:19:38 +00:00
GstBinClass *bin_class = GST_BIN_CLASS (klass);
2009-08-04 15:13:11 +00:00
gstelement_class->change_state = GST_DEBUG_FUNCPTR (ges_track_change_state);
2019-06-07 03:19:38 +00:00
bin_class->handle_message = GST_DEBUG_FUNCPTR (ges_track_handle_message);
2009-08-04 15:13:11 +00:00
object_class->get_property = ges_track_get_property;
object_class->set_property = ges_track_set_property;
object_class->dispose = ges_track_dispose;
object_class->finalize = ges_track_finalize;
object_class->constructed = ges_track_constructed;
2009-08-07 16:18:42 +00:00
2009-09-14 13:51:49 +00:00
/**
2012-08-10 16:39:10 +00:00
* GESTrack:caps:
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* The capabilities used to choose the output of the #GESTrack's
* elements. Internally, this is used to select output streams when
* several may be available, by determining whether its #GstPad is
2020-06-23 14:11:59 +00:00
* compatible (see #NleObject:caps for #nlecomposition). As such,
2020-01-15 14:44:38 +00:00
* this is used as a weaker indication of the desired output type of the
* track, **before** the #GESTrack:restriction-caps is applied.
* Therefore, this should be set to a *generic* superset of the
* #GESTrack:restriction-caps, such as "video/x-raw(ANY)". In addition,
* it should match with the track's #GESTrack:track-type.
*
* Note that when you set this property, the #GstCapsFeatures of all its
* #GstStructure-s will be automatically set to #GST_CAPS_FEATURES_ANY.
*
* Once a track has been added to a #GESTimeline, you should not change
* this.
2009-09-14 13:51:49 +00:00
*
* Default value: #GST_CAPS_ANY.
*/
properties[ARG_CAPS] = g_param_spec_boxed ("caps", "Caps",
2020-01-15 14:44:38 +00:00
"Caps used to choose the output stream",
GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
2009-08-07 16:18:42 +00:00
g_object_class_install_property (object_class, ARG_CAPS,
properties[ARG_CAPS]);
/**
* GESTrack:restriction-caps:
*
2020-01-15 14:44:38 +00:00
* The capabilities that specifies the final output format of the
* #GESTrack. For example, for a video track, it would specify the
* height, width, framerate and other properties of the stream.
*
* You may change this property after the track has been added to a
* #GESTimeline, but it must remain compatible with the track's
* #GESTrack:caps.
*
* Default value: #GST_CAPS_ANY.
*/
properties[ARG_RESTRICTION_CAPS] =
g_param_spec_boxed ("restriction-caps", "Restriction caps",
2020-01-15 14:44:38 +00:00
"Caps used as a final filter on the output stream", GST_TYPE_CAPS,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, ARG_RESTRICTION_CAPS,
properties[ARG_RESTRICTION_CAPS]);
/**
2012-08-10 16:39:10 +00:00
* GESTrack:duration:
*
* Current duration of the track
*
* Default value: O
*/
2020-01-15 14:44:38 +00:00
/* FIXME: is duration the duration of the timeline or the duration of
* the underlying composition? */
properties[ARG_DURATION] = g_param_spec_uint64 ("duration", "Duration",
"The current duration of the track", 0, G_MAXUINT64, GST_SECOND,
G_PARAM_READABLE);
g_object_class_install_property (object_class, ARG_DURATION,
properties[ARG_DURATION]);
2009-09-14 13:51:49 +00:00
/**
2012-08-10 16:39:10 +00:00
* GESTrack:track-type:
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* The track type of the track. This controls the type of
* #GESTrackElement-s that can be added to the track. This should
* match with the track's #GESTrack:caps.
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Once a track has been added to a #GESTimeline, you should not change
* this.
2009-09-14 13:51:49 +00:00
*/
properties[ARG_TYPE] = g_param_spec_flags ("track-type", "TrackType",
"Type of stream the track outputs",
GES_TYPE_TRACK_TYPE, GES_TRACK_TYPE_CUSTOM,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, ARG_TYPE,
properties[ARG_TYPE]);
/**
* GESTrack:mixing:
*
2020-01-15 14:44:38 +00:00
* Whether the track should support the mixing of #GESLayer data, such
* as composing the video data of each layer (when part of the video
* data is transparent, the next layer will become visible) or adding
* together the audio data. As such, for audio and video tracks, you'll
* likely want to keep this set to %TRUE.
*/
properties[ARG_MIXING] = g_param_spec_boolean ("mixing", "Mixing",
"Whether layer mixing is activated on the track or not",
TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_property (object_class, ARG_MIXING,
properties[ARG_MIXING]);
2019-08-12 13:49:45 +00:00
/**
2020-01-15 14:44:38 +00:00
* GESTrack:id:
2019-08-12 13:49:45 +00:00
*
2020-01-15 14:44:38 +00:00
* The #nlecomposition:id of the underlying #nlecomposition.
2019-08-12 13:49:45 +00:00
*
* Since: 1.18
*/
2019-06-06 21:21:01 +00:00
properties[ARG_ID] =
g_param_spec_string ("id", "Id", "The stream-id of the composition",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_DOC_SHOW_DEFAULT);
2019-06-06 21:21:01 +00:00
g_object_class_install_property (object_class, ARG_ID, properties[ARG_ID]);
gst_element_class_add_static_pad_template (gstelement_class,
&ges_track_src_pad_template);
/**
* GESTrack::track-element-added:
2020-01-15 14:44:38 +00:00
* @object: The #GESTrack
* @effect: The element that was added
*
2020-01-15 14:44:38 +00:00
* Will be emitted after a track element is added to the track.
*/
ges_track_signals[TRACK_ELEMENT_ADDED] =
g_signal_new ("track-element-added", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, GES_TYPE_TRACK_ELEMENT);
/**
* GESTrack::track-element-removed:
2020-01-15 14:44:38 +00:00
* @object: The #GESTrack
* @effect: The element that was removed
*
2020-01-15 14:44:38 +00:00
* Will be emitted after a track element is removed from the track.
*/
ges_track_signals[TRACK_ELEMENT_REMOVED] =
g_signal_new ("track-element-removed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 1, GES_TYPE_TRACK_ELEMENT);
/**
* GESTrack::commited:
2020-01-15 14:44:38 +00:00
* @track: The #GESTrack
*
* This signal will be emitted once the changes initiated by
* ges_track_commit() have been executed in the backend. In particular,
* this will be emitted whenever the underlying #nlecomposition has been
* committed (see #nlecomposition::commited).
*/
ges_track_signals[COMMITED] =
g_signal_new ("commited", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
klass->get_mixing_element = NULL;
2009-08-04 15:13:11 +00:00
}
static void
2009-08-04 15:16:31 +00:00
ges_track_init (GESTrack * self)
2009-08-04 15:13:11 +00:00
{
self->priv = ges_track_get_instance_private (self);
self->priv->valid_thread = g_thread_self ();
2010-12-04 18:54:13 +00:00
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
self->priv->composition = gst_element_factory_make ("nlecomposition", NULL);
self->priv->capsfilter = gst_element_factory_make ("capsfilter", NULL);
self->priv->updating = TRUE;
self->priv->trackelements_by_start = g_sequence_new (NULL);
self->priv->trackelements_iter =
g_hash_table_new (g_direct_hash, g_direct_equal);
self->priv->create_element_for_gaps = NULL;
self->priv->gaps = NULL;
self->priv->mixing = TRUE;
self->priv->restriction_caps = NULL;
self->priv->last_gap_disabled = TRUE;
g_signal_connect (G_OBJECT (self->priv->composition), "notify::duration",
G_CALLBACK (composition_duration_cb), self);
g_signal_connect (G_OBJECT (self->priv->composition), "commited",
G_CALLBACK (composition_commited_cb), self);
2009-08-04 15:13:11 +00:00
}
2009-09-14 13:51:49 +00:00
/**
* ges_track_new:
2020-01-15 14:44:38 +00:00
* @type: The #GESTrack:track-type for the track
* @caps: (transfer full): The #GESTrack:caps for the track
*
* Creates a new track with the given track-type and caps.
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* If @type is #GES_TRACK_TYPE_VIDEO, and @caps is a subset of
* "video/x-raw(ANY)", then a #GESVideoTrack is created. This will
* automatically choose a gap creation method suitable for video data. You
* will likely want to set #GESTrack:restriction-caps separately. You may
* prefer to use the ges_video_track_new() method instead.
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* If @type is #GES_TRACK_TYPE_AUDIO, and @caps is a subset of
* "audio/x-raw(ANY)", then a #GESAudioTrack is created. This will
* automatically choose a gap creation method suitable for audio data, and
* will set the #GESTrack:restriction-caps to the default for
* #GESAudioTrack. You may prefer to use the ges_audio_track_new() method
* instead.
*
2020-01-15 14:44:38 +00:00
* Otherwise, a plain #GESTrack is returned. You will likely want to set
* the #GESTrack:restriction-caps and call
* ges_track_set_create_element_for_gap_func() on the returned track.
*
* Returns: (transfer floating): A new track.
2009-09-14 13:51:49 +00:00
*/
2009-08-04 15:16:31 +00:00
GESTrack *
ges_track_new (GESTrackType type, GstCaps * caps)
2009-08-04 15:13:11 +00:00
{
GESTrack *track;
GstCaps *tmpcaps;
/* TODO Be smarter with well known track types */
if (type == GES_TRACK_TYPE_VIDEO) {
tmpcaps = gst_caps_new_empty_simple ("video/x-raw");
gst_caps_set_features (tmpcaps, 0, gst_caps_features_new_any ());
if (gst_caps_is_subset (caps, tmpcaps)) {
track = GES_TRACK (ges_video_track_new ());
ges_track_set_caps (track, caps);
gst_caps_unref (tmpcaps);
2020-01-15 14:44:38 +00:00
/* FIXME: ges_track_set_caps does not take ownership of caps,
* so we also need to unref caps */
return track;
}
gst_caps_unref (tmpcaps);
} else if (type == GES_TRACK_TYPE_AUDIO) {
tmpcaps = gst_caps_new_empty_simple ("audio/x-raw");
gst_caps_set_features (tmpcaps, 0, gst_caps_features_new_any ());
if (gst_caps_is_subset (caps, tmpcaps)) {
track = GES_TRACK (ges_audio_track_new ());
ges_track_set_caps (track, caps);
gst_caps_unref (tmpcaps);
2020-01-15 14:44:38 +00:00
/* FIXME: ges_track_set_caps does not take ownership of caps,
* so we also need to unref caps */
return track;
}
gst_caps_unref (tmpcaps);
}
track = g_object_new (GES_TYPE_TRACK, "caps", caps, "track-type", type, NULL);
gst_caps_unref (caps);
return track;
}
/**
* ges_track_set_timeline:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @timeline (nullable): A #GESTimeline
*
2020-01-15 14:44:38 +00:00
* Informs the track that it belongs to the given timeline. Calling this
* does not actually add the track to the timeline. For that, you should
* use ges_timeline_add_track(), which will also take care of informing
* the track that it belongs to the timeline. As such, there is no need
* for you to call this method.
*/
2020-01-15 14:44:38 +00:00
/* FIXME: this should probably be deprecated and only used internally */
void
ges_track_set_timeline (GESTrack * track, GESTimeline * timeline)
{
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
GSequenceIter *it;
g_return_if_fail (GES_IS_TRACK (track));
g_return_if_fail (timeline == NULL || GES_IS_TIMELINE (timeline));
GST_DEBUG ("track:%p, timeline:%p", track, timeline);
track->priv->timeline = timeline;
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 (it = g_sequence_get_begin_iter (track->priv->trackelements_by_start);
g_sequence_iter_is_end (it) == FALSE; it = g_sequence_iter_next (it)) {
GESTimelineElement *trackelement =
GES_TIMELINE_ELEMENT (g_sequence_get (it));
ges_timeline_element_set_timeline (trackelement, timeline);
}
track_resort_and_fill_gaps (track);
}
2009-09-14 13:51:49 +00:00
/**
* ges_track_set_caps:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @caps: The new caps for @track
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Sets the #GESTrack:caps for the track. The new #GESTrack:caps of the
* track will be a copy of @caps, except its #GstCapsFeatures will be
* automatically set to #GST_CAPS_FEATURES_ANY.
2009-09-14 13:51:49 +00:00
*/
2009-08-07 16:18:42 +00:00
void
ges_track_set_caps (GESTrack * track, const GstCaps * caps)
{
GESTrackPrivate *priv;
gint i;
2009-08-07 16:18:42 +00:00
g_return_if_fail (GES_IS_TRACK (track));
CHECK_THREAD (track);
2009-08-07 16:18:42 +00:00
GST_DEBUG ("track:%p, caps:%" GST_PTR_FORMAT, track, caps);
g_return_if_fail (GST_IS_CAPS (caps));
priv = track->priv;
if (priv->caps)
gst_caps_unref (priv->caps);
priv->caps = gst_caps_copy (caps);
2009-08-07 16:18:42 +00:00
for (i = 0; i < (int) gst_caps_get_size (priv->caps); i++)
gst_caps_set_features (priv->caps, i, gst_caps_features_new_any ());
g_object_set (priv->composition, "caps", caps, NULL);
/* FIXME : update all trackelements ? */
2009-08-07 16:18:42 +00:00
}
/**
* ges_track_set_restriction_caps:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @caps: The new restriction-caps for @track
*
2020-01-15 14:44:38 +00:00
* Sets the #GESTrack:restriction-caps for the track.
*
* > **NOTE**: Restriction caps are **not** taken into account when
* > using #GESPipeline:mode=#GES_PIPELINE_MODE_SMART_RENDER.
*/
void
ges_track_set_restriction_caps (GESTrack * track, const GstCaps * caps)
{
GESTrackPrivate *priv;
g_return_if_fail (GES_IS_TRACK (track));
CHECK_THREAD (track);
GST_DEBUG ("track:%p, restriction caps:%" GST_PTR_FORMAT, track, caps);
g_return_if_fail (GST_IS_CAPS (caps));
priv = track->priv;
if (priv->restriction_caps)
gst_caps_unref (priv->restriction_caps);
priv->restriction_caps = gst_caps_copy (caps);
if (!track->priv->timeline ||
!ges_timeline_get_smart_rendering (track->priv->timeline))
g_object_set (priv->capsfilter, "caps", caps, NULL);
g_object_notify (G_OBJECT (track), "restriction-caps");
}
/**
* ges_track_update_restriction_caps:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @caps: The caps to update the restriction-caps with
*
2020-01-15 14:44:38 +00:00
* Updates the #GESTrack:restriction-caps of the track using the fields
* found in the given caps. Each of the #GstStructure-s in @caps is
* compared against the existing structure with the same index in the
* current #GESTrack:restriction-caps. If there is no corresponding
* existing structure at that index, then the new structure is simply
* copied to that index. Otherwise, any fields in the new structure are
* copied into the existing structure. This will replace existing values,
* and may introduce new ones, but any fields 'missing' in the new
* structure are left unchanged in the existing structure.
*
2020-01-15 14:44:38 +00:00
* For example, if the existing #GESTrack:restriction-caps are
* "video/x-raw, width=480, height=360", and the updating caps is
* "video/x-raw, format=I420, width=500; video/x-bayer, width=400", then
* the new #GESTrack:restriction-caps after calling this will be
* "video/x-raw, width=500, height=360, format=I420; video/x-bayer,
* width=400".
*/
void
ges_track_update_restriction_caps (GESTrack * self, const GstCaps * caps)
{
guint i;
GstCaps *new_restriction_caps;
g_return_if_fail (GES_IS_TRACK (self));
CHECK_THREAD (self);
if (!self->priv->restriction_caps) {
ges_track_set_restriction_caps (self, caps);
return;
}
new_restriction_caps = gst_caps_copy (self->priv->restriction_caps);
for (i = 0; i < gst_caps_get_size (caps); i++) {
GstStructure *new = gst_caps_get_structure (caps, i);
if (gst_caps_get_size (new_restriction_caps) > i) {
GstStructure *original = gst_caps_get_structure (new_restriction_caps, i);
gst_structure_foreach (new, (GstStructureForeachFunc) update_field,
original);
} else
gst_caps_append_structure (new_restriction_caps,
gst_structure_copy (new));
2020-01-15 14:44:38 +00:00
/* FIXME: maybe appended structure should also have its CapsFeatures
* copied over? */
}
ges_track_set_restriction_caps (self, new_restriction_caps);
gst_caps_unref (new_restriction_caps);
}
/**
* ges_track_set_mixing:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @mixing: Whether @track should be mixing
*
2020-01-15 14:44:38 +00:00
* Sets the #GESTrack:mixing for the track.
*/
void
ges_track_set_mixing (GESTrack * track, gboolean mixing)
{
g_return_if_fail (GES_IS_TRACK (track));
CHECK_THREAD (track);
if (mixing == track->priv->mixing) {
GST_DEBUG_OBJECT (track, "Mixing is already set to the same value");
return;
}
if (!track->priv->mixing_operation) {
GST_DEBUG_OBJECT (track, "Track will be set to mixing = %d", mixing);
goto notify;
}
if (mixing) {
if (!ges_nle_composition_add_object (track->priv->composition,
track->priv->mixing_operation)) {
GST_WARNING_OBJECT (track, "Could not add the mixer to our composition");
return;
}
} else {
if (!ges_nle_composition_remove_object (track->priv->composition,
track->priv->mixing_operation)) {
GST_WARNING_OBJECT (track,
"Could not remove the mixer from our composition");
return;
}
}
notify:
track->priv->mixing = mixing;
if (track->priv->timeline)
ges_timeline_set_smart_rendering (track->priv->timeline,
ges_timeline_get_smart_rendering (track->priv->timeline));
g_object_notify_by_pspec (G_OBJECT (track), properties[ARG_MIXING]);
GST_DEBUG_OBJECT (track, "The track has been set to mixing = %d", mixing);
}
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 gboolean
remove_element_internal (GESTrack * track, GESTrackElement * object,
gboolean emit, GError ** error)
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
{
GSequenceIter *it;
GESTrackPrivate *priv = track->priv;
GST_DEBUG_OBJECT (track, "Removing %" GST_PTR_FORMAT, object);
it = g_hash_table_lookup (priv->trackelements_iter, object);
g_sequence_remove (it);
if (remove_object_internal (track, object, emit, error) == 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
ges_timeline_element_set_timeline (GES_TIMELINE_ELEMENT (object), NULL);
return TRUE;
}
g_hash_table_insert (track->priv->trackelements_iter, object,
g_sequence_insert_sorted (track->priv->trackelements_by_start, object,
(GCompareDataFunc) element_start_compare, NULL));
return FALSE;
}
2009-09-14 13:51:49 +00:00
/**
* ges_track_add_element_full:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @object: (transfer floating): The element to add
* @error: (nullable): Return location for an error
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Adds the given track element to the track, which takes ownership of the
* 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
* Note that this can fail if it would break a configuration rule of the
* track's #GESTimeline.
*
2020-01-15 14:44:38 +00:00
* Note that a #GESTrackElement can only be added to one track.
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Returns: %TRUE if @object was successfully added to @track.
* Since: 1.18
2009-09-14 13:51:49 +00:00
*/
gboolean
ges_track_add_element_full (GESTrack * track, GESTrackElement * object,
GError ** error)
{
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;
GESTimelineElement *el;
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
g_return_val_if_fail (!error || !*error, 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
el = GES_TIMELINE_ELEMENT (object);
CHECK_THREAD (track);
GST_DEBUG ("track:%p, object:%p", track, object);
if (G_UNLIKELY (ges_track_element_get_track (object) != NULL)) {
GST_WARNING ("Object already belongs to another track");
gst_object_ref_sink (object);
gst_object_unref (object);
return FALSE;
}
if (!ges_track_element_set_track (object, track, error)) {
GST_INFO_OBJECT (track, "Failed to set the track for %" GES_FORMAT,
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_ARGS (object));
gst_object_ref_sink (object);
gst_object_unref (object);
2009-08-07 14:43:49 +00:00
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
ges_timeline_element_set_timeline (el, NULL);
GST_DEBUG ("Adding object %s to ourself %s",
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
GST_OBJECT_NAME (ges_track_element_get_nleobject (object)),
GST_OBJECT_NAME (track->priv->composition));
if (G_UNLIKELY (!ges_nle_composition_add_object (track->priv->composition,
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
ges_track_element_get_nleobject (object)))) {
GST_WARNING ("Couldn't add object to the NleComposition");
if (!ges_track_element_set_track (object, NULL, NULL))
GST_ERROR_OBJECT (track, "Failed to unset track of element %"
GES_FORMAT, GES_ARGS (object));
gst_object_ref_sink (object);
gst_object_unref (object);
return FALSE;
}
gst_object_ref_sink (object);
g_hash_table_insert (track->priv->trackelements_iter, object,
g_sequence_insert_sorted (track->priv->trackelements_by_start, object,
(GCompareDataFunc) element_start_compare, 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
timeline = track->priv->timeline;
ges_timeline_element_set_timeline (el, timeline);
timeline-tree: simplify and fix editing Editing has been simplified by breaking down each edit into a combination of three basic single-element edits: MOVE, TRIM_START, and TRIM_END. Each edit follows these steps: + Determine which elements are to be edited and under which basic mode + Determine which track elements will move as a result + Snap the edit position to one of the edges of the main edited element, (or the edge of one of its descendants, in the case of MOVE), avoiding moving elements. NOTE: in particular, we can *not* snap to the edge of a neighbouring element in a roll edit. This was previously possible, even though the neighbour was moving! + Determine the edit positions for clips (or track elements with no parent) using the snapped value. In addition, we replace any edits of a group with an edit of its descendant clips. If any value would be out of bounds (e.g. negative start) we do not edit. NOTE: this is now done *after* checking the snapping. This allows the edit to succeed if snapping would cause it to go from being invalid to valid! + Determine whether the collection of edits would result in a valid timeline-configuration which does not break the rules for sources overlapping. + If all this succeeds, we emit snapping-started on the timeline. + We then perform all the edits. At this point they should all succeed. The simplification/unification should make it easier to make other changes. Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/97 Fixes https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/issues/98 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-editing-services/-/merge_requests/169>
2020-04-27 12:58:38 +00:00
/* check that we haven't broken the timeline configuration by adding this
* element to the 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
if (timeline
&& !timeline_tree_can_move_element (timeline_get_tree (timeline), el,
GES_TIMELINE_ELEMENT_LAYER_PRIORITY (el), el->start, el->duration,
error)) {
GST_INFO_OBJECT (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
"Could not add the track element %" GES_FORMAT
" to the track because it breaks the timeline " "configuration rules",
GES_ARGS (el));
remove_element_internal (track, object, FALSE, 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
return FALSE;
}
g_signal_emit (track, ges_track_signals[TRACK_ELEMENT_ADDED], 0,
GES_TRACK_ELEMENT (object));
return TRUE;
}
2009-08-07 14:43:49 +00:00
/**
* ges_track_add_element:
* @track: A #GESTrack
* @object: (transfer floating): The element to add
*
* See ges_track_add_element(), which also gives an error.
*
* Returns: %TRUE if @object was successfully added to @track.
*/
gboolean
ges_track_add_element (GESTrack * track, GESTrackElement * object)
{
return ges_track_add_element_full (track, object, NULL);
}
2011-12-07 02:11:25 +00:00
/**
* ges_track_get_elements:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
2011-12-07 02:11:25 +00:00
*
2020-01-15 14:44:38 +00:00
* Gets the track elements contained in the track. The returned list is
* sorted by the element's #GESTimelineElement:priority and
* #GESTimelineElement:start.
2011-12-07 02:11:25 +00:00
*
2020-01-15 14:44:38 +00:00
* Returns: (transfer full) (element-type GESTrackElement): A list of
* all the #GESTrackElement-s in @track.
2011-12-07 02:11:25 +00:00
*/
GList *
ges_track_get_elements (GESTrack * track)
{
GList *ret = NULL;
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
CHECK_THREAD (track);
g_sequence_foreach (track->priv->trackelements_by_start,
(GFunc) add_trackelement_to_list_foreach, &ret);
ret = g_list_reverse (ret);
return ret;
}
2009-09-14 13:51:49 +00:00
/**
* ges_track_remove_element_full:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @object: The element to remove
* @error: (nullable): Return location for an error
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Removes the given track element from the track, which revokes
* ownership of the element.
2009-09-14 13:51:49 +00:00
*
2020-01-15 14:44:38 +00:00
* Returns: %TRUE if @object was successfully removed from @track.
* Since: 1.18
2009-09-14 13:51:49 +00:00
*/
2009-08-07 14:43:49 +00:00
gboolean
ges_track_remove_element_full (GESTrack * track, GESTrackElement * object,
GError ** error)
2009-08-07 14:43:49 +00:00
{
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
g_return_val_if_fail (GES_IS_TRACK_ELEMENT (object), FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
if (!track->priv->timeline
|| !ges_timeline_is_disposed (track->priv->timeline))
CHECK_THREAD (track);
return remove_element_internal (track, object, TRUE, error);
}
/**
* ges_track_remove_element:
* @track: A #GESTrack
* @object: The element to remove
*
* See ges_track_remove_element_full(), which also returns an error.
*
* Returns: %TRUE if @object was successfully removed from @track.
*/
gboolean
ges_track_remove_element (GESTrack * track, GESTrackElement * object)
{
return ges_track_remove_element_full (track, object, NULL);
}
/**
* ges_track_get_caps:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
*
2020-01-15 14:44:38 +00:00
* Get the #GESTrack:caps of the track.
*
* Returns: (nullable): The caps of @track.
*/
const GstCaps *
ges_track_get_caps (GESTrack * track)
{
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
CHECK_THREAD (track);
return track->priv->caps;
}
/**
* ges_track_get_timeline:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
*
2020-01-15 14:44:38 +00:00
* Get the timeline this track belongs to.
*
2020-01-15 14:44:38 +00:00
* Returns: (nullable): The timeline that @track belongs to, or %NULL if
* it does not belong to a timeline.
*/
const GESTimeline *
ges_track_get_timeline (GESTrack * track)
{
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
CHECK_THREAD (track);
return track->priv->timeline;
}
/**
* ges_track_get_mixing:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
*
2020-01-15 14:44:38 +00:00
* Gets the #GESTrack:mixing of the track.
*
2020-01-15 14:44:38 +00:00
* Returns: Whether @track is mixing.
*/
gboolean
ges_track_get_mixing (GESTrack * track)
{
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
return track->priv->mixing;
}
/**
* ges_track_commit:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
*
2020-01-15 14:44:38 +00:00
* Commits all the pending changes for the elements contained in the
* track.
*
2020-01-15 14:44:38 +00:00
* When changes are made to the timing or priority of elements within a
* track, they are not directly executed for the underlying
* #nlecomposition and its children. This method will finally execute
* these changes so they are reflected in the data output of the track.
*
* Any pending changes will be executed in the backend. The
* #GESTimeline::commited signal will be emitted once this has completed.
*
* Note that ges_timeline_commit() will call this method on all of its
* tracks, so you are unlikely to need to use this directly.
2012-01-12 15:34:13 +00:00
*
2020-01-15 14:44:38 +00:00
* Returns: %TRUE if pending changes were committed, or %FALSE if nothing
* needed to be committed.
*/
gboolean
ges_track_commit (GESTrack * track)
{
g_return_val_if_fail (GES_IS_TRACK (track), FALSE);
CHECK_THREAD (track);
track_resort_and_fill_gaps (track);
return ges_nle_object_commit (track->priv->composition, TRUE);
}
/**
* ges_track_set_create_element_for_gap_func:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
* @func: (scope notified): The function to be used to create a source
* #GstElement that can fill gaps in @track
*
2020-01-15 14:44:38 +00:00
* Sets the function that will be used to create a #GstElement that can be
* used as a source to fill the gaps of the track. A gap is a timeline
* region where the track has no #GESTrackElement sources. Therefore, you
* are likely to want the #GstElement returned by the function to always
* produce 'empty' content, defined relative to the stream type, such as
* transparent frames for a video, or mute samples for audio.
*
* #GESAudioTrack and #GESVideoTrack objects are created with such a
* function already set appropriately.
*/
void
ges_track_set_create_element_for_gap_func (GESTrack * track,
GESCreateElementForGapFunc func)
{
g_return_if_fail (GES_IS_TRACK (track));
CHECK_THREAD (track);
track->priv->create_element_for_gaps = func;
}
/**
* ges_track_get_restriction_caps:
2020-01-15 14:44:38 +00:00
* @track: A #GESTrack
*
* Gets the #GESTrack:restriction-caps of the track.
*
* Returns: (transfer full) (nullable): The restriction-caps of @track.
*
* Since: 1.18
*/
GstCaps *
ges_track_get_restriction_caps (GESTrack * track)
{
GESTrackPrivate *priv;
g_return_val_if_fail (GES_IS_TRACK (track), NULL);
CHECK_THREAD (track);
priv = track->priv;
if (priv->restriction_caps)
return gst_caps_ref (priv->restriction_caps);
return NULL;
}