Removed dead code
[platform/upstream/gstreamer.git] / gst / gstbin.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstbin.c: GstBin container object and support code
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
25
26 #include "gstbin.h"
27
28 #include "gstscheduler.h"
29
30 GstElementDetails gst_bin_details = {
31   "Generic bin",
32   "Bin",
33   "Simple container object",
34   VERSION,
35   "Erik Walthinsen <omega@cse.ogi.edu>",
36   "(C) 1999",
37 };
38
39 GType _gst_bin_type = 0;
40
41 static void                     gst_bin_dispose         (GObject *object);
42
43 static GstElementStateReturn    gst_bin_change_state            (GstElement *element);
44 static GstElementStateReturn    gst_bin_change_state_norecurse  (GstBin *bin);
45 static gboolean                 gst_bin_change_state_type       (GstBin *bin,
46                                                                  GstElementState state,
47                                                                  GType type);
48 static void                     gst_bin_child_state_change      (GstBin *bin, GstElementState old, 
49                                                                  GstElementState new, GstElement *child);
50
51 static gboolean                 gst_bin_iterate_func            (GstBin *bin);
52
53 #ifndef GST_DISABLE_LOADSAVE
54 static xmlNodePtr               gst_bin_save_thyself            (GstObject *object, xmlNodePtr parent);
55 static void                     gst_bin_restore_thyself         (GstObject *object, xmlNodePtr self);
56 #endif
57
58 /* Bin signals and args */
59 enum {
60   OBJECT_ADDED,
61   LAST_SIGNAL
62 };
63
64 enum {
65   ARG_0,
66   /* FILL ME */
67 };
68
69
70 static void gst_bin_class_init  (GstBinClass *klass);
71 static void gst_bin_init        (GstBin *bin);
72
73
74 static GstElementClass *parent_class = NULL;
75 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
76
77 GType
78 gst_bin_get_type (void)
79 {
80   if (!_gst_bin_type) {
81     static const GTypeInfo bin_info = {
82       sizeof(GstBinClass),
83       NULL,
84       NULL,
85       (GClassInitFunc)gst_bin_class_init,
86       NULL,
87       NULL,
88       sizeof(GstBin),
89       8,
90       (GInstanceInitFunc)gst_bin_init,
91       NULL
92     };
93     _gst_bin_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
94   }
95   return _gst_bin_type;
96 }
97
98 static void
99 gst_bin_class_init (GstBinClass *klass)
100 {
101   GObjectClass *gobject_class;
102   GstObjectClass *gstobject_class;
103   GstElementClass *gstelement_class;
104
105   gobject_class = (GObjectClass*)klass;
106   gstobject_class = (GstObjectClass*)klass;
107   gstelement_class = (GstElementClass*)klass;
108
109   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
110
111   gst_bin_signals[OBJECT_ADDED] =
112     g_signal_new ("object_added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST,
113                     G_STRUCT_OFFSET (GstBinClass, object_added), NULL, NULL,
114                     gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
115                     GST_TYPE_ELEMENT);
116
117   klass->change_state_type =            GST_DEBUG_FUNCPTR (gst_bin_change_state_type);
118   klass->iterate =                      GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
119
120 #ifndef GST_DISABLE_LOADSAVE
121   gstobject_class->save_thyself =       GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
122   gstobject_class->restore_thyself =    GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
123 #endif
124
125   gstelement_class->change_state =      GST_DEBUG_FUNCPTR (gst_bin_change_state);
126
127   gobject_class->dispose =              GST_DEBUG_FUNCPTR (gst_bin_dispose);
128 }
129
130 static void
131 gst_bin_init (GstBin *bin)
132 {
133   // in general, we prefer to use cothreads for most things
134   GST_FLAG_SET (bin, GST_BIN_FLAG_PREFER_COTHREADS);
135
136   bin->numchildren = 0;
137   bin->children = NULL;
138   bin->eoscond = g_cond_new ();
139 }
140
141 /**
142  * gst_bin_new:
143  * @name: name of new bin
144  *
145  * Create a new bin with given name.
146  *
147  * Returns: new bin
148  */
149 GstElement*
150 gst_bin_new (const gchar *name)
151 {
152   return gst_elementfactory_make ("bin", name);
153 }
154
155 static inline void
156 gst_bin_reset_element_sched (GstElement *element, GstScheduler *sched)
157 {
158   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
159
160   gst_element_set_sched (element,sched);
161 }
162
163 static void
164 gst_bin_set_element_sched (GstElement *element,GstScheduler *sched)
165 {
166   GList *children;
167   GstElement *child;
168
169   g_return_if_fail (element != NULL);
170   g_return_if_fail (GST_IS_ELEMENT(element));
171   g_return_if_fail (sched != NULL);
172   g_return_if_fail (GST_IS_SCHEDULER(sched));
173
174   GST_INFO (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",GST_ELEMENT_NAME(element),
175             sched);
176
177   // if it's actually a Bin
178   if (GST_IS_BIN(element)) {
179     if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
180       GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
181       return;
182     }
183
184     GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's schedule to parent's");
185     gst_scheduler_add_element (sched, element);
186
187     // set the children's schedule
188     children = GST_BIN(element)->children;
189     while (children) {
190       child = GST_ELEMENT (children->data);
191       children = g_list_next(children);
192
193       gst_bin_set_element_sched (child, sched);
194     }
195
196   // otherwise, if it's just a regular old element
197   } else {
198     gst_scheduler_add_element (sched, element);
199   }
200 }
201
202
203 static void
204 gst_bin_unset_element_sched (GstElement *element)
205 {
206   GList *children;
207   GstElement *child;
208
209   g_return_if_fail (element != NULL);
210   g_return_if_fail (GST_IS_ELEMENT(element));
211
212   GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
213             GST_ELEMENT_NAME(element),GST_ELEMENT_SCHED(element));
214
215   // if it's actually a Bin
216   if (GST_IS_BIN(element)) {
217
218     if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
219       GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched");
220       return;
221     }
222
223     // FIXME this check should be irrelevant
224     if (GST_ELEMENT_SCHED (element))
225       gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element);
226
227     // for each child, remove them from their schedule
228     children = GST_BIN(element)->children;
229     while (children) {
230       child = GST_ELEMENT (children->data);
231       children = g_list_next(children);
232
233       gst_bin_unset_element_sched (child);
234     }
235
236   // otherwise, if it's just a regular old element
237   } else {
238     // FIXME this check should be irrelevant
239     if (GST_ELEMENT_SCHED (element))
240       gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element);
241   }
242 }
243
244
245 /**
246  * gst_bin_add:
247  * @bin: #GstBin to add element to
248  * @element: #GstElement to add to bin
249  *
250  * Add the given element to the bin.  Set the elements parent, and thus
251  * add a reference.
252  */
253 void
254 gst_bin_add (GstBin *bin,
255              GstElement *element)
256 {
257   gint state_idx = 0;
258   GstElementState state;
259
260   g_return_if_fail (bin != NULL);
261   g_return_if_fail (GST_IS_BIN (bin));
262   g_return_if_fail (element != NULL);
263   g_return_if_fail (GST_IS_ELEMENT (element));
264
265   GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n",
266              GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
267
268   // must be not be in PLAYING state in order to modify bin
269   g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
270
271   // the element must not already have a parent
272   g_return_if_fail (GST_ELEMENT_PARENT (element) == NULL);
273
274   // then check to see if the element's name is already taken in the bin
275   g_return_if_fail (gst_object_check_uniqueness (bin->children, GST_ELEMENT_NAME (element)) == TRUE);
276
277   // set the element's parent and add the element to the bin's list of children
278   gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
279   g_signal_connect_swapped (G_OBJECT (element), "state_change", gst_bin_child_state_change, G_OBJECT (bin));
280
281   bin->children = g_list_append (bin->children, element);
282   bin->numchildren++;
283
284   // bump our internal state counter
285   state = GST_STATE (element);
286   while (state>>=1) state_idx++;
287   bin->child_states[state_idx]++;
288
289   ///// now we have to deal with manager stuff
290   // we can only do this if there's a scheduler:
291   // if we're not a manager, and aren't attached to anything, we have no sched (yet)
292   if (GST_IS_BIN(element) && GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
293     GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is a manager");
294   }
295   else if (GST_ELEMENT_SCHED (bin) != NULL) {
296     gst_bin_set_element_sched (element, GST_ELEMENT_SCHED (bin));
297   }
298
299   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
300
301   g_signal_emit (G_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], 0, element);
302 }
303
304 /**
305  * gst_bin_remove:
306  * @bin: #GstBin to remove element from
307  * @element: #GstElement to remove
308  *
309  * Remove the element from its associated bin, unparenting as well.
310  */
311 void
312 gst_bin_remove (GstBin *bin,
313                 GstElement *element)
314 {
315   gint state_idx = 0;
316   GstElementState state;
317
318   g_return_if_fail (bin != NULL);
319   g_return_if_fail (GST_IS_BIN (bin));
320   g_return_if_fail (element != NULL);
321   g_return_if_fail (GST_IS_ELEMENT (element));
322   g_return_if_fail (bin->children != NULL);
323
324   // must not be in PLAYING state in order to modify bin
325   g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
326
327   // the element must have its parent set to the current bin
328   g_return_if_fail (GST_ELEMENT_PARENT(element) == (GstObject *)bin);
329
330   // the element must be in the bin's list of children
331   if (g_list_find(bin->children, element) == NULL) {
332     // FIXME this should be a warning!!!
333     GST_ERROR_OBJECT(bin,element,"no such element in bin");
334     return;
335   }
336
337   // remove this element from the list of managed elements
338   gst_bin_unset_element_sched (element);
339
340   // now remove the element from the list of elements
341   bin->children = g_list_remove (bin->children, element);
342   bin->numchildren--;
343
344   // bump our internal state counter
345   state = GST_STATE (element);
346   while (state>>=1) state_idx++;
347   bin->child_states[state_idx]--;
348
349   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element));
350
351   gst_object_unparent (GST_OBJECT (element));
352
353   /* if we're down to zero children, force state to NULL */
354   if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
355     gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
356 }
357
358 static void
359 gst_bin_child_state_change (GstBin *bin, GstElementState old, GstElementState new, GstElement *child)
360 {
361   gint old_idx = 0, new_idx = 0, i;
362
363   GST_INFO (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s", 
364                   GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
365                   gst_element_statename (old), gst_element_statename (new));
366
367   while (old>>=1) old_idx++;
368   while (new>>=1) new_idx++;
369
370   GST_LOCK (bin);
371   bin->child_states[old_idx]--;
372   bin->child_states[new_idx]++;
373
374   for (i = GST_NUM_STATES-1; i >= 0; i--) {
375     if (bin->child_states[i] != 0) {
376       if (GST_STATE (bin) != (1 << i)) {
377         GST_INFO (GST_CAT_STATES, "bin %s need state change to %s", 
378                         GST_ELEMENT_NAME (bin), gst_element_statename (1<<i));
379         GST_STATE_PENDING (bin) = (1<<i);
380         gst_bin_change_state_norecurse (bin);
381       }
382       break;
383     }
384   }
385           
386   GST_UNLOCK (bin);
387 }
388
389 static GstElementStateReturn
390 gst_bin_change_state (GstElement *element)
391 {
392   GstBin *bin;
393   GList *children;
394   GstElement *child;
395   GstElementStateReturn ret;
396   GstElementState old_state, pending;
397   gboolean have_async = FALSE;
398
399   g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
400
401   bin = GST_BIN (element);
402
403   old_state = GST_STATE (element);
404   pending = GST_STATE_PENDING (element);
405
406   GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
407                 gst_element_statename (old_state),
408                 gst_element_statename (pending));
409
410   children = bin->children;
411   while (children) {
412     child = GST_ELEMENT (children->data);
413     children = g_list_next (children);
414
415     switch (gst_element_set_state (child, pending)) {
416       case GST_STATE_FAILURE:
417         GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
418         GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
419               pending, gst_element_statename (pending));
420
421         gst_element_set_state (child, old_state);
422         if (GST_ELEMENT_SCHED (child) == GST_ELEMENT_SCHED (element)) {
423           return GST_STATE_FAILURE;
424         }
425         break;
426       case GST_STATE_ASYNC:
427         GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
428         have_async = TRUE;
429         break;
430     }
431   }
432
433   GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
434                 gst_element_statename (old_state),
435                 gst_element_statename (pending));
436
437   if (have_async)
438     ret = GST_STATE_ASYNC;
439   else
440     ret = GST_STATE_SUCCESS;
441
442   return ret;
443 }
444
445
446 static GstElementStateReturn
447 gst_bin_change_state_norecurse (GstBin *bin)
448 {
449   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
450     GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
451     return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
452   } else
453     return GST_STATE_FAILURE;
454 }
455
456 static gboolean
457 gst_bin_change_state_type (GstBin *bin,
458                            GstElementState state,
459                            GType type)
460 {
461   GList *children;
462   GstElement *child;
463
464   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
465   g_return_val_if_fail (bin->numchildren != 0, FALSE);
466
467   children = bin->children;
468   while (children) {
469     child = GST_ELEMENT (children->data);
470     if (GST_IS_BIN (child)) {
471       if (!gst_bin_set_state_type (GST_BIN (child), state,type))
472         return FALSE;
473     } else if (G_TYPE_CHECK_INSTANCE_TYPE (child,type)) {
474       if (!gst_element_set_state (child,state))
475         return FALSE;
476     }
477     children = g_list_next (children);
478   }
479   if (type == GST_TYPE_BIN)
480     gst_element_set_state (GST_ELEMENT (bin), state);
481
482   return TRUE;
483 }
484
485 /**
486  * gst_bin_set_state_type:
487  * @bin: #GstBin to set the state
488  * @state: the new state to set the elements to
489  * @type: the type of elements to change
490  *
491  * Sets the state of only those objects of the given type.
492  *
493  * Returns: indication if the state change was successfull
494  */
495 gboolean
496 gst_bin_set_state_type (GstBin *bin,
497                         GstElementState state,
498                         GType type)
499 {
500   GstBinClass *oclass;
501
502   GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
503           GST_ELEMENT_NAME (bin), state,type);
504
505   g_return_val_if_fail (bin != NULL, FALSE);
506   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
507
508   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
509
510   if (oclass->change_state_type)
511     (oclass->change_state_type) (bin,state,type);
512   return TRUE;
513 }
514
515 static void
516 gst_bin_dispose (GObject *object)
517 {
518   GstBin *bin = GST_BIN (object);
519   GList *children, *orig;
520   GstElement *child;
521
522   GST_DEBUG (GST_CAT_REFCOUNTING,"dispose\n");
523
524   if (bin->children) {
525     orig = children = g_list_copy (bin->children);
526     while (children) {
527       child = GST_ELEMENT (children->data);
528       //gst_object_unref (GST_OBJECT (child));
529       //gst_object_unparent (GST_OBJECT (child));
530       gst_bin_remove (bin, child);
531       children = g_list_next (children);
532     }
533     g_list_free (orig);
534     g_list_free (bin->children);
535   }
536   bin->children = NULL;
537   bin->numchildren = 0;
538
539   g_cond_free (bin->eoscond);
540
541   G_OBJECT_CLASS (parent_class)->dispose (object);
542 }
543
544 /**
545  * gst_bin_get_by_name:
546  * @bin: #Gstbin to search
547  * @name: the element name to search for
548  *
549  * Get the element with the given name from this bin.
550  *
551  * Returns: the element with the given name
552  */
553 GstElement*
554 gst_bin_get_by_name (GstBin *bin,
555                      const gchar *name)
556 {
557   GList *children;
558   GstElement *child;
559
560   g_return_val_if_fail (bin != NULL, NULL);
561   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
562   g_return_val_if_fail (name != NULL, NULL);
563
564   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "looking up child element %s", name);
565
566   children = bin->children;
567   while (children) {
568     child = GST_ELEMENT (children->data);
569     if (!strcmp (GST_OBJECT_NAME(child),name))
570       return child;
571     if (GST_IS_BIN (child)) {
572       GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
573       if (res)
574         return res;
575     }
576     children = g_list_next (children);
577   }
578
579   return NULL;
580 }
581
582 /**
583  * gst_bin_get_by_name_recurse_up:
584  * @bin: #Gstbin to search
585  * @name: the element name to search for
586  *
587  * Get the element with the given name from this bin. If the
588  * element is not found, a recursion is performed on the parent bin.
589  *
590  * Returns: the element with the given name
591  */
592 GstElement*
593 gst_bin_get_by_name_recurse_up (GstBin *bin,
594                                 const gchar *name)
595 {
596   GstElement *result = NULL;
597   GstObject *parent;
598
599   g_return_val_if_fail (bin != NULL, NULL);
600   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
601   g_return_val_if_fail (name != NULL, NULL);
602
603   result = gst_bin_get_by_name (bin, name);
604
605   if (result)
606     return result;
607
608   parent = gst_object_get_parent (GST_OBJECT (bin));
609
610   if (parent && GST_IS_BIN (parent)) {
611     result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
612   }
613
614   return result;
615 }
616
617 /**
618  * gst_bin_get_list:
619  * @bin: #Gstbin to get the list from
620  *
621  * Get the list of elements in this bin.
622  *
623  * Returns: a GList of elements
624  */
625 GList*
626 gst_bin_get_list (GstBin *bin)
627 {
628   g_return_val_if_fail (bin != NULL, NULL);
629   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
630
631   return bin->children;
632 }
633
634 #ifndef GST_DISABLE_LOADSAVE
635 static xmlNodePtr
636 gst_bin_save_thyself (GstObject *object,
637                       xmlNodePtr parent)
638 {
639   GstBin *bin = GST_BIN (object);
640   xmlNodePtr childlist, elementnode;
641   GList *children;
642   GstElement *child;
643
644   if (GST_OBJECT_CLASS (parent_class)->save_thyself)
645     GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
646
647   childlist = xmlNewChild (parent, NULL, "children", NULL);
648
649   GST_INFO_ELEMENT (GST_CAT_XML, bin, "saving %d children", bin->numchildren);
650
651   children = bin->children;
652   while (children) {
653     child = GST_ELEMENT (children->data);
654     elementnode = xmlNewChild (childlist, NULL, "element", NULL);
655     gst_object_save_thyself (GST_OBJECT (child), elementnode);
656     children = g_list_next (children);
657   }
658   return childlist;
659 }
660
661 static void
662 gst_bin_restore_thyself (GstObject *object,
663                          xmlNodePtr self)
664 {
665   GstBin *bin = GST_BIN (object);
666   xmlNodePtr field = self->xmlChildrenNode;
667   xmlNodePtr childlist;
668
669   while (field) {
670     if (!strcmp (field->name, "children")) {
671       GST_INFO_ELEMENT (GST_CAT_XML, GST_ELEMENT (object), "loading children");
672       childlist = field->xmlChildrenNode;
673       while (childlist) {
674         if (!strcmp (childlist->name, "element")) {
675           GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
676
677           gst_bin_add (bin, element);
678         }
679         childlist = childlist->next;
680       }
681     }
682
683     field = field->next;
684   }
685 }
686 #endif /* GST_DISABLE_LOADSAVE */
687
688 static gboolean
689 gst_bin_iterate_func (GstBin *bin)
690 {
691   // only iterate if this is the manager bin
692   if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
693     return gst_scheduler_iterate (GST_ELEMENT_SCHED(bin));
694   } else {
695     g_warning ("bin \"%d\" can't be iterated on!\n", GST_ELEMENT_NAME (bin));
696   }
697
698   return FALSE;
699 }
700
701 /**
702  * gst_bin_iterate:
703  * @bin: #Gstbin to iterate
704  *
705  * Iterates over the elements in this bin.
706  *
707  * Returns: TRUE if the bin did something usefull. This value
708  *          can be used to determine it the bin is in EOS.
709  */
710 gboolean
711 gst_bin_iterate (GstBin *bin)
712 {
713   GstBinClass *oclass;
714   gboolean running = TRUE;
715
716   GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (bin));
717
718   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
719
720   if (oclass->iterate)
721     running = (oclass->iterate) (bin);
722
723   GST_DEBUG_LEAVE("(\"%s\") %d",GST_ELEMENT_NAME (bin), running);
724
725   if (!running) {
726     if (GST_STATE (bin) == GST_STATE_PLAYING && GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING) {
727       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "waiting for child shutdown after useless iteration\n");
728       //gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
729       gst_element_wait_state_change (GST_ELEMENT (bin));
730       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "child shutdown\n");
731     }
732   }
733
734   return running;
735 }
736