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);
1086 if (self->start == start)
1089 GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
1090 " new start: %" GST_TIME_FORMAT,
1091 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
1093 if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1094 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_NORMAL,
1095 GES_EDGE_NONE, start);
1097 toplevel_container = ges_timeline_element_peak_toplevel (self);
1098 parent = self->parent;
1100 /* FIXME This should not belong to GESTimelineElement */
1101 /* only check if no timeline, otherwise the timeline-tree will handle this
1103 if (!self->timeline && toplevel_container &&
1104 ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
1106 && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
1107 GST_INFO_OBJECT (self,
1108 "Can not move the object as it would imply its "
1109 "container to have a negative start value");
1114 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1115 if (klass->set_start) {
1116 gint res = klass->set_start (self, start);
1120 self->start = start;
1121 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
1124 GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
1125 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
1130 GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
1131 " on class %s. Can not set start %" GST_TIME_FORMAT,
1132 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1137 * ges_timeline_element_set_inpoint:
1138 * @self: A #GESTimelineElement
1139 * @inpoint: The in-point, in internal time coordinates
1141 * Sets #GESTimelineElement:in-point for the element. If the new in-point
1142 * is above the current #GESTimelineElement:max-duration of the element,
1143 * this method will fail.
1145 * Returns: %TRUE if @inpoint could be set for @self.
1148 ges_timeline_element_set_inpoint (GESTimelineElement * self,
1149 GstClockTime inpoint)
1151 GESTimelineElementClass *klass;
1153 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1155 GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
1156 " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (self->inpoint),
1157 GST_TIME_ARGS (inpoint));
1159 if (G_UNLIKELY (inpoint == self->inpoint))
1162 if (GES_CLOCK_TIME_IS_LESS (self->maxduration, inpoint)) {
1163 GST_WARNING_OBJECT (self, "Can not set an in-point of %" GST_TIME_FORMAT
1164 " because it exceeds the element's max-duration: %" GST_TIME_FORMAT,
1165 GST_TIME_ARGS (inpoint), GST_TIME_ARGS (self->maxduration));
1169 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1171 if (klass->set_inpoint) {
1172 /* FIXME: Could we instead use g_object_freeze_notify() to prevent
1173 * duplicate notify signals? Rather than relying on the return value
1174 * being -1 for setting that succeeds but does not want a notify
1175 * signal because it will call this method on itself a second time. */
1176 if (!klass->set_inpoint (self, inpoint))
1179 self->inpoint = inpoint;
1180 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
1185 GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
1186 " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
1187 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
1193 * ges_timeline_element_set_max_duration:
1194 * @self: A #GESTimelineElement
1195 * @maxduration: The maximum duration, in internal time coordinates
1197 * Sets #GESTimelineElement:max-duration for the element. If the new
1198 * maximum duration is below the current #GESTimelineElement:in-point of
1199 * the element, this method will fail.
1201 * Returns: %TRUE if @maxduration could be set for @self.
1204 ges_timeline_element_set_max_duration (GESTimelineElement * self,
1205 GstClockTime maxduration)
1207 GESTimelineElementClass *klass;
1209 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1211 GST_DEBUG_OBJECT (self, "current max-duration: %" GST_TIME_FORMAT
1212 " new max-duration: %" GST_TIME_FORMAT,
1213 GST_TIME_ARGS (self->maxduration), GST_TIME_ARGS (maxduration));
1215 if (G_UNLIKELY (maxduration == self->maxduration))
1218 if (GES_CLOCK_TIME_IS_LESS (maxduration, self->inpoint)) {
1219 GST_WARNING_OBJECT (self, "Can not set a max-duration of %"
1220 GST_TIME_FORMAT " because it lies below the element's in-point: %"
1221 GST_TIME_FORMAT, GST_TIME_ARGS (maxduration),
1222 GST_TIME_ARGS (self->inpoint));
1226 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1228 if (klass->set_max_duration) {
1229 if (!klass->set_max_duration (self, maxduration))
1231 self->maxduration = maxduration;
1232 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
1237 GST_DEBUG_OBJECT (self, "No set_max_duration virtual method implementation"
1238 " on class %s. Can not set max-duration %" GST_TIME_FORMAT,
1239 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (maxduration));
1245 * ges_timeline_element_set_duration:
1246 * @self: A #GESTimelineElement
1247 * @duration: The desired duration in its timeline
1249 * Sets #GESTimelineElement:duration for the element.
1251 * Whilst the element is part of a #GESTimeline, this is the same as
1252 * editing the element with ges_timeline_element_edit() under
1253 * #GES_EDIT_MODE_TRIM with #GES_EDGE_END. In particular, the
1254 * #GESTimelineElement:duration of the element may be snapped to a
1255 * different timeline time difference from the one given. In addition,
1256 * setting may fail if it would place the timeline in an unsupported
1257 * configuration, or the element does not have enough internal content to
1258 * last the desired duration.
1260 * Returns: %TRUE if @duration could be set for @self.
1263 ges_timeline_element_set_duration (GESTimelineElement * self,
1264 GstClockTime duration)
1266 GESTimelineElementClass *klass;
1268 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1270 if (duration == self->duration)
1273 if (self->timeline && !GES_TIMELINE_ELEMENT_BEING_EDITED (self))
1274 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1275 GES_EDGE_END, self->start + duration);
1277 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
1278 " new duration: %" GST_TIME_FORMAT,
1279 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
1280 GST_TIME_ARGS (duration));
1282 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1283 if (klass->set_duration) {
1284 gint res = klass->set_duration (self, duration);
1288 self->duration = duration;
1289 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
1295 GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
1296 " on class %s. Can not set duration %" GST_TIME_FORMAT,
1297 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
1302 * ges_timeline_element_get_start:
1303 * @self: A #GESTimelineElement
1305 * Gets the #GESTimelineElement:start for the element.
1307 * Returns: The start of @self (in nanoseconds).
1310 ges_timeline_element_get_start (GESTimelineElement * self)
1312 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1318 * ges_timeline_element_get_inpoint:
1319 * @self: A #GESTimelineElement
1321 * Gets the #GESTimelineElement:in-point for the element.
1323 * Returns: The in-point of @self (in nanoseconds).
1326 ges_timeline_element_get_inpoint (GESTimelineElement * self)
1328 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1330 return self->inpoint;
1334 * ges_timeline_element_get_duration:
1335 * @self: A #GESTimelineElement
1337 * Gets the #GESTimelineElement:duration for the element.
1339 * Returns: The duration of @self (in nanoseconds).
1342 ges_timeline_element_get_duration (GESTimelineElement * self)
1344 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1346 return self->duration;
1350 * ges_timeline_element_get_max_duration:
1351 * @self: A #GESTimelineElement
1353 * Gets the #GESTimelineElement:max-duration for the element.
1355 * Returns: The max-duration of @self (in nanoseconds).
1358 ges_timeline_element_get_max_duration (GESTimelineElement * self)
1360 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
1362 return self->maxduration;
1366 * ges_timeline_element_get_priority:
1367 * @self: A #GESTimelineElement
1369 * Gets the #GESTimelineElement:priority for the element.
1371 * Returns: The priority of @self.
1374 ges_timeline_element_get_priority (GESTimelineElement * self)
1376 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1378 return self->priority;
1382 * ges_timeline_element_set_priority:
1383 * @self: A #GESTimelineElement
1384 * @priority: The priority
1386 * Sets the priority of the element within the containing layer.
1388 * Deprecated:1.10: All priority management is done by GES itself now.
1389 * To set #GESEffect priorities #ges_clip_set_top_effect_index should
1392 * Returns: %TRUE if @priority could be set for @self.
1395 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
1397 GESTimelineElementClass *klass;
1399 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1401 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1403 GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
1404 self->priority, priority);
1406 if (klass->set_priority) {
1407 gboolean res = klass->set_priority (self, priority);
1409 self->priority = priority;
1410 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
1416 GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
1417 " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
1423 * ges_timeline_element_ripple:
1424 * @self: The #GESTimelineElement to ripple
1425 * @start: The new start time of @self in ripple mode
1427 * Edits the start time of an element within its timeline in ripple mode.
1428 * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1431 * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1435 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
1437 GESTimelineElementClass *klass;
1439 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1441 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1444 return klass->ripple (self, start);
1446 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1447 GES_EDGE_NONE, start);
1453 * ges_timeline_element_ripple_end:
1454 * @self: The #GESTimelineElement to ripple
1455 * @end: The new end time of @self in ripple mode
1457 * Edits the end time of an element within its timeline in ripple mode.
1458 * See ges_timeline_element_edit() with #GES_EDIT_MODE_RIPPLE and
1461 * Returns: %TRUE if the ripple edit of @self completed, %FALSE on
1465 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1467 GESTimelineElementClass *klass;
1469 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1471 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1473 if (klass->ripple_end)
1474 return klass->ripple_end (self, end);
1476 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_RIPPLE,
1481 * ges_timeline_element_roll_start:
1482 * @self: The #GESTimelineElement to roll
1483 * @start: The new start time of @self in roll mode
1485 * Edits the start time of an element within its timeline in roll mode.
1486 * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1489 * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1492 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1494 GESTimelineElementClass *klass;
1496 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1498 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1500 if (klass->roll_start)
1501 return klass->roll_start (self, start);
1503 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1504 GES_EDGE_START, start);
1508 * ges_timeline_element_roll_end:
1509 * @self: The #GESTimelineElement to roll
1510 * @end: The new end time of @self in roll mode
1512 * Edits the end time of an element within its timeline in roll mode.
1513 * See ges_timeline_element_edit() with #GES_EDIT_MODE_ROLL and
1516 * Returns: %TRUE if the roll edit of @self completed, %FALSE on failure.
1519 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1521 GESTimelineElementClass *klass;
1523 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1525 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1527 if (klass->roll_end)
1528 return klass->roll_end (self, end);
1530 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_ROLL,
1535 * ges_timeline_element_trim:
1536 * @self: The #GESTimelineElement to trim
1537 * @start: The new start time of @self in trim mode
1539 * Edits the start time of an element within its timeline in trim mode.
1540 * See ges_timeline_element_edit() with #GES_EDIT_MODE_TRIM and
1543 * Returns: %TRUE if the trim edit of @self completed, %FALSE on failure.
1546 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1548 GESTimelineElementClass *klass;
1550 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1552 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1555 return klass->trim (self, start);
1557 return ges_timeline_element_edit (self, NULL, -1, GES_EDIT_MODE_TRIM,
1558 GES_EDGE_START, start);
1562 * ges_timeline_element_copy:
1563 * @self: The #GESTimelineElement to copy
1564 * @deep: Whether the copy is needed for pasting
1566 * Create a copy of @self. All the properties of @self are copied into
1567 * a new element, with the exception of #GESTimelineElement:parent,
1568 * #GESTimelineElement:timeline and #GESTimelineElement:name. Other data,
1569 * such the list of a #GESContainer's children, is **not** copied.
1571 * If @deep is %TRUE, then the new element is prepared so that it can be
1572 * used in ges_timeline_element_paste() or ges_timeline_paste_element().
1573 * In the case of copying a #GESContainer, this ensures that the children
1574 * of @self will also be pasted. The new element should not be used for
1575 * anything else and can only be used **once** in a pasting operation. In
1576 * particular, the new element itself is not an actual 'deep' copy of
1577 * @self, but should be thought of as an intermediate object used for a
1578 * single paste operation.
1580 * Returns: (transfer floating): The newly create element,
1581 * copied from @self.
1583 G_GNUC_BEGIN_IGNORE_DEPRECATIONS; /* Start ignoring GParameter deprecation */
1584 GESTimelineElement *
1585 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1589 GESTimelineElementClass *klass;
1592 GESTimelineElement *ret = NULL;
1594 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1596 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1598 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1600 asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1602 ret = GES_TIMELINE_ELEMENT (ges_asset_extract (asset, NULL));
1603 for (n = 0; n < n_specs; ++n) {
1604 /* We do not want the timeline or the name to be copied */
1605 if (g_strcmp0 (specs[n]->name, "parent") &&
1606 g_strcmp0 (specs[n]->name, "timeline") &&
1607 g_strcmp0 (specs[n]->name, "name") &&
1608 (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
1609 (specs[n]->flags & G_PARAM_CONSTRUCT_ONLY) == 0) {
1610 GValue v = G_VALUE_INIT;
1611 g_value_init (&v, specs[n]->value_type);
1612 g_object_get_property (G_OBJECT (self), specs[n]->name, &v);
1614 g_object_set_property (G_OBJECT (ret), specs[n]->name, &v);
1621 if (klass->deep_copy)
1622 klass->deep_copy (self, ret);
1624 GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1625 " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1629 ret->priv->copied_from = gst_object_ref (self);
1635 G_GNUC_END_IGNORE_DEPRECATIONS; /* End ignoring GParameter deprecation */
1638 * ges_timeline_element_get_toplevel_parent:
1639 * @self: The #GESTimelineElement to get the toplevel parent from
1641 * Gets the toplevel #GESTimelineElement:parent of the element.
1643 * Returns: (transfer full): The toplevel parent of @self.
1645 GESTimelineElement *
1646 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1648 GESTimelineElement *toplevel;
1650 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1652 toplevel = ges_timeline_element_peak_toplevel (self);
1654 return gst_object_ref (toplevel);
1658 * ges_timeline_element_get_name:
1659 * @self: A #GESTimelineElement
1661 * Gets the #GESTimelineElement:name for the element.
1663 * Returns: (transfer full): The name of @self.
1666 ges_timeline_element_get_name (GESTimelineElement * self)
1668 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1670 return g_strdup (self->name);
1674 * ges_timeline_element_set_name:
1675 * @self: A #GESTimelineElement
1676 * @name: (allow-none): The name @self should take
1678 * Sets the #GESTimelineElement:name for the element. If %NULL is given
1679 * for @name, then the library will instead generate a new name based on
1680 * the type name of the element, such as the name "uriclip3" for a
1681 * #GESUriClip, and will set that name instead.
1683 * If @self already has a #GESTimelineElement:timeline, you should not
1684 * call this function with @name set to %NULL.
1686 * You should ensure that, within each #GESTimeline, every element has a
1687 * unique name. If you call this function with @name as %NULL, then
1688 * the library should ensure that the set generated name is unique from
1689 * previously **generated** names. However, if you choose a @name that
1690 * interferes with the naming conventions of the library, the library will
1691 * attempt to ensure that the generated names will not conflict with the
1692 * chosen name, which may lead to a different name being set instead, but
1693 * the uniqueness between generated and user-chosen names is not
1696 * Returns: %TRUE if @name or a generated name for @self could be set.
1699 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1701 gboolean result = TRUE, readd_to_timeline = FALSE;
1703 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1705 if (name != NULL && !g_strcmp0 (name, self->name)) {
1706 GST_DEBUG_OBJECT (self, "Same name!");
1710 /* parented objects cannot be renamed */
1711 if (self->timeline != NULL && name) {
1712 GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1714 /* FIXME: if tmp == self then this means that we setting the name of
1715 * self to its existing name. There is no need to throw an error */
1717 gst_object_unref (tmp);
1721 timeline_remove_element (self->timeline, self);
1722 readd_to_timeline = TRUE;
1724 /* FIXME: if self already has a timeline and name is NULL, then it also
1725 * needs to be re-added to the timeline (or, at least its entry in
1726 * timeline->priv->all_elements needs its key to be updated) using the
1727 * new generated name */
1729 _set_name (self, name);
1731 /* FIXME: the set name may not always be unique in a given timeline, see
1732 * _set_name(). This can cause timeline_add_element to fail! */
1733 if (readd_to_timeline)
1734 timeline_add_element (self->timeline, self);
1741 /* FIXME: message is misleading. We are here if some other object in
1742 * the timeline was added under @name (see above) */
1743 GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1750 * ges_timeline_element_add_child_property:
1751 * @self: A #GESTimelineElement
1752 * @pspec: The specification for the property to add
1753 * @child: The #GstObject who the property belongs to
1755 * Register a property of a child of the element to allow it to be
1756 * written with ges_timeline_element_set_child_property() and read with
1757 * ges_timeline_element_get_child_property(). A change in the property
1758 * will also appear in the #GESTimelineElement::deep-notify signal.
1760 * @pspec should be unique from other children properties that have been
1761 * registered on @self.
1763 * Returns: %TRUE if the property was successfully registered.
1766 ges_timeline_element_add_child_property (GESTimelineElement * self,
1767 GParamSpec * pspec, GObject * child)
1769 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1770 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1771 g_return_val_if_fail (G_IS_OBJECT (child), FALSE);
1773 return ges_timeline_element_add_child_property_full (self, NULL, pspec,
1778 * ges_timeline_element_get_child_property_by_pspec:
1779 * @self: A #GESTimelineElement
1780 * @pspec: The specification of a registered child property to get
1781 * @value: (out): The return location for the value
1783 * Gets the property of a child of the element. Specifically, the property
1784 * corresponding to the @pspec used in
1785 * ges_timeline_element_add_child_property() is copied into @value.
1788 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1789 GParamSpec * pspec, GValue * value)
1791 ChildPropHandler *handler;
1793 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1794 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1796 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1800 g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1806 GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1812 * ges_timeline_element_set_child_property_by_pspec:
1813 * @self: A #GESTimelineElement
1814 * @pspec: The specification of a registered child property to set
1815 * @value: The value to set the property to
1817 * Sets the property of a child of the element. Specifically, the property
1818 * corresponding to the @pspec used in
1819 * ges_timeline_element_add_child_property() is set to @value.
1822 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1823 GParamSpec * pspec, const GValue * value)
1825 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1826 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1828 set_child_property_by_pspec (self, pspec, value, NULL);
1832 * ges_timeline_element_set_child_property_full:
1833 * @self: A #GESTimelineElement
1834 * @property_name: The name of the child property to set
1835 * @value: The value to set the property to
1836 * @error: (nullable): Return location for an error
1838 * Sets the property of a child of the element.
1840 * @property_name can either be in the format "prop-name" or
1841 * "TypeName::prop-name", where "prop-name" is the name of the property
1842 * to set (as used in g_object_set()), and "TypeName" is the type name of
1843 * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1844 * useful when two children of different types share the same property
1847 * The first child found with the given "prop-name" property that was
1848 * registered with ges_timeline_element_add_child_property() (and of the
1849 * type "TypeName", if it was given) will have the corresponding
1850 * property set to @value. Other children that may have also matched the
1851 * property name (and type name) are left unchanged!
1853 * Returns: %TRUE if the property was found and set.
1857 ges_timeline_element_set_child_property_full (GESTimelineElement * self,
1858 const gchar * property_name, const GValue * value, GError ** error)
1863 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1864 g_return_val_if_fail (!error || !*error, FALSE);
1866 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1869 return set_child_property_by_pspec (self, pspec, value, error);
1873 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1880 * ges_timeline_element_set_child_property:
1881 * @self: A #GESTimelineElement
1882 * @property_name: The name of the child property to set
1883 * @value: The value to set the property to
1885 * See ges_timeline_element_set_child_property_full(), which also gives an
1888 * Note that ges_timeline_element_set_child_properties() may be more
1889 * convenient for C programming.
1891 * Returns: %TRUE if the property was found and set.
1894 ges_timeline_element_set_child_property (GESTimelineElement * self,
1895 const gchar * property_name, const GValue * value)
1897 return ges_timeline_element_set_child_property_full (self, property_name,
1902 * ges_timeline_element_get_child_property:
1903 * @self: A #GESTimelineElement
1904 * @property_name: The name of the child property to get
1905 * @value: (out): The return location for the value
1907 * Gets the property of a child of the element.
1909 * @property_name can either be in the format "prop-name" or
1910 * "TypeName::prop-name", where "prop-name" is the name of the property
1911 * to get (as used in g_object_get()), and "TypeName" is the type name of
1912 * the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1913 * useful when two children of different types share the same property
1916 * The first child found with the given "prop-name" property that was
1917 * registered with ges_timeline_element_add_child_property() (and of the
1918 * type "TypeName", if it was given) will have the corresponding
1919 * property copied into @value.
1921 * Note that ges_timeline_element_get_child_properties() may be more
1922 * convenient for C programming.
1924 * Returns: %TRUE if the property was found and copied to @value.
1927 ges_timeline_element_get_child_property (GESTimelineElement * self,
1928 const gchar * property_name, GValue * value)
1933 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1935 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1938 /* FIXME: since GLib 2.60, g_object_get_property() will automatically
1939 * initialize the type */
1940 if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1941 g_value_init (value, pspec->value_type);
1943 g_object_get_property (child, pspec->name, value);
1945 gst_object_unref (child);
1946 g_param_spec_unref (pspec);
1952 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1959 * ges_timeline_element_lookup_child:
1960 * @self: A #GESTimelineElement
1961 * @prop_name: The name of a child property
1962 * @child: (out) (optional) (transfer full): The return location for the
1964 * @pspec: (out) (optional) (transfer full): The return location for the
1965 * specification of the child property
1967 * Looks up a child property of the element.
1969 * @prop_name can either be in the format "prop-name" or
1970 * "TypeName::prop-name", where "prop-name" is the name of the property
1971 * to look up (as used in g_object_get()), and "TypeName" is the type name
1972 * of the child (as returned by G_OBJECT_TYPE_NAME()). The latter format is
1973 * useful when two children of different types share the same property
1976 * The first child found with the given "prop-name" property that was
1977 * registered with ges_timeline_element_add_child_property() (and of the
1978 * type "TypeName", if it was given) will be passed to @child, and the
1979 * registered specification of this property will be passed to @pspec.
1981 * Returns: %TRUE if a child corresponding to the property was found, in
1982 * which case @child and @pspec are set.
1985 ges_timeline_element_lookup_child (GESTimelineElement * self,
1986 const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1988 GESTimelineElementClass *class;
1990 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1991 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1992 g_return_val_if_fail (class->lookup_child, FALSE);
1994 return class->lookup_child (self, prop_name, child, pspec);
1998 * ges_timeline_element_set_child_property_valist:
1999 * @self: A #GESTimelineElement
2000 * @first_property_name: The name of the first child property to set
2001 * @var_args: The value for the first property, followed optionally by more
2002 * name/value pairs, followed by %NULL
2004 * Sets several of the children properties of the element. See
2005 * ges_timeline_element_set_child_property().
2008 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
2009 const gchar * first_property_name, va_list var_args)
2014 gchar *error = NULL;
2015 GValue value = { 0, };
2017 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2019 name = first_property_name;
2021 /* Note: This part is in big part copied from the gst_child_object_set_valist
2024 /* iterate over pairs */
2026 if (!ges_timeline_element_lookup_child (self, name, NULL, &pspec))
2029 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
2030 G_VALUE_NOCOPY_CONTENTS, &error);
2035 set_child_property_by_pspec (self, pspec, &value, NULL);
2037 g_param_spec_unref (pspec);
2038 g_value_unset (&value);
2040 name = va_arg (var_args, gchar *);
2046 GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
2051 GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
2054 g_param_spec_unref (pspec);
2055 g_value_unset (&value);
2061 * ges_timeline_element_set_child_properties:
2062 * @self: A #GESTimelineElement
2063 * @first_property_name: The name of the first child property to set
2064 * @...: The value for the first property, followed optionally by more
2065 * name/value pairs, followed by %NULL
2067 * Sets several of the children properties of the element. See
2068 * ges_timeline_element_set_child_property().
2071 ges_timeline_element_set_child_properties (GESTimelineElement * self,
2072 const gchar * first_property_name, ...)
2076 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2078 va_start (var_args, first_property_name);
2079 ges_timeline_element_set_child_property_valist (self, first_property_name,
2085 * ges_timeline_element_get_child_property_valist:
2086 * @self: A #GESTimelineElement
2087 * @first_property_name: The name of the first child property to get
2088 * @var_args: The return location for the first property, followed
2089 * optionally by more name/return location pairs, followed by %NULL
2091 * Gets several of the children properties of the element. See
2092 * ges_timeline_element_get_child_property().
2095 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
2096 const gchar * first_property_name, va_list var_args)
2099 gchar *error = NULL;
2100 GValue value = { 0, };
2104 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2106 name = first_property_name;
2108 /* This part is in big part copied from the gst_child_object_get_valist method */
2110 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
2113 g_value_init (&value, pspec->value_type);
2114 g_object_get_property (child, pspec->name, &value);
2115 gst_object_unref (child);
2116 g_param_spec_unref (pspec);
2118 G_VALUE_LCOPY (&value, var_args, 0, &error);
2121 g_value_unset (&value);
2122 name = va_arg (var_args, gchar *);
2128 GST_WARNING_OBJECT (self, "no child property %s", name);
2133 GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
2136 g_value_unset (&value);
2142 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
2144 return g_strcmp0 ((*a)->name, (*b)->name);
2149 * ges_timeline_element_list_children_properties:
2150 * @self: A #GESTimelineElement
2151 * @n_properties: (out): The return location for the length of the
2154 * Get a list of children properties of the element, which is a list of
2155 * all the specifications passed to
2156 * ges_timeline_element_add_child_property().
2158 * Returns: (transfer full) (array length=n_properties): An array of
2159 * #GParamSpec corresponding to the child properties of @self, or %NULL if
2160 * something went wrong.
2163 ges_timeline_element_list_children_properties (GESTimelineElement * self,
2164 guint * n_properties)
2167 GESTimelineElementClass *class;
2169 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
2171 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2173 if (!class->list_children_properties) {
2174 GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
2175 G_OBJECT_TYPE_NAME (self));
2181 ret = class->list_children_properties (self, n_properties);
2182 g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
2183 (GCompareDataFunc) compare_gparamspec, NULL);
2189 * ges_timeline_element_get_child_properties:
2190 * @self: A #GESTimelineElement
2191 * @first_property_name: The name of the first child property to get
2192 * @...: The return location for the first property, followed
2193 * optionally by more name/return location pairs, followed by %NULL
2195 * Gets several of the children properties of the element. See
2196 * ges_timeline_element_get_child_property().
2199 ges_timeline_element_get_child_properties (GESTimelineElement * self,
2200 const gchar * first_property_name, ...)
2204 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
2206 va_start (var_args, first_property_name);
2207 ges_timeline_element_get_child_property_valist (self, first_property_name,
2213 * ges_timeline_element_remove_child_property:
2214 * @self: A #GESTimelineElement
2215 * @pspec: The specification for the property to remove
2217 * Remove a child property from the element. @pspec should be a
2218 * specification that was passed to
2219 * ges_timeline_element_add_child_property(). The corresponding property
2220 * will no longer be registered as a child property for the element.
2222 * Returns: %TRUE if the property was successfully un-registered for @self.
2225 ges_timeline_element_remove_child_property (GESTimelineElement * self,
2228 gpointer key, value;
2229 GParamSpec *found_pspec;
2230 ChildPropHandler *handler;
2232 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2233 g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2235 if (!g_hash_table_lookup_extended (self->priv->children_props, pspec,
2237 GST_WARNING_OBJECT (self, "No child property with pspec %p (%s) found",
2238 pspec, pspec->name);
2241 g_hash_table_steal (self->priv->children_props, pspec);
2242 found_pspec = G_PARAM_SPEC (key);
2243 handler = (ChildPropHandler *) value;
2245 g_signal_emit (self, ges_timeline_element_signals[CHILD_PROPERTY_REMOVED], 0,
2246 handler->child, found_pspec);
2248 g_param_spec_unref (found_pspec);
2249 _child_prop_handler_free (handler);
2255 * ges_timeline_element_get_track_types:
2256 * @self: A #GESTimelineElement
2258 * Gets the track types that the element can interact with, i.e. the type
2259 * of #GESTrack it can exist in, or will create #GESTrackElement-s for.
2261 * Returns: The track types that @self supports.
2266 ges_timeline_element_get_track_types (GESTimelineElement * self)
2268 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
2269 g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
2272 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
2276 * ges_timeline_element_paste:
2277 * @self: The #GESTimelineElement to paste
2278 * @paste_position: The position in the timeline @element should be pasted
2279 * to, i.e. the #GESTimelineElement:start value for the pasted element.
2281 * Paste an element inside the same timeline and layer as @self. @self
2282 * **must** be the return of ges_timeline_element_copy() with `deep=TRUE`,
2283 * and it should not be changed before pasting.
2284 * @self is not placed in the timeline, instead a new element is created,
2285 * alike to the originally copied element. Note that the originally
2286 * copied element must stay within the same timeline and layer, at both
2287 * the point of copying and pasting.
2289 * Pasting may fail if it would place the timeline in an unsupported
2292 * After calling this function @element should not be used. In particular,
2293 * @element can **not** be pasted again. Instead, you can copy the
2294 * returned element and paste that copy (although, this is only possible
2295 * if the paste was successful).
2297 * See also ges_timeline_paste_element().
2299 * Returns: (transfer full) (nullable): The newly created element, or
2300 * %NULL if pasting fails.
2304 GESTimelineElement *
2305 ges_timeline_element_paste (GESTimelineElement * self,
2306 GstClockTime paste_position)
2308 GESTimelineElement *res;
2309 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2311 if (!self->priv->copied_from) {
2312 GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
2317 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
2318 GST_ERROR_OBJECT (self, "No paste vmethod implemented");
2323 res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
2324 self->priv->copied_from, paste_position);
2326 g_clear_object (&self->priv->copied_from);
2328 return res ? g_object_ref_sink (res) : res;
2332 * ges_timeline_element_get_layer_priority:
2333 * @self: A #GESTimelineElement
2335 * Gets the priority of the layer the element is in. A #GESGroup may span
2336 * several layers, so this would return the highest priority (numerically,
2337 * the smallest) amongst them.
2339 * Returns: The priority of the layer @self is in, or
2340 * #GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY if @self does not exist in a
2346 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
2348 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
2349 GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
2351 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
2352 return self->priority;
2354 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
2358 * ges_timeline_element_edit_full:
2359 * @self: The #GESTimelineElement to edit
2360 * @new_layer_priority: The priority/index of the layer @self should be
2361 * moved to. -1 means no move
2362 * @mode: The edit mode
2363 * @edge: The edge of @self where the edit should occur
2364 * @position: The edit position: a new location for the edge of @self
2365 * (in nanoseconds) in the timeline coordinates
2366 * @error: (nullable): Return location for an error
2368 * Edits the element within its timeline by adjusting its
2369 * #GESTimelineElement:start, #GESTimelineElement:duration or
2370 * #GESTimelineElement:in-point, and potentially doing the same for
2371 * other elements in the timeline. See #GESEditMode for details about each
2372 * edit mode. An edit may fail if it would place one of these properties
2373 * out of bounds, or if it would place the timeline in an unsupported
2376 * Note that if you act on a #GESTrackElement, this will edit its parent
2377 * #GESClip instead. Moreover, for any #GESTimelineElement, if you select
2378 * #GES_EDGE_NONE for #GES_EDIT_MODE_NORMAL or #GES_EDIT_MODE_RIPPLE, this
2379 * will edit the toplevel instead, but still in such a way as to make the
2380 * #GESTimelineElement:start of @self reach the edit @position.
2382 * Note that if the element's timeline has a
2383 * #GESTimeline:snapping-distance set, then the edit position may be
2384 * snapped to the edge of some element under the edited element.
2386 * @new_layer_priority can be used to switch @self, and other elements
2387 * moved by the edit, to a new layer. New layers may be be created if the
2388 * the corresponding layer priority/index does not yet exist for the
2391 * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2396 ges_timeline_element_edit_full (GESTimelineElement * self,
2397 gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position,
2400 GESTimeline *timeline;
2403 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2404 g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (position), FALSE);
2405 g_return_val_if_fail (!error || !*error, FALSE);
2407 timeline = GES_TIMELINE_ELEMENT_TIMELINE (self);
2408 g_return_val_if_fail (timeline, FALSE);
2410 layer_prio = GES_TIMELINE_ELEMENT_LAYER_PRIORITY (self);
2412 if (new_layer_priority < 0)
2413 new_layer_priority = layer_prio;
2415 GST_DEBUG_OBJECT (self, "Editing %s at edge %s to position %"
2416 GST_TIME_FORMAT " under %s mode, and to layer %" G_GINT64_FORMAT,
2417 self->name, ges_edge_name (edge), GST_TIME_ARGS (position),
2418 ges_edit_mode_name (mode), new_layer_priority);
2420 return ges_timeline_edit (timeline, self, new_layer_priority, mode,
2421 edge, position, error);
2425 * ges_timeline_element_edit:
2426 * @self: The #GESTimelineElement to edit
2427 * @layers: (element-type GESLayer) (nullable): A whitelist of layers
2428 * where the edit can be performed, %NULL allows all layers in the
2430 * @new_layer_priority: The priority/index of the layer @self should be
2431 * moved to. -1 means no move
2432 * @mode: The edit mode
2433 * @edge: The edge of @self where the edit should occur
2434 * @position: The edit position: a new location for the edge of @self
2435 * (in nanoseconds) in the timeline coordinates
2437 * See ges_timeline_element_edit_full(), which also gives an error.
2439 * Note that the @layers argument is currently ignored, so you should
2442 * Returns: %TRUE if the edit of @self completed, %FALSE on failure.
2447 /* FIXME: handle the layers argument. Currently we always treat it as if
2448 * it is NULL in the ges-timeline code */
2450 ges_timeline_element_edit (GESTimelineElement * self, GList * layers,
2451 gint64 new_layer_priority, GESEditMode mode, GESEdge edge, guint64 position)
2453 return ges_timeline_element_edit_full (self, new_layer_priority, mode, edge,
2458 * ges_timeline_element_get_natural_framerate:
2459 * @self: The #GESTimelineElement to get "natural" framerate from
2460 * @framerate_n: (out): The framerate numerator
2461 * @framerate_d: (out): The framerate denominator
2463 * Get the "natural" framerate of @self. This is to say, for example
2464 * for a #GESVideoUriSource the framerate of the source.
2466 * Note that a #GESAudioSource may also have a natural framerate if it derives
2467 * from the same #GESSourceClip asset as a #GESVideoSource, and its value will
2468 * be that of the video source. For example, if the uri of a #GESUriClip points
2469 * to a file that contains both a video and audio stream, then the corresponding
2470 * #GESAudioUriSource will share the natural framerate of the corresponding
2471 * #GESVideoUriSource.
2473 * Returns: Whether @self has a natural framerate or not, @framerate_n
2474 * and @framerate_d will be set to, respectively, 0 and -1 if it is
2480 ges_timeline_element_get_natural_framerate (GESTimelineElement * self,
2481 gint * framerate_n, gint * framerate_d)
2483 GESTimelineElementClass *klass;
2485 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
2486 g_return_val_if_fail (framerate_n && framerate_d, FALSE);
2488 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
2492 return klass->get_natural_framerate (self, framerate_n, framerate_d);