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 that will be in a way or
23 * another inside a GESTimeline.
25 * The GESTimelineElement base class implements the notion of timing as well
26 * as priority. A GESTimelineElement can have a parent object which will be
27 * responsible for controlling its timing properties.
33 #include "ges-utils.h"
34 #include "ges-timeline-element.h"
35 #include "ges-extractable.h"
36 #include "ges-meta-container.h"
37 #include "ges-internal.h"
38 #include "ges-effect.h"
41 #include <gobject/gvaluecollector.h>
43 /* maps type name quark => count */
44 static GData *object_name_counts = NULL;
47 extractable_set_asset (GESExtractable * extractable, GESAsset * asset)
49 GES_TIMELINE_ELEMENT (extractable)->asset = asset;
53 ges_extractable_interface_init (GESExtractableInterface * iface)
55 iface->set_asset = extractable_set_asset;
79 static guint ges_timeline_element_signals[LAST_SIGNAL] = { 0 };
81 static GParamSpec *properties[PROP_LAST] = { NULL, };
89 struct _GESTimelineElementPrivate
93 /* We keep a link between properties name and elements internally
94 * The hashtable should look like
95 * {GParamaSpec ---> child}*/
96 GHashTable *children_props;
98 GESTimelineElement *copied_from;
100 GESTimelineElementFlags flags;
107 GESTimelineElement *self;
108 } EmitDeepNotifyInIdleData;
110 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GESTimelineElement, ges_timeline_element,
111 G_TYPE_INITIALLY_UNOWNED, G_ADD_PRIVATE (GESTimelineElement)
112 G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE, ges_extractable_interface_init)
113 G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
116 _set_child_property (GESTimelineElement * self G_GNUC_UNUSED, GObject * child,
117 GParamSpec * pspec, GValue * value)
119 g_object_set_property (child, pspec->name, value);
123 _lookup_child (GESTimelineElement * self, const gchar * prop_name,
124 GObject ** child, GParamSpec ** pspec)
128 gchar **names, *name, *classename;
134 names = g_strsplit (prop_name, "::", 2);
135 if (names[1] != NULL) {
136 classename = names[0];
141 g_hash_table_iter_init (&iter, self->priv->children_props);
142 while (g_hash_table_iter_next (&iter, &key, &value)) {
143 if (g_strcmp0 (G_PARAM_SPEC (key)->name, name) == 0) {
144 ChildPropHandler *handler = (ChildPropHandler *) value;
145 if (classename == NULL ||
146 g_strcmp0 (G_OBJECT_TYPE_NAME (G_OBJECT (handler->child)),
148 g_strcmp0 (g_type_name (G_PARAM_SPEC (key)->owner_type),
150 GST_DEBUG_OBJECT (self, "The %s property from %s has been found", name,
153 *child = gst_object_ref (handler->child);
156 *pspec = g_param_spec_ref (key);
168 default_list_children_properties (GESTimelineElement * self,
169 guint * n_properties)
171 GParamSpec **pspec, *spec;
177 *n_properties = g_hash_table_size (self->priv->children_props);
178 pspec = g_new (GParamSpec *, *n_properties);
180 g_hash_table_iter_init (&iter, self->priv->children_props);
181 while (g_hash_table_iter_next (&iter, &key, &value)) {
182 spec = G_PARAM_SPEC (key);
183 pspec[i] = g_param_spec_ref (spec);
191 _get_property (GObject * object, guint property_id,
192 GValue * value, GParamSpec * pspec)
194 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
196 switch (property_id) {
198 g_value_take_object (value, self->parent);
201 g_value_take_object (value, self->timeline);
204 g_value_set_uint64 (value, self->start);
207 g_value_set_uint64 (value, self->inpoint);
210 g_value_set_uint64 (value, self->duration);
212 case PROP_MAX_DURATION:
213 g_value_set_uint64 (value, self->maxduration);
216 g_value_set_uint (value, self->priority);
219 g_value_take_string (value, ges_timeline_element_get_name (self));
222 g_value_set_boolean (value, self->priv->serialize);
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
230 _set_property (GObject * object, guint property_id,
231 const GValue * value, GParamSpec * pspec)
233 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
235 switch (property_id) {
237 ges_timeline_element_set_parent (self, g_value_get_object (value));
240 ges_timeline_element_set_timeline (self, g_value_get_object (value));
243 ges_timeline_element_set_start (self, g_value_get_uint64 (value));
246 ges_timeline_element_set_inpoint (self, g_value_get_uint64 (value));
249 ges_timeline_element_set_duration (self, g_value_get_uint64 (value));
252 ges_timeline_element_set_priority (self, g_value_get_uint (value));
254 case PROP_MAX_DURATION:
255 ges_timeline_element_set_max_duration (self, g_value_get_uint64 (value));
258 ges_timeline_element_set_name (self, g_value_get_string (value));
261 self->priv->serialize = g_value_get_boolean (value);
264 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
269 ges_timeline_element_dispose (GObject * object)
271 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
273 if (self->priv->children_props) {
274 g_hash_table_unref (self->priv->children_props);
275 self->priv->children_props = NULL;
278 g_clear_object (&self->priv->copied_from);
280 G_OBJECT_CLASS (ges_timeline_element_parent_class)->dispose (object);
284 ges_timeline_element_finalize (GObject * self)
286 GESTimelineElement *tle = GES_TIMELINE_ELEMENT (self);
290 G_OBJECT_CLASS (ges_timeline_element_parent_class)->finalize (self);
294 _child_prop_handler_free (ChildPropHandler * handler)
296 g_object_freeze_notify (handler->child);
297 if (handler->handler_id)
298 g_signal_handler_disconnect (handler->child, handler->handler_id);
299 g_object_thaw_notify (handler->child);
300 gst_object_unref (handler->child);
301 g_slice_free (ChildPropHandler, handler);
305 ges_timeline_element_init (GESTimelineElement * self)
307 self->priv = ges_timeline_element_get_instance_private (self);
309 self->priv->serialize = TRUE;
311 self->priv->children_props =
312 g_hash_table_new_full ((GHashFunc) ges_pspec_hash, ges_pspec_equal,
313 (GDestroyNotify) g_param_spec_unref,
314 (GDestroyNotify) _child_prop_handler_free);
318 ges_timeline_element_class_init (GESTimelineElementClass * klass)
320 GObjectClass *object_class = G_OBJECT_CLASS (klass);
322 object_class->get_property = _get_property;
323 object_class->set_property = _set_property;
326 * GESTimelineElement:parent:
328 * The parent container of the object
330 properties[PROP_PARENT] =
331 g_param_spec_object ("parent", "Parent",
332 "The parent container of the object", GES_TYPE_TIMELINE_ELEMENT,
336 * GESTimelineElement:timeline:
338 * The timeline in which @element is
340 properties[PROP_TIMELINE] =
341 g_param_spec_object ("timeline", "Timeline",
342 "The timeline the object is in", GES_TYPE_TIMELINE, G_PARAM_READWRITE);
345 * GESTimelineElement:start:
347 * The position of the object in its container (in nanoseconds).
349 properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
350 "The position in the container", 0, G_MAXUINT64, 0, G_PARAM_READWRITE);
353 * GESTimelineElement:in-point:
355 * The in-point at which this #GESTimelineElement will start outputting data
356 * from its contents (in nanoseconds).
358 * Ex : an in-point of 5 seconds means that the first outputted buffer will
359 * be the one located 5 seconds in the controlled resource.
361 properties[PROP_INPOINT] =
362 g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
363 G_MAXUINT64, 0, G_PARAM_READWRITE);
366 * GESTimelineElement:duration:
368 * The duration (in nanoseconds) which will be used in the container
370 properties[PROP_DURATION] =
371 g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
372 G_MAXUINT64, GST_CLOCK_TIME_NONE, G_PARAM_READWRITE);
375 * GESTimelineElement:max-duration:
377 * The maximum duration (in nanoseconds) of the #GESTimelineElement.
379 properties[PROP_MAX_DURATION] =
380 g_param_spec_uint64 ("max-duration", "Maximum duration",
381 "The maximum duration of the object", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
382 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
385 * GESTimelineElement:priority:
387 * The priority of the object.
389 * Setting GESTimelineElement priorities is deprecated
390 * as all priority management is done by GES itself now.
392 properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
393 "The priority of the object", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
396 * GESTimelineElement:name:
398 * The name of the object
400 properties[PROP_NAME] =
401 g_param_spec_string ("name", "Name", "The name of the timeline object",
402 NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
405 * GESTimelineElement:serialize:
407 * Whether the element should be serialized.
409 properties[PROP_SERIALIZE] = g_param_spec_boolean ("serialize", "Serialize",
410 "Whether the element should be serialized", TRUE,
411 G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
413 g_object_class_install_properties (object_class, PROP_LAST, properties);
416 * GESTimelineElement::deep-notify:
417 * @timeline_element: a #GESTtimelineElement
418 * @prop_object: the object that originated the signal
419 * @prop: the property that changed
421 * The deep notify signal is used to be notified of property changes of all
422 * the childs of @timeline_element
424 ges_timeline_element_signals[DEEP_NOTIFY] =
425 g_signal_new ("deep-notify", G_TYPE_FROM_CLASS (klass),
426 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED |
427 G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic,
428 G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_PARAM);
430 object_class->dispose = ges_timeline_element_dispose;
431 object_class->finalize = ges_timeline_element_finalize;
433 klass->set_parent = NULL;
434 klass->set_start = NULL;
435 klass->set_inpoint = NULL;
436 klass->set_duration = NULL;
437 klass->set_max_duration = NULL;
438 klass->set_priority = NULL;
440 klass->ripple = NULL;
441 klass->ripple_end = NULL;
442 klass->roll_start = NULL;
443 klass->roll_end = NULL;
446 klass->list_children_properties = default_list_children_properties;
447 klass->lookup_child = _lookup_child;
448 klass->set_child_property = _set_child_property;
452 _set_name (GESTimelineElement * self, const gchar * wanted_name)
454 const gchar *type_name;
461 if (!object_name_counts) {
462 g_datalist_init (&object_name_counts);
465 q = g_type_qname (G_OBJECT_TYPE (self));
466 count = GPOINTER_TO_INT (g_datalist_id_get_data (&object_name_counts, q));
468 /* GstFooSink -> foosink<N> */
469 type_name = g_quark_to_string (q);
470 if (strncmp (type_name, "GES", 3) == 0)
473 lowcase_type = g_strdup (type_name);
474 l = strlen (lowcase_type);
475 for (i = 0; i < l; i++)
476 lowcase_type[i] = g_ascii_tolower (lowcase_type[i]);
478 if (wanted_name == NULL) {
479 /* give the 20th "uriclip" element and the first "uriclip2" (if needed in the future)
481 l = strlen (type_name);
482 if (l > 0 && g_ascii_isdigit (type_name[l - 1])) {
483 name = g_strdup_printf ("%s-%d", lowcase_type, count++);
485 name = g_strdup_printf ("%s%d", lowcase_type, count++);
488 /* If the wanted name uses the same 'namespace' as default, make
489 * sure it does not badly interfere with our counting system */
491 if (g_str_has_prefix (wanted_name, lowcase_type)) {
493 g_ascii_strtoull (&wanted_name[strlen (lowcase_type)], NULL, 10);
495 if (tmpcount > count) {
496 count = tmpcount + 1;
497 GST_DEBUG_OBJECT (self, "Using same naming %s but updated count to %i",
499 } else if (tmpcount < count) {
500 name = g_strdup_printf ("%s%d", lowcase_type, count);
502 GST_DEBUG_OBJECT (self, "Name %s already allocated, giving: %s instead"
503 " New count is %i", wanted_name, name, count);
506 GST_DEBUG_OBJECT (self, "Perfect name, just bumping object count");
511 name = g_strdup (wanted_name);
514 g_free (lowcase_type);
515 g_datalist_id_set_data (&object_name_counts, q, GINT_TO_POINTER (count));
521 /*********************************************
522 * API implementation *
523 *********************************************/
526 * ges_timeline_element_set_parent:
527 * @self: a #GESTimelineElement
528 * @parent: new parent of self
530 * Sets the parent of @self to @parent. The parents needs to already
531 * own a hard reference on @self.
533 * Returns: %TRUE if @parent could be set or %FALSE when @self
534 * already had a parent or @self and @parent are the same.
537 ges_timeline_element_set_parent (GESTimelineElement * self,
538 GESTimelineElement * parent)
540 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
541 g_return_val_if_fail (parent == NULL
542 || GES_IS_TIMELINE_ELEMENT (parent), FALSE);
544 if (self == parent) {
545 GST_INFO_OBJECT (self, "Trying to add %p in itself, not a good idea!",
547 gst_object_ref_sink (self);
548 gst_object_unref (self);
552 GST_DEBUG_OBJECT (self, "set parent to %" GST_PTR_FORMAT, parent);
554 if (self->parent != NULL && parent != NULL)
557 if (GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent) {
558 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->set_parent (self, parent))
562 self->parent = parent;
564 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PARENT]);
570 GST_WARNING_OBJECT (self, "set parent failed, object already had a parent");
571 gst_object_ref_sink (self);
572 gst_object_unref (self);
578 * ges_timeline_element_get_parent:
579 * @self: a #GESTimelineElement
581 * Returns the parent of @self. This function increases the refcount
582 * of the parent object so you should gst_object_unref() it after usage.
584 * Returns: (transfer full) (nullable): parent of @self, this can be %NULL if
585 * @self has no parent. unref after usage.
588 ges_timeline_element_get_parent (GESTimelineElement * self)
590 GESTimelineElement *result = NULL;
592 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
594 result = self->parent;
595 if (G_LIKELY (result))
596 gst_object_ref (result);
602 * ges_timeline_element_set_timeline:
603 * @self: a #GESTimelineElement
604 * @timeline: The #GESTimeline @self is in
606 * Sets the timeline of @self to @timeline.
608 * Returns: %TRUE if @timeline could be set or %FALSE when @timeline
609 * already had a timeline.
612 ges_timeline_element_set_timeline (GESTimelineElement * self,
613 GESTimeline * timeline)
615 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
616 g_return_val_if_fail (timeline == NULL || GES_IS_TIMELINE (timeline), FALSE);
618 GST_DEBUG_OBJECT (self, "set timeline to %" GST_PTR_FORMAT, timeline);
620 if (timeline != NULL && G_UNLIKELY (self->timeline != NULL))
623 if (timeline == NULL) {
624 if (self->timeline) {
625 if (!timeline_remove_element (self->timeline, self)) {
626 GST_INFO_OBJECT (self, "Could not remove from"
627 " currently set timeline %" GST_PTR_FORMAT, self->timeline);
632 if (!timeline_add_element (timeline, self)) {
633 GST_INFO_OBJECT (self, "Could not add to timeline %" GST_PTR_FORMAT,
639 self->timeline = timeline;
641 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TIMELINE]);
647 GST_DEBUG_OBJECT (self, "set timeline failed, object already had a "
654 * ges_timeline_element_get_timeline:
655 * @self: a #GESTimelineElement
657 * Returns the timeline of @self. This function increases the refcount
658 * of the timeline so you should gst_object_unref() it after usage.
660 * Returns: (transfer full) (nullable): timeline of @self, this can be %NULL if
661 * @self has no timeline. unref after usage.
664 ges_timeline_element_get_timeline (GESTimelineElement * self)
666 GESTimeline *result = NULL;
668 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
670 result = self->timeline;
671 if (G_LIKELY (result))
672 gst_object_ref (result);
678 * ges_timeline_element_set_start:
679 * @self: a #GESTimelineElement
680 * @start: the position in #GstClockTime
682 * Set the position of the object in its containing layer.
684 * Note that if the snapping-distance property of the timeline containing
685 * @self is set, @self will properly snap to the edges around @start.
687 * Returns: %TRUE if @start could be set.
690 ges_timeline_element_set_start (GESTimelineElement * self, GstClockTime start)
692 GESTimelineElementClass *klass;
693 GESTimelineElement *toplevel_container, *parent;
695 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
697 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
699 GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
700 " new start: %" GST_TIME_FORMAT,
701 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
703 toplevel_container = ges_timeline_element_get_toplevel_parent (self);
704 parent = self->parent;
706 /* FIXME This should not belong to GESTimelineElement */
707 if (toplevel_container &&
708 ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
710 && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
711 GST_INFO_OBJECT (self,
712 "Can not move the object as it would imply its "
713 "container to have a negative start value");
715 gst_object_unref (toplevel_container);
719 gst_object_unref (toplevel_container);
720 if (klass->set_start) {
721 gboolean res = klass->set_start (self, start);
724 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
727 GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
728 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
732 GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
733 " on class %s. Can not set start %" GST_TIME_FORMAT,
734 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
739 * ges_timeline_element_set_inpoint:
740 * @self: a #GESTimelineElement
741 * @inpoint: the in-point in #GstClockTime
743 * Set the in-point, that is the moment at which the @self will start
744 * outputting data from its contents.
746 * Returns: %TRUE if @inpoint could be set.
749 ges_timeline_element_set_inpoint (GESTimelineElement * self,
750 GstClockTime inpoint)
752 GESTimelineElementClass *klass;
754 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
756 GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
757 " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (inpoint),
758 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_INPOINT (self)));
760 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
762 if (klass->set_inpoint) {
763 gboolean res = klass->set_inpoint (self, inpoint);
765 self->inpoint = inpoint;
766 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
772 GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
773 " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
774 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
780 * ges_timeline_element_set_max_duration:
781 * @self: a #GESTimelineElement
782 * @maxduration: the maximum duration in #GstClockTime
784 * Set the maximun duration of the object
786 * Returns: %TRUE if @maxduration could be set.
789 ges_timeline_element_set_max_duration (GESTimelineElement * self,
790 GstClockTime maxduration)
792 GESTimelineElementClass *klass;
794 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
796 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
798 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
799 " new duration: %" GST_TIME_FORMAT,
800 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_MAX_DURATION (self)),
801 GST_TIME_ARGS (maxduration));
803 if (klass->set_max_duration) {
804 if (klass->set_max_duration (self, maxduration) == FALSE)
808 self->maxduration = maxduration;
809 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
814 * ges_timeline_element_set_duration:
815 * @self: a #GESTimelineElement
816 * @duration: the duration in #GstClockTime
818 * Set the duration of the object
820 * Note that if the timeline snap-distance property of the timeline containing
821 * @self is set, @self will properly snap to its neighboors.
823 * Returns: %TRUE if @duration could be set.
826 ges_timeline_element_set_duration (GESTimelineElement * self,
827 GstClockTime duration)
829 GESTimelineElementClass *klass;
831 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
833 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
835 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
836 " new duration: %" GST_TIME_FORMAT,
837 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
838 GST_TIME_ARGS (duration));
840 if (klass->set_duration) {
841 gboolean res = klass->set_duration (self, duration);
843 self->duration = duration;
844 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
850 GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
851 " on class %s. Can not set duration %" GST_TIME_FORMAT,
852 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
857 * ges_timeline_element_get_start:
858 * @self: a #GESTimelineElement
860 * Returns: The @start of @self
863 ges_timeline_element_get_start (GESTimelineElement * self)
865 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
871 * ges_timeline_element_get_inpoint:
872 * @self: a #GESTimelineElement
874 * Returns: The @inpoint of @self
877 ges_timeline_element_get_inpoint (GESTimelineElement * self)
879 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
881 return self->inpoint;
885 * ges_timeline_element_get_duration:
886 * @self: a #GESTimelineElement
888 * Returns: The @duration of @self
891 ges_timeline_element_get_duration (GESTimelineElement * self)
893 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
895 return self->duration;
899 * ges_timeline_element_get_max_duration:
900 * @self: a #GESTimelineElement
902 * Returns: The @maxduration of @self
905 ges_timeline_element_get_max_duration (GESTimelineElement * self)
907 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
909 return self->maxduration;
913 * ges_timeline_element_get_priority:
914 * @self: a #GESTimelineElement
916 * Returns: The @priority of @self
919 ges_timeline_element_get_priority (GESTimelineElement * self)
921 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
923 return self->priority;
927 * ges_timeline_element_set_priority:
928 * @self: a #GESTimelineElement
929 * @priority: the priority
931 * Sets the priority of the object within the containing layer
933 * Deprecated: All priority management is done by GES itself now.
934 * To set #GESEffect priorities #ges_clip_set_top_effect_index should
937 * Returns: %TRUE if @priority could be set.
940 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
942 GESTimelineElementClass *klass;
944 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
946 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
948 GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
949 self->priority, priority);
951 if (klass->set_priority) {
952 gboolean res = klass->set_priority (self, priority);
954 self->priority = priority;
955 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
961 GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
962 " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
968 * ges_timeline_element_ripple:
969 * @self: The #GESTimelineElement to ripple.
970 * @start: The new start of @self in ripple mode.
972 * Edits @self in ripple mode. It allows you to modify the
973 * start of @self and move the following neighbours accordingly.
974 * This will change the overall timeline duration.
976 * Returns: %TRUE if the self as been rippled properly, %FALSE if an error
980 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
982 GESTimelineElementClass *klass;
984 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
986 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
989 return klass->ripple (self, start);
991 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
992 " on class %s. Can not ripple to %" GST_TIME_FORMAT,
993 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
999 * ges_timeline_element_ripple_end:
1000 * @self: The #GESTimelineElement to ripple.
1001 * @end: The new end (start + duration) of @self in ripple mode. It will
1002 * basically only change the duration of @self.
1004 * Edits @self in ripple mode. It allows you to modify the
1005 * duration of a @self and move the following neighbours accordingly.
1006 * This will change the overall timeline duration.
1008 * Returns: %TRUE if the self as been rippled properly, %FALSE if an error
1012 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1014 GESTimelineElementClass *klass;
1016 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1018 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1020 if (klass->ripple_end) {
1021 return klass->ripple_end (self, end);
1024 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1025 " on class %s. Can not ripple end to %" GST_TIME_FORMAT,
1026 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (end));
1032 * ges_timeline_element_roll_start:
1033 * @self: The #GESTimelineElement to roll
1034 * @start: The new start of @self in roll mode, it will also adapat
1035 * the in-point of @self according
1037 * Edits @self in roll mode. It allows you to modify the
1038 * start and inpoint of a @self and "resize" (basicly change the duration
1039 * in this case) of the previous neighbours accordingly.
1040 * This will not change the overall timeline duration.
1042 * Returns: %TRUE if the self as been roll properly, %FALSE if an error
1046 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1048 GESTimelineElementClass *klass;
1050 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1052 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1054 if (klass->roll_start) {
1055 return klass->roll_start (self, start);
1058 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1059 " on class %s. Can not roll to %" GST_TIME_FORMAT,
1060 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1066 * ges_timeline_element_roll_end:
1067 * @self: The #GESTimelineElement to roll.
1068 * @end: The new end (start + duration) of @self in roll mode
1070 * Edits @self in roll mode. It allows you to modify the
1071 * duration of a @self and trim (basicly change the start + inpoint
1072 * in this case) the following neighbours accordingly.
1073 * This will not change the overall timeline duration.
1075 * Returns: %TRUE if the self as been rolled properly, %FALSE if an error
1079 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1081 GESTimelineElementClass *klass;
1083 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1085 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1087 if (klass->roll_end)
1088 return klass->roll_end (self, end);
1090 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1091 " on class %s. Can not roll end to %" GST_TIME_FORMAT,
1092 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (end));
1098 * ges_timeline_element_trim:
1099 * @self: The #GESTimelineElement to trim.
1100 * @start: The new start of @self in trim mode, will adapt the inpoint
1101 * of @self accordingly
1103 * Edits @self in trim mode. It allows you to modify the
1104 * inpoint and start of @self.
1105 * This will not change the overall timeline duration.
1107 * Note that to trim the end of an self you can just set its duration. The same way
1108 * as this method, it will take into account the snapping-distance property of the
1109 * timeline in which @self is.
1111 * Returns: %TRUE if the self as been trimmed properly, %FALSE if an error
1115 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1117 GESTimelineElementClass *klass;
1119 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1121 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1124 return klass->trim (self, start);
1126 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1127 " on class %s. Can not trim to %" GST_TIME_FORMAT,
1128 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1134 * ges_timeline_element_copy:
1135 * @self: The #GESTimelineElement to copy
1136 * @deep: whether we want to create the elements @self contains or not
1140 * Returns: (transfer floating): The newly create #GESTimelineElement, copied from @self
1142 GESTimelineElement *
1143 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1148 GESTimelineElementClass *klass;
1149 guint n, n_specs, n_params;
1151 GESTimelineElement *ret = NULL;
1153 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1155 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1157 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1158 params = g_new0 (GParameter, n_specs);
1161 for (n = 0; n < n_specs; ++n) {
1162 /* We do not want the timeline or the name to be copied */
1163 if (g_strcmp0 (specs[n]->name, "parent") &&
1164 g_strcmp0 (specs[n]->name, "timeline") &&
1165 g_strcmp0 (specs[n]->name, "name") &&
1166 (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
1167 params[n_params].name = g_intern_string (specs[n]->name);
1168 g_value_init (¶ms[n_params].value, specs[n]->value_type);
1169 g_object_get_property (G_OBJECT (self), specs[n]->name,
1170 ¶ms[n_params].value);
1175 #if GLIB_CHECK_VERSION(2, 53, 1)
1179 const gchar **names;
1180 values = g_malloc0 (sizeof (GValue) * n_specs);
1181 names = g_malloc0 (sizeof (gchar *) * n_specs);
1183 for (i = 0; i < n_params; i++) {
1184 values[i] = params[i].value;
1185 names[i] = params[i].name;
1189 GES_TIMELINE_ELEMENT (g_object_new_with_properties (G_OBJECT_TYPE
1190 (self), n_params, names, values));
1195 ret = g_object_newv (G_OBJECT_TYPE (self), n_params, params);
1199 g_value_unset (¶ms[n_params].value);
1205 asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1207 ges_extractable_set_asset (GES_EXTRACTABLE (ret), asset);
1209 if (klass->deep_copy)
1210 klass->deep_copy (self, ret);
1212 GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1213 " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1217 ret->priv->copied_from = gst_object_ref (self);
1224 * ges_timeline_element_get_toplevel_parent:
1225 * @self: The #GESTimelineElement to get the toplevel parent from
1227 * Gets the toplevel #GESTimelineElement controlling @self
1229 * Returns: (transfer full): The toplevel controlling parent of @self
1231 GESTimelineElement *
1232 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1234 GESTimelineElement *toplevel = self;
1236 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1238 while (GES_TIMELINE_ELEMENT_PARENT (toplevel))
1239 toplevel = GES_TIMELINE_ELEMENT_PARENT (toplevel);
1241 return gst_object_ref (toplevel);
1245 * ges_timeline_element_get_name:
1246 * @self: a #GESTimelineElement
1248 * Returns a copy of the name of @self.
1249 * Caller should g_free() the return value after usage.
1251 * Returns: (transfer full): The name of @self
1254 ges_timeline_element_get_name (GESTimelineElement * self)
1256 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1258 return g_strdup (self->name);
1262 * ges_timeline_element_set_name:
1263 * @self: a #GESTimelineElement
1264 * @name: (allow-none): The name @self should take (if avalaible<)
1266 * Sets the name of object, or gives @self a guaranteed unique name (if name is NULL).
1267 * This function makes a copy of the provided name, so the caller retains ownership
1268 * of the name it sent.
1271 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1273 gboolean result = TRUE, readd_to_timeline = FALSE;
1275 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1277 if (name != NULL && !g_strcmp0 (name, self->name)) {
1278 GST_DEBUG_OBJECT (self, "Same name!");
1282 /* parented objects cannot be renamed */
1283 if (self->timeline != NULL && name) {
1284 GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1287 gst_object_unref (tmp);
1291 timeline_remove_element (self->timeline, self);
1292 readd_to_timeline = TRUE;
1295 _set_name (self, name);
1297 if (readd_to_timeline)
1298 timeline_add_element (self->timeline, self);
1305 GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1312 emit_deep_notify_in_idle (EmitDeepNotifyInIdleData * data)
1314 g_signal_emit (data->self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
1315 data->child, data->arg);
1317 gst_object_unref (data->child);
1318 g_param_spec_unref (data->arg);
1319 gst_object_unref (data->self);
1320 g_slice_free (EmitDeepNotifyInIdleData, data);
1326 child_prop_changed_cb (GObject * child, GParamSpec * arg
1327 G_GNUC_UNUSED, GESTimelineElement * self)
1329 EmitDeepNotifyInIdleData *data;
1331 /* Emit "deep-notify" right away if in main thread */
1332 if (g_main_context_acquire (g_main_context_default ())) {
1333 g_main_context_release (g_main_context_default ());
1334 g_signal_emit (self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
1339 data = g_slice_new (EmitDeepNotifyInIdleData);
1341 data->child = gst_object_ref (child);
1342 data->arg = g_param_spec_ref (arg);
1343 data->self = gst_object_ref (self);
1345 g_idle_add ((GSourceFunc) emit_deep_notify_in_idle, data);
1349 ges_timeline_element_add_child_property (GESTimelineElement * self,
1350 GParamSpec * pspec, GObject * child)
1353 ChildPropHandler *handler;
1355 if (g_hash_table_contains (self->priv->children_props, pspec)) {
1356 GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
1360 GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
1361 child, pspec->name);
1363 signame = g_strconcat ("notify::", pspec->name, NULL);
1364 handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
1365 handler->child = gst_object_ref (child);
1366 handler->handler_id =
1367 g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
1369 g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
1378 * ges_timeline_element_get_child_property_by_pspec:
1379 * @self: a #GESTrackElement
1380 * @pspec: The #GParamSpec that specifies the property you want to get
1381 * @value: (out): return location for the value
1383 * Gets a property of a child of @self.
1386 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1387 GParamSpec * pspec, GValue * value)
1389 ChildPropHandler *handler;
1391 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1393 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1397 g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1403 GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1409 * ges_timeline_element_set_child_property_by_pspec:
1410 * @self: a #GESTimelineElement
1411 * @pspec: The #GParamSpec that specifies the property you want to set
1414 * Sets a property of a child of @self.
1417 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1418 GParamSpec * pspec, const GValue * value)
1420 ChildPropHandler *handler;
1421 GESTimelineElementClass *klass;
1423 g_return_if_fail (GES_IS_TRACK_ELEMENT (self));
1425 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1430 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1431 g_assert (klass->set_child_property);
1432 klass->set_child_property (self, handler->child, pspec, (GValue *) value);
1438 GST_ERROR ("The %s property doesn't exist", pspec->name);
1444 * ges_timeline_element_set_child_property:
1445 * @self: The origin #GESTimelineElement
1446 * @property_name: The name of the property
1449 * Sets a property of a child of @self
1451 * Note that #ges_timeline_element_set_child_property is really
1452 * intended for language bindings, #ges_timeline_element_set_child_properties
1453 * is much more convenient for C programming.
1455 * Returns: %TRUE if the property was set, %FALSE otherwize
1458 ges_timeline_element_set_child_property (GESTimelineElement * self,
1459 const gchar * property_name, const GValue * value)
1462 GESTimelineElementClass *klass;
1465 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1467 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1470 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1471 g_assert (klass->set_child_property);
1472 klass->set_child_property (self, child, pspec, (GValue *) value);
1474 gst_object_unref (child);
1475 g_param_spec_unref (pspec);
1481 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1488 * ges_timeline_element_get_child_property:
1489 * @self: The origin #GESTimelineElement
1490 * @property_name: The name of the property
1491 * @value: (out): return location for the property value, it will
1492 * be initialized if it is initialized with 0
1494 * In general, a copy is made of the property contents and
1495 * the caller is responsible for freeing the memory by calling
1498 * Gets a property of a GstElement contained in @object.
1500 * Note that #ges_timeline_element_get_child_property is really
1501 * intended for language bindings, #ges_timeline_element_get_child_properties
1502 * is much more convenient for C programming.
1504 * Returns: %TRUE if the property was found, %FALSE otherwize
1507 ges_timeline_element_get_child_property (GESTimelineElement * self,
1508 const gchar * property_name, GValue * value)
1513 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1515 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1518 if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1519 g_value_init (value, pspec->value_type);
1521 g_object_get_property (child, pspec->name, value);
1523 gst_object_unref (child);
1524 g_param_spec_unref (pspec);
1530 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1537 * ges_timeline_element_lookup_child:
1538 * @self: object to lookup the property in
1539 * @prop_name: name of the property to look up. You can specify the name of the
1540 * class as such: "ClassName::property-name", to guarantee that you get the
1541 * proper GParamSpec in case various GstElement-s contain the same property
1542 * name. If you don't do so, you will get the first element found, having
1543 * this property and the and the corresponding GParamSpec.
1544 * @child: (out) (allow-none) (transfer full): pointer to a #GstElement that
1545 * takes the real object to set property on
1546 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
1547 * describing the property
1549 * Looks up which @element and @pspec would be effected by the given @name. If various
1550 * contained elements have this property name you will get the first one, unless you
1551 * specify the class name in @name.
1553 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
1554 * case the values for @pspec and @element are not modified. Unref @element after
1558 ges_timeline_element_lookup_child (GESTimelineElement * self,
1559 const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1561 GESTimelineElementClass *class;
1563 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1564 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1565 g_return_val_if_fail (class->lookup_child, FALSE);
1567 return class->lookup_child (self, prop_name, child, pspec);
1571 * ges_timeline_element_set_child_property_valist:
1572 * @self: The #GESTimelineElement parent object
1573 * @first_property_name: The name of the first property to set
1574 * @var_args: value for the first property, followed optionally by more
1575 * name/return location pairs, followed by NULL
1577 * Sets a property of a child of @self. If there are various child elements
1578 * that have the same property name, you can distinguish them using the following
1579 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1580 * corresponding property of the first element found will be set.
1583 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
1584 const gchar * first_property_name, va_list var_args)
1590 gchar *error = NULL;
1591 GValue value = { 0, };
1593 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1595 name = first_property_name;
1597 /* Note: This part is in big part copied from the gst_child_object_set_valist
1600 /* iterate over pairs */
1602 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
1605 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
1606 G_VALUE_NOCOPY_CONTENTS, &error);
1611 g_object_set_property (child, pspec->name, &value);
1613 gst_object_unref (child);
1614 g_param_spec_unref (pspec);
1615 g_value_unset (&value);
1617 name = va_arg (var_args, gchar *);
1623 GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
1628 GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
1631 gst_object_unref (child);
1632 g_param_spec_unref (pspec);
1633 g_value_unset (&value);
1639 * ges_timeline_element_set_child_properties:
1640 * @self: The #GESTimelineElement parent object
1641 * @first_property_name: The name of the first property to set
1642 * @...: value for the first property, followed optionally by more
1643 * name/return location pairs, followed by NULL
1645 * Sets a property of a child of @self. If there are various child elements
1646 * that have the same property name, you can distinguish them using the following
1647 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1648 * corresponding property of the first element found will be set.
1651 ges_timeline_element_set_child_properties (GESTimelineElement * self,
1652 const gchar * first_property_name, ...)
1656 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1658 va_start (var_args, first_property_name);
1659 ges_timeline_element_set_child_property_valist (self, first_property_name,
1665 * ges_timeline_element_get_child_property_valist:
1666 * @self: The #GESTimelineElement parent object
1667 * @first_property_name: The name of the first property to get
1668 * @var_args: value for the first property, followed optionally by more
1669 * name/return location pairs, followed by NULL
1671 * Gets a property of a child of @self. If there are various child elements
1672 * that have the same property name, you can distinguish them using the following
1673 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1674 * corresponding property of the first element found will be set.
1677 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
1678 const gchar * first_property_name, va_list var_args)
1681 gchar *error = NULL;
1682 GValue value = { 0, };
1686 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1688 name = first_property_name;
1690 /* This part is in big part copied from the gst_child_object_get_valist method */
1692 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
1695 g_value_init (&value, pspec->value_type);
1696 g_object_get_property (child, pspec->name, &value);
1697 gst_object_unref (child);
1698 g_param_spec_unref (pspec);
1700 G_VALUE_LCOPY (&value, var_args, 0, &error);
1703 g_value_unset (&value);
1704 name = va_arg (var_args, gchar *);
1710 GST_WARNING_OBJECT (self, "no child property %s", name);
1715 GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
1718 g_value_unset (&value);
1724 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
1726 return g_strcmp0 ((*a)->name, (*b)->name);
1731 * ges_timeline_element_list_children_properties:
1732 * @self: The #GESTimelineElement to get the list of children properties from
1733 * @n_properties: (out): return location for the length of the returned array
1735 * Gets an array of #GParamSpec* for all configurable properties of the
1736 * children of @self.
1738 * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or
1739 * %NULL if something went wrong
1742 ges_timeline_element_list_children_properties (GESTimelineElement * self,
1743 guint * n_properties)
1746 GESTimelineElementClass *class;
1748 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1750 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1752 if (!class->list_children_properties) {
1753 GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
1754 G_OBJECT_TYPE_NAME (self));
1760 ret = class->list_children_properties (self, n_properties);
1761 g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
1762 (GCompareDataFunc) compare_gparamspec, NULL);
1768 * ges_timeline_element_get_child_properties:
1769 * @self: The origin #GESTimelineElement
1770 * @first_property_name: The name of the first property to get
1771 * @...: return location for the first property, followed optionally by more
1772 * name/return location pairs, followed by NULL
1774 * Gets properties of a child of @self.
1777 ges_timeline_element_get_child_properties (GESTimelineElement * self,
1778 const gchar * first_property_name, ...)
1782 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1784 va_start (var_args, first_property_name);
1785 ges_timeline_element_get_child_property_valist (self, first_property_name,
1791 ges_timeline_element_remove_child_property (GESTimelineElement * self,
1794 return g_hash_table_remove (self->priv->children_props, pspec);
1798 * ges_timeline_element_get_track_types:
1799 * @self: A #GESTimelineElement
1801 * Gets all the TrackTypes @self will interact with
1806 ges_timeline_element_get_track_types (GESTimelineElement * self)
1808 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1809 g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
1812 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
1816 * ges_timeline_element_paste:
1817 * @self: The #GESTimelineElement to paste
1818 * @paste_position: The position in the timeline the element should
1819 * be copied to, meaning it will become the start of @self
1821 * Paste @self inside the timeline. @self must have been created
1822 * using ges_timeline_element_copy with recurse=TRUE set,
1823 * otherwise it will fail.
1825 * Returns: (transfer none): Paste @self copying the element
1829 GESTimelineElement *
1830 ges_timeline_element_paste (GESTimelineElement * self,
1831 GstClockTime paste_position)
1833 GESTimelineElement *res;
1834 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1836 if (!self->priv->copied_from) {
1837 GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
1842 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
1843 GST_ERROR_OBJECT (self, "No paste vmethod implemented");
1848 res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
1849 self->priv->copied_from, paste_position);
1851 g_clear_object (&self->priv->copied_from);
1853 return g_object_ref (res);
1857 * ges_timeline_element_get_layer_priority:
1858 * @self: A #GESTimelineElement
1860 * Returns: The priority of the first layer the element is in (note that only
1861 * groups can span over several layers). %GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY
1862 * means that the element is not in a layer.
1865 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
1867 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
1868 GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
1870 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
1871 return self->priority;
1873 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
1878 ges_timeline_element_get_media_duration_factor (GESTimelineElement * self)
1880 gdouble media_duration_factor;
1881 GESEffectClass *class;
1884 media_duration_factor = 1.0;
1886 class = GES_EFFECT_CLASS (g_type_class_ref (GES_TYPE_EFFECT));
1888 for (props = class->rate_properties; props != NULL; props = props->next) {
1891 if (ges_timeline_element_lookup_child (self, props->data, &child, &pspec)) {
1892 if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_FLOAT) {
1894 g_object_get (child, pspec->name, &rate_change, NULL);
1895 media_duration_factor *= rate_change;
1896 } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_DOUBLE) {
1897 gdouble rate_change;
1898 g_object_get (child, pspec->name, &rate_change, NULL);
1899 media_duration_factor *= rate_change;
1901 GST_WARNING_OBJECT (self,
1902 "Rate property %s in child %" GST_PTR_FORMAT
1903 " is of unsupported type %s", pspec->name, child,
1904 G_VALUE_TYPE_NAME (pspec->value_type));
1907 gst_object_unref (child);
1908 g_param_spec_unref (pspec);
1910 GST_DEBUG_OBJECT (self,
1911 "Added rate changing property %s, set to value %lf",
1912 (const char *) props->data, media_duration_factor);
1916 g_type_class_unref (class);
1917 return media_duration_factor;
1921 GESTimelineElement *
1922 ges_timeline_element_get_copied_from (GESTimelineElement * self)
1924 GESTimelineElement *copied_from = self->priv->copied_from;
1925 self->priv->copied_from = NULL;
1929 GESTimelineElementFlags
1930 ges_timeline_element_flags (GESTimelineElement * self)
1932 return self->priv->flags;
1936 ges_timeline_element_set_flags (GESTimelineElement * self,
1937 GESTimelineElementFlags flags)
1939 self->priv->flags = flags;