3 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
4 * 2004 Wim Taymans <wim@fluendo.com>
6 * gstbin.c: GstBin container object and support code
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 #include "gst_private.h"
30 #include "gstmarshal.h"
35 #include "gstscheduler.h"
39 GST_DEBUG_CATEGORY_STATIC (bin_debug);
40 #define GST_CAT_DEFAULT bin_debug
41 #define GST_LOG_BIN_CONTENTS(bin, text) GST_LOG_OBJECT ((bin), \
42 text ": %d elements: %u PLAYING, %u PAUSED, %u READY, %u NULL, own state: %s", \
43 (bin)->numchildren, (guint) (bin)->child_states[3], \
44 (guint) (bin)->child_states[2], (bin)->child_states[1], \
45 (bin)->child_states[0], gst_element_state_get_name (GST_STATE (bin)))
48 static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
50 "Simple container object",
51 "Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
53 GType _gst_bin_type = 0;
55 static gboolean _gst_boolean_did_something_accumulator (GSignalInvocationHint *
56 ihint, GValue * return_accu, const GValue * handler_return, gpointer dummy);
58 static void gst_bin_dispose (GObject * object);
60 static GstElementStateReturn gst_bin_change_state (GstElement * element);
61 static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin);
63 #ifndef GST_DISABLE_INDEX
64 static void gst_bin_set_index (GstElement * element, GstIndex * index);
67 static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
68 static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
69 static void gst_bin_child_state_change_func (GstBin * bin,
70 GstElementState oldstate, GstElementState newstate, GstElement * child);
71 GstElementStateReturn gst_bin_set_state (GstElement * element,
72 GstElementState state);
74 static GstClock *gst_bin_get_clock_func (GstElement * element);
75 static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
77 static gboolean gst_bin_iterate_func (GstBin * bin);
79 #ifndef GST_DISABLE_LOADSAVE
80 static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
81 static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
84 /* Bin signals and args */
99 static void gst_bin_base_init (gpointer g_class);
100 static void gst_bin_class_init (GstBinClass * klass);
101 static void gst_bin_init (GstBin * bin);
103 static GstElementClass *parent_class = NULL;
104 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
109 * Returns: the type of #GstBin
112 gst_bin_get_type (void)
114 if (!_gst_bin_type) {
115 static const GTypeInfo bin_info = {
116 sizeof (GstBinClass),
119 (GClassInitFunc) gst_bin_class_init,
124 (GInstanceInitFunc) gst_bin_init,
129 g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
131 GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
132 "debugging info for the 'bin' container element");
134 return _gst_bin_type;
138 gst_bin_base_init (gpointer g_class)
140 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
142 gst_element_class_set_details (gstelement_class, &gst_bin_details);
146 gst_bin_class_init (GstBinClass * klass)
148 GObjectClass *gobject_class;
149 GstObjectClass *gstobject_class;
150 GstElementClass *gstelement_class;
152 gobject_class = (GObjectClass *) klass;
153 gstobject_class = (GstObjectClass *) klass;
154 gstelement_class = (GstElementClass *) klass;
156 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
158 gst_bin_signals[ELEMENT_ADDED] =
159 g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
160 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
161 NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
162 gst_bin_signals[ELEMENT_REMOVED] =
163 g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
164 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
165 NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
166 gst_bin_signals[ITERATE] =
167 g_signal_new ("iterate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
168 G_STRUCT_OFFSET (GstBinClass, iterate),
169 _gst_boolean_did_something_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
172 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
174 #ifndef GST_DISABLE_LOADSAVE
175 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
176 gstobject_class->restore_thyself =
177 GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
180 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
181 gstelement_class->set_state = GST_DEBUG_FUNCPTR (gst_bin_set_state);
182 #ifndef GST_DISABLE_INDEX
183 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index);
186 klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
187 klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
188 klass->child_state_change =
189 GST_DEBUG_FUNCPTR (gst_bin_child_state_change_func);
190 klass->iterate = GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
194 _gst_boolean_did_something_accumulator (GSignalInvocationHint * ihint,
195 GValue * return_accu, const GValue * handler_return, gpointer dummy)
197 gboolean did_something;
199 did_something = g_value_get_boolean (handler_return);
201 g_value_set_boolean (return_accu, TRUE);
204 /* always continue emission */
209 gst_bin_init (GstBin * bin)
211 bin->numchildren = 0;
212 bin->children = NULL;
213 bin->children_cookie = 0;
218 * @name: name of new bin
220 * Create a new bin with given name.
225 gst_bin_new (const gchar * name)
227 return gst_element_factory_make ("bin", name);
231 gst_bin_get_clock_func (GstElement * element)
233 if (GST_ELEMENT_SCHEDULER (element))
234 return gst_scheduler_get_clock (GST_ELEMENT_SCHEDULER (element));
240 gst_bin_set_clock_func (GstElement * element, GstClock * clock)
242 if (GST_ELEMENT_SCHEDULER (element))
243 gst_scheduler_use_clock (GST_ELEMENT_SCHEDULER (element), clock);
248 * @bin: a #GstBin to get the clock of
250 * Gets the current clock of the (scheduler of the) bin.
252 * Returns: the #GstClock of the bin
255 gst_bin_get_clock (GstBin * bin)
257 g_return_val_if_fail (bin != NULL, NULL);
258 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
260 return gst_bin_get_clock_func (GST_ELEMENT (bin));
265 * @bin: the bin to set the clock for
266 * @clock: the clock to use.
268 * Force the bin to use the given clock. Use NULL to
269 * force it to use no clock at all.
272 gst_bin_use_clock (GstBin * bin, GstClock * clock)
274 g_return_if_fail (GST_IS_BIN (bin));
276 gst_bin_set_clock_func (GST_ELEMENT (bin), clock);
280 * gst_bin_auto_clock:
281 * @bin: the bin to autoclock
283 * Let the bin select a clock automatically.
286 gst_bin_auto_clock (GstBin * bin)
288 g_return_if_fail (GST_IS_BIN (bin));
290 if (GST_ELEMENT_SCHEDULER (bin))
291 gst_scheduler_auto_clock (GST_ELEMENT_SCHEDULER (bin));
294 #ifndef GST_DISABLE_INDEX
296 gst_bin_set_index (GstElement * element, GstIndex * index)
301 bin = GST_BIN (element);
304 for (children = bin->children; children; children = g_list_next (children)) {
305 GstElement *child = GST_ELEMENT (children->data);
307 gst_element_set_index (child, index);
314 gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
316 GST_CAT_LOG (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",
317 GST_ELEMENT_NAME (element), sched);
319 /* if it's actually a Bin */
320 if (GST_IS_BIN (element)) {
321 if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
322 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
323 "child is already a manager, not resetting sched");
324 if (GST_ELEMENT_SCHEDULER (element))
325 gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
329 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
330 "setting child bin's scheduler to be the same as the parent's");
331 gst_scheduler_add_element (sched, element);
333 /* set the children's schedule */
334 g_list_foreach (GST_BIN (element)->children,
335 (GFunc) gst_bin_set_element_sched, sched);
337 /* otherwise, if it's just a regular old element */
340 gst_scheduler_add_element (sched, element);
342 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
343 /* set the sched pointer in all the pads */
344 pads = element->pads;
348 pad = GST_PAD (pads->data);
349 pads = g_list_next (pads);
351 /* we only operate on real pads */
352 if (!GST_IS_REAL_PAD (pad))
355 /* if the peer element exists and is a candidate */
356 if (GST_PAD_PEER (pad)) {
357 if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
358 GST_CAT_LOG (GST_CAT_SCHEDULING,
359 "peer is in same scheduler, telling scheduler");
361 if (GST_PAD_IS_SRC (pad))
362 gst_scheduler_pad_link (sched, pad, GST_PAD_PEER (pad));
364 gst_scheduler_pad_link (sched, GST_PAD_PEER (pad), pad);
373 gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
375 if (GST_ELEMENT_SCHEDULER (element) == NULL) {
376 GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element \"%s\" has no scheduler",
377 GST_ELEMENT_NAME (element));
381 GST_CAT_DEBUG (GST_CAT_SCHEDULING,
382 "removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element),
383 GST_ELEMENT_SCHEDULER (element));
385 /* if it's actually a Bin */
386 if (GST_IS_BIN (element)) {
388 if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
389 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
390 "child is already a manager, not unsetting sched");
392 gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
396 /* for each child, remove them from their schedule */
397 g_list_foreach (GST_BIN (element)->children,
398 (GFunc) gst_bin_unset_element_sched, sched);
400 gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
402 /* otherwise, if it's just a regular old element */
405 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
406 /* unset the sched pointer in all the pads */
407 pads = element->pads;
411 pad = GST_PAD (pads->data);
412 pads = g_list_next (pads);
414 /* we only operate on real pads */
415 if (!GST_IS_REAL_PAD (pad))
418 /* if the peer element exists and is a candidate */
419 if (GST_PAD_PEER (pad)) {
420 if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
421 GST_CAT_LOG (GST_CAT_SCHEDULING,
422 "peer is in same scheduler, telling scheduler");
424 if (GST_PAD_IS_SRC (pad))
425 gst_scheduler_pad_unlink (sched, pad, GST_PAD_PEER (pad));
427 gst_scheduler_pad_unlink (sched, GST_PAD_PEER (pad), pad);
433 gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
437 /* add an element to this bin
442 gst_bin_add_func (GstBin * bin, GstElement * element)
446 /* we obviously can't add ourself to ourself */
447 if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
450 /* get the element name to make sure it is unique in this bin, FIXME, another
451 * thread can change the name after the unlock. */
453 elem_name = g_strdup (GST_ELEMENT_NAME (element));
454 GST_UNLOCK (element);
457 /* then check to see if the element's name is already taken in the bin,
458 * we can safely take the lock here. This check is probably bogus because
459 * you can safely change the element name after adding it to the bin. */
460 if (G_UNLIKELY (gst_object_check_uniqueness (bin->children,
461 elem_name) == FALSE))
464 /* set the element's parent and add the element to the bin's list of children */
465 if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT (element),
469 bin->children = g_list_prepend (bin->children, element);
471 bin->children_cookie++;
473 gst_element_set_scheduler (element, GST_ELEMENT_SCHEDULER (bin));
477 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
481 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
485 /* ERROR handling here */
488 g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
493 g_warning ("Name %s is not unique in bin %s, not adding",
494 elem_name, GST_ELEMENT_NAME (bin));
500 g_warning ("Element %s already has parent", elem_name);
508 * @bin: #GstBin to add element to
509 * @element: #GstElement to add to bin
511 * Adds the given element to the bin. Sets the element's parent, and thus
512 * takes ownership of the element. An element can only be added to one bin.
514 * Returns: TRUE if the element could be added, FALSE on wrong parameters or
515 * the bin does not want to accept the element.
520 gst_bin_add (GstBin * bin, GstElement * element)
525 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
526 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
528 bclass = GST_BIN_GET_CLASS (bin);
530 if (G_UNLIKELY (bclass->add_element == NULL))
533 GST_CAT_DEBUG (GST_CAT_PARENTAGE, "adding element %s to bin %s",
534 GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
536 result = bclass->add_element (bin, element);
541 g_warning ("adding elements to bin %s is not supported",
542 GST_ELEMENT_NAME (bin));
546 /* remove an element from the bin
551 gst_bin_remove_func (GstBin * bin, GstElement * element)
555 /* grab element name so we can print it */
557 elem_name = g_strdup (GST_ELEMENT_NAME (element));
558 GST_UNLOCK (element);
561 /* the element must be in the bin's list of children */
562 if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
565 /* now remove the element from the list of elements */
566 bin->children = g_list_remove (bin->children, element);
568 bin->children_cookie++;
571 GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
575 gst_element_set_scheduler (element, NULL);
577 /* we ref here because after the _unparent() the element can be disposed
578 * and we still need it to fire a signal. */
579 gst_object_ref (GST_OBJECT (element));
580 gst_object_unparent (GST_OBJECT (element));
582 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
583 /* element is really out of our control now */
584 gst_object_unref (GST_OBJECT (element));
589 g_warning ("Element %s is not in bin %s", elem_name, GST_ELEMENT_NAME (bin));
597 * @bin: #GstBin to remove element from
598 * @element: #GstElement to remove
600 * Remove the element from its associated bin, unparenting it as well.
601 * Unparenting the element means that the element will be dereferenced,
602 * so if the bin holds the only reference to the element, the element
603 * will be freed in the process of removing it from the bin. If you
604 * want the element to still exist after removing, you need to call
605 * #gst_object_ref before removing it from the bin.
607 * Returns: TRUE if the element could be removed, FALSE on wrong parameters or
608 * the bin does not want to remove the element.
613 gst_bin_remove (GstBin * bin, GstElement * element)
618 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
619 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
621 bclass = GST_BIN_GET_CLASS (bin);
623 if (G_UNLIKELY (bclass->remove_element == NULL))
626 GST_CAT_DEBUG (GST_CAT_PARENTAGE, "removing element %s from bin %s",
627 GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
629 result = bclass->remove_element (bin, element);
634 g_warning ("removing elements from bin %s is not supported",
635 GST_ELEMENT_NAME (bin));
639 static GstIteratorItem
640 iterate_child (GstIterator * it, GstElement * child)
642 gst_object_ref (GST_OBJECT (child));
643 return GST_ITERATOR_ITEM_PASS;
647 * gst_bin_iterate_elements:
648 * @bin: #Gstbin to iterate the elements of
650 * Get an iterator for the elements in this bin.
651 * Each element will have its refcount increased, so unref
654 * Returns: a #GstIterator of #GstElements. gst_iterator_free after
655 * use. returns NULL when passing bad parameters.
660 gst_bin_iterate_elements (GstBin * bin)
664 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
667 /* add ref because the iterator refs the bin. When the iterator
668 * is freed it will unref the bin again using the provided dispose
670 gst_object_ref (GST_OBJECT (bin));
671 result = gst_iterator_new_list (GST_GET_LOCK (bin),
672 &bin->children_cookie,
675 (GstIteratorItemFunction) iterate_child,
676 (GstIteratorDisposeFunction) gst_object_unref);
682 static GstIteratorItem
683 iterate_child_recurse (GstIterator * it, GstElement * child)
685 gst_object_ref (GST_OBJECT (child));
686 if (GST_IS_BIN (child)) {
687 GstIterator *other = gst_bin_iterate_recurse (GST_BIN (child));
689 gst_iterator_push (it, other);
691 return GST_ITERATOR_ITEM_PASS;
695 * gst_bin_iterate_recurse:
696 * @bin: #Gstbin to iterate the elements of
698 * Get an iterator for the elements in this bin.
699 * Each element will have its refcount increased, so unref
700 * after usage. This iterator recurses into GstBin children.
702 * Returns: a #GstIterator of #GstElements. gst_iterator_free after
703 * use. returns NULL when passing bad parameters.
708 gst_bin_iterate_recurse (GstBin * bin)
712 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
715 /* add ref because the iterator refs the bin. When the iterator
716 * is freed it will unref the bin again using the provided dispose
718 gst_object_ref (GST_OBJECT (bin));
719 result = gst_iterator_new_list (GST_GET_LOCK (bin),
720 &bin->children_cookie,
723 (GstIteratorItemFunction) iterate_child_recurse,
724 (GstIteratorDisposeFunction) gst_object_unref);
733 * gst_bin_child_state_change:
734 * @bin: #GstBin with the child
735 * @oldstate: The old child state
736 * @newstate: The new child state
737 * @child: #GstElement that signaled an changed state
739 * An internal function to inform the parent bin about a state change
743 gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
744 GstElementState newstate, GstElement * child)
748 g_return_if_fail (GST_IS_BIN (bin));
749 g_return_if_fail (GST_IS_ELEMENT (child));
751 GST_CAT_LOG (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s",
752 GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
753 gst_element_state_get_name (oldstate),
754 gst_element_state_get_name (newstate));
756 bclass = GST_BIN_GET_CLASS (bin);
758 if (bclass->child_state_change) {
759 bclass->child_state_change (bin, oldstate, newstate, child);
761 g_warning ("cannot signal state change of child %s to bin %s\n",
762 GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin));
767 gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
768 GstElementState newstate, GstElement * child)
770 GstElementState old = 0, new = 0;
771 gint old_idx = 0, new_idx = 0, i;
775 while ((old >>= 1) != 0)
777 while ((new >>= 1) != 0)
781 GST_LOG_BIN_CONTENTS (bin, "before child state change");
782 bin->child_states[old_idx]--;
783 bin->child_states[new_idx]++;
785 for (i = GST_NUM_STATES - 1; i >= 0; i--) {
786 if (bin->child_states[i] != 0) {
787 gint state = (1 << i);
789 /* We only change state on the parent if the state is not locked.
790 * State locking can occur if the bin itself set state on children,
791 * which should not recurse since it leads to infinite loops. */
792 if (GST_STATE (bin) != state &&
793 !GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
794 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
795 "highest child state is %s, changing bin state accordingly",
796 gst_element_state_get_name (state));
797 GST_STATE_PENDING (bin) = state;
799 gst_bin_change_state_norecurse (bin);
800 if (state != GST_STATE (bin)) {
801 g_warning ("%s: state change in callback %d %d",
802 GST_ELEMENT_NAME (bin), state, GST_STATE (bin));
804 GST_LOG_BIN_CONTENTS (bin, "after child state change");
810 GST_LOG_BIN_CONTENTS (bin, "after child state change");
814 typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
819 * @bin: bin to traverse
820 * @func: function to call on each child
821 * @data: user data handed to each function call
823 * Calls @func on each child of the bin. If @func returns FALSE,
824 * gst_bin_foreach() immediately returns.
825 * It is assumed that calling @func may alter the set of @bin's children. @func
826 * will only be called on children that were in @bin when gst_bin_foreach() was
827 * called, and that are still in @bin when the child is reached.
829 * Returns: TRUE if @func always returned TRUE, FALSE otherwise
832 gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
836 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
837 g_return_val_if_fail (func != NULL, FALSE);
839 kids = g_list_copy (bin->children);
841 for (walk = kids; walk; walk = g_list_next (walk)) {
842 GstElement *element = (GstElement *) walk->data;
844 if (g_list_find (bin->children, element)) {
845 gboolean res = func (bin, element, data);
860 GstElementState pending;
861 GstElementStateReturn result;
865 set_kid_state_func (GstBin * bin, GstElement * child, gpointer user_data)
867 GstElementState old_child_state;
868 SetKidStateData *data = user_data;
870 if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) {
874 old_child_state = GST_STATE (child);
876 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
877 "changing state of child %s from current %s to pending %s",
878 GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state),
879 gst_element_state_get_name (data->pending));
881 switch (gst_element_set_state (child, data->pending)) {
882 case GST_STATE_FAILURE:
883 GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
884 "child '%s' failed to go to state %d(%s)",
885 GST_ELEMENT_NAME (child),
886 data->pending, gst_element_state_get_name (data->pending));
888 gst_element_set_state (child, old_child_state);
889 return FALSE; /* error out to the caller */
891 case GST_STATE_ASYNC:
892 GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
893 "child '%s' is changing state asynchronously",
894 GST_ELEMENT_NAME (child));
895 data->result = GST_STATE_ASYNC;
898 case GST_STATE_SUCCESS:
899 GST_CAT_DEBUG (GST_CAT_STATES,
900 "child '%s' changed state to %d(%s) successfully",
901 GST_ELEMENT_NAME (child), data->pending,
902 gst_element_state_get_name (data->pending));
906 g_assert_not_reached ();
907 return FALSE; /* satisfy gcc */
911 static GstElementStateReturn
912 gst_bin_change_state (GstElement * element)
915 GstElementStateReturn ret;
916 GstElementState old_state, pending;
918 g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
920 bin = GST_BIN (element);
922 old_state = GST_STATE (element);
923 pending = GST_STATE_PENDING (element);
925 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
926 "changing state of children from %s to %s",
927 gst_element_state_get_name (old_state),
928 gst_element_state_get_name (pending));
930 if (pending == GST_STATE_VOID_PENDING)
931 return GST_STATE_SUCCESS;
933 /* If we're changing state non-recursively (see _norecurse()),
934 * this flag is already set and we should not set children states. */
935 if (!GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
936 SetKidStateData data;
938 /* So now we use this flag to make sure that kids don't re-set our
939 * state, which would lead to infinite loops. */
940 GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
941 data.pending = pending;
942 data.result = GST_STATE_SUCCESS;
943 if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
944 GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
945 GST_STATE_PENDING (element) = old_state;
946 return GST_STATE_FAILURE;
948 GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
950 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
951 "done changing bin's state from %s to %s, now in %s",
952 gst_element_state_get_name (old_state),
953 gst_element_state_get_name (pending),
954 gst_element_state_get_name (GST_STATE (element)));
956 /* if we're async, the kids will change state later (when the
957 * lock-state flag is no longer held) and all will be fine. */
958 if (data.result == GST_STATE_ASYNC)
959 return GST_STATE_ASYNC;
961 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
962 "Not recursing state change onto children");
965 /* FIXME: this should have been done by the children already, no? */
966 if (parent_class->change_state) {
967 ret = parent_class->change_state (element);
969 ret = GST_STATE_SUCCESS;
974 GstElementStateReturn
975 gst_bin_set_state (GstElement * element, GstElementState state)
977 GstBin *bin = GST_BIN (element);
979 if (GST_STATE (bin) == state) {
980 SetKidStateData data;
982 data.pending = state;
983 data.result = GST_STATE_SUCCESS;
984 if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
985 return GST_STATE_FAILURE;
990 return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, set_state, (element,
991 state), GST_STATE_FAILURE);
995 static GstElementStateReturn
996 gst_bin_change_state_norecurse (GstBin * bin)
998 GstElementStateReturn ret;
1000 if (GST_ELEMENT_GET_CLASS (bin)->change_state) {
1001 GST_CAT_LOG_OBJECT (GST_CAT_STATES, bin, "setting bin's own state");
1003 /* Non-recursive state change flag */
1004 GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
1005 ret = GST_ELEMENT_GET_CLASS (bin)->change_state (GST_ELEMENT (bin));
1006 GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
1010 return GST_STATE_FAILURE;
1014 gst_bin_dispose (GObject * object)
1016 GstBin *bin = GST_BIN (object);
1018 GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
1020 /* ref to not hit 0 again */
1021 gst_object_ref (GST_OBJECT (object));
1023 while (bin->children) {
1024 gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
1026 GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose no children");
1027 g_assert (bin->children == NULL);
1028 g_assert (bin->numchildren == 0);
1030 G_OBJECT_CLASS (parent_class)->dispose (object);
1034 compare_name (GstElement * element, const gchar * name)
1039 eq = strcmp (GST_ELEMENT_NAME (element), name) == 0;
1040 GST_UNLOCK (element);
1043 gst_object_unref (GST_OBJECT (element));
1049 * gst_bin_get_by_name:
1050 * @bin: #Gstbin to search
1051 * @name: the element name to search for
1053 * Get the element with the given name from this bin. This
1054 * function recurses into subbins.
1056 * Returns: the element with the given name. Returns NULL if the
1057 * element is not found or when bad parameters were given. Unref after
1063 gst_bin_get_by_name (GstBin * bin, const gchar * name)
1065 GstIterator *children;
1066 GstIterator *result;
1068 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1070 children = gst_bin_iterate_recurse (bin);
1071 result = gst_iterator_find_custom (children,
1072 (GCompareFunc) compare_name, (gpointer) name);
1074 return GST_ELEMENT_CAST (result);
1078 * gst_bin_get_by_name_recurse_up:
1079 * @bin: #Gstbin to search
1080 * @name: the element name to search for
1082 * Get the element with the given name from this bin. If the
1083 * element is not found, a recursion is performed on the parent bin.
1085 * Returns: the element with the given name or NULL when the element
1086 * was not found or bad parameters were given. Unref after usage.
1091 gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
1095 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1096 g_return_val_if_fail (name != NULL, NULL);
1098 result = gst_bin_get_by_name (bin, name);
1103 parent = gst_object_get_parent (GST_OBJECT_CAST (bin));
1105 if (parent && GST_IS_BIN (parent)) {
1106 result = gst_bin_get_by_name_recurse_up (GST_BIN_CAST (parent), name);
1108 gst_object_unref (parent);
1115 compare_interface (GstElement * element, gpointer interface)
1119 if (G_TYPE_CHECK_INSTANCE_TYPE (element, GPOINTER_TO_INT (interface))) {
1122 /* we did not find the element, need to release the ref
1123 * added by the iterator */
1124 gst_object_unref (GST_OBJECT (element));
1131 * gst_bin_get_by_interface:
1132 * @bin: bin to find element in
1133 * @interface: interface to be implemented by interface
1135 * Looks for the first element inside the bin that implements the given
1136 * interface. If such an element is found, it returns the element. You can
1137 * cast this element to the given interface afterwards.
1138 * If you want all elements that implement the interface, use
1139 * gst_bin_iterate_all_by_interface(). The function recurses bins inside bins.
1141 * Returns: An element inside the bin implementing the interface. Unref after
1147 gst_bin_get_by_interface (GstBin * bin, GType interface)
1149 GstIterator *children;
1150 GstIterator *result;
1152 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1154 children = gst_bin_iterate_recurse (bin);
1155 result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
1156 GINT_TO_POINTER (interface));
1158 return GST_ELEMENT_CAST (result);
1162 * gst_bin_get_all_by_interface:
1163 * @bin: bin to find elements in
1164 * @interface: interface to be implemented by interface
1166 * Looks for all elements inside the bin that implements the given
1167 * interface. You can safely cast all returned elements to the given interface.
1168 * The function recurses bins inside bins. The iterator will return a series
1169 * of #GstElement that should be unreffed after usage.
1171 * Returns: An iterator for the elements inside the bin implementing the interface.
1175 gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)
1177 GstIterator *children;
1178 GstIterator *result;
1180 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1182 children = gst_bin_iterate_recurse (bin);
1183 result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
1184 GINT_TO_POINTER (interface));
1190 * gst_bin_sync_children_state:
1191 * @bin: #Gstbin to sync state
1193 * Tries to set the state of the children of this bin to the same state of the
1194 * bin by calling gst_element_set_state for each child not already having a
1195 * synchronized state.
1197 * Returns: The worst return value of any gst_element_set_state. So if one child
1198 * returns #GST_STATE_FAILURE while all others return #GST_STATE_SUCCESS
1199 * this function returns #GST_STATE_FAILURE.
1201 GstElementStateReturn
1202 gst_bin_sync_children_state (GstBin * bin)
1205 GstElement *element;
1206 GstElementState state;
1207 GstElementStateReturn ret = GST_STATE_SUCCESS;
1209 g_return_val_if_fail (GST_IS_BIN (bin), GST_STATE_FAILURE);
1211 state = GST_STATE (bin);
1212 children = bin->children;
1213 GST_CAT_INFO (GST_CAT_STATES,
1214 "syncing state of children with bin \"%s\"'s state %s",
1215 GST_ELEMENT_NAME (bin), gst_element_state_get_name (state));
1218 element = GST_ELEMENT (children->data);
1219 children = children->next;
1220 if (GST_STATE (element) != state) {
1221 switch (gst_element_set_state (element, state)) {
1222 case GST_STATE_SUCCESS:
1224 case GST_STATE_ASYNC:
1225 if (ret == GST_STATE_SUCCESS)
1226 ret = GST_STATE_ASYNC;
1228 case GST_STATE_FAILURE:
1229 ret = GST_STATE_FAILURE;
1232 /* make sure gst_element_set_state never returns this */
1233 g_assert_not_reached ();
1241 #ifndef GST_DISABLE_LOADSAVE
1243 gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
1245 GstBin *bin = GST_BIN (object);
1246 xmlNodePtr childlist, elementnode;
1250 if (GST_OBJECT_CLASS (parent_class)->save_thyself)
1251 GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
1253 childlist = xmlNewChild (parent, NULL, "children", NULL);
1255 GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
1256 GST_ELEMENT_NAME (bin), bin->numchildren);
1258 children = bin->children;
1260 child = GST_ELEMENT (children->data);
1261 elementnode = xmlNewChild (childlist, NULL, "element", NULL);
1262 gst_object_save_thyself (GST_OBJECT (child), elementnode);
1263 children = g_list_next (children);
1269 gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
1271 GstBin *bin = GST_BIN (object);
1272 xmlNodePtr field = self->xmlChildrenNode;
1273 xmlNodePtr childlist;
1276 if (!strcmp (field->name, "children")) {
1277 GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
1278 GST_ELEMENT_NAME (object));
1279 childlist = field->xmlChildrenNode;
1281 if (!strcmp (childlist->name, "element")) {
1282 GstElement *element =
1283 gst_xml_make_element (childlist, GST_OBJECT (bin));
1285 /* it had to be parented to find the pads, now we ref and unparent so
1286 * we can add it to the bin */
1287 gst_object_ref (GST_OBJECT (element));
1288 gst_object_unparent (GST_OBJECT (element));
1290 gst_bin_add (bin, element);
1292 childlist = childlist->next;
1296 field = field->next;
1298 if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
1299 (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
1301 #endif /* GST_DISABLE_LOADSAVE */
1303 static GStaticRecMutex iterate_lock = G_STATIC_REC_MUTEX_INIT;
1306 gst_bin_iterate_func (GstBin * bin)
1308 GstScheduler *sched = GST_ELEMENT_SCHEDULER (bin);
1310 g_static_rec_mutex_unlock (&iterate_lock);
1312 /* only iterate if this is the manager bin */
1313 if (sched && sched->parent == GST_ELEMENT (bin)) {
1314 GstSchedulerState state;
1316 state = gst_scheduler_iterate (sched);
1318 if (state == GST_SCHEDULER_STATE_RUNNING) {
1320 } else if (state == GST_SCHEDULER_STATE_ERROR) {
1321 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
1322 } else if (state == GST_SCHEDULER_STATE_STOPPED) {
1323 /* check if we have children scheds that are still running */
1324 /* FIXME: remove in 0.9? autouseless because iterations gone? */
1327 for (walk = sched->schedulers; walk; walk = g_list_next (walk)) {
1328 GstScheduler *test = walk->data;
1330 g_return_val_if_fail (test->parent, FALSE);
1331 if (GST_STATE (test->parent) == GST_STATE_PLAYING) {
1332 GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, bin,
1333 "current bin is not iterating, but children are, "
1334 "so returning TRUE anyway...");
1341 g_warning ("bin \"%s\" is not the managing bin, can't be iterated on!\n",
1342 GST_ELEMENT_NAME (bin));
1345 g_static_rec_mutex_lock (&iterate_lock);
1350 g_static_rec_mutex_lock (&iterate_lock);
1356 * @bin: a#GstBin to iterate.
1358 * Iterates over the elements in this bin.
1360 * Returns: TRUE if the bin did something useful. This value
1361 * can be used to determine it the bin is in EOS.
1364 gst_bin_iterate (GstBin * bin)
1368 g_return_val_if_fail (bin != NULL, FALSE);
1369 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
1371 GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "starting iteration");
1372 gst_object_ref (GST_OBJECT (bin));
1374 g_static_rec_mutex_lock (&iterate_lock);
1376 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ITERATE], 0, &running);
1377 g_static_rec_mutex_unlock (&iterate_lock);
1379 gst_object_unref (GST_OBJECT (bin));
1380 GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "finished iteration");