1 /* GStreamer Editing Services
2 * Copyright (C) 2013 Thibault Saunier <thibault.saunier@collabora.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 * @short_description: Class that permits to group GESClip-s in a timeline,
24 * letting the user manage it a single GESTimelineElement
26 * A #GESGroup is an object which controls one or more
27 * #GESClips in one or more #GESLayer(s).
29 * To instanciate a group, you should use the ges_container_group method,
30 * this will be responsible for deciding what subclass of #GESContainer
31 * should be instaciated to group the various #GESTimelineElement passed
35 #include "ges-group.h"
37 #include "ges-internal.h"
41 #define parent_class ges_group_parent_class
42 G_DEFINE_TYPE (GESGroup, ges_group, GES_TYPE_CONTAINER);
44 #define GES_CHILDREN_INIBIT_SIGNAL_EMISSION (GES_CHILDREN_LAST + 1)
45 #define GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT "ges-group-signals-ids-%p"
47 struct _GESGroupPrivate
49 gboolean reseting_start;
51 guint32 max_layer_prio;
53 /* This is used while were are setting ourselve a proper timing value,
54 * in this case the value should always be kept */
55 gboolean setting_value;
61 gulong child_clip_changed_layer_sid;
62 gulong child_priority_changed_sid;
63 gulong child_group_priority_changed_sid;
77 static GParamSpec *properties[PROP_LAST] = { NULL, };
79 /****************************************************
80 * Our listening of children *
81 ****************************************************/
83 _update_our_values (GESGroup * group)
86 GESContainer *container = GES_CONTAINER (group);
87 guint32 min_layer_prio = G_MAXINT32, max_layer_prio = 0;
89 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
90 GESContainer *child = tmp->data;
92 if (GES_IS_CLIP (child)) {
93 GESLayer *layer = ges_clip_get_layer (GES_CLIP (child));
94 gint32 prio = ges_layer_get_priority (layer);
96 min_layer_prio = MIN (prio, min_layer_prio);
97 max_layer_prio = MAX (prio, max_layer_prio);
98 } else if (GES_IS_GROUP (child)) {
99 gint32 prio = _PRIORITY (child), height = GES_CONTAINER_HEIGHT (child);
101 min_layer_prio = MIN (prio, min_layer_prio);
102 max_layer_prio = MAX ((prio + height), max_layer_prio);
106 if (min_layer_prio != _PRIORITY (group)) {
107 group->priv->setting_value = TRUE;
108 _set_priority0 (GES_TIMELINE_ELEMENT (group), min_layer_prio);
109 group->priv->setting_value = FALSE;
110 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
111 GESTimelineElement *child = tmp->data;
112 guint32 child_prio = GES_IS_CLIP (child) ?
113 ges_clip_get_layer_priority (GES_CLIP (child)) : _PRIORITY (child);
115 _ges_container_set_priority_offset (container,
116 child, min_layer_prio - child_prio);
120 group->priv->max_layer_prio = max_layer_prio;
121 _ges_container_set_height (GES_CONTAINER (group),
122 max_layer_prio - min_layer_prio + 1);
126 _child_priority_changed_cb (GESLayer * layer,
127 GParamSpec * arg G_GNUC_UNUSED, GESTimelineElement * clip)
129 GESContainer *container = GES_CONTAINER (GES_TIMELINE_ELEMENT_PARENT (clip));
131 gint layer_prio = ges_layer_get_priority (layer);
132 gint offset = _ges_container_get_priority_offset (container, clip);
134 if (container->children_control_mode != GES_CHILDREN_UPDATE) {
135 GST_DEBUG_OBJECT (container, "Ignoring updated");
139 if (layer_prio + offset == _PRIORITY (container))
142 container->initiated_move = clip;
143 _set_priority0 (GES_TIMELINE_ELEMENT (container), layer_prio + offset);
144 container->initiated_move = NULL;
148 _child_clip_changed_layer_cb (GESTimelineElement * clip,
149 GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
151 ChildSignalIds *sigids;
152 gchar *signals_ids_key;
153 GESLayer *old_layer, *new_layer;
154 gint offset, layer_prio = ges_clip_get_layer_priority (GES_CLIP (clip));
155 GESContainer *container = GES_CONTAINER (group);
157 offset = _ges_container_get_priority_offset (container, clip);
159 g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, clip);
160 sigids = g_object_get_data (G_OBJECT (group), signals_ids_key);
161 g_free (signals_ids_key);
162 old_layer = sigids->layer;
164 new_layer = ges_clip_get_layer (GES_CLIP (clip));
166 if (sigids->child_priority_changed_sid) {
167 g_signal_handler_disconnect (old_layer, sigids->child_priority_changed_sid);
168 sigids->child_priority_changed_sid = 0;
172 sigids->child_priority_changed_sid =
173 g_signal_connect (new_layer, "notify::priority",
174 (GCallback) _child_priority_changed_cb, clip);
176 sigids->layer = new_layer;
178 if (container->children_control_mode != GES_CHILDREN_UPDATE) {
179 if (container->children_control_mode == GES_CHILDREN_INIBIT_SIGNAL_EMISSION) {
180 container->children_control_mode = GES_CHILDREN_UPDATE;
181 g_signal_stop_emission_by_name (clip, "notify::layer");
186 if (new_layer && (layer_prio + offset < 0 ||
187 (GES_TIMELINE_ELEMENT_TIMELINE (group) &&
188 layer_prio + offset + GES_CONTAINER_HEIGHT (group) - 1 >
189 g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers)))) {
191 GST_INFO_OBJECT (container, "Trying to move to a layer outside of"
192 "the timeline layers, moving back to old layer (prio %i)",
193 _PRIORITY (group) - offset);
195 container->children_control_mode = GES_CHILDREN_INIBIT_SIGNAL_EMISSION;
196 ges_clip_move_to_layer (GES_CLIP (clip), old_layer);
197 g_signal_stop_emission_by_name (clip, "notify::layer");
202 container->initiated_move = clip;
203 _set_priority0 (GES_TIMELINE_ELEMENT (group), layer_prio + offset);
204 container->initiated_move = NULL;
208 _child_group_priority_changed (GESTimelineElement * child,
209 GParamSpec * arg G_GNUC_UNUSED, GESGroup * group)
212 GESContainer *container = GES_CONTAINER (group);
214 if (container->children_control_mode != GES_CHILDREN_UPDATE) {
215 GST_DEBUG_OBJECT (group, "Ignoring updated");
219 offset = _ges_container_get_priority_offset (container, child);
221 if (_PRIORITY (group) < offset ||
222 (GES_TIMELINE_ELEMENT_TIMELINE (group) &&
223 _PRIORITY (group) + offset + GES_CONTAINER_HEIGHT (group) >
224 g_list_length (GES_TIMELINE_ELEMENT_TIMELINE (group)->layers))) {
226 GST_WARNING_OBJECT (container, "Trying to move to a layer outside of"
227 "the timeline layers");
232 container->initiated_move = child;
233 _set_priority0 (GES_TIMELINE_ELEMENT (group), _PRIORITY (child) + offset);
234 container->initiated_move = NULL;
237 /****************************************************
238 * GESTimelineElement vmethods *
239 ****************************************************/
241 _trim (GESTimelineElement * group, GstClockTime start)
244 GstClockTime last_child_end = 0, oldstart = _START (group);
245 GESContainer *container = GES_CONTAINER (group);
246 GESTimeline *timeline = GES_TIMELINE_ELEMENT_TIMELINE (group);
247 gboolean ret = TRUE, expending = (start < _START (group));
249 if (timeline == NULL) {
250 GST_DEBUG ("Not in a timeline yet");
255 container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
256 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
257 GESTimelineElement *child = tmp->data;
260 /* If the start is bigger, we do not touch it (in case we are expending) */
261 if (_START (child) > oldstart) {
262 GST_DEBUG_OBJECT (child, "Skipping as not at begining of the group");
266 ret &= ges_timeline_element_trim (child, start);
268 if (start > _END (child))
269 ret &= ges_timeline_element_trim (child, _END (child));
270 else if (_START (child) < start && _DURATION (child))
271 ret &= ges_timeline_element_trim (child, start);
276 for (tmp = GES_CONTAINER_CHILDREN (group); tmp; tmp = tmp->next) {
277 if (_DURATION (tmp->data))
279 MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
282 GES_GROUP (group)->priv->setting_value = TRUE;
283 _set_start0 (group, start);
284 _set_duration0 (group, last_child_end - start);
285 GES_GROUP (group)->priv->setting_value = FALSE;
286 container->children_control_mode = GES_CHILDREN_UPDATE;
292 _set_priority (GESTimelineElement * element, guint32 priority)
295 gint diff = priority - _PRIORITY (element);
296 GESContainer *container = GES_CONTAINER (element);
298 if (GES_GROUP (element)->priv->setting_value == TRUE)
301 container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
302 layers = GES_TIMELINE_ELEMENT_TIMELINE (element) ?
303 GES_TIMELINE_ELEMENT_TIMELINE (element)->layers : NULL;
305 if (layers == NULL) {
306 GST_WARNING_OBJECT (element, "Not any layer in the timeline, not doing"
307 "anything, timeline: %" GST_PTR_FORMAT,
308 GES_TIMELINE_ELEMENT_TIMELINE (element));
311 } else if (priority + GES_CONTAINER_HEIGHT (container) - 1 >
312 g_list_length (layers)) {
313 GST_WARNING_OBJECT (container, "Trying to move to a layer outside of"
314 "the timeline layers");
318 for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
319 GESTimelineElement *child = tmp->data;
321 if (child != container->initiated_move) {
322 if (GES_IS_CLIP (child)) {
324 ges_clip_get_layer_priority (GES_CLIP (child)) + diff;
326 GST_DEBUG_OBJECT (child, "moving from layer: %i to %i",
327 ges_clip_get_layer_priority (GES_CLIP (child)), layer_prio);
328 ges_clip_move_to_layer (GES_CLIP (child),
329 g_list_nth_data (layers, layer_prio));
330 } else if (GES_IS_GROUP (child)) {
331 GST_DEBUG_OBJECT (child, "moving from %i to %i",
332 _PRIORITY (child), diff + _PRIORITY (child));
333 ges_timeline_element_set_priority (child, diff + _PRIORITY (child));
337 container->children_control_mode = GES_CHILDREN_UPDATE;
343 _set_start (GESTimelineElement * element, GstClockTime start)
346 gint64 diff = start - _START (element);
347 GESContainer *container = GES_CONTAINER (element);
349 if (GES_GROUP (element)->priv->setting_value == TRUE)
350 /* Let GESContainer update itself */
351 return GES_TIMELINE_ELEMENT_CLASS (parent_class)->set_start (element,
355 container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
356 for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
357 GESTimelineElement *child = (GESTimelineElement *) tmp->data;
359 if (child != container->initiated_move &&
360 (_END (child) > _START (element) || _END (child) > start)) {
361 _set_start0 (child, _START (child) + diff);
364 container->children_control_mode = GES_CHILDREN_UPDATE;
370 _set_inpoint (GESTimelineElement * element, GstClockTime inpoint)
376 _set_duration (GESTimelineElement * element, GstClockTime duration)
379 GstClockTime last_child_end = 0, new_end;
380 GESContainer *container = GES_CONTAINER (element);
381 GESGroupPrivate *priv = GES_GROUP (element)->priv;
383 if (priv->setting_value == TRUE)
384 /* Let GESContainer update itself */
385 return GES_TIMELINE_ELEMENT_CLASS (parent_class)->set_duration (element,
388 if (container->initiated_move == NULL) {
389 gboolean expending = (_DURATION (element) < duration);
391 new_end = _START (element) + duration;
392 container->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
393 for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
394 GESTimelineElement *child = tmp->data;
397 if ((!expending && _END (child) > new_end) ||
398 (expending && (_END (child) >= _END (element)))) {
399 n_dur = MAX (0, ((gint64) (new_end - _START (child))));
400 _set_duration0 (child, n_dur);
403 container->children_control_mode = GES_CHILDREN_UPDATE;
406 for (tmp = GES_CONTAINER_CHILDREN (element); tmp; tmp = tmp->next) {
407 if (_DURATION (tmp->data))
409 MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
412 priv->setting_value = TRUE;
413 _set_duration0 (element, last_child_end - _START (element));
414 priv->setting_value = FALSE;
419 /****************************************************
421 * GESContainer virtual methods implementation *
423 ****************************************************/
426 _add_child (GESContainer * group, GESTimelineElement * child)
428 g_return_val_if_fail (GES_IS_CONTAINER (child), FALSE);
434 _child_added (GESContainer * group, GESTimelineElement * child)
436 GList *children, *tmp;
437 gchar *signals_ids_key;
438 ChildSignalIds *signals_ids;
440 GESGroupPrivate *priv = GES_GROUP (group)->priv;
441 GstClockTime last_child_end = 0, first_child_start = G_MAXUINT64;
443 if (!GES_TIMELINE_ELEMENT_TIMELINE (group)) {
444 timeline_add_group (GES_TIMELINE_ELEMENT_TIMELINE (child),
446 timeline_emit_group_added (GES_TIMELINE_ELEMENT_TIMELINE (child),
450 children = GES_CONTAINER_CHILDREN (group);
452 for (tmp = children; tmp; tmp = tmp->next) {
453 last_child_end = MAX (GES_TIMELINE_ELEMENT_END (tmp->data), last_child_end);
455 MIN (GES_TIMELINE_ELEMENT_START (tmp->data), first_child_start);
458 priv->setting_value = TRUE;
459 if (first_child_start != GES_TIMELINE_ELEMENT_START (group)) {
460 group->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
461 _set_start0 (GES_TIMELINE_ELEMENT (group), first_child_start);
464 if (last_child_end != GES_TIMELINE_ELEMENT_END (group)) {
465 _set_duration0 (GES_TIMELINE_ELEMENT (group),
466 last_child_end - first_child_start);
468 priv->setting_value = FALSE;
470 group->children_control_mode = GES_CHILDREN_UPDATE;
471 _update_our_values (GES_GROUP (group));
474 g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, child);
475 signals_ids = g_malloc0 (sizeof (ChildSignalIds));
476 g_object_set_data_full (G_OBJECT (group), signals_ids_key,
477 signals_ids, g_free);
478 g_free (signals_ids_key);
479 if (GES_IS_CLIP (child)) {
480 GESLayer *layer = ges_clip_get_layer (GES_CLIP (child));
482 signals_ids->child_clip_changed_layer_sid =
483 g_signal_connect (child, "notify::layer",
484 (GCallback) _child_clip_changed_layer_cb, group);
487 signals_ids->child_priority_changed_sid = g_signal_connect (layer,
488 "notify::priority", (GCallback) _child_priority_changed_cb, child);
490 signals_ids->layer = layer;
492 } else if (GES_IS_GROUP (child), group) {
493 signals_ids->child_group_priority_changed_sid =
494 g_signal_connect (child, "notify::priority",
495 (GCallback) _child_group_priority_changed, group);
500 _disconnect_signals (GESGroup * group, GESTimelineElement * child,
501 ChildSignalIds * sigids)
503 if (sigids->child_group_priority_changed_sid) {
504 g_signal_handler_disconnect (child,
505 sigids->child_group_priority_changed_sid);
506 sigids->child_group_priority_changed_sid = 0;
509 if (sigids->child_clip_changed_layer_sid) {
510 g_signal_handler_disconnect (child, sigids->child_clip_changed_layer_sid);
511 sigids->child_clip_changed_layer_sid = 0;
514 if (sigids->child_priority_changed_sid) {
515 g_signal_handler_disconnect (sigids->layer,
516 sigids->child_priority_changed_sid);
517 sigids->child_priority_changed_sid = 0;
523 _child_removed (GESContainer * group, GESTimelineElement * child)
526 GstClockTime first_child_start;
527 gchar *signals_ids_key;
528 ChildSignalIds *sigids;
529 GESGroupPrivate *priv = GES_GROUP (group)->priv;
531 _ges_container_sort_children (group);
533 children = GES_CONTAINER_CHILDREN (group);
536 g_strdup_printf (GES_GROUP_SIGNALS_IDS_DATA_KEY_FORMAT, child);
537 sigids = g_object_get_data (G_OBJECT (group), signals_ids_key);
538 _disconnect_signals (GES_GROUP (group), child, sigids);
539 g_free (signals_ids_key);
540 if (children == NULL) {
541 GST_FIXME_OBJECT (group, "Auto destroy myself?");
542 timeline_remove_group (GES_TIMELINE_ELEMENT_TIMELINE (group),
547 priv->setting_value = TRUE;
548 first_child_start = GES_TIMELINE_ELEMENT_START (children->data);
549 if (first_child_start > GES_TIMELINE_ELEMENT_START (group)) {
550 group->children_control_mode = GES_CHILDREN_IGNORE_NOTIFIES;
551 _set_start0 (GES_TIMELINE_ELEMENT (group), first_child_start);
552 group->children_control_mode = GES_CHILDREN_UPDATE;
554 priv->setting_value = FALSE;
558 _ungroup (GESContainer * group, gboolean recursive)
560 GPtrArray *children_array;
561 GESTimeline *timeline;
562 GList *children, *tmp, *ret = NULL;
564 /* We choose 16 just as an arbitrary value */
565 children_array = g_ptr_array_sized_new (16);
566 timeline = GES_TIMELINE_ELEMENT_TIMELINE (group);
568 children = ges_container_get_children (group, FALSE);
569 for (tmp = children; tmp; tmp = tmp->next) {
570 GESTimelineElement *child = tmp->data;
572 gst_object_ref (child);
573 ges_container_remove (group, child);
574 g_ptr_array_add (children_array, child);
575 ret = g_list_append (ret, child);
579 timeline_emit_group_removed (timeline, (GESGroup *) group, children_array);
580 g_ptr_array_free (children_array, TRUE);
581 g_list_free_full (children, gst_object_unref);
583 /* No need to remove from the timeline here, this will be done in _child_removed */
588 static GESContainer *
589 _group (GList * containers)
592 GESTimeline *timeline = NULL;
593 GESContainer *ret = g_object_new (GES_TYPE_GROUP, NULL);
598 for (tmp = containers; tmp; tmp = tmp->next) {
600 timeline = GES_TIMELINE_ELEMENT_TIMELINE (tmp->data);
601 } else if (timeline != GES_TIMELINE_ELEMENT_TIMELINE (tmp->data)) {
602 g_object_unref (ret);
607 ges_container_add (ret, tmp->data);
610 /* No need to add to the timeline here, this will be done in _child_added */
615 static GESTimelineElement *
616 _paste (GESTimelineElement * element, GESTimelineElement * ref,
617 GstClockTime paste_position)
619 GESTimelineElement *ngroup =
620 GES_TIMELINE_ELEMENT_CLASS (parent_class)->paste (element, ref,
624 if (GES_CONTAINER_CHILDREN (ngroup)) {
625 timeline_add_group (GES_TIMELINE_ELEMENT_TIMELINE (GES_CONTAINER_CHILDREN
626 (ngroup)->data), GES_GROUP (element));
627 timeline_emit_group_added (GES_TIMELINE_ELEMENT_TIMELINE
628 (GES_CONTAINER_CHILDREN (ngroup)->data), GES_GROUP (element));
636 /****************************************************
638 * GObject virtual methods implementation *
640 ****************************************************/
642 ges_group_get_property (GObject * object, guint property_id,
643 GValue * value, GParamSpec * pspec)
645 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
647 switch (property_id) {
649 g_value_set_uint64 (value, self->start);
652 g_value_set_uint64 (value, self->inpoint);
655 g_value_set_uint64 (value, self->duration);
657 case PROP_MAX_DURATION:
658 g_value_set_uint64 (value, self->maxduration);
661 g_value_set_uint (value, self->priority);
664 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
669 ges_group_set_property (GObject * object, guint property_id,
670 const GValue * value, GParamSpec * pspec)
672 GESTimelineElement *self = GES_TIMELINE_ELEMENT (object);
674 switch (property_id) {
676 ges_timeline_element_set_start (self, g_value_get_uint64 (value));
679 ges_timeline_element_set_inpoint (self, g_value_get_uint64 (value));
682 ges_timeline_element_set_duration (self, g_value_get_uint64 (value));
685 ges_timeline_element_set_priority (self, g_value_get_uint (value));
687 case PROP_MAX_DURATION:
688 ges_timeline_element_set_max_duration (self, g_value_get_uint64 (value));
691 G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
696 ges_group_class_init (GESGroupClass * klass)
698 GObjectClass *object_class = G_OBJECT_CLASS (klass);
699 GESContainerClass *container_class = GES_CONTAINER_CLASS (klass);
700 GESTimelineElementClass *element_class = GES_TIMELINE_ELEMENT_CLASS (klass);
702 g_type_class_add_private (klass, sizeof (GESGroupPrivate));
704 object_class->get_property = ges_group_get_property;
705 object_class->set_property = ges_group_set_property;
707 element_class->trim = _trim;
708 element_class->set_duration = _set_duration;
709 element_class->set_inpoint = _set_inpoint;
710 element_class->set_start = _set_start;
711 element_class->set_priority = _set_priority;
712 element_class->paste = _paste;
714 /* We override start, inpoint, duration and max-duration from GESTimelineElement
715 * in order to makes sure those fields are not serialized.
720 * The position of the object in its container (in nanoseconds).
722 properties[PROP_START] = g_param_spec_uint64 ("start", "Start",
723 "The position in the container", 0, G_MAXUINT64, 0,
724 G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
729 * The in-point at which this #GESGroup will start outputting data
730 * from its contents (in nanoseconds).
732 * Ex : an in-point of 5 seconds means that the first outputted buffer will
733 * be the one located 5 seconds in the controlled resource.
735 properties[PROP_INPOINT] =
736 g_param_spec_uint64 ("in-point", "In-point", "The in-point", 0,
737 G_MAXUINT64, 0, G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
742 * The duration (in nanoseconds) which will be used in the container
744 properties[PROP_DURATION] =
745 g_param_spec_uint64 ("duration", "Duration", "The duration to use", 0,
746 G_MAXUINT64, GST_CLOCK_TIME_NONE,
747 G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
750 * GESGroup:max-duration:
752 * The maximum duration (in nanoseconds) of the #GESGroup.
754 properties[PROP_MAX_DURATION] =
755 g_param_spec_uint64 ("max-duration", "Maximum duration",
756 "The maximum duration of the object", 0, G_MAXUINT64, GST_CLOCK_TIME_NONE,
757 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GES_PARAM_NO_SERIALIZATION);
760 * GESTGroup:priority:
762 * The priority of the object.
764 properties[PROP_PRIORITY] = g_param_spec_uint ("priority", "Priority",
765 "The priority of the object", 0, G_MAXUINT, 0,
766 G_PARAM_READWRITE | GES_PARAM_NO_SERIALIZATION);
768 g_object_class_install_properties (object_class, PROP_LAST, properties);
770 container_class->add_child = _add_child;
771 container_class->child_added = _child_added;
772 container_class->child_removed = _child_removed;
773 container_class->ungroup = _ungroup;
774 container_class->group = _group;
775 container_class->grouping_priority = 0;
779 ges_group_init (GESGroup * self)
781 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
782 GES_TYPE_GROUP, GESGroupPrivate);
784 self->priv->setting_value = FALSE;
787 /****************************************************
789 * API implementation *
791 ****************************************************/
796 * Created a new empty #GESGroup, if you want to group several container
797 * together, it is recommanded to use the #ges_container_group method so the
798 * proper subclass is selected.
800 * Returns: (transfer floating): The new empty group.
805 return g_object_new (GES_TYPE_GROUP, NULL);