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 if (self->start == start)
700 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
702 GST_DEBUG_OBJECT (self, "current start: %" GST_TIME_FORMAT
703 " new start: %" GST_TIME_FORMAT,
704 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)), GST_TIME_ARGS (start));
706 toplevel_container = ges_timeline_element_get_toplevel_parent (self);
707 parent = self->parent;
709 /* FIXME This should not belong to GESTimelineElement */
710 if (toplevel_container &&
711 ((gint64) (_START (toplevel_container) + start - _START (self))) < 0 &&
713 && GES_CONTAINER (parent)->children_control_mode == GES_CHILDREN_UPDATE) {
714 GST_INFO_OBJECT (self,
715 "Can not move the object as it would imply its "
716 "container to have a negative start value");
718 gst_object_unref (toplevel_container);
722 gst_object_unref (toplevel_container);
723 if (klass->set_start) {
724 gboolean res = klass->set_start (self, start);
727 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_START]);
730 GST_DEBUG_OBJECT (self, "New start: %" GST_TIME_FORMAT,
731 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_START (self)));
735 GST_WARNING_OBJECT (self, "No set_start virtual method implementation"
736 " on class %s. Can not set start %" GST_TIME_FORMAT,
737 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
742 * ges_timeline_element_set_inpoint:
743 * @self: a #GESTimelineElement
744 * @inpoint: the in-point in #GstClockTime
746 * Set the in-point, that is the moment at which the @self will start
747 * outputting data from its contents.
749 * Returns: %TRUE if @inpoint could be set.
752 ges_timeline_element_set_inpoint (GESTimelineElement * self,
753 GstClockTime inpoint)
755 GESTimelineElementClass *klass;
757 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
759 GST_DEBUG_OBJECT (self, "current inpoint: %" GST_TIME_FORMAT
760 " new inpoint: %" GST_TIME_FORMAT, GST_TIME_ARGS (inpoint),
761 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_INPOINT (self)));
763 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
765 if (klass->set_inpoint) {
766 gboolean res = klass->set_inpoint (self, inpoint);
768 self->inpoint = inpoint;
769 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INPOINT]);
775 GST_DEBUG_OBJECT (self, "No set_inpoint virtual method implementation"
776 " on class %s. Can not set inpoint %" GST_TIME_FORMAT,
777 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (inpoint));
783 * ges_timeline_element_set_max_duration:
784 * @self: a #GESTimelineElement
785 * @maxduration: the maximum duration in #GstClockTime
787 * Set the maximun duration of the object
789 * Returns: %TRUE if @maxduration could be set.
792 ges_timeline_element_set_max_duration (GESTimelineElement * self,
793 GstClockTime maxduration)
795 GESTimelineElementClass *klass;
797 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
799 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
801 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
802 " new duration: %" GST_TIME_FORMAT,
803 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_MAX_DURATION (self)),
804 GST_TIME_ARGS (maxduration));
806 if (klass->set_max_duration) {
807 if (klass->set_max_duration (self, maxduration) == FALSE)
811 self->maxduration = maxduration;
812 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MAX_DURATION]);
817 * ges_timeline_element_set_duration:
818 * @self: a #GESTimelineElement
819 * @duration: the duration in #GstClockTime
821 * Set the duration of the object
823 * Note that if the timeline snap-distance property of the timeline containing
824 * @self is set, @self will properly snap to its neighboors.
826 * Returns: %TRUE if @duration could be set.
829 ges_timeline_element_set_duration (GESTimelineElement * self,
830 GstClockTime duration)
832 GESTimelineElementClass *klass;
834 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
836 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
838 GST_DEBUG_OBJECT (self, "current duration: %" GST_TIME_FORMAT
839 " new duration: %" GST_TIME_FORMAT,
840 GST_TIME_ARGS (GES_TIMELINE_ELEMENT_DURATION (self)),
841 GST_TIME_ARGS (duration));
843 if (klass->set_duration) {
844 gboolean res = klass->set_duration (self, duration);
846 self->duration = duration;
847 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
853 GST_WARNING_OBJECT (self, "No set_duration virtual method implementation"
854 " on class %s. Can not set duration %" GST_TIME_FORMAT,
855 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (duration));
860 * ges_timeline_element_get_start:
861 * @self: a #GESTimelineElement
863 * Returns: The @start of @self
866 ges_timeline_element_get_start (GESTimelineElement * self)
868 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
874 * ges_timeline_element_get_inpoint:
875 * @self: a #GESTimelineElement
877 * Returns: The @inpoint of @self
880 ges_timeline_element_get_inpoint (GESTimelineElement * self)
882 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
884 return self->inpoint;
888 * ges_timeline_element_get_duration:
889 * @self: a #GESTimelineElement
891 * Returns: The @duration of @self
894 ges_timeline_element_get_duration (GESTimelineElement * self)
896 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
898 return self->duration;
902 * ges_timeline_element_get_max_duration:
903 * @self: a #GESTimelineElement
905 * Returns: The @maxduration of @self
908 ges_timeline_element_get_max_duration (GESTimelineElement * self)
910 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), GST_CLOCK_TIME_NONE);
912 return self->maxduration;
916 * ges_timeline_element_get_priority:
917 * @self: a #GESTimelineElement
919 * Returns: The @priority of @self
922 ges_timeline_element_get_priority (GESTimelineElement * self)
924 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
926 return self->priority;
930 * ges_timeline_element_set_priority:
931 * @self: a #GESTimelineElement
932 * @priority: the priority
934 * Sets the priority of the object within the containing layer
936 * Deprecated: All priority management is done by GES itself now.
937 * To set #GESEffect priorities #ges_clip_set_top_effect_index should
940 * Returns: %TRUE if @priority could be set.
943 ges_timeline_element_set_priority (GESTimelineElement * self, guint32 priority)
945 GESTimelineElementClass *klass;
947 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
949 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
951 GST_DEBUG_OBJECT (self, "current priority: %d new priority: %d",
952 self->priority, priority);
954 if (klass->set_priority) {
955 gboolean res = klass->set_priority (self, priority);
957 self->priority = priority;
958 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIORITY]);
964 GST_WARNING_OBJECT (self, "No set_priority virtual method implementation"
965 " on class %s. Can not set priority %d", G_OBJECT_CLASS_NAME (klass),
971 * ges_timeline_element_ripple:
972 * @self: The #GESTimelineElement to ripple.
973 * @start: The new start of @self in ripple mode.
975 * Edits @self in ripple mode. It allows you to modify the
976 * start of @self and move the following neighbours accordingly.
977 * This will change the overall timeline duration.
979 * Returns: %TRUE if the self as been rippled properly, %FALSE if an error
983 ges_timeline_element_ripple (GESTimelineElement * self, GstClockTime start)
985 GESTimelineElementClass *klass;
987 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
989 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
992 return klass->ripple (self, start);
994 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
995 " on class %s. Can not ripple to %" GST_TIME_FORMAT,
996 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1002 * ges_timeline_element_ripple_end:
1003 * @self: The #GESTimelineElement to ripple.
1004 * @end: The new end (start + duration) of @self in ripple mode. It will
1005 * basically only change the duration of @self.
1007 * Edits @self in ripple mode. It allows you to modify the
1008 * duration of a @self and move the following neighbours accordingly.
1009 * This will change the overall timeline duration.
1011 * Returns: %TRUE if the self as been rippled properly, %FALSE if an error
1015 ges_timeline_element_ripple_end (GESTimelineElement * self, GstClockTime end)
1017 GESTimelineElementClass *klass;
1019 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1021 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1023 if (klass->ripple_end) {
1024 return klass->ripple_end (self, end);
1027 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1028 " on class %s. Can not ripple end to %" GST_TIME_FORMAT,
1029 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (end));
1035 * ges_timeline_element_roll_start:
1036 * @self: The #GESTimelineElement to roll
1037 * @start: The new start of @self in roll mode, it will also adapat
1038 * the in-point of @self according
1040 * Edits @self in roll mode. It allows you to modify the
1041 * start and inpoint of a @self and "resize" (basicly change the duration
1042 * in this case) of the previous neighbours accordingly.
1043 * This will not change the overall timeline duration.
1045 * Returns: %TRUE if the self as been roll properly, %FALSE if an error
1049 ges_timeline_element_roll_start (GESTimelineElement * self, GstClockTime start)
1051 GESTimelineElementClass *klass;
1053 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1055 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1057 if (klass->roll_start) {
1058 return klass->roll_start (self, start);
1061 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1062 " on class %s. Can not roll to %" GST_TIME_FORMAT,
1063 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1069 * ges_timeline_element_roll_end:
1070 * @self: The #GESTimelineElement to roll.
1071 * @end: The new end (start + duration) of @self in roll mode
1073 * Edits @self in roll mode. It allows you to modify the
1074 * duration of a @self and trim (basicly change the start + inpoint
1075 * in this case) the following neighbours accordingly.
1076 * This will not change the overall timeline duration.
1078 * Returns: %TRUE if the self as been rolled properly, %FALSE if an error
1082 ges_timeline_element_roll_end (GESTimelineElement * self, GstClockTime end)
1084 GESTimelineElementClass *klass;
1086 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1088 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1090 if (klass->roll_end)
1091 return klass->roll_end (self, end);
1093 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1094 " on class %s. Can not roll end to %" GST_TIME_FORMAT,
1095 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (end));
1101 * ges_timeline_element_trim:
1102 * @self: The #GESTimelineElement to trim.
1103 * @start: The new start of @self in trim mode, will adapt the inpoint
1104 * of @self accordingly
1106 * Edits @self in trim mode. It allows you to modify the
1107 * inpoint and start of @self.
1108 * This will not change the overall timeline duration.
1110 * Note that to trim the end of an self you can just set its duration. The same way
1111 * as this method, it will take into account the snapping-distance property of the
1112 * timeline in which @self is.
1114 * Returns: %TRUE if the self as been trimmed properly, %FALSE if an error
1118 ges_timeline_element_trim (GESTimelineElement * self, GstClockTime start)
1120 GESTimelineElementClass *klass;
1122 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1124 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1127 return klass->trim (self, start);
1129 GST_WARNING_OBJECT (self, "No ripple virtual method implementation"
1130 " on class %s. Can not trim to %" GST_TIME_FORMAT,
1131 G_OBJECT_CLASS_NAME (klass), GST_TIME_ARGS (start));
1137 * ges_timeline_element_copy:
1138 * @self: The #GESTimelineElement to copy
1139 * @deep: whether we want to create the elements @self contains or not
1143 * Returns: (transfer floating): The newly create #GESTimelineElement, copied from @self
1145 GESTimelineElement *
1146 ges_timeline_element_copy (GESTimelineElement * self, gboolean deep)
1151 GESTimelineElementClass *klass;
1152 guint n, n_specs, n_params;
1154 GESTimelineElement *ret = NULL;
1156 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1158 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1160 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_specs);
1161 params = g_new0 (GParameter, n_specs);
1164 for (n = 0; n < n_specs; ++n) {
1165 /* We do not want the timeline or the name to be copied */
1166 if (g_strcmp0 (specs[n]->name, "parent") &&
1167 g_strcmp0 (specs[n]->name, "timeline") &&
1168 g_strcmp0 (specs[n]->name, "name") &&
1169 (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
1170 params[n_params].name = g_intern_string (specs[n]->name);
1171 g_value_init (¶ms[n_params].value, specs[n]->value_type);
1172 g_object_get_property (G_OBJECT (self), specs[n]->name,
1173 ¶ms[n_params].value);
1178 #if GLIB_CHECK_VERSION(2, 53, 1)
1182 const gchar **names;
1183 values = g_malloc0 (sizeof (GValue) * n_specs);
1184 names = g_malloc0 (sizeof (gchar *) * n_specs);
1186 for (i = 0; i < n_params; i++) {
1187 values[i] = params[i].value;
1188 names[i] = params[i].name;
1192 GES_TIMELINE_ELEMENT (g_object_new_with_properties (G_OBJECT_TYPE
1193 (self), n_params, names, values));
1198 ret = g_object_newv (G_OBJECT_TYPE (self), n_params, params);
1202 g_value_unset (¶ms[n_params].value);
1208 asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
1210 ges_extractable_set_asset (GES_EXTRACTABLE (ret), asset);
1212 if (klass->deep_copy)
1213 klass->deep_copy (self, ret);
1215 GST_WARNING_OBJECT (self, "No deep_copy virtual method implementation"
1216 " on class %s. Can not finish the copy", G_OBJECT_CLASS_NAME (klass));
1220 ret->priv->copied_from = gst_object_ref (self);
1227 * ges_timeline_element_get_toplevel_parent:
1228 * @self: The #GESTimelineElement to get the toplevel parent from
1230 * Gets the toplevel #GESTimelineElement controlling @self
1232 * Returns: (transfer full): The toplevel controlling parent of @self
1234 GESTimelineElement *
1235 ges_timeline_element_get_toplevel_parent (GESTimelineElement * self)
1237 GESTimelineElement *toplevel = self;
1239 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1241 while (GES_TIMELINE_ELEMENT_PARENT (toplevel))
1242 toplevel = GES_TIMELINE_ELEMENT_PARENT (toplevel);
1244 return gst_object_ref (toplevel);
1248 * ges_timeline_element_get_name:
1249 * @self: a #GESTimelineElement
1251 * Returns a copy of the name of @self.
1252 * Caller should g_free() the return value after usage.
1254 * Returns: (transfer full): The name of @self
1257 ges_timeline_element_get_name (GESTimelineElement * self)
1259 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1261 return g_strdup (self->name);
1265 * ges_timeline_element_set_name:
1266 * @self: a #GESTimelineElement
1267 * @name: (allow-none): The name @self should take (if avalaible<)
1269 * Sets the name of object, or gives @self a guaranteed unique name (if name is NULL).
1270 * This function makes a copy of the provided name, so the caller retains ownership
1271 * of the name it sent.
1274 ges_timeline_element_set_name (GESTimelineElement * self, const gchar * name)
1276 gboolean result = TRUE, readd_to_timeline = FALSE;
1278 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1280 if (name != NULL && !g_strcmp0 (name, self->name)) {
1281 GST_DEBUG_OBJECT (self, "Same name!");
1285 /* parented objects cannot be renamed */
1286 if (self->timeline != NULL && name) {
1287 GESTimelineElement *tmp = ges_timeline_get_element (self->timeline, name);
1290 gst_object_unref (tmp);
1294 timeline_remove_element (self->timeline, self);
1295 readd_to_timeline = TRUE;
1298 _set_name (self, name);
1300 if (readd_to_timeline)
1301 timeline_add_element (self->timeline, self);
1308 GST_WARNING ("Object %s already in a timeline can't be renamed to %s",
1315 emit_deep_notify_in_idle (EmitDeepNotifyInIdleData * data)
1317 g_signal_emit (data->self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
1318 data->child, data->arg);
1320 gst_object_unref (data->child);
1321 g_param_spec_unref (data->arg);
1322 gst_object_unref (data->self);
1323 g_slice_free (EmitDeepNotifyInIdleData, data);
1329 child_prop_changed_cb (GObject * child, GParamSpec * arg
1330 G_GNUC_UNUSED, GESTimelineElement * self)
1332 EmitDeepNotifyInIdleData *data;
1334 /* Emit "deep-notify" right away if in main thread */
1335 if (g_main_context_acquire (g_main_context_default ())) {
1336 g_main_context_release (g_main_context_default ());
1337 g_signal_emit (self, ges_timeline_element_signals[DEEP_NOTIFY], 0,
1342 data = g_slice_new (EmitDeepNotifyInIdleData);
1344 data->child = gst_object_ref (child);
1345 data->arg = g_param_spec_ref (arg);
1346 data->self = gst_object_ref (self);
1348 g_idle_add ((GSourceFunc) emit_deep_notify_in_idle, data);
1352 ges_timeline_element_add_child_property (GESTimelineElement * self,
1353 GParamSpec * pspec, GObject * child)
1356 ChildPropHandler *handler;
1358 if (g_hash_table_contains (self->priv->children_props, pspec)) {
1359 GST_INFO_OBJECT (self, "Child property already exists: %s", pspec->name);
1363 GST_DEBUG_OBJECT (self, "Adding child property: %" GST_PTR_FORMAT "::%s",
1364 child, pspec->name);
1366 signame = g_strconcat ("notify::", pspec->name, NULL);
1367 handler = (ChildPropHandler *) g_slice_new0 (ChildPropHandler);
1368 handler->child = gst_object_ref (child);
1369 handler->handler_id =
1370 g_signal_connect (child, signame, G_CALLBACK (child_prop_changed_cb),
1372 g_hash_table_insert (self->priv->children_props, g_param_spec_ref (pspec),
1381 * ges_timeline_element_get_child_property_by_pspec:
1382 * @self: a #GESTrackElement
1383 * @pspec: The #GParamSpec that specifies the property you want to get
1384 * @value: (out): return location for the value
1386 * Gets a property of a child of @self.
1389 ges_timeline_element_get_child_property_by_pspec (GESTimelineElement * self,
1390 GParamSpec * pspec, GValue * value)
1392 ChildPropHandler *handler;
1394 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1396 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1400 g_object_get_property (G_OBJECT (handler->child), pspec->name, value);
1406 GST_ERROR_OBJECT (self, "The %s property doesn't exist", pspec->name);
1412 * ges_timeline_element_set_child_property_by_pspec:
1413 * @self: a #GESTimelineElement
1414 * @pspec: The #GParamSpec that specifies the property you want to set
1417 * Sets a property of a child of @self.
1420 ges_timeline_element_set_child_property_by_pspec (GESTimelineElement * self,
1421 GParamSpec * pspec, const GValue * value)
1423 ChildPropHandler *handler;
1424 GESTimelineElementClass *klass;
1426 g_return_if_fail (GES_IS_TRACK_ELEMENT (self));
1428 handler = g_hash_table_lookup (self->priv->children_props, pspec);
1433 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1434 g_assert (klass->set_child_property);
1435 klass->set_child_property (self, handler->child, pspec, (GValue *) value);
1441 GST_ERROR ("The %s property doesn't exist", pspec->name);
1447 * ges_timeline_element_set_child_property:
1448 * @self: The origin #GESTimelineElement
1449 * @property_name: The name of the property
1452 * Sets a property of a child of @self
1454 * Note that #ges_timeline_element_set_child_property is really
1455 * intended for language bindings, #ges_timeline_element_set_child_properties
1456 * is much more convenient for C programming.
1458 * Returns: %TRUE if the property was set, %FALSE otherwize
1461 ges_timeline_element_set_child_property (GESTimelineElement * self,
1462 const gchar * property_name, const GValue * value)
1465 GESTimelineElementClass *klass;
1468 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1470 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1473 klass = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1474 g_assert (klass->set_child_property);
1475 klass->set_child_property (self, child, pspec, (GValue *) value);
1477 gst_object_unref (child);
1478 g_param_spec_unref (pspec);
1484 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1491 * ges_timeline_element_get_child_property:
1492 * @self: The origin #GESTimelineElement
1493 * @property_name: The name of the property
1494 * @value: (out): return location for the property value, it will
1495 * be initialized if it is initialized with 0
1497 * In general, a copy is made of the property contents and
1498 * the caller is responsible for freeing the memory by calling
1501 * Gets a property of a GstElement contained in @object.
1503 * Note that #ges_timeline_element_get_child_property is really
1504 * intended for language bindings, #ges_timeline_element_get_child_properties
1505 * is much more convenient for C programming.
1507 * Returns: %TRUE if the property was found, %FALSE otherwize
1510 ges_timeline_element_get_child_property (GESTimelineElement * self,
1511 const gchar * property_name, GValue * value)
1516 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1518 if (!ges_timeline_element_lookup_child (self, property_name, &child, &pspec))
1521 if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
1522 g_value_init (value, pspec->value_type);
1524 g_object_get_property (child, pspec->name, value);
1526 gst_object_unref (child);
1527 g_param_spec_unref (pspec);
1533 GST_WARNING_OBJECT (self, "The %s property doesn't exist", property_name);
1540 * ges_timeline_element_lookup_child:
1541 * @self: object to lookup the property in
1542 * @prop_name: name of the property to look up. You can specify the name of the
1543 * class as such: "ClassName::property-name", to guarantee that you get the
1544 * proper GParamSpec in case various GstElement-s contain the same property
1545 * name. If you don't do so, you will get the first element found, having
1546 * this property and the and the corresponding GParamSpec.
1547 * @child: (out) (allow-none) (transfer full): pointer to a #GstElement that
1548 * takes the real object to set property on
1549 * @pspec: (out) (allow-none) (transfer full): pointer to take the #GParamSpec
1550 * describing the property
1552 * Looks up which @element and @pspec would be effected by the given @name. If various
1553 * contained elements have this property name you will get the first one, unless you
1554 * specify the class name in @name.
1556 * Returns: TRUE if @element and @pspec could be found. FALSE otherwise. In that
1557 * case the values for @pspec and @element are not modified. Unref @element after
1561 ges_timeline_element_lookup_child (GESTimelineElement * self,
1562 const gchar * prop_name, GObject ** child, GParamSpec ** pspec)
1564 GESTimelineElementClass *class;
1566 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1567 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1568 g_return_val_if_fail (class->lookup_child, FALSE);
1570 return class->lookup_child (self, prop_name, child, pspec);
1574 * ges_timeline_element_set_child_property_valist:
1575 * @self: The #GESTimelineElement parent object
1576 * @first_property_name: The name of the first property to set
1577 * @var_args: value for the first property, followed optionally by more
1578 * name/return location pairs, followed by NULL
1580 * Sets a property of a child of @self. If there are various child elements
1581 * that have the same property name, you can distinguish them using the following
1582 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1583 * corresponding property of the first element found will be set.
1586 ges_timeline_element_set_child_property_valist (GESTimelineElement * self,
1587 const gchar * first_property_name, va_list var_args)
1593 gchar *error = NULL;
1594 GValue value = { 0, };
1596 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1598 name = first_property_name;
1600 /* Note: This part is in big part copied from the gst_child_object_set_valist
1603 /* iterate over pairs */
1605 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
1608 G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args,
1609 G_VALUE_NOCOPY_CONTENTS, &error);
1614 g_object_set_property (child, pspec->name, &value);
1616 gst_object_unref (child);
1617 g_param_spec_unref (pspec);
1618 g_value_unset (&value);
1620 name = va_arg (var_args, gchar *);
1626 GST_WARNING_OBJECT (self, "No property %s in OBJECT\n", name);
1631 GST_WARNING_OBJECT (self, "error copying value %s in %p: %s", pspec->name,
1634 gst_object_unref (child);
1635 g_param_spec_unref (pspec);
1636 g_value_unset (&value);
1642 * ges_timeline_element_set_child_properties:
1643 * @self: The #GESTimelineElement parent object
1644 * @first_property_name: The name of the first property to set
1645 * @...: value for the first property, followed optionally by more
1646 * name/return location pairs, followed by NULL
1648 * Sets a property of a child of @self. If there are various child elements
1649 * that have the same property name, you can distinguish them using the following
1650 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1651 * corresponding property of the first element found will be set.
1654 ges_timeline_element_set_child_properties (GESTimelineElement * self,
1655 const gchar * first_property_name, ...)
1659 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1661 va_start (var_args, first_property_name);
1662 ges_timeline_element_set_child_property_valist (self, first_property_name,
1668 * ges_timeline_element_get_child_property_valist:
1669 * @self: The #GESTimelineElement parent object
1670 * @first_property_name: The name of the first property to get
1671 * @var_args: value for the first property, followed optionally by more
1672 * name/return location pairs, followed by NULL
1674 * Gets a property of a child of @self. If there are various child elements
1675 * that have the same property name, you can distinguish them using the following
1676 * syntax: 'ClasseName::property_name' as property name. If you don't, the
1677 * corresponding property of the first element found will be set.
1680 ges_timeline_element_get_child_property_valist (GESTimelineElement * self,
1681 const gchar * first_property_name, va_list var_args)
1684 gchar *error = NULL;
1685 GValue value = { 0, };
1689 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1691 name = first_property_name;
1693 /* This part is in big part copied from the gst_child_object_get_valist method */
1695 if (!ges_timeline_element_lookup_child (self, name, &child, &pspec))
1698 g_value_init (&value, pspec->value_type);
1699 g_object_get_property (child, pspec->name, &value);
1700 gst_object_unref (child);
1701 g_param_spec_unref (pspec);
1703 G_VALUE_LCOPY (&value, var_args, 0, &error);
1706 g_value_unset (&value);
1707 name = va_arg (var_args, gchar *);
1713 GST_WARNING_OBJECT (self, "no child property %s", name);
1718 GST_WARNING_OBJECT (self, "error copying value %s in %s", pspec->name,
1721 g_value_unset (&value);
1727 compare_gparamspec (GParamSpec ** a, GParamSpec ** b, gpointer udata)
1729 return g_strcmp0 ((*a)->name, (*b)->name);
1734 * ges_timeline_element_list_children_properties:
1735 * @self: The #GESTimelineElement to get the list of children properties from
1736 * @n_properties: (out): return location for the length of the returned array
1738 * Gets an array of #GParamSpec* for all configurable properties of the
1739 * children of @self.
1741 * Returns: (transfer full) (array length=n_properties): an array of #GParamSpec* which should be freed after use or
1742 * %NULL if something went wrong
1745 ges_timeline_element_list_children_properties (GESTimelineElement * self,
1746 guint * n_properties)
1749 GESTimelineElementClass *class;
1751 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), NULL);
1753 class = GES_TIMELINE_ELEMENT_GET_CLASS (self);
1755 if (!class->list_children_properties) {
1756 GST_INFO_OBJECT (self, "No %s->list_children_properties implementation",
1757 G_OBJECT_TYPE_NAME (self));
1763 ret = class->list_children_properties (self, n_properties);
1764 g_qsort_with_data (ret, *n_properties, sizeof (GParamSpec *),
1765 (GCompareDataFunc) compare_gparamspec, NULL);
1771 * ges_timeline_element_get_child_properties:
1772 * @self: The origin #GESTimelineElement
1773 * @first_property_name: The name of the first property to get
1774 * @...: return location for the first property, followed optionally by more
1775 * name/return location pairs, followed by NULL
1777 * Gets properties of a child of @self.
1780 ges_timeline_element_get_child_properties (GESTimelineElement * self,
1781 const gchar * first_property_name, ...)
1785 g_return_if_fail (GES_IS_TIMELINE_ELEMENT (self));
1787 va_start (var_args, first_property_name);
1788 ges_timeline_element_get_child_property_valist (self, first_property_name,
1794 ges_timeline_element_remove_child_property (GESTimelineElement * self,
1797 return g_hash_table_remove (self->priv->children_props, pspec);
1801 * ges_timeline_element_get_track_types:
1802 * @self: A #GESTimelineElement
1804 * Gets all the TrackTypes @self will interact with
1809 ges_timeline_element_get_track_types (GESTimelineElement * self)
1811 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), 0);
1812 g_return_val_if_fail (GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types,
1815 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_track_types (self);
1819 * ges_timeline_element_paste:
1820 * @self: The #GESTimelineElement to paste
1821 * @paste_position: The position in the timeline the element should
1822 * be copied to, meaning it will become the start of @self
1824 * Paste @self inside the timeline. @self must have been created
1825 * using ges_timeline_element_copy with recurse=TRUE set,
1826 * otherwise it will fail.
1828 * Returns: (transfer none): Paste @self copying the element
1832 GESTimelineElement *
1833 ges_timeline_element_paste (GESTimelineElement * self,
1834 GstClockTime paste_position)
1836 GESTimelineElement *res;
1837 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self), FALSE);
1839 if (!self->priv->copied_from) {
1840 GST_ERROR_OBJECT (self, "Is not being 'deeply' copied!");
1845 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste) {
1846 GST_ERROR_OBJECT (self, "No paste vmethod implemented");
1851 res = GES_TIMELINE_ELEMENT_GET_CLASS (self)->paste (self,
1852 self->priv->copied_from, paste_position);
1854 g_clear_object (&self->priv->copied_from);
1856 return g_object_ref (res);
1860 * ges_timeline_element_get_layer_priority:
1861 * @self: A #GESTimelineElement
1863 * Returns: The priority of the first layer the element is in (note that only
1864 * groups can span over several layers). %GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY
1865 * means that the element is not in a layer.
1870 ges_timeline_element_get_layer_priority (GESTimelineElement * self)
1872 g_return_val_if_fail (GES_IS_TIMELINE_ELEMENT (self),
1873 GES_TIMELINE_ELEMENT_NO_LAYER_PRIORITY);
1875 if (!GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority)
1876 return self->priority;
1878 return GES_TIMELINE_ELEMENT_GET_CLASS (self)->get_layer_priority (self);
1883 ges_timeline_element_get_media_duration_factor (GESTimelineElement * self)
1885 gdouble media_duration_factor;
1886 GESEffectClass *class;
1889 media_duration_factor = 1.0;
1891 class = GES_EFFECT_CLASS (g_type_class_ref (GES_TYPE_EFFECT));
1893 for (props = class->rate_properties; props != NULL; props = props->next) {
1896 if (ges_timeline_element_lookup_child (self, props->data, &child, &pspec)) {
1897 if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_FLOAT) {
1899 g_object_get (child, pspec->name, &rate_change, NULL);
1900 media_duration_factor *= rate_change;
1901 } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_DOUBLE) {
1902 gdouble rate_change;
1903 g_object_get (child, pspec->name, &rate_change, NULL);
1904 media_duration_factor *= rate_change;
1906 GST_WARNING_OBJECT (self,
1907 "Rate property %s in child %" GST_PTR_FORMAT
1908 " is of unsupported type %s", pspec->name, child,
1909 G_VALUE_TYPE_NAME (pspec->value_type));
1912 gst_object_unref (child);
1913 g_param_spec_unref (pspec);
1915 GST_DEBUG_OBJECT (self,
1916 "Added rate changing property %s, set to value %lf",
1917 (const char *) props->data, media_duration_factor);
1921 g_type_class_unref (class);
1922 return media_duration_factor;
1926 GESTimelineElement *
1927 ges_timeline_element_get_copied_from (GESTimelineElement * self)
1929 GESTimelineElement *copied_from = self->priv->copied_from;
1930 self->priv->copied_from = NULL;
1934 GESTimelineElementFlags
1935 ges_timeline_element_flags (GESTimelineElement * self)
1937 return self->priv->flags;
1941 ges_timeline_element_set_flags (GESTimelineElement * self,
1942 GESTimelineElementFlags flags)
1944 self->priv->flags = flags;