3 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
4 * 2000 Wim Taymans <wtay@chello.be>
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.
24 #include "gst_private.h"
28 #include "gstmarshal.h"
33 #include "gstscheduler.h"
37 GST_DEBUG_CATEGORY_STATIC (bin_debug);
38 #define GST_CAT_DEFAULT bin_debug
39 #define GST_LOG_BIN_CONTENTS(bin, text) GST_LOG_OBJECT ((bin), \
40 text ": %d elements: %u PLAYING, %u PAUSED, %u READY, %u NULL, own state: %s", \
41 (bin)->numchildren, (guint) (bin)->child_states[3], \
42 (guint) (bin)->child_states[2], (bin)->child_states[1], \
43 (bin)->child_states[0], gst_element_state_get_name (GST_STATE (bin)))
46 static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
48 "Simple container object",
49 "Erik Walthinsen <omega@cse.ogi.edu>");
51 GType _gst_bin_type = 0;
53 static gboolean _gst_boolean_did_something_accumulator (GSignalInvocationHint *
54 ihint, GValue * return_accu, const GValue * handler_return, gpointer dummy);
56 static void gst_bin_dispose (GObject * object);
58 static GstElementStateReturn gst_bin_change_state (GstElement * element);
59 static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin);
61 #ifndef GST_DISABLE_INDEX
62 static void gst_bin_set_index (GstElement * element, GstIndex * index);
65 static void gst_bin_add_func (GstBin * bin, GstElement * element);
66 static void gst_bin_remove_func (GstBin * bin, GstElement * element);
67 static void gst_bin_child_state_change_func (GstBin * bin,
68 GstElementState oldstate, GstElementState newstate, GstElement * child);
69 GstElementStateReturn gst_bin_set_state (GstElement * element,
70 GstElementState state);
72 static GstClock *gst_bin_get_clock_func (GstElement * element);
73 static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
75 static gboolean gst_bin_iterate_func (GstBin * bin);
77 #ifndef GST_DISABLE_LOADSAVE
78 static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
79 static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
82 /* Bin signals and args */
97 static void gst_bin_base_init (gpointer g_class);
98 static void gst_bin_class_init (GstBinClass * klass);
99 static void gst_bin_init (GstBin * bin);
101 static GstElementClass *parent_class = NULL;
102 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
107 * Returns: the type of #GstBin
110 gst_bin_get_type (void)
112 if (!_gst_bin_type) {
113 static const GTypeInfo bin_info = {
114 sizeof (GstBinClass),
117 (GClassInitFunc) gst_bin_class_init,
122 (GInstanceInitFunc) gst_bin_init,
127 g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
129 GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
130 "debugging info for the 'bin' container element");
132 return _gst_bin_type;
136 gst_bin_base_init (gpointer g_class)
138 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
140 gst_element_class_set_details (gstelement_class, &gst_bin_details);
144 gst_bin_class_init (GstBinClass * klass)
146 GObjectClass *gobject_class;
147 GstObjectClass *gstobject_class;
148 GstElementClass *gstelement_class;
150 gobject_class = (GObjectClass *) klass;
151 gstobject_class = (GstObjectClass *) klass;
152 gstelement_class = (GstElementClass *) klass;
154 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
156 gst_bin_signals[ELEMENT_ADDED] =
157 g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
158 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
159 NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
160 gst_bin_signals[ELEMENT_REMOVED] =
161 g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
162 G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
163 NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
164 gst_bin_signals[ITERATE] =
165 g_signal_new ("iterate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
166 G_STRUCT_OFFSET (GstBinClass, iterate),
167 _gst_boolean_did_something_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
170 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
172 #ifndef GST_DISABLE_LOADSAVE
173 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
174 gstobject_class->restore_thyself =
175 GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
178 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
179 gstelement_class->set_state = GST_DEBUG_FUNCPTR (gst_bin_set_state);
180 #ifndef GST_DISABLE_INDEX
181 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index);
184 klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
185 klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
186 klass->child_state_change =
187 GST_DEBUG_FUNCPTR (gst_bin_child_state_change_func);
188 klass->iterate = GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
192 _gst_boolean_did_something_accumulator (GSignalInvocationHint * ihint,
193 GValue * return_accu, const GValue * handler_return, gpointer dummy)
195 gboolean did_something;
197 did_something = g_value_get_boolean (handler_return);
199 g_value_set_boolean (return_accu, TRUE);
202 /* always continue emission */
207 gst_bin_init (GstBin * bin)
209 /* in general, we prefer to use cothreads for most things */
210 GST_FLAG_SET (bin, GST_BIN_FLAG_PREFER_COTHREADS);
212 bin->numchildren = 0;
213 bin->children = NULL;
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_SCHED (element))
234 return gst_scheduler_get_clock (GST_ELEMENT_SCHED (element));
240 gst_bin_set_clock_func (GstElement * element, GstClock * clock)
242 if (GST_ELEMENT_SCHED (element))
243 gst_scheduler_use_clock (GST_ELEMENT_SCHED (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_SCHED (bin))
291 gst_scheduler_auto_clock (GST_ELEMENT_SCHED (bin));
294 #ifndef GST_DISABLE_INDEX
296 gst_bin_set_index (GstElement * element, GstIndex * index)
298 GstBin *bin = GST_BIN (element);
300 g_return_if_fail (GST_IS_BIN (bin));
302 g_list_foreach (bin->children, (GFunc) gst_element_set_index, index);
307 gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
309 GST_CAT_LOG (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",
310 GST_ELEMENT_NAME (element), sched);
312 /* if it's actually a Bin */
313 if (GST_IS_BIN (element)) {
314 if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
315 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
316 "child is already a manager, not resetting sched");
317 if (GST_ELEMENT_SCHED (element))
318 gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHED (element));
322 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
323 "setting child bin's scheduler to be the same as the parent's");
324 gst_scheduler_add_element (sched, element);
326 /* set the children's schedule */
327 g_list_foreach (GST_BIN (element)->children,
328 (GFunc) gst_bin_set_element_sched, sched);
330 /* otherwise, if it's just a regular old element */
333 gst_scheduler_add_element (sched, element);
335 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
336 /* set the sched pointer in all the pads */
337 pads = element->pads;
341 pad = GST_PAD (pads->data);
342 pads = g_list_next (pads);
344 /* we only operate on real pads */
345 if (!GST_IS_REAL_PAD (pad))
348 /* if the peer element exists and is a candidate */
349 if (GST_PAD_PEER (pad)) {
350 if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
351 GST_CAT_LOG (GST_CAT_SCHEDULING,
352 "peer is in same scheduler, telling scheduler");
354 if (GST_PAD_IS_SRC (pad))
355 gst_scheduler_pad_link (sched, pad, GST_PAD_PEER (pad));
357 gst_scheduler_pad_link (sched, GST_PAD_PEER (pad), pad);
366 gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
368 if (GST_ELEMENT_SCHED (element) == NULL) {
369 GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element \"%s\" has no scheduler",
370 GST_ELEMENT_NAME (element));
374 GST_CAT_DEBUG (GST_CAT_SCHEDULING,
375 "removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element),
376 GST_ELEMENT_SCHED (element));
378 /* if it's actually a Bin */
379 if (GST_IS_BIN (element)) {
381 if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
382 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
383 "child is already a manager, not unsetting sched");
385 gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHED (element));
389 /* for each child, remove them from their schedule */
390 g_list_foreach (GST_BIN (element)->children,
391 (GFunc) gst_bin_unset_element_sched, sched);
393 gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
395 /* otherwise, if it's just a regular old element */
398 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
399 /* unset the sched pointer in all the pads */
400 pads = element->pads;
404 pad = GST_PAD (pads->data);
405 pads = g_list_next (pads);
407 /* we only operate on real pads */
408 if (!GST_IS_REAL_PAD (pad))
411 /* if the peer element exists and is a candidate */
412 if (GST_PAD_PEER (pad)) {
413 if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
414 GST_CAT_LOG (GST_CAT_SCHEDULING,
415 "peer is in same scheduler, telling scheduler");
417 if (GST_PAD_IS_SRC (pad))
418 gst_scheduler_pad_unlink (sched, pad, GST_PAD_PEER (pad));
420 gst_scheduler_pad_unlink (sched, GST_PAD_PEER (pad), pad);
426 gst_scheduler_remove_element (GST_ELEMENT_SCHED (element), element);
433 * @bin: the bin to add the elements to
434 * @element_1: the first element to add to the bin
435 * @...: additional elements to add to the bin
437 * Adds a NULL-terminated list of elements to a bin. This function is
438 * equivalent to calling #gst_bin_add() for each member of the list.
441 gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)
445 g_return_if_fail (GST_IS_BIN (bin));
446 g_return_if_fail (GST_IS_ELEMENT (element_1));
448 va_start (args, element_1);
451 gst_bin_add (bin, element_1);
453 element_1 = va_arg (args, GstElement *);
460 gst_bin_add_func (GstBin * bin, GstElement * element)
463 GstElementState state;
466 /* the element must not already have a parent */
467 g_return_if_fail (GST_ELEMENT_PARENT (element) == NULL);
469 /* then check to see if the element's name is already taken in the bin */
470 if (gst_object_check_uniqueness (bin->children,
471 GST_ELEMENT_NAME (element)) == FALSE) {
472 g_warning ("Name %s is not unique in bin %s, not adding\n",
473 GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
477 if (GST_STATE (element) > GST_STATE (bin)) {
478 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
479 "setting state to receive element \"%s\"", GST_OBJECT_NAME (element));
480 gst_element_set_state ((GstElement *) bin, GST_STATE (element));
483 /* set the element's parent and add the element to the bin's list of children */
484 gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
486 bin->children = g_list_append (bin->children, element);
489 /* bump our internal state counter */
490 state = GST_STATE (element);
491 while ((state >>= 1) != 0)
493 bin->child_states[state_idx]++;
495 /* now we have to deal with manager stuff
496 * we can only do this if there's a scheduler:
497 * if we're not a manager, and aren't attached to anything, we have no sched (yet) */
498 sched = GST_ELEMENT_SCHED (bin);
500 gst_bin_set_element_sched (element, sched);
503 GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
504 GST_OBJECT_NAME (element));
506 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
511 * @bin: #GstBin to add element to
512 * @element: #GstElement to add to bin
514 * Adds the given element to the bin. Sets the element's parent, and thus
515 * takes ownership of the element. An element can only be added to one bin.
518 gst_bin_add (GstBin * bin, GstElement * element)
522 g_return_if_fail (GST_IS_BIN (bin));
523 g_return_if_fail (GST_IS_ELEMENT (element));
525 GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "adding element \"%s\"",
526 GST_OBJECT_NAME (element));
528 bclass = GST_BIN_GET_CLASS (bin);
530 if (bclass->add_element) {
531 bclass->add_element (bin, element);
533 GST_ELEMENT_ERROR (bin, CORE, FAILED, (NULL),
534 ("cannot add element %s to bin %s",
535 GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin)));
540 gst_bin_remove_func (GstBin * bin, GstElement * element)
543 GstElementState state;
545 /* the element must have its parent set to the current bin */
546 g_return_if_fail (GST_ELEMENT_PARENT (element) == (GstObject *) bin);
548 /* the element must be in the bin's list of children */
549 if (g_list_find (bin->children, element) == NULL) {
550 g_warning ("no element \"%s\" in bin \"%s\"\n", GST_ELEMENT_NAME (element),
551 GST_ELEMENT_NAME (bin));
555 /* remove this element from the list of managed elements */
556 gst_bin_unset_element_sched (element, GST_ELEMENT_SCHED (bin));
558 /* now remove the element from the list of elements */
559 bin->children = g_list_remove (bin->children, element);
562 /* bump our internal state counter */
563 state = GST_STATE (element);
564 while ((state >>= 1) != 0)
566 bin->child_states[state_idx]--;
568 GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
569 GST_OBJECT_NAME (element));
571 /* ref as we're going to emit a signal */
572 gst_object_ref (GST_OBJECT (element));
573 gst_object_unparent (GST_OBJECT (element));
575 /* if we're down to zero children, force state to NULL */
576 while (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL &&
577 GST_STATE (bin) > GST_STATE_NULL) {
578 GstElementState next = GST_STATE (bin) >> 1;
580 GST_STATE_PENDING (bin) = next;
581 gst_bin_change_state_norecurse (bin);
582 if (!GST_STATE (bin) == next) {
583 g_warning ("bin %s failed state change to %d", GST_ELEMENT_NAME (bin),
588 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
590 /* element is really out of our control now */
591 gst_object_unref (GST_OBJECT (element));
596 * @bin: #GstBin to remove element from
597 * @element: #GstElement to remove
599 * Remove the element from its associated bin, unparenting it as well.
600 * Unparenting the element means that the element will be dereferenced,
601 * so if the bin holds the only reference to the element, the element
602 * will be freed in the process of removing it from the bin. If you
603 * want the element to still exist after removing, you need to call
604 * #gst_object_ref before removing it from the bin.
607 gst_bin_remove (GstBin * bin, GstElement * element)
611 GST_CAT_DEBUG (GST_CAT_PARENTAGE, "[%s]: trying to remove child %s",
612 GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (element));
614 g_return_if_fail (GST_IS_BIN (bin));
615 g_return_if_fail (GST_IS_ELEMENT (element));
617 bclass = GST_BIN_GET_CLASS (bin);
619 if (bclass->remove_element) {
620 bclass->remove_element (bin, element);
622 g_warning ("cannot remove elements from bin %s\n", GST_ELEMENT_NAME (bin));
627 * gst_bin_remove_many:
628 * @bin: the bin to remove the elements from
629 * @element_1: the first element to remove from the bin
630 * @...: NULL-terminated list of elements to remove from the bin
632 * Remove a list of elements from a bin. This function is equivalent
633 * to calling #gst_bin_remove with each member of the list.
636 gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
640 g_return_if_fail (GST_IS_BIN (bin));
641 g_return_if_fail (GST_IS_ELEMENT (element_1));
643 va_start (args, element_1);
646 gst_bin_remove (bin, element_1);
648 element_1 = va_arg (args, GstElement *);
655 * gst_bin_child_state_change:
656 * @bin: #GstBin with the child
657 * @oldstate: The old child state
658 * @newstate: The new child state
659 * @child: #GstElement that signaled an changed state
661 * An internal function to inform the parent bin about a state change
665 gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
666 GstElementState newstate, GstElement * child)
670 g_return_if_fail (GST_IS_BIN (bin));
671 g_return_if_fail (GST_IS_ELEMENT (child));
673 GST_CAT_LOG (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s",
674 GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
675 gst_element_state_get_name (oldstate),
676 gst_element_state_get_name (newstate));
678 bclass = GST_BIN_GET_CLASS (bin);
680 if (bclass->child_state_change) {
681 bclass->child_state_change (bin, oldstate, newstate, child);
683 g_warning ("cannot signal state change of child %s to bin %s\n",
684 GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin));
689 gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
690 GstElementState newstate, GstElement * child)
692 GstElementState old = 0, new = 0;
693 gint old_idx = 0, new_idx = 0, i;
697 while ((old >>= 1) != 0)
699 while ((new >>= 1) != 0)
703 GST_LOG_BIN_CONTENTS (bin, "before child state change");
704 bin->child_states[old_idx]--;
705 bin->child_states[new_idx]++;
707 for (i = GST_NUM_STATES - 1; i >= 0; i--) {
708 if (bin->child_states[i] != 0) {
709 gint state = (1 << i);
711 if (GST_STATE (bin) != state) {
712 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
713 "highest child state is %s, changing bin state accordingly",
714 gst_element_state_get_name (state));
715 GST_STATE_PENDING (bin) = state;
717 gst_bin_change_state_norecurse (bin);
718 if (state != GST_STATE (bin)) {
719 g_warning ("%s: state change in callback %d %d",
720 GST_ELEMENT_NAME (bin), state, GST_STATE (bin));
722 GST_LOG_BIN_CONTENTS (bin, "after child state change");
728 GST_LOG_BIN_CONTENTS (bin, "after child state change");
732 typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
737 * @bin: bin to traverse
738 * @func: function to call on each child
739 * @data: user data handed to each function call
741 * Calls @func on each child of the bin. If @func returns FALSE,
742 * gst_bin_foreach() immediately returns.
743 * It is assumed that calling @func may alter the set of @bin's children. @func
744 * will only be called on children that were in @bin when gst_bin_foreach() was
745 * called, and that are still in @bin when the child is reached.
747 * Returns: TRUE if @func always returned TRUE, FALSE otherwise
750 gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
754 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
755 g_return_val_if_fail (func != NULL, FALSE);
757 kids = g_list_copy (bin->children);
759 for (walk = kids; walk; walk = g_list_next (walk)) {
760 GstElement *element = (GstElement *) walk->data;
762 if (g_list_find (bin->children, element)) {
763 gboolean res = func (bin, element, data);
778 GstElementState pending;
779 GstElementStateReturn result;
783 set_kid_state_func (GstBin * bin, GstElement * child, gpointer user_data)
785 GstElementState old_child_state;
786 SetKidStateData *data = user_data;
788 if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) {
792 old_child_state = GST_STATE (child);
794 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
795 "changing state of child %s from current %s to pending %s",
796 GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state),
797 gst_element_state_get_name (data->pending));
799 switch (gst_element_set_state (child, data->pending)) {
800 case GST_STATE_FAILURE:
801 GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
802 "child '%s' failed to go to state %d(%s)",
803 GST_ELEMENT_NAME (child),
804 data->pending, gst_element_state_get_name (data->pending));
806 gst_element_set_state (child, old_child_state);
807 return FALSE; /* error out to the caller */
809 case GST_STATE_ASYNC:
810 GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
811 "child '%s' is changing state asynchronously",
812 GST_ELEMENT_NAME (child));
813 data->result = GST_STATE_ASYNC;
816 case GST_STATE_SUCCESS:
817 GST_CAT_DEBUG (GST_CAT_STATES,
818 "child '%s' changed state to %d(%s) successfully",
819 GST_ELEMENT_NAME (child), data->pending,
820 gst_element_state_get_name (data->pending));
824 g_assert_not_reached ();
825 return FALSE; /* satisfy gcc */
829 static GstElementStateReturn
830 gst_bin_change_state (GstElement * element)
833 GstElementStateReturn ret;
834 GstElementState old_state, pending;
835 SetKidStateData data;
837 g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
839 bin = GST_BIN (element);
841 old_state = GST_STATE (element);
842 pending = GST_STATE_PENDING (element);
844 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
845 "changing state of children from %s to %s",
846 gst_element_state_get_name (old_state),
847 gst_element_state_get_name (pending));
849 if (pending == GST_STATE_VOID_PENDING)
850 return GST_STATE_SUCCESS;
852 data.pending = pending;
853 data.result = GST_STATE_SUCCESS;
854 if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
855 GST_STATE_PENDING (element) = old_state;
856 return GST_STATE_FAILURE;
859 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
860 "done changing bin's state from %s to %s, now in %s",
861 gst_element_state_get_name (old_state),
862 gst_element_state_get_name (pending),
863 gst_element_state_get_name (GST_STATE (element)));
865 if (data.result == GST_STATE_ASYNC)
866 ret = GST_STATE_ASYNC;
868 /* FIXME: this should have been done by the children already, no? */
869 if (parent_class->change_state) {
870 ret = parent_class->change_state (element);
872 ret = GST_STATE_SUCCESS;
877 GstElementStateReturn
878 gst_bin_set_state (GstElement * element, GstElementState state)
880 GstBin *bin = GST_BIN (element);
882 if (GST_STATE (bin) == state) {
883 SetKidStateData data;
885 data.pending = state;
886 data.result = GST_STATE_SUCCESS;
887 if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
888 return GST_STATE_FAILURE;
893 return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, set_state, (element,
894 state), GST_STATE_FAILURE);
898 static GstElementStateReturn
899 gst_bin_change_state_norecurse (GstBin * bin)
901 GstElementStateReturn ret;
903 if (parent_class->change_state) {
904 GST_CAT_LOG_OBJECT (GST_CAT_STATES, bin, "setting bin's own state");
905 ret = parent_class->change_state (GST_ELEMENT (bin));
909 return GST_STATE_FAILURE;
913 gst_bin_dispose (GObject * object)
915 GstBin *bin = GST_BIN (object);
917 GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
919 gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
921 while (bin->children) {
922 gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
924 g_assert (bin->children == NULL);
925 g_assert (bin->numchildren == 0);
927 G_OBJECT_CLASS (parent_class)->dispose (object);
931 * gst_bin_get_by_name:
932 * @bin: #Gstbin to search
933 * @name: the element name to search for
935 * Get the element with the given name from this bin.
937 * Returns: the element with the given name
940 gst_bin_get_by_name (GstBin * bin, const gchar * name)
945 g_return_val_if_fail (bin != NULL, NULL);
946 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
947 g_return_val_if_fail (name != NULL, NULL);
949 GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
950 GST_ELEMENT_NAME (bin), name);
952 children = bin->children;
954 child = GST_ELEMENT (children->data);
955 if (!strcmp (GST_OBJECT_NAME (child), name))
957 if (GST_IS_BIN (child)) {
958 GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
963 children = g_list_next (children);
970 * gst_bin_get_by_name_recurse_up:
971 * @bin: #Gstbin to search
972 * @name: the element name to search for
974 * Get the element with the given name from this bin. If the
975 * element is not found, a recursion is performed on the parent bin.
977 * Returns: the element with the given name
980 gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
982 GstElement *result = NULL;
985 g_return_val_if_fail (bin != NULL, NULL);
986 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
987 g_return_val_if_fail (name != NULL, NULL);
989 result = gst_bin_get_by_name (bin, name);
992 parent = gst_object_get_parent (GST_OBJECT (bin));
994 if (parent && GST_IS_BIN (parent)) {
995 result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
1004 * @bin: #Gstbin to get the list from
1006 * Get the list of elements in this bin.
1008 * Returns: a GList of elements
1011 gst_bin_get_list (GstBin * bin)
1013 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1015 return bin->children;
1019 * gst_bin_get_by_interface:
1020 * @bin: bin to find element in
1021 * @interface: interface to be implemented by interface
1023 * Looks for the first element inside the bin that implements the given
1024 * interface. If such an element is found, it returns the element. You can
1025 * cast this element to the given interface afterwards.
1026 * If you want all elements that implement the interface, use
1027 * gst_bin_get_all_by_interface(). The function recurses bins inside bins.
1029 * Returns: An element inside the bin implementing the interface.
1032 gst_bin_get_by_interface (GstBin * bin, GType interface)
1036 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1037 g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
1039 walk = bin->children;
1041 if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface))
1042 return GST_ELEMENT (walk->data);
1043 if (GST_IS_BIN (walk->data)) {
1046 ret = gst_bin_get_by_interface (GST_BIN (walk->data), interface);
1050 walk = g_list_next (walk);
1057 * gst_bin_get_all_by_interface:
1058 * @bin: bin to find elements in
1059 * @interface: interface to be implemented by interface
1061 * Looks for all elements inside the bin that implements the given
1062 * interface. You can safely cast all returned elements to the given interface.
1063 * The function recurses bins inside bins. You need to free the list using
1064 * g_list_free() after use.
1066 * Returns: An element inside the bin implementing the interface.
1069 gst_bin_get_all_by_interface (GstBin * bin, GType interface)
1071 GList *walk, *ret = NULL;
1073 g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1074 g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface), NULL);
1076 walk = bin->children;
1078 if (G_TYPE_CHECK_INSTANCE_TYPE (walk->data, interface)) {
1079 GST_DEBUG_OBJECT (bin, "element %s implements requested interface",
1080 GST_ELEMENT_NAME (GST_ELEMENT (walk->data)));
1081 ret = g_list_prepend (ret, walk->data);
1083 if (GST_IS_BIN (walk->data)) {
1084 ret = g_list_concat (ret,
1085 gst_bin_get_all_by_interface (GST_BIN (walk->data), interface));
1087 walk = g_list_next (walk);
1094 * gst_bin_sync_children_state:
1095 * @bin: #Gstbin to sync state
1097 * Tries to set the state of the children of this bin to the same state of the
1098 * bin by calling gst_element_set_state for each child not already having a
1099 * synchronized state.
1101 * Returns: The worst return value of any gst_element_set_state. So if one child
1102 * returns #GST_STATE_FAILURE while all others return #GST_STATE_SUCCESS
1103 * this function returns #GST_STATE_FAILURE.
1105 GstElementStateReturn
1106 gst_bin_sync_children_state (GstBin * bin)
1109 GstElement *element;
1110 GstElementState state;
1111 GstElementStateReturn ret = GST_STATE_SUCCESS;
1113 g_return_val_if_fail (GST_IS_BIN (bin), GST_STATE_FAILURE);
1115 state = GST_STATE (bin);
1116 children = bin->children;
1117 GST_CAT_INFO (GST_CAT_STATES,
1118 "syncing state of children with bin \"%s\"'s state %s",
1119 GST_ELEMENT_NAME (bin), gst_element_state_get_name (state));
1122 element = GST_ELEMENT (children->data);
1123 children = children->next;
1124 if (GST_STATE (element) != state) {
1125 switch (gst_element_set_state (element, state)) {
1126 case GST_STATE_SUCCESS:
1128 case GST_STATE_ASYNC:
1129 if (ret == GST_STATE_SUCCESS)
1130 ret = GST_STATE_ASYNC;
1132 case GST_STATE_FAILURE:
1133 ret = GST_STATE_FAILURE;
1136 /* make sure gst_element_set_state never returns this */
1137 g_assert_not_reached ();
1145 #ifndef GST_DISABLE_LOADSAVE
1147 gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
1149 GstBin *bin = GST_BIN (object);
1150 xmlNodePtr childlist, elementnode;
1154 if (GST_OBJECT_CLASS (parent_class)->save_thyself)
1155 GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
1157 childlist = xmlNewChild (parent, NULL, "children", NULL);
1159 GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
1160 GST_ELEMENT_NAME (bin), bin->numchildren);
1162 children = bin->children;
1164 child = GST_ELEMENT (children->data);
1165 elementnode = xmlNewChild (childlist, NULL, "element", NULL);
1166 gst_object_save_thyself (GST_OBJECT (child), elementnode);
1167 children = g_list_next (children);
1173 gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
1175 GstBin *bin = GST_BIN (object);
1176 xmlNodePtr field = self->xmlChildrenNode;
1177 xmlNodePtr childlist;
1180 if (!strcmp (field->name, "children")) {
1181 GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
1182 GST_ELEMENT_NAME (object));
1183 childlist = field->xmlChildrenNode;
1185 if (!strcmp (childlist->name, "element")) {
1186 GstElement *element =
1187 gst_xml_make_element (childlist, GST_OBJECT (bin));
1189 /* it had to be parented to find the pads, now we ref and unparent so
1190 * we can add it to the bin */
1191 gst_object_ref (GST_OBJECT (element));
1192 gst_object_unparent (GST_OBJECT (element));
1194 gst_bin_add (bin, element);
1196 childlist = childlist->next;
1200 field = field->next;
1202 if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
1203 (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
1205 #endif /* GST_DISABLE_LOADSAVE */
1208 gst_bin_iterate_func (GstBin * bin)
1210 GstScheduler *sched = GST_ELEMENT_SCHED (bin);
1212 /* only iterate if this is the manager bin */
1213 if (sched && sched->parent == GST_ELEMENT (bin)) {
1214 GstSchedulerState state;
1216 state = gst_scheduler_iterate (sched);
1218 if (state == GST_SCHEDULER_STATE_RUNNING) {
1220 } else if (state == GST_SCHEDULER_STATE_ERROR) {
1221 gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
1222 } else if (state == GST_SCHEDULER_STATE_STOPPED) {
1223 /* check if we have children scheds that are still running */
1224 /* FIXME: remove in 0.9? autouseless because iterations gone? */
1227 for (walk = sched->schedulers; walk; walk = g_list_next (walk)) {
1228 GstScheduler *test = walk->data;
1230 g_return_val_if_fail (test->parent, FALSE);
1231 if (GST_STATE (test->parent) == GST_STATE_PLAYING) {
1232 GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, bin,
1233 "current bin is not iterating, but children are, "
1234 "so returning TRUE anyway...");
1241 g_warning ("bin \"%s\" is not the managing bin, can't be iterated on!\n",
1242 GST_ELEMENT_NAME (bin));
1250 * @bin: a#GstBin to iterate.
1252 * Iterates over the elements in this bin.
1254 * Returns: TRUE if the bin did something useful. This value
1255 * can be used to determine it the bin is in EOS.
1258 gst_bin_iterate (GstBin * bin)
1262 g_return_val_if_fail (bin != NULL, FALSE);
1263 g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
1265 GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "starting iteration");
1266 gst_object_ref (GST_OBJECT (bin));
1269 g_signal_emit (G_OBJECT (bin), gst_bin_signals[ITERATE], 0, &running);
1271 gst_object_unref (GST_OBJECT (bin));
1272 GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "finished iteration");