1 /* gst-editing-services
2 * Copyright (C) <2013> Thibault Saunier <thibault.saunier@collabora.com>
3 * <2013> Collabora Ltd.
5 * gst-editing-services is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * gst-editing-services is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 * SECTION:gestimelineelement
21 * @title: GESTimelineElement
22 * @short_description: Base Class for all elements with some temporal extent
23 * within a #GESTimeline.
25 * A #GESTimelineElement will have some temporal extent in its
26 * corresponding #GESTimelineElement:timeline, controlled by its
27 * #GESTimelineElement:start and #GESTimelineElement:duration. This
28 * determines when its content will be displayed, or its effect applied,
29 * in the timeline. Several objects may overlap within a given
30 * #GESTimeline, in which case their #GESTimelineElement:priority is used
31 * to determine their ordering in the timeline. Priority is mostly handled
32 * internally by #GESLayer-s and #GESClip-s.
34 * A timeline element can have a #GESTimelineElement:parent,
35 * such as a #GESClip, which is responsible for controlling its timing.
39 * Elements can be moved around in their #GESTimelineElement:timeline by
40 * setting their #GESTimelineElement:start and
41 * #GESTimelineElement:duration using ges_timeline_element_set_start()
42 * and ges_timeline_element_set_duration(). Additionally, which parts of
43 * the underlying content are played in the timeline can be adjusted by
44 * setting the #GESTimelineElement:in-point using
45 * ges_timeline_element_set_inpoint(). The library also provides
46 * ges_timeline_element_edit(), with various #GESEditMode-s, which can
47 * adjust these properties in a convenient way, as well as introduce
48 * similar changes in neighbouring or later elements in the timeline.
50 * However, a timeline may refuse a change in these properties if they
51 * would place the timeline in an unsupported configuration. See
52 * #GESTimeline for its overlap rules.
54 * Additionally, an edit may be refused if it would place one of the
55 * timing properties out of bounds (such as a negative time value for
56 * #GESTimelineElement:start, or having insufficient internal
57 * content to last for the desired #GESTimelineElement:duration).
61 * There are three main sets of time coordinates to consider when using
64 * + Timeline coordinates: these are the time coordinates used in the
65 * output of the timeline in its #GESTrack-s. Each track share the same
66 * coordinates, so there is only one set of coordinates for the
67 * timeline. These extend indefinitely from 0. The times used for
68 * editing (including setting #GESTimelineElement:start and
69 * #GESTimelineElement:duration) use these coordinates, since these
70 * define when an element is present and for how long the element lasts
71 * for in the timeline.
72 * + Internal source coordinates: these are the time coordinates used
73 * internally at the element's output. This is only really defined for
74 * #GESTrackElement-s, where it refers to time coordinates used at the
75 * final source pad of the wrapped #GstElement-s. However, these
76 * coordinates may also be used in a #GESClip in reference to its
77 * children. In particular, these are the coordinates used for
78 * #GESTimelineElement:in-point and #GESTimelineElement:max-duration.
79 * + Internal sink coordinates: these are the time coordinates used
80 * internally at the element's input. A #GESSource has no input, so
81 * these would be undefined. Otherwise, for most #GESTrackElement-s
82 * these will be the same set of coordinates as the internal source
83 * coordinates because the element does not change the timing
84 * internally. Only #GESBaseEffect can support elements where these
85 * are different. See #GESBaseEffect for more information.
87 * You can determine the timeline time for a given internal source time
88 * in a #GESTrack in a #GESClip using
89 * ges_clip_get_timeline_time_from_internal_time(), and vice versa using
90 * ges_clip_get_internal_time_from_timeline_time(), for the purposes of
91 * editing and setting timings properties.
93 * ## Children Properties
95 * If a timeline element owns another #GstObject and wishes to expose
96 * some of its properties, it can do so by registering the property as one
97 * of the timeline element's children properties using
98 * ges_timeline_element_add_child_property(). The registered property of
99 * the child can then be read and set using the
100 * ges_timeline_element_get_child_property() and
101 * ges_timeline_element_set_child_property() methods, respectively. Some
102 * sub-classed objects will be created with pre-registered children
103 * properties; for example, to expose part of an underlying #GstElement
104 * that is used internally. The registered properties can be listed with
105 * ges_timeline_element_list_children_properties().
111 #include "ges-utils.h"
112 #include "ges-timeline-element.h"
113 #include "ges-extractable.h"
114 #include "ges-meta-container.h"
115 #include "ges-internal.h"
116 #include "ges-effect.h"
119 #include <gobject/gvaluecollector.h>
121 /* maps type name quark => count */
122 static GData *object_name_counts = NULL;
125 extractable_set_asset (GESExtractable * extractable, GESAsset * asset)
127 GES_TIMELINE_ELEMENT (extractable)->asset = asset;
131 ges_extractable_interface_init (GESExtractableInterface * iface)
133 iface->set_asset = extractable_set_asset;
154 CHILD_PROPERTY_ADDED,
155 CHILD_PROPERTY_REMOVED,
159 static guint ges_timeline_element_signals[LAST_SIGNAL] = { 0 };
161 static GParamSpec *properties[PROP_LAST] = { NULL, };
166 GESTimelineElement *owner;
168 GESTimelineElement *self;
171 struct _GESTimelineElementPrivate
175 /* We keep a link between properties name and elements internally
176 * The hashtable should look like
177 * {GParamaSpec ---> child}*/
178 GHashTable *children_props;
180 GESTimelineElement *copied_from;
182 GESTimelineElementFlags flags;
189 GESTimelineElement *self;
190 } EmitDeepNotifyInIdleData;
192 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GESTimelineElement, ges_timeline_element,
193 G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (GESTimelineElement)
194 G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE, ges_extractable_interface_init)
195 G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
197 /*********************************************
198 * Virtual methods implementation *
199 *********************************************/
201 _set_child_property (GESTimelineElement * self G_GNUC_UNUSED, GObject * child,
202 GParamSpec * pspec, GValue * value)
204 if (G_VALUE_TYPE (value) != pspec->value_type
205 && G_VALUE_TYPE (value) == G_TYPE_STRING)
206 gst_util_set_object_arg (child, pspec->name, g_value_get_string (value));
208 g_object_set_property (child, pspec->name, value);
212 _set_child_property_full (GESTimelineElement * self, GObject * child,
213 GParamSpec * pspec, const GValue * value, GError ** error)
215 GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_child_property (self, child,
216 pspec, (GValue *) value);
221 _lookup_child (GESTimelineElement * self, const gchar * prop_name,
222 GObject ** child, GParamSpec ** pspec)
226 gchar **names, *name, *classename;
232 names = g_strsplit (prop_name, "::", 2);
233 if (names[1] != NULL) {
234 classename = names[0];
239 g_hash_table_iter_init (&iter, self->priv->children_props);
240 while (g_hash_table_iter_next (&iter, &key, &value)) {
241 if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
242 ChildPropHandler *handler = (ChildPropHandler *) value;
243 if (classename == NULL ||
244 g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (handler->child)),
246 g_strcmp0 (g_type_name (G_PARAM_SPEC (key)->owner_type),
248 GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name,
251 *child = gst_object_ref (handler->child);
254 *pspec = g_param_spec_ref (key);
266 ges_timeline_element_get_children_properties (GESTimelineElement * self,
267 guint * n_properties)
269 GParamSpec **pspec, *spec;
275 *n_properties = g_hash_table_size (self->priv->children_props);
276 pspec = g_new (GParamSpec *, *n_properties);
278 g_hash_table_iter_init (&iter, self->priv->children_props);
279 while (g_hash_table_iter_next (&iter, &key, &value)) {
280 spec = G_PARAM_SPEC (key);
281 pspec[i] = g_param_spec_ref (spec);
289 _get_property (GObject * object, guint property_id,
290 GValue * value, GParamSpec * pspec)
292 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
294 switch (property_id) {
296 g_value_take_object (value, self->parent);
299 g_value_take_object (value, self->timeline);
302 g_value_set_uint64 (value, self->start);
305 g_value_set_uint64 (value, self->inpoint);
308 g_value_set_uint64 (value, self->duration);
310 case PROP_MAX_DURATION:
311 g_value_set_uint64 (value, self->maxduration);
314 g_value_set_uint (value, self->priority);
317 g_value_take_string (value, ges_timeline_element_get_name (self));
320 g_value_set_boolean (value, self->priv->serialize);
323 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
328 _set_property (GObject * object, guint property_id,
329 const GValue * value, GParamSpec * pspec)
331 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
333 switch (property_id) {
335 ges_timeline_element_set_parent (self, g_value_get_object (value));
338 ges_timeline_element_set_timeline (self, g_value_get_object (value));
341 ges_timeline_element_set_start (self, g_value_get_uint64 (value));
344 ges_timeline_element_set_inpoint (self, g_value_get_uint64 (value));
347 ges_timeline_element_set_duration (self, g_value_get_uint64 (value));
350 ges_timeline_element_set_priority (self, g_value_get_uint (value));
352 case PROP_MAX_DURATION:
353 ges_timeline_element_set_max_duration (self, g_value_get_uint64 (value));
356 ges_timeline_element_set_name (self, g_value_get_string (value));
359 self->priv->serialize = g_value_get_boolean (value);
362 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
367 ges_timeline_element_dispose (GObject * object)
369 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
371 if (self->priv->children_props) {
372 g_hash_table_unref (self->priv->children_props);
373 self->priv->children_props = NULL;
376 g_clear_object (&self->priv->copied_from);
378 G_OBJECT_CLASS (ges_timeline_element_parent_class)->dispose (object);
382 ges_timeline_element_finalize (GObject * self)
384 GESTimelineElement *tle = GES_TIMELINE_ELEMENT (self);
388 G_OBJECT_CLASS (ges_timeline_element_parent_class)->finalize (self);
392 _child_prop_handler_free (ChildPropHandler * handler)
394 g_object_freeze_notify (handler->child);
395 if (handler->handler_id)
396 g_signal_handler_disconnect (handler->child, handler->handler_id);
397 g_object_thaw_notify (handler->child);
399 if (handler->child != (GObject *) handler->self &&
400 handler->child != (GObject *) handler->owner)
401 gst_object_unref (handler->child);
402 g_slice_free (ChildPropHandler, handler);
406 _get_natural_framerate (GESTimelineElement * self, gint * framerate_n,
409 GST_INFO_OBJECT (self, "No natural framerate");
415 ges_timeline_element_init (GESTimelineElement * self)
417 self->priv = ges_timeline_element_get_instance_private (self);
419 self->priv->serialize = TRUE;
421 self->priv->children_props =
422 g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal,
423 (GDestroyNotify) g_param_spec_unref,
424 (GDestroyNotify) _child_prop_handler_free);
428 ges_timeline_element_class_init (GESTimelineElementClass * klass)
430 GObjectClass *object_class = G_OBJECT_CLASS (klass);
432 object_class->get_property = _get_property;
433 object_class->set_property = _set_property;
436 * GESTimelineElement:parent:
438 * The parent container of the element.
440 properties[PROP_PARENT] =
441 g_param_spec_object ("parent", "Parent",
442 "The parent container of the object", GES_TYPE_TIMELINE_ELEMENT,
446 * GESTimelineElement:timeline:
448 * The timeline that the element lies within.
450 properties[PROP_TIMELINE] =
451 g_param_spec_object ("timeline", "Timeline",
452 "The timeline the object is in", GES_TYPE_TIMELINE,
453 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
456 * GESTimelineElement:start:
458 * The starting position of the element in the timeline (in nanoseconds
459 * and in the time coordinates of the timeline). For example, for a
460 * source element, this would determine the time at which it should
461 * start outputting its internal content. For an operation element, this
462 * would determine the time at which it should start applying its effect
463 * to any source content.
465 properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
466 "The position in the timeline", 0, G_MAXUINT64, 0,
467 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
470 * GESTimelineElement:in-point:
472 * The initial offset to use internally when outputting content (in
473 * nanoseconds, but in the time coordinates of the internal content).
475 * For example, for a #GESVideoUriSource that references some media
476 * file, the "internal content" is the media file data, and the
477 * in-point would correspond to some timestamp in the media file.
478 * When playing the timeline, and when the element is first reached at
479 * timeline-time #GESTimelineElement:start, it will begin outputting the
480 * data from the timestamp in-point **onwards**, until it reaches the
481 * end of its #GESTimelineElement:duration in the timeline.
483 * For elements that have no internal content, this should be kept
486 properties[PROP_INPOINT] =
487 g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
488 G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
491 * GESTimelineElement:duration:
493 * The duration that the element is in effect for in the timeline (a
494 * time difference in nanoseconds using the time coordinates of the
495 * timeline). For example, for a source element, this would determine
496 * for how long it should output its internal content for. For an
497 * operation element, this would determine for how long its effect
498 * should be applied to any source content.
500 properties[PROP_DURATION] =
501 g_param_spec_uint64 ("duration", "Duration", "The play duration", 0,
502 G_MAXUINT64, GST_CLOCK_TIME_NONE,
503 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
506 * GESTimelineElement:max-duration:
508 * The full duration of internal content that is available (a time
509 * difference in nanoseconds using the time coordinates of the internal
512 * This will act as a cap on the #GESTimelineElement:in-point of the
513 * element (which is in the same time coordinates), and will sometimes
514 * be used to limit the #GESTimelineElement:duration of the element in
517 * For example, for a #GESVideoUriSource that references some media
518 * file, this would be the length of the media file.
520 * For elements that have no internal content, or whose content is
521 * indefinite, this should be kept as #GST_CLOCK_TIME_NONE.
523 properties[PROP_MAX_DURATION] =
524 g_param_spec_uint64 ("max-duration", "Maximum duration",
525 "The maximum duration of the object", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
526 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
529 * GESTimelineElement:priority:
531 * The priority of the element.
533 * Deprecated: 1.10: Priority management is now done by GES itself.
535 properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
536 "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
539 * GESTimelineElement:name:
541 * The name of the element. This should be unique within its timeline.
543 properties[PROP_NAME] =
544 g_param_spec_string ("name", "Name", "The name of the timeline object",
545 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
548 * GESTimelineElement:serialize:
550 * Whether the element should be serialized.
552 properties[PROP_SERIALIZE] = g_param_spec_boolean ("serialize", "Serialize",
553 "Whether the element should be serialized", TRUE,
554 G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
556 g_object_class_install_properties (object_class, PROP_LAST, properties);
559 * GESTimelineElement::deep-notify:
560 * @timeline_element: A #GESTtimelineElement
561 * @prop_object: The child whose property has been set
562 * @prop: The specification for the property that been set
564 * Emitted when a child of the element has one of its registered
565 * properties set. See ges_timeline_element_add_child_property().
566 * Note that unlike #GObject::notify, a child property name can not be
567 * used as a signal detail.
569 ges_timeline_element_signals[DEEP_NOTIFY] =
570 g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
571 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
572 G_SIGNAL_NO_HOOKS, 0, NULL, NULL, NULL,
573 G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM);
576 * GESTimelineElement::child-property-added:
577 * @timeline_element: A #GESTtimelineElement
578 * @prop_object: The child whose property has been registered
579 * @prop: The specification for the property that has been registered
581 * Emitted when the element has a new child property registered. See
582 * ges_timeline_element_add_child_property().
584 * Note that some GES elements will be automatically created with
585 * pre-registered children properties. You can use
586 * ges_timeline_element_list_children_properties() to list these.
590 ges_timeline_element_signals[CHILD_PROPERTY_ADDED] =
591 g_signal_new ("child-property-added", G_TYPE_FROM_CLASS (klass),
592 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
593 G_TYPE_OBJECT, G_TYPE_PARAM);
596 * GESTimelineElement::child-property-removed:
597 * @timeline_element: A #GESTimelineElement
598 * @prop_object: The child whose property has been unregistered
599 * @prop: The specification for the property that has been unregistered
601 * Emitted when the element has a child property unregistered. See
602 * ges_timeline_element_remove_child_property().
606 ges_timeline_element_signals[CHILD_PROPERTY_REMOVED] =
607 g_signal_new ("child-property-removed", G_TYPE_FROM_CLASS (klass),
608 G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2,
609 G_TYPE_OBJECT, G_TYPE_PARAM);
612 object_class->dispose = ges_timeline_element_dispose;
613 object_class->finalize = ges_timeline_element_finalize;
615 klass->set_parent = NULL;
616 klass->set_start = NULL;
617 klass->set_inpoint = NULL;
618 klass->set_duration = NULL;
619 klass->set_max_duration = NULL;
620 klass->set_priority = NULL;
622 klass->ripple = NULL;
623 klass->ripple_end = NULL;
624 klass->roll_start = NULL;
625 klass->roll_end = NULL;
628 klass->list_children_properties =
629 ges_timeline_element_get_children_properties;
630 klass->lookup_child = _lookup_child;
631 klass->set_child_property = _set_child_property;
632 klass->set_child_property_full = _set_child_property_full;
633 klass->get_natural_framerate = _get_natural_framerate;
637 _set_name (GESTimelineElement * self, const gchar * wanted_name)
639 const gchar *type_name;
646 if (!object_name_counts) {
647 g_datalist_init (&object_name_counts);
650 q = g_type_qname (G_OBJECT_TYPE (self));
651 count = GPOINTER_TO_INT (g_datalist_id_get_data (&object_name_counts, q));
653 /* GstFooSink -> foosink<N> */
654 type_name = g_quark_to_string (q);
655 if (strncmp (type_name, "GES", 3) == 0)
658 lowcase_type = g_strdup (type_name);
659 l = strlen (lowcase_type);
660 for (i = 0; i < l; i++)
661 lowcase_type[i] = g_ascii_tolower (lowcase_type[i]);
663 if (wanted_name == NULL) {
664 /* give the 20th "uriclip" element and the first "uriclip2" (if needed in the future)
666 l = strlen (type_name);
667 if (l > 0 && g_ascii_isdigit (type_name[l - 1])) {
668 name = g_strdup_printf ("%s-%d", lowcase_type, count++);
670 name = g_strdup_printf ("%s%d", lowcase_type, count++);
673 /* If the wanted name uses the same 'namespace' as default, make
674 * sure it does not badly interfere with our counting system */
676 /* FIXME: should we really be allowing a user to set the name
677 * "uriclip1" for, say, a GESTransition? The below code *does not*
678 * capture this case (because the prefix does not match "transition").
679 * If the user subsequently calls _set_name with name == NULL, on a
680 * GESClip *for the first time*, then the GES library will
681 * automatically choose the *same* name "uriclip1", but this is not
683 if (g_str_has_prefix (wanted_name, lowcase_type)) {
685 g_ascii_strtoull (&wanted_name[strlen (lowcase_type)], NULL, 10);
687 if (tmpcount > count) {
688 count = tmpcount + 1;
689 GST_DEBUG_OBJECT (self, "Using same naming %s but updated count to %i",
691 } else if (tmpcount < count) {
692 /* FIXME: this can unexpectedly change names given by the user
693 * E.g. if "transition2" already exists, and a user then wants to
694 * set a GESTransition to have the name "transition-custom" or
695 * "transition 1 too many" then tmpcount would in fact be 0 or 1,
696 * and the name would then be changed to "transition3"! */
697 name = g_strdup_printf ("%s%d", lowcase_type, count);
699 GST_DEBUG_OBJECT (self, "Name %s already allocated, giving: %s instead"
700 " New count is %i", wanted_name, name, count);
703 GST_DEBUG_OBJECT (self, "Perfect name, just bumping object count");
708 name = g_strdup (wanted_name);
711 g_free (lowcase_type);
712 g_datalist_id_set_data (&object_name_counts, q, GINT_TO_POINTER (count));
718 /*********************************************
719 * Internal and private helpers *
720 *********************************************/
723 ges_timeline_element_peak_toplevel (GESTimelineElement * self)
725 GESTimelineElement *toplevel = self;
727 while (toplevel->parent)
728 toplevel = toplevel->parent;
734 ges_timeline_element_get_copied_from (GESTimelineElement * self)
736 GESTimelineElement *copied_from = self->priv->copied_from;
737 self->priv->copied_from = NULL;
741 GESTimelineElementFlags
742 ges_timeline_element_flags (GESTimelineElement * self)
744 return self->priv->flags;
748 ges_timeline_element_set_flags (GESTimelineElement * self,
749 GESTimelineElementFlags flags)
751 self->priv->flags = flags;
756 emit_deep_notify_in_idle (EmitDeepNotifyInIdleData * data)
758 g_signal_emit (data->self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
759 data->child, data->arg);
761 gst_object_unref (data->child);
762 g_param_spec_unref (data->arg);
763 gst_object_unref (data->self);
764 g_slice_free (EmitDeepNotifyInIdleData, data);
770 child_prop_changed_cb (GObject * child, GParamSpec * arg,
771 GESTimelineElement * self)
773 EmitDeepNotifyInIdleData *data;
775 /* Emit "deep-notify" right away if in main thread */
776 if (g_main_context_acquire (g_main_context_default ())) {
777 g_main_context_release (g_main_context_default ());
778 g_signal_emit (self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
783 data = g_slice_new (EmitDeepNotifyInIdleData);
785 data->child = gst_object_ref (child);
786 data->arg = g_param_spec_ref (arg);
787 data->self = gst_object_ref (self);
789 ges_idle_add ((GSourceFunc) emit_deep_notify_in_idle, data, NULL);
793 set_child_property_by_pspec (GESTimelineElement * self,
794 GParamSpec * pspec, const GValue * value, GError ** error)
796 GESTimelineElementClass *klass;
797 GESTimelineElement *setter = self;
798 ChildPropHandler *handler =
799 g_hash_table_lookup (self->priv->children_props, pspec);
802 GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
806 if (handler->owner) {
807 klass = GES_TIMELINE_ELEMENT_GET_CLASS (handler->owner);
808 setter = handler->owner;
810 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
813 if (klass->set_child_property_full)
814 return klass->set_child_property_full (setter, handler->child, pspec,
817 g_assert (klass->set_child_property);
818 klass->set_child_property (setter, handler->child, pspec, (GValue *) value);
824 ges_timeline_element_add_child_property_full (GESTimelineElement * self,
825 GESTimelineElement * owner, GParamSpec * pspec, GObject * child)
828 ChildPropHandler *handler;
830 /* FIXME: allow the same pspec, provided the child is different. This
831 * is important for containers that may have duplicate children
832 * If this is changed, _remove_childs_child_property in ges-container.c
833 * should be changed to reflect this.
834 * We could hack around this by copying the pspec into a new instance
835 * of GParamSpec, but there is no such GLib method, and it would break
836 * the usage of get_..._from_pspec and set_..._from_pspec */
837 if (g_hash_table_contains (self->priv->children_props, pspec)) {
838 GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
842 GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
845 signame = g_strconcat ("notify::", pspec->name, NULL);
846 handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
847 handler->self = self;
848 if (child == G_OBJECT (self) || child == G_OBJECT (owner))
849 handler->child = child;
851 handler->child = gst_object_ref (child);
852 handler->owner = owner;
853 handler->handler_id =
854 g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
856 g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
859 g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_ADDED], 0,
867 ges_timeline_element_get_child_from_child_property (GESTimelineElement * self,
870 ChildPropHandler *handler =
871 g_hash_table_lookup (self->priv->children_props, pspec);
873 return handler->child;
878 /*********************************************
879 * API implementation *
880 *********************************************/
883 * ges_timeline_element_set_parent:
884 * @self: A #GESTimelineElement
885 * @parent (nullable): New parent of @self
887 * Sets the #GESTimelineElement:parent for the element.
889 * This is used internally and you should normally not call this. A
890 * #GESContainer will set the #GESTimelineElement:parent of its children
891 * in ges_container_add() and ges_container_remove().
893 * Note, if @parent is not %NULL, @self must not already have a parent
894 * set. Therefore, if you wish to switch parents, you will need to call
895 * this function twice: first to set the parent to %NULL, and then to the
898 * If @parent is not %NULL, you must ensure it already has a
899 * (non-floating) reference to @self before calling this.
901 * Returns: %TRUE if @parent could be set for @self.
904 ges_timeline_element_set_parent (GESTimelineElement * self,
905 GESTimelineElement * parent)
907 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
908 g_return_val_if_fail (parent == NULL
909 || GES_IS_TIMELINE_ELEMENT (parent), FALSE);
911 if (self == parent) {
912 GST_INFO_OBJECT (self, "Trying to add %p in itself, not a good idea!",
914 /* FIXME: why are we sinking and then unreffing self when we do not
916 gst_object_ref_sink (self);
917 gst_object_unref (self);
921 GST_DEBUG_OBJECT (self, "set parent to %" GST_PTR_FORMAT, parent);
923 if (self->parent != NULL && parent != NULL)
926 if (GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent) {
927 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent (self, parent))
931 self->parent = parent;
933 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PARENT]);
939 GST_WARNING_OBJECT (self, "set parent failed, object already had a parent");
940 /* FIXME: why are we sinking and then unreffing self when we do not
942 gst_object_ref_sink (self);
943 gst_object_unref (self);
949 * ges_timeline_element_get_parent:
950 * @self: A #GESTimelineElement
952 * Gets the #GESTimelineElement:parent for the element.
954 * Returns: (transfer full) (nullable): The parent of @self, or %NULL if
955 * @self has no parent.
958 ges_timeline_element_get_parent (GESTimelineElement * self)
960 GESTimelineElement *result = NULL;
962 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
964 result = self->parent;
965 if (G_LIKELY (result))
966 gst_object_ref (result);
972 * ges_timeline_element_set_timeline:
973 * @self: A #GESTimelineElement
974 * @timeline (nullable): The #GESTimeline @self should be in
976 * Sets the #GESTimelineElement:timeline of the element.
978 * This is used internally and you should normally not call this. A
979 * #GESClip will have its #GESTimelineElement:timeline set through its
980 * #GESLayer. A #GESTrack will similarly take care of setting the
981 * #GESTimelineElement:timeline of its #GESTrackElement-s. A #GESGroup
982 * will adopt the same #GESTimelineElement:timeline as its children.
984 * If @timeline is %NULL, this will stop its current
985 * #GESTimelineElement:timeline from tracking it, otherwise @timeline will
986 * start tracking @self. Note, in the latter case, @self must not already
987 * have a timeline set. Therefore, if you wish to switch timelines, you
988 * will need to call this function twice: first to set the timeline to
989 * %NULL, and then to the new timeline.
991 * Returns: %TRUE if @timeline could be set for @self.
994 ges_timeline_element_set_timeline (GESTimelineElement * self,
995 GESTimeline * timeline)
997 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
998 g_return_val_if_fail (timeline == NULL || GES_IS_TIMELINE (timeline), FALSE);
1000 GST_DEBUG_OBJECT (self, "set timeline to %" GST_PTR_FORMAT, timeline);
1002 if (self->timeline == timeline)
1005 if (timeline != NULL && G_UNLIKELY (self->timeline != NULL))
1008 if (timeline == NULL) {
1009 if (self->timeline) {
1010 if (!timeline_remove_element (self->timeline, self)) {
1011 GST_INFO_OBJECT (self, "Could not remove from"
1012 " currently set timeline %" GST_PTR_FORMAT, self->timeline);
1017 if (!timeline_add_element (timeline, self)) {
1018 GST_INFO_OBJECT (self, "Could not add to timeline %" GST_PTR_FORMAT,
1024 self->timeline = timeline;
1026 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TIMELINE]);
1029 /* ERROR handling */
1032 GST_DEBUG_OBJECT (self, "set timeline failed, object already had a "
1039 * ges_timeline_element_get_timeline:
1040 * @self: A #GESTimelineElement
1042 * Gets the #GESTimelineElement:timeline for the element.
1044 * Returns: (transfer full) (nullable): The timeline of @self, or %NULL
1045 * if @self has no timeline.
1048 ges_timeline_element_get_timeline (GESTimelineElement * self)
1050 GESTimeline *result = NULL;
1052 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1054 result = self->timeline;
1055 if (G_LIKELY (result))
1056 gst_object_ref (result);
1062 * ges_timeline_element_set_start:
1063 * @self: A #GESTimelineElement
1064 * @start: The desired start position of the element in its timeline
1066 * Sets #GESTimelineElement:start for the element. If the element has a
1067 * parent, this will also move its siblings with the same shift.
1069 * Whilst the element is part of a #GESTimeline, this is the same as
1070 * editing the element with ges_timeline_element_edit() under
1071 * #GES_EDIT_MODE_NORMAL with #GES_EDGE_NONE. In particular, the
1072 * #GESTimelineElement:start of the element may be snapped to a different
1073 * timeline time from the one given. In addition, setting may fail if it
1074 * would place the timeline in an unsupported configuration.
1076 * Returns: %TRUE if @start could be set for @self.
1079 ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
1081 GESTimelineElementClass *klass;
1082 GESTimelineElement *toplevel_container, *parent;
1084 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1085 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1087 if (self->start == start)
1090 GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
1091 " new start: %" GST_TIME_FORMAT,
1092 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
1094 if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1095 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_NORMAL,
1096 GES_EDGE_NONE, start);
1098 toplevel_container = ges_timeline_element_peak_toplevel (self);
1099 parent = self->parent;
1101 /* FIXME This should not belong to GESTimelineElement */
1102 /* only check if no timeline, otherwise the timeline-tree will handle this
1104 if (!self->timeline && toplevel_container &&
1105 ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
1107 && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
1108 GST_INFO_OBJECT (self,
1109 "Can not move the object as it would imply its "
1110 "container to have a negative start value");
1115 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1116 if (klass->set_start) {
1117 gint res = klass->set_start (self, start);
1121 self->start = start;
1122 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
1125 GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
1126 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
1131 GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
1132 " on class %s. Can not set start %" GST_TIME_FORMAT,
1133 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1138 * ges_timeline_element_set_inpoint:
1139 * @self: A #GESTimelineElement
1140 * @inpoint: The in-point, in internal time coordinates
1142 * Sets #GESTimelineElement:in-point for the element. If the new in-point
1143 * is above the current #GESTimelineElement:max-duration of the element,
1144 * this method will fail.
1146 * Returns: %TRUE if @inpoint could be set for @self.
1149 ges_timeline_element_set_inpoint (GESTimelineElement * self,
1150 GstClockTime inpoint)
1152 GESTimelineElementClass *klass;
1154 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1156 GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
1157 " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (self->inpoint),
1158 GST_TIME_ARGS (inpoint));
1160 if (G_UNLIKELY (inpoint == self->inpoint))
1163 if (GES_CLOCK_TIME_IS_LESS (self->maxduration, inpoint)) {
1164 GST_WARNING_OBJECT (self, "Can not set an in-point of %" GST_TIME_FORMAT
1165 " because it exceeds the element's max-duration: %" GST_TIME_FORMAT,
1166 GST_TIME_ARGS (inpoint), GST_TIME_ARGS (self->maxduration));
1170 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1172 if (klass->set_inpoint) {
1173 /* FIXME: Could we instead use g_object_freeze_notify() to prevent
1174 * duplicate notify signals? Rather than relying on the return value
1175 * being -1 for setting that succeeds but does not want a notify
1176 * signal because it will call this method on itself a second time. */
1177 if (!klass->set_inpoint (self, inpoint))
1180 self->inpoint = inpoint;
1181 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
1186 GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
1187 " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
1188 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
1194 * ges_timeline_element_set_max_duration:
1195 * @self: A #GESTimelineElement
1196 * @maxduration: The maximum duration, in internal time coordinates
1198 * Sets #GESTimelineElement:max-duration for the element. If the new
1199 * maximum duration is below the current #GESTimelineElement:in-point of
1200 * the element, this method will fail.
1202 * Returns: %TRUE if @maxduration could be set for @self.
1205 ges_timeline_element_set_max_duration (GESTimelineElement * self,
1206 GstClockTime maxduration)
1208 GESTimelineElementClass *klass;
1210 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1212 GST_DEBUG_OBJECT (self, "current max-duration: %" GST_TIME_FORMAT
1213 " new max-duration: %" GST_TIME_FORMAT,
1214 GST_TIME_ARGS (self->maxduration), GST_TIME_ARGS (maxduration));
1216 if (G_UNLIKELY (maxduration == self->maxduration))
1219 if (GES_CLOCK_TIME_IS_LESS (maxduration, self->inpoint)) {
1220 GST_WARNING_OBJECT (self, "Can not set a max-duration of %"
1221 GST_TIME_FORMAT " because it lies below the element's in-point: %"
1222 GST_TIME_FORMAT, GST_TIME_ARGS (maxduration),
1223 GST_TIME_ARGS (self->inpoint));
1227 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1229 if (klass->set_max_duration) {
1230 if (!klass->set_max_duration (self, maxduration))
1232 self->maxduration = maxduration;
1233 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
1238 GST_DEBUG_OBJECT (self, "No set_max_duration virtual method implementation"
1239 " on class %s. Can not set max-duration %" GST_TIME_FORMAT,
1240 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (maxduration));
1246 * ges_timeline_element_set_duration:
1247 * @self: A #GESTimelineElement
1248 * @duration: The desired duration in its timeline
1250 * Sets #GESTimelineElement:duration for the element.
1252 * Whilst the element is part of a #GESTimeline, this is the same as
1253 * editing the element with ges_timeline_element_edit() under
1254 * #GES_EDIT_MODE_TRIM with #GES_EDGE_END. In particular, the
1255 * #GESTimelineElement:duration of the element may be snapped to a
1256 * different timeline time difference from the one given. In addition,
1257 * setting may fail if it would place the timeline in an unsupported
1258 * configuration, or the element does not have enough internal content to
1259 * last the desired duration.
1261 * Returns: %TRUE if @duration could be set for @self.
1264 ges_timeline_element_set_duration (GESTimelineElement * self,
1265 GstClockTime duration)
1267 GESTimelineElementClass *klass;
1269 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1271 if (duration == self->duration)
1274 if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1275 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1276 GES_EDGE_END, self->start + duration);
1278 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
1279 " new duration: %" GST_TIME_FORMAT,
1280 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
1281 GST_TIME_ARGS (duration));
1283 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1284 if (klass->set_duration) {
1285 gint res = klass->set_duration (self, duration);
1289 self->duration = duration;
1290 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
1296 GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
1297 " on class %s. Can not set duration %" GST_TIME_FORMAT,
1298 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
1303 * ges_timeline_element_get_start:
1304 * @self: A #GESTimelineElement
1306 * Gets the #GESTimelineElement:start for the element.
1308 * Returns: The start of @self (in nanoseconds).
1311 ges_timeline_element_get_start (GESTimelineElement * self)
1313 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1319 * ges_timeline_element_get_inpoint:
1320 * @self: A #GESTimelineElement
1322 * Gets the #GESTimelineElement:in-point for the element.
1324 * Returns: The in-point of @self (in nanoseconds).
1327 ges_timeline_element_get_inpoint (GESTimelineElement * self)
1329 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1331 return self->inpoint;
1335 * ges_timeline_element_get_duration:
1336 * @self: A #GESTimelineElement
1338 * Gets the #GESTimelineElement:duration for the element.
1340 * Returns: The duration of @self (in nanoseconds).
1343 ges_timeline_element_get_duration (GESTimelineElement * self)
1345 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1347 return self->duration;
1351 * ges_timeline_element_get_max_duration:
1352 * @self: A #GESTimelineElement
1354 * Gets the #GESTimelineElement:max-duration for the element.
1356 * Returns: The max-duration of @self (in nanoseconds).
1359 ges_timeline_element_get_max_duration (GESTimelineElement * self)
1361 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1363 return self->maxduration;
1367 * ges_timeline_element_get_priority:
1368 * @self: A #GESTimelineElement
1370 * Gets the #GESTimelineElement:priority for the element.
1372 * Returns: The priority of @self.
1375 ges_timeline_element_get_priority (GESTimelineElement * self)
1377 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1379 return self->priority;
1383 * ges_timeline_element_set_priority:
1384 * @self: A #GESTimelineElement
1385 * @priority: The priority
1387 * Sets the priority of the element within the containing layer.
1389 * Deprecated:1.10: All priority management is done by GES itself now.
1390 * To set #GESEffect priorities #ges_clip_set_top_effect_index should
1393 * Returns: %TRUE if @priority could be set for @self.
1396 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
1398 GESTimelineElementClass *klass;
1400 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1402 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1404 GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
1405 self->priority, priority);
1407 if (klass->set_priority) {
1408 gboolean res = klass->set_priority (self, priority);
1410 self->priority = priority;
1411 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
1417 GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
1418 " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
1424 * ges_timeline_element_ripple:
1425 * @self: The #GESTimelineElement to ripple
1426 * @start: The new start time of @self in ripple mode
1428 * Edits the start time of an element within its timeline in ripple mode.
1429 * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1432 * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1436 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
1438 GESTimelineElementClass *klass;
1440 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1441 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1443 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1446 return klass->ripple (self, start);
1448 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1449 GES_EDGE_NONE, start);
1455 * ges_timeline_element_ripple_end:
1456 * @self: The #GESTimelineElement to ripple
1457 * @end: The new end time of @self in ripple mode
1459 * Edits the end time of an element within its timeline in ripple mode.
1460 * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1463 * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1467 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1469 GESTimelineElementClass *klass;
1471 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1472 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (end), FALSE);
1474 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1476 if (klass->ripple_end)
1477 return klass->ripple_end (self, end);
1479 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1484 * ges_timeline_element_roll_start:
1485 * @self: The #GESTimelineElement to roll
1486 * @start: The new start time of @self in roll mode
1488 * Edits the start time of an element within its timeline in roll mode.
1489 * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1492 * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1495 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1497 GESTimelineElementClass *klass;
1499 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1500 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1502 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1504 if (klass->roll_start)
1505 return klass->roll_start (self, start);
1507 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1508 GES_EDGE_START, start);
1512 * ges_timeline_element_roll_end:
1513 * @self: The #GESTimelineElement to roll
1514 * @end: The new end time of @self in roll mode
1516 * Edits the end time of an element within its timeline in roll mode.
1517 * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1520 * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1523 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1525 GESTimelineElementClass *klass;
1527 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1528 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (end), FALSE);
1530 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1532 if (klass->roll_end)
1533 return klass->roll_end (self, end);
1535 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1540 * ges_timeline_element_trim:
1541 * @self: The #GESTimelineElement to trim
1542 * @start: The new start time of @self in trim mode
1544 * Edits the start time of an element within its timeline in trim mode.
1545 * See ges_timeline_element_edit() with #GES_EDIT_MODE_TRIM and
1548 * Returns: %TRUE if the trim edit of @self completed, %FALSE on failure.
1551 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1553 GESTimelineElementClass *klass;
1555 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1556 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start), FALSE);
1558 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1561 return klass->trim (self, start);
1563 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1564 GES_EDGE_START, start);
1568 * ges_timeline_element_copy:
1569 * @self: The #GESTimelineElement to copy
1570 * @deep: Whether the copy is needed for pasting
1572 * Create a copy of @self. All the properties of @self are copied into
1573 * a new element, with the exception of #GESTimelineElement:parent,
1574 * #GESTimelineElement:timeline and #GESTimelineElement:name. Other data,
1575 * such the list of a #GESContainer's children, is **not** copied.
1577 * If @deep is %TRUE, then the new element is prepared so that it can be
1578 * used in ges_timeline_element_paste() or ges_timeline_paste_element().
1579 * In the case of copying a #GESContainer, this ensures that the children
1580 * of @self will also be pasted. The new element should not be used for
1581 * anything else and can only be used **once** in a pasting operation. In
1582 * particular, the new element itself is not an actual 'deep' copy of
1583 * @self, but should be thought of as an intermediate object used for a
1584 * single paste operation.
1586 * Returns: (transfer floating): The newly create element,
1587 * copied from @self.
1589 G_GNUC_BEGIN_IGNORE_DEPRECATIONS; /* Start ignoring GParameter deprecation */
1590 GESTimelineElement *
1591 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1595 GESTimelineElementClass *klass;
1598 GESTimelineElement *ret = NULL;
1600 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1602 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1604 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1606 asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1608 ret = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
1609 for (n = 0; n < n_specs; ++n) {
1610 /* We do not want the timeline or the name to be copied */
1611 if (g_strcmp0 (specs[n]->name, "parent") &&
1612 g_strcmp0 (specs[n]->name, "timeline") &&
1613 g_strcmp0 (specs[n]->name, "name") &&
1614 (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
1615 (specs[n]->flags & G_PARAM_CONSTRUCT_ONLY) == 0) {
1616 GValue v = G_VALUE_INIT;
1617 g_value_init (&v, specs[n]->value_type);
1618 g_object_get_property (G_OBJECT (self), specs[n]->name, &v);
1620 g_object_set_property (G_OBJECT (ret), specs[n]->name, &v);
1627 if (klass->deep_copy)
1628 klass->deep_copy (self, ret);
1630 GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1631 " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1635 ret->priv->copied_from = gst_object_ref (self);
1641 G_GNUC_END_IGNORE_DEPRECATIONS; /* End ignoring GParameter deprecation */
1644 * ges_timeline_element_get_toplevel_parent:
1645 * @self: The #GESTimelineElement to get the toplevel parent from
1647 * Gets the toplevel #GESTimelineElement:parent of the element.
1649 * Returns: (transfer full): The toplevel parent of @self.
1651 GESTimelineElement *
1652 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1654 GESTimelineElement *toplevel;
1656 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1658 toplevel = ges_timeline_element_peak_toplevel (self);
1660 return gst_object_ref (toplevel);
1664 * ges_timeline_element_get_name:
1665 * @self: A #GESTimelineElement
1667 * Gets the #GESTimelineElement:name for the element.
1669 * Returns: (transfer full): The name of @self.
1672 ges_timeline_element_get_name (GESTimelineElement * self)
1674 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1676 return g_strdup (self->name);
1680 * ges_timeline_element_set_name:
1681 * @self: A #GESTimelineElement
1682 * @name: (allow-none): The name @self should take
1684 * Sets the #GESTimelineElement:name for the element. If %NULL is given
1685 * for @name, then the library will instead generate a new name based on
1686 * the type name of the element, such as the name "uriclip3" for a
1687 * #GESUriClip, and will set that name instead.
1689 * If @self already has a #GESTimelineElement:timeline, you should not
1690 * call this function with @name set to %NULL.
1692 * You should ensure that, within each #GESTimeline, every element has a
1693 * unique name. If you call this function with @name as %NULL, then
1694 * the library should ensure that the set generated name is unique from
1695 * previously **generated** names. However, if you choose a @name that
1696 * interferes with the naming conventions of the library, the library will
1697 * attempt to ensure that the generated names will not conflict with the
1698 * chosen name, which may lead to a different name being set instead, but
1699 * the uniqueness between generated and user-chosen names is not
1702 * Returns: %TRUE if @name or a generated name for @self could be set.
1705 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1707 gboolean result = TRUE, readd_to_timeline = FALSE;
1709 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1711 if (name != NULL && !g_strcmp0 (name, self->name)) {
1712 GST_DEBUG_OBJECT (self, "Same name!");
1716 /* parented objects cannot be renamed */
1717 if (self->timeline != NULL && name) {
1718 GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1720 /* FIXME: if tmp == self then this means that we setting the name of
1721 * self to its existing name. There is no need to throw an error */
1723 gst_object_unref (tmp);
1727 timeline_remove_element (self->timeline, self);
1728 readd_to_timeline = TRUE;
1730 /* FIXME: if self already has a timeline and name is NULL, then it also
1731 * needs to be re-added to the timeline (or, at least its entry in
1732 * timeline->priv->all_elements needs its key to be updated) using the
1733 * new generated name */
1735 _set_name (self, name);
1737 /* FIXME: the set name may not always be unique in a given timeline, see
1738 * _set_name(). This can cause timeline_add_element to fail! */
1739 if (readd_to_timeline)
1740 timeline_add_element (self->timeline, self);
1747 /* FIXME: message is misleading. We are here if some other object in
1748 * the timeline was added under @name (see above) */
1749 GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1756 * ges_timeline_element_add_child_property:
1757 * @self: A #GESTimelineElement
1758 * @pspec: The specification for the property to add
1759 * @child: The #GstObject who the property belongs to
1761 * Register a property of a child of the element to allow it to be
1762 * written with ges_timeline_element_set_child_property() and read with
1763 * ges_timeline_element_get_child_property(). A change in the property
1764 * will also appear in the #GESTimelineElement::deep-notify signal.
1766 * @pspec should be unique from other children properties that have been
1767 * registered on @self.
1769 * Returns: %TRUE if the property was successfully registered.
1772 ges_timeline_element_add_child_property (GESTimelineElement * self,
1773 GParamSpec * pspec, GObject * child)
1775 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1776 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1777 g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
1779 return ges_timeline_element_add_child_property_full (self, NULL, pspec,
1784 * ges_timeline_element_get_child_property_by_pspec:
1785 * @self: A #GESTimelineElement
1786 * @pspec: The specification of a registered child property to get
1787 * @value: (out): The return location for the value
1789 * Gets the property of a child of the element. Specifically, the property
1790 * corresponding to the @pspec used in
1791 * ges_timeline_element_add_child_property() is copied into @value.
1794 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1795 GParamSpec * pspec, GValue * value)
1797 ChildPropHandler *handler;
1799 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1800 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1802 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1806 g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1812 GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1818 * ges_timeline_element_set_child_property_by_pspec:
1819 * @self: A #GESTimelineElement
1820 * @pspec: The specification of a registered child property to set
1821 * @value: The value to set the property to
1823 * Sets the property of a child of the element. Specifically, the property
1824 * corresponding to the @pspec used in
1825 * ges_timeline_element_add_child_property() is set to @value.
1828 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1829 GParamSpec * pspec, const GValue * value)
1831 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1832 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1834 set_child_property_by_pspec (self, pspec, value, NULL);
1838 * ges_timeline_element_set_child_property_full:
1839 * @self: A #GESTimelineElement
1840 * @property_name: The name of the child property to set
1841 * @value: The value to set the property to
1842 * @error: (nullable): Return location for an error
1844 * Sets the property of a child of the element.
1846 * @property_name can either be in the format "prop-name" or
1847 * "TypeName::prop-name", where "prop-name" is the name of the property
1848 * to set (as used in g_object_set()), and "TypeName" is the type name of
1849 * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1850 * useful when two children of different types share the same property
1853 * The first child found with the given "prop-name" property that was
1854 * registered with ges_timeline_element_add_child_property() (and of the
1855 * type "TypeName", if it was given) will have the corresponding
1856 * property set to @value. Other children that may have also matched the
1857 * property name (and type name) are left unchanged!
1859 * Returns: %TRUE if the property was found and set.
1863 ges_timeline_element_set_child_property_full (GESTimelineElement * self,
1864 const gchar * property_name, const GValue * value, GError ** error)
1869 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1870 g_return_val_if_fail (!error || !*error, FALSE);
1872 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1875 return set_child_property_by_pspec (self, pspec, value, error);
1879 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1886 * ges_timeline_element_set_child_property:
1887 * @self: A #GESTimelineElement
1888 * @property_name: The name of the child property to set
1889 * @value: The value to set the property to
1891 * See ges_timeline_element_set_child_property_full(), which also gives an
1894 * Note that ges_timeline_element_set_child_properties() may be more
1895 * convenient for C programming.
1897 * Returns: %TRUE if the property was found and set.
1900 ges_timeline_element_set_child_property (GESTimelineElement * self,
1901 const gchar * property_name, const GValue * value)
1903 return ges_timeline_element_set_child_property_full (self, property_name,
1908 * ges_timeline_element_get_child_property:
1909 * @self: A #GESTimelineElement
1910 * @property_name: The name of the child property to get
1911 * @value: (out): The return location for the value
1913 * Gets the property of a child of the element.
1915 * @property_name can either be in the format "prop-name" or
1916 * "TypeName::prop-name", where "prop-name" is the name of the property
1917 * to get (as used in g_object_get()), and "TypeName" is the type name of
1918 * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1919 * useful when two children of different types share the same property
1922 * The first child found with the given "prop-name" property that was
1923 * registered with ges_timeline_element_add_child_property() (and of the
1924 * type "TypeName", if it was given) will have the corresponding
1925 * property copied into @value.
1927 * Note that ges_timeline_element_get_child_properties() may be more
1928 * convenient for C programming.
1930 * Returns: %TRUE if the property was found and copied to @value.
1933 ges_timeline_element_get_child_property (GESTimelineElement * self,
1934 const gchar * property_name, GValue * value)
1939 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1941 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1944 /* FIXME: since GLib 2.60, g_object_get_property() will automatically
1945 * initialize the type */
1946 if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1947 g_value_init (value, pspec->value_type);
1949 g_object_get_property (child, pspec->name, value);
1951 gst_object_unref (child);
1952 g_param_spec_unref (pspec);
1958 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1965 * ges_timeline_element_lookup_child:
1966 * @self: A #GESTimelineElement
1967 * @prop_name: The name of a child property
1968 * @child: (out) (optional) (transfer full): The return location for the
1970 * @pspec: (out) (optional) (transfer full): The return location for the
1971 * specification of the child property
1973 * Looks up a child property of the element.
1975 * @prop_name can either be in the format "prop-name" or
1976 * "TypeName::prop-name", where "prop-name" is the name of the property
1977 * to look up (as used in g_object_get()), and "TypeName" is the type name
1978 * of the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1979 * useful when two children of different types share the same property
1982 * The first child found with the given "prop-name" property that was
1983 * registered with ges_timeline_element_add_child_property() (and of the
1984 * type "TypeName", if it was given) will be passed to @child, and the
1985 * registered specification of this property will be passed to @pspec.
1987 * Returns: %TRUE if a child corresponding to the property was found, in
1988 * which case @child and @pspec are set.
1991 ges_timeline_element_lookup_child (GESTimelineElement * self,
1992 const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1994 GESTimelineElementClass *class;
1996 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1997 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1998 g_return_val_if_fail (class->lookup_child, FALSE);
2000 return class->lookup_child (self, prop_name, child, pspec);
2004 * ges_timeline_element_set_child_property_valist:
2005 * @self: A #GESTimelineElement
2006 * @first_property_name: The name of the first child property to set
2007 * @var_args: The value for the first property, followed optionally by more
2008 * name/value pairs, followed by %NULL
2010 * Sets several of the children properties of the element. See
2011 * ges_timeline_element_set_child_property().
2014 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
2015 const gchar * first_property_name, va_list var_args)
2020 gchar *error = NULL;
2021 GValue value = { 0, };
2023 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2025 name = first_property_name;
2027 /* Note: This part is in big part copied from the gst_child_object_set_valist
2030 /* iterate over pairs */
2032 if (!ges_timeline_element_lookup_child (self, name, NULL, &pspec))
2035 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
2036 G_VALUE_NOCOPY_CONTENTS, &error);
2041 set_child_property_by_pspec (self, pspec, &value, NULL);
2043 g_param_spec_unref (pspec);
2044 g_value_unset (&value);
2046 name = va_arg (var_args, gchar *);
2052 GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
2057 GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
2060 g_param_spec_unref (pspec);
2061 g_value_unset (&value);
2067 * ges_timeline_element_set_child_properties:
2068 * @self: A #GESTimelineElement
2069 * @first_property_name: The name of the first child property to set
2070 * @...: The value for the first property, followed optionally by more
2071 * name/value pairs, followed by %NULL
2073 * Sets several of the children properties of the element. See
2074 * ges_timeline_element_set_child_property().
2077 ges_timeline_element_set_child_properties (GESTimelineElement * self,
2078 const gchar * first_property_name, ...)
2082 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2084 va_start (var_args, first_property_name);
2085 ges_timeline_element_set_child_property_valist (self, first_property_name,
2091 * ges_timeline_element_get_child_property_valist:
2092 * @self: A #GESTimelineElement
2093 * @first_property_name: The name of the first child property to get
2094 * @var_args: The return location for the first property, followed
2095 * optionally by more name/return location pairs, followed by %NULL
2097 * Gets several of the children properties of the element. See
2098 * ges_timeline_element_get_child_property().
2101 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
2102 const gchar * first_property_name, va_list var_args)
2105 gchar *error = NULL;
2106 GValue value = { 0, };
2110 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2112 name = first_property_name;
2114 /* This part is in big part copied from the gst_child_object_get_valist method */
2116 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
2119 g_value_init (&value, pspec->value_type);
2120 g_object_get_property (child, pspec->name, &value);
2121 gst_object_unref (child);
2122 g_param_spec_unref (pspec);
2124 G_VALUE_LCOPY (&value, var_args, 0, &error);
2127 g_value_unset (&value);
2128 name = va_arg (var_args, gchar *);
2134 GST_WARNING_OBJECT (self, "no child property %s", name);
2139 GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
2142 g_value_unset (&value);
2148 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
2150 return g_strcmp0 ((*a)->name, (*b)->name);
2155 * ges_timeline_element_list_children_properties:
2156 * @self: A #GESTimelineElement
2157 * @n_properties: (out): The return location for the length of the
2160 * Get a list of children properties of the element, which is a list of
2161 * all the specifications passed to
2162 * ges_timeline_element_add_child_property().
2164 * Returns: (transfer full) (array length=n_properties): An array of
2165 * #GParamSpec corresponding to the child properties of @self, or %NULL if
2166 * something went wrong.
2169 ges_timeline_element_list_children_properties (GESTimelineElement * self,
2170 guint * n_properties)
2173 GESTimelineElementClass *class;
2175 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
2177 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2179 if (!class->list_children_properties) {
2180 GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
2181 G_OBJECT_TYPE_NAME (self));
2187 ret = class->list_children_properties (self, n_properties);
2188 g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
2189 (GCompareDataFunc) compare_gparamspec, NULL);
2195 * ges_timeline_element_get_child_properties:
2196 * @self: A #GESTimelineElement
2197 * @first_property_name: The name of the first child property to get
2198 * @...: The return location for the first property, followed
2199 * optionally by more name/return location pairs, followed by %NULL
2201 * Gets several of the children properties of the element. See
2202 * ges_timeline_element_get_child_property().
2205 ges_timeline_element_get_child_properties (GESTimelineElement * self,
2206 const gchar * first_property_name, ...)
2210 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2212 va_start (var_args, first_property_name);
2213 ges_timeline_element_get_child_property_valist (self, first_property_name,
2219 * ges_timeline_element_remove_child_property:
2220 * @self: A #GESTimelineElement
2221 * @pspec: The specification for the property to remove
2223 * Remove a child property from the element. @pspec should be a
2224 * specification that was passed to
2225 * ges_timeline_element_add_child_property(). The corresponding property
2226 * will no longer be registered as a child property for the element.
2228 * Returns: %TRUE if the property was successfully un-registered for @self.
2231 ges_timeline_element_remove_child_property (GESTimelineElement * self,
2234 gpointer key, value;
2235 GParamSpec *found_pspec;
2236 ChildPropHandler *handler;
2238 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2239 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2241 if (!g_hash_table_lookup_extended (self->priv->children_props, pspec,
2243 GST_WARNING_OBJECT (self, "No child property with pspec %p (%s) found",
2244 pspec, pspec->name);
2247 g_hash_table_steal (self->priv->children_props, pspec);
2248 found_pspec = G_PARAM_SPEC (key);
2249 handler = (ChildPropHandler *) value;
2251 g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0,
2252 handler->child, found_pspec);
2254 g_param_spec_unref (found_pspec);
2255 _child_prop_handler_free (handler);
2261 * ges_timeline_element_get_track_types:
2262 * @self: A #GESTimelineElement
2264 * Gets the track types that the element can interact with, i.e. the type
2265 * of #GESTrack it can exist in, or will create #GESTrackElement-s for.
2267 * Returns: The track types that @self supports.
2272 ges_timeline_element_get_track_types (GESTimelineElement * self)
2274 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
2275 g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
2278 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
2282 * ges_timeline_element_paste:
2283 * @self: The #GESTimelineElement to paste
2284 * @paste_position: The position in the timeline @element should be pasted
2285 * to, i.e. the #GESTimelineElement:start value for the pasted element.
2287 * Paste an element inside the same timeline and layer as @self. @self
2288 * **must** be the return of ges_timeline_element_copy() with `deep=TRUE`,
2289 * and it should not be changed before pasting.
2290 * @self is not placed in the timeline, instead a new element is created,
2291 * alike to the originally copied element. Note that the originally
2292 * copied element must stay within the same timeline and layer, at both
2293 * the point of copying and pasting.
2295 * Pasting may fail if it would place the timeline in an unsupported
2298 * After calling this function @element should not be used. In particular,
2299 * @element can **not** be pasted again. Instead, you can copy the
2300 * returned element and paste that copy (although, this is only possible
2301 * if the paste was successful).
2303 * See also ges_timeline_paste_element().
2305 * Returns: (transfer full) (nullable): The newly created element, or
2306 * %NULL if pasting fails.
2310 GESTimelineElement *
2311 ges_timeline_element_paste (GESTimelineElement * self,
2312 GstClockTime paste_position)
2314 GESTimelineElement *res;
2315 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2316 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (paste_position), FALSE);
2318 if (!self->priv->copied_from) {
2319 GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
2324 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
2325 GST_ERROR_OBJECT (self, "No paste vmethod implemented");
2330 res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
2331 self->priv->copied_from, paste_position);
2333 g_clear_object (&self->priv->copied_from);
2335 return res ? g_object_ref_sink (res) : res;
2339 * ges_timeline_element_get_layer_priority:
2340 * @self: A #GESTimelineElement
2342 * Gets the priority of the layer the element is in. A #GESGroup may span
2343 * several layers, so this would return the highest priority (numerically,
2344 * the smallest) amongst them.
2346 * Returns: The priority of the layer @self is in, or
2347 * #GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY if @self does not exist in a
2353 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
2355 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
2356 GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
2358 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
2359 return self->priority;
2361 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
2365 * ges_timeline_element_edit_full:
2366 * @self: The #GESTimelineElement to edit
2367 * @new_layer_priority: The priority/index of the layer @self should be
2368 * moved to. -1 means no move
2369 * @mode: The edit mode
2370 * @edge: The edge of @self where the edit should occur
2371 * @position: The edit position: a new location for the edge of @self
2372 * (in nanoseconds) in the timeline coordinates
2373 * @error: (nullable): Return location for an error
2375 * Edits the element within its timeline by adjusting its
2376 * #GESTimelineElement:start, #GESTimelineElement:duration or
2377 * #GESTimelineElement:in-point, and potentially doing the same for
2378 * other elements in the timeline. See #GESEditMode for details about each
2379 * edit mode. An edit may fail if it would place one of these properties
2380 * out of bounds, or if it would place the timeline in an unsupported
2383 * Note that if you act on a #GESTrackElement, this will edit its parent
2384 * #GESClip instead. Moreover, for any #GESTimelineElement, if you select
2385 * #GES_EDGE_NONE for #GES_EDIT_MODE_NORMAL or #GES_EDIT_MODE_RIPPLE, this
2386 * will edit the toplevel instead, but still in such a way as to make the
2387 * #GESTimelineElement:start of @self reach the edit @position.
2389 * Note that if the element's timeline has a
2390 * #GESTimeline:snapping-distance set, then the edit position may be
2391 * snapped to the edge of some element under the edited element.
2393 * @new_layer_priority can be used to switch @self, and other elements
2394 * moved by the edit, to a new layer. New layers may be be created if the
2395 * the corresponding layer priority/index does not yet exist for the
2398 * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2403 ges_timeline_element_edit_full (GESTimelineElement * self,
2404 gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position,
2407 GESTimeline *timeline;
2410 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2411 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), FALSE);
2412 g_return_val_if_fail (!error || !*error, FALSE);
2414 timeline = GES_TIMELINE_ELEMENT_TIMELINE (self);
2415 g_return_val_if_fail (timeline, FALSE);
2417 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self);
2419 if (new_layer_priority < 0)
2420 new_layer_priority = layer_prio;
2422 GST_DEBUG_OBJECT (self, "Editing %s at edge %s to position %"
2423 GST_TIME_FORMAT " under %s mode, and to layer %" G_GINT64_FORMAT,
2424 self->name, ges_edge_name (edge), GST_TIME_ARGS (position),
2425 ges_edit_mode_name (mode), new_layer_priority);
2427 return ges_timeline_edit (timeline, self, new_layer_priority, mode,
2428 edge, position, error);
2432 * ges_timeline_element_edit:
2433 * @self: The #GESTimelineElement to edit
2434 * @layers: (element-type GESLayer) (nullable): A whitelist of layers
2435 * where the edit can be performed, %NULL allows all layers in the
2437 * @new_layer_priority: The priority/index of the layer @self should be
2438 * moved to. -1 means no move
2439 * @mode: The edit mode
2440 * @edge: The edge of @self where the edit should occur
2441 * @position: The edit position: a new location for the edge of @self
2442 * (in nanoseconds) in the timeline coordinates
2444 * See ges_timeline_element_edit_full(), which also gives an error.
2446 * Note that the @layers argument is currently ignored, so you should
2449 * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2454 /* FIXME: handle the layers argument. Currently we always treat it as if
2455 * it is NULL in the ges-timeline code */
2457 ges_timeline_element_edit (GESTimelineElement * self, GList * layers,
2458 gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position)
2460 return ges_timeline_element_edit_full (self, new_layer_priority, mode, edge,
2465 * ges_timeline_element_get_natural_framerate:
2466 * @self: The #GESTimelineElement to get "natural" framerate from
2467 * @framerate_n: (out): The framerate numerator
2468 * @framerate_d: (out): The framerate denominator
2470 * Get the "natural" framerate of @self. This is to say, for example
2471 * for a #GESVideoUriSource the framerate of the source.
2473 * Note that a #GESAudioSource may also have a natural framerate if it derives
2474 * from the same #GESSourceClip asset as a #GESVideoSource, and its value will
2475 * be that of the video source. For example, if the uri of a #GESUriClip points
2476 * to a file that contains both a video and audio stream, then the corresponding
2477 * #GESAudioUriSource will share the natural framerate of the corresponding
2478 * #GESVideoUriSource.
2480 * Returns: Whether @self has a natural framerate or not, @framerate_n
2481 * and @framerate_d will be set to, respectively, 0 and -1 if it is
2487 ges_timeline_element_get_natural_framerate (GESTimelineElement * self,
2488 gint * framerate_n, gint * framerate_d)
2490 GESTimelineElementClass *klass;
2492 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2493 g_return_val_if_fail (framerate_n && framerate_d, FALSE);
2495 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2499 return klass->get_natural_framerate (self, framerate_n, framerate_d);