Also swap the args in the callback function
[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      (GstElement *child, GstElementState old, 
49                                                                  GstElementState new, GstBin *bin);
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->eos_providers = NULL;
139   bin->num_eos_providers = 0;
140   bin->eoscond = g_cond_new ();
141 }
142
143 /**
144  * gst_bin_new:
145  * @name: name of new bin
146  *
147  * Create a new bin with given name.
148  *
149  * Returns: new bin
150  */
151 GstElement*
152 gst_bin_new (const gchar *name)
153 {
154   return gst_elementfactory_make ("bin", name);
155 }
156
157 static inline void
158 gst_bin_reset_element_sched (GstElement *element, GstScheduler *sched)
159 {
160   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "resetting element's scheduler");
161
162   gst_element_set_sched (element,sched);
163 }
164
165 static void
166 gst_bin_set_element_sched (GstElement *element,GstScheduler *sched)
167 {
168   GList *children;
169   GstElement *child;
170
171   g_return_if_fail (element != NULL);
172   g_return_if_fail (GST_IS_ELEMENT(element));
173   g_return_if_fail (sched != NULL);
174   g_return_if_fail (GST_IS_SCHEDULER(sched));
175
176   GST_INFO (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",GST_ELEMENT_NAME(element),
177             sched);
178
179   // if it's actually a Bin
180   if (GST_IS_BIN(element)) {
181     if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
182       GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not resetting");
183       return;
184     }
185
186     GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting children's schedule to parent's");
187     gst_scheduler_add_element (sched, element);
188
189     // set the children's schedule
190     children = GST_BIN(element)->children;
191     while (children) {
192       child = GST_ELEMENT (children->data);
193       children = g_list_next(children);
194
195       gst_bin_set_element_sched (child, sched);
196     }
197
198   // otherwise, if it's just a regular old element
199   } else {
200     gst_scheduler_add_element (sched, element);
201   }
202 }
203
204
205 static void
206 gst_bin_unset_element_sched (GstElement *element)
207 {
208   GList *children;
209   GstElement *child;
210
211   g_return_if_fail (element != NULL);
212   g_return_if_fail (GST_IS_ELEMENT(element));
213
214   GST_INFO (GST_CAT_SCHEDULING, "removing element \"%s\" from it sched %p",
215             GST_ELEMENT_NAME(element),GST_ELEMENT_SCHED(element));
216
217   // if it's actually a Bin
218   if (GST_IS_BIN(element)) {
219
220     if (GST_FLAG_IS_SET(element,GST_BIN_FLAG_MANAGER)) {
221       GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is already a manager, not unsetting sched");
222       return;
223     }
224
225     // FIXME this check should be irrelevant
226     if (GST_ELEMENT_SCHED (element))
227       gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element);
228
229     // for each child, remove them from their schedule
230     children = GST_BIN(element)->children;
231     while (children) {
232       child = GST_ELEMENT (children->data);
233       children = g_list_next(children);
234
235       gst_bin_unset_element_sched (child);
236     }
237
238   // otherwise, if it's just a regular old element
239   } else {
240     // FIXME this check should be irrelevant
241     if (GST_ELEMENT_SCHED (element))
242       gst_scheduler_remove_element (GST_ELEMENT_SCHED(element), element);
243   }
244 }
245
246
247 /**
248  * gst_bin_add:
249  * @bin: #GstBin to add element to
250  * @element: #GstElement to add to bin
251  *
252  * Add the given element to the bin.  Set the elements parent, and thus
253  * add a reference.
254  */
255 void
256 gst_bin_add (GstBin *bin,
257              GstElement *element)
258 {
259   gint state_idx = 0;
260   GstElementState state;
261
262   g_return_if_fail (bin != NULL);
263   g_return_if_fail (GST_IS_BIN (bin));
264   g_return_if_fail (element != NULL);
265   g_return_if_fail (GST_IS_ELEMENT (element));
266
267   GST_DEBUG (GST_CAT_PARENTAGE, "adding element \"%s\" to bin \"%s\"\n",
268              GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
269
270   // must be not be in PLAYING state in order to modify bin
271   g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
272
273   // the element must not already have a parent
274   g_return_if_fail (GST_ELEMENT_PARENT (element) == NULL);
275
276   // then check to see if the element's name is already taken in the bin
277   g_return_if_fail (gst_object_check_uniqueness (bin->children, GST_ELEMENT_NAME (element)) == TRUE);
278
279   // set the element's parent and add the element to the bin's list of children
280   gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (bin));
281   g_signal_connect (G_OBJECT (element), "state_change", gst_bin_child_state_change, G_OBJECT (bin));
282
283   bin->children = g_list_append (bin->children, element);
284   bin->numchildren++;
285
286   // bump our internal state counter
287   state = GST_STATE (element);
288   while (state>>=1) state_idx++;
289   bin->child_states[state_idx]++;
290
291   ///// now we have to deal with manager stuff
292   // we can only do this if there's a scheduler:
293   // if we're not a manager, and aren't attached to anything, we have no sched (yet)
294   if (GST_IS_BIN(element) && GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
295     GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "child is a manager");
296   }
297   else if (GST_ELEMENT_SCHED (bin) != NULL) {
298     gst_bin_set_element_sched (element, GST_ELEMENT_SCHED (bin));
299   }
300
301   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "added child \"%s\"", GST_ELEMENT_NAME (element));
302
303   g_signal_emit (G_OBJECT (bin), gst_bin_signals[OBJECT_ADDED], 0, element);
304 }
305
306 /**
307  * gst_bin_remove:
308  * @bin: #GstBin to remove element from
309  * @element: #GstElement to remove
310  *
311  * Remove the element from its associated bin, unparenting as well.
312  */
313 void
314 gst_bin_remove (GstBin *bin,
315                 GstElement *element)
316 {
317   gint state_idx = 0;
318   GstElementState state;
319
320   g_return_if_fail (bin != NULL);
321   g_return_if_fail (GST_IS_BIN (bin));
322   g_return_if_fail (element != NULL);
323   g_return_if_fail (GST_IS_ELEMENT (element));
324   g_return_if_fail (bin->children != NULL);
325
326   // must not be in PLAYING state in order to modify bin
327   g_return_if_fail (GST_STATE (bin) != GST_STATE_PLAYING);
328
329   // the element must have its parent set to the current bin
330   g_return_if_fail (GST_ELEMENT_PARENT(element) == (GstObject *)bin);
331
332   // the element must be in the bin's list of children
333   if (g_list_find(bin->children, element) == NULL) {
334     // FIXME this should be a warning!!!
335     GST_ERROR_OBJECT(bin,element,"no such element in bin");
336     return;
337   }
338
339   // remove this element from the list of managed elements
340   gst_bin_unset_element_sched (element);
341
342   // now remove the element from the list of elements
343   bin->children = g_list_remove (bin->children, element);
344   bin->numchildren--;
345
346   // bump our internal state counter
347   state = GST_STATE (element);
348   while (state>>=1) state_idx++;
349   bin->child_states[state_idx]--;
350
351   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "removed child %s", GST_ELEMENT_NAME (element));
352
353   gst_object_unparent (GST_OBJECT (element));
354
355   /* if we're down to zero children, force state to NULL */
356   if (bin->numchildren == 0 && GST_ELEMENT_SCHED (bin) != NULL)
357     gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL);
358 }
359
360 static void
361 gst_bin_child_state_change (GstElement *child, GstElementState old, GstElementState new, GstBin *bin)
362 {
363   gint old_idx = 0, new_idx = 0, i;
364
365   GST_INFO (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s", 
366                   GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
367                   gst_element_statename (old), gst_element_statename (new));
368
369   while (old>>=1) old_idx++;
370   while (new>>=1) new_idx++;
371
372   GST_LOCK (bin);
373   bin->child_states[old_idx]--;
374   bin->child_states[new_idx]++;
375
376   for (i = GST_NUM_STATES-1; i >= 0; i--) {
377     if (bin->child_states[i] != 0) {
378       if (GST_STATE (bin) != (1 << i)) {
379         GST_INFO (GST_CAT_STATES, "bin %s need state change to %s", 
380                         GST_ELEMENT_NAME (bin), gst_element_statename (1<<i));
381         GST_STATE_PENDING (bin) = (1<<i);
382         gst_bin_change_state_norecurse (bin);
383       }
384       break;
385     }
386   }
387           
388   GST_UNLOCK (bin);
389 }
390
391 static GstElementStateReturn
392 gst_bin_change_state (GstElement *element)
393 {
394   GstBin *bin;
395   GList *children;
396   GstElement *child;
397   GstElementStateReturn ret;
398   GstElementState old_state, pending;
399   gboolean have_async = FALSE;
400
401   g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
402
403   bin = GST_BIN (element);
404
405   old_state = GST_STATE (element);
406   pending = GST_STATE_PENDING (element);
407
408   GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
409                 gst_element_statename (old_state),
410                 gst_element_statename (pending));
411
412   children = bin->children;
413   while (children) {
414     child = GST_ELEMENT (children->data);
415     children = g_list_next (children);
416
417     switch (gst_element_set_state (child, pending)) {
418       case GST_STATE_FAILURE:
419         GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
420         GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
421               pending, gst_element_statename (pending));
422
423         gst_element_set_state (child, old_state);
424         if (GST_ELEMENT_SCHED (child) == GST_ELEMENT_SCHED (element)) {
425           return GST_STATE_FAILURE;
426         }
427         break;
428       case GST_STATE_ASYNC:
429         GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
430         have_async = TRUE;
431         break;
432     }
433   }
434
435   GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
436                 gst_element_statename (old_state),
437                 gst_element_statename (pending));
438
439   if (have_async)
440     ret = GST_STATE_ASYNC;
441   else
442     ret = GST_STATE_SUCCESS;
443
444   return ret;
445 }
446
447
448 static GstElementStateReturn
449 gst_bin_change_state_norecurse (GstBin *bin)
450 {
451   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
452     GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
453     return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
454   } else
455     return GST_STATE_FAILURE;
456 }
457
458 static gboolean
459 gst_bin_change_state_type (GstBin *bin,
460                            GstElementState state,
461                            GType type)
462 {
463   GList *children;
464   GstElement *child;
465
466   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
467   g_return_val_if_fail (bin->numchildren != 0, FALSE);
468
469   children = bin->children;
470   while (children) {
471     child = GST_ELEMENT (children->data);
472     if (GST_IS_BIN (child)) {
473       if (!gst_bin_set_state_type (GST_BIN (child), state,type))
474         return FALSE;
475     } else if (G_TYPE_CHECK_INSTANCE_TYPE (child,type)) {
476       if (!gst_element_set_state (child,state))
477         return FALSE;
478     }
479     children = g_list_next (children);
480   }
481   if (type == GST_TYPE_BIN)
482     gst_element_set_state (GST_ELEMENT (bin), state);
483
484   return TRUE;
485 }
486
487 /**
488  * gst_bin_set_state_type:
489  * @bin: #GstBin to set the state
490  * @state: the new state to set the elements to
491  * @type: the type of elements to change
492  *
493  * Sets the state of only those objects of the given type.
494  *
495  * Returns: indication if the state change was successfull
496  */
497 gboolean
498 gst_bin_set_state_type (GstBin *bin,
499                         GstElementState state,
500                         GType type)
501 {
502   GstBinClass *oclass;
503
504   GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
505           GST_ELEMENT_NAME (bin), state,type);
506
507   g_return_val_if_fail (bin != NULL, FALSE);
508   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
509
510   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
511
512   if (oclass->change_state_type)
513     (oclass->change_state_type) (bin,state,type);
514   return TRUE;
515 }
516
517 static void
518 gst_bin_dispose (GObject *object)
519 {
520   GstBin *bin = GST_BIN (object);
521   GList *children, *orig;
522   GstElement *child;
523
524   GST_DEBUG (GST_CAT_REFCOUNTING,"dispose\n");
525
526   if (bin->children) {
527     orig = children = g_list_copy (bin->children);
528     while (children) {
529       child = GST_ELEMENT (children->data);
530       //gst_object_unref (GST_OBJECT (child));
531       //gst_object_unparent (GST_OBJECT (child));
532       gst_bin_remove (bin, child);
533       children = g_list_next (children);
534     }
535     g_list_free (orig);
536     g_list_free (bin->children);
537   }
538   bin->children = NULL;
539   bin->numchildren = 0;
540
541   g_cond_free (bin->eoscond);
542
543   G_OBJECT_CLASS (parent_class)->dispose (object);
544 }
545
546 /**
547  * gst_bin_get_by_name:
548  * @bin: #Gstbin to search
549  * @name: the element name to search for
550  *
551  * Get the element with the given name from this bin.
552  *
553  * Returns: the element with the given name
554  */
555 GstElement*
556 gst_bin_get_by_name (GstBin *bin,
557                      const gchar *name)
558 {
559   GList *children;
560   GstElement *child;
561
562   g_return_val_if_fail (bin != NULL, NULL);
563   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
564   g_return_val_if_fail (name != NULL, NULL);
565
566   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "looking up child element %s", name);
567
568   children = bin->children;
569   while (children) {
570     child = GST_ELEMENT (children->data);
571     if (!strcmp (GST_OBJECT_NAME(child),name))
572       return child;
573     if (GST_IS_BIN (child)) {
574       GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
575       if (res)
576         return res;
577     }
578     children = g_list_next (children);
579   }
580
581   return NULL;
582 }
583
584 /**
585  * gst_bin_get_by_name_recurse_up:
586  * @bin: #Gstbin to search
587  * @name: the element name to search for
588  *
589  * Get the element with the given name from this bin. If the
590  * element is not found, a recursion is performed on the parent bin.
591  *
592  * Returns: the element with the given name
593  */
594 GstElement*
595 gst_bin_get_by_name_recurse_up (GstBin *bin,
596                                 const gchar *name)
597 {
598   GstElement *result = NULL;
599   GstObject *parent;
600
601   g_return_val_if_fail (bin != NULL, NULL);
602   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
603   g_return_val_if_fail (name != NULL, NULL);
604
605   result = gst_bin_get_by_name (bin, name);
606
607   if (result)
608     return result;
609
610   parent = gst_object_get_parent (GST_OBJECT (bin));
611
612   if (parent && GST_IS_BIN (parent)) {
613     result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
614   }
615
616   return result;
617 }
618
619 /**
620  * gst_bin_get_list:
621  * @bin: #Gstbin to get the list from
622  *
623  * Get the list of elements in this bin.
624  *
625  * Returns: a GList of elements
626  */
627 GList*
628 gst_bin_get_list (GstBin *bin)
629 {
630   g_return_val_if_fail (bin != NULL, NULL);
631   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
632
633   return bin->children;
634 }
635
636 #ifndef GST_DISABLE_LOADSAVE
637 static xmlNodePtr
638 gst_bin_save_thyself (GstObject *object,
639                       xmlNodePtr parent)
640 {
641   GstBin *bin = GST_BIN (object);
642   xmlNodePtr childlist, elementnode;
643   GList *children;
644   GstElement *child;
645
646   if (GST_OBJECT_CLASS (parent_class)->save_thyself)
647     GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
648
649   childlist = xmlNewChild (parent, NULL, "children", NULL);
650
651   GST_INFO_ELEMENT (GST_CAT_XML, bin, "saving %d children", bin->numchildren);
652
653   children = bin->children;
654   while (children) {
655     child = GST_ELEMENT (children->data);
656     elementnode = xmlNewChild (childlist, NULL, "element", NULL);
657     gst_object_save_thyself (GST_OBJECT (child), elementnode);
658     children = g_list_next (children);
659   }
660   return childlist;
661 }
662
663 static void
664 gst_bin_restore_thyself (GstObject *object,
665                          xmlNodePtr self)
666 {
667   GstBin *bin = GST_BIN (object);
668   xmlNodePtr field = self->xmlChildrenNode;
669   xmlNodePtr childlist;
670
671   while (field) {
672     if (!strcmp (field->name, "children")) {
673       GST_INFO_ELEMENT (GST_CAT_XML, GST_ELEMENT (object), "loading children");
674       childlist = field->xmlChildrenNode;
675       while (childlist) {
676         if (!strcmp (childlist->name, "element")) {
677           GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
678
679           gst_bin_add (bin, element);
680         }
681         childlist = childlist->next;
682       }
683     }
684
685     field = field->next;
686   }
687 }
688 #endif /* GST_DISABLE_LOADSAVE */
689
690 static gboolean
691 gst_bin_iterate_func (GstBin *bin)
692 {
693   // only iterate if this is the manager bin
694   if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
695     return gst_scheduler_iterate (GST_ELEMENT_SCHED(bin));
696   } else {
697     g_warning ("bin \"%d\" can't be iterated on!\n", GST_ELEMENT_NAME (bin));
698   }
699
700   return FALSE;
701 }
702
703 /**
704  * gst_bin_iterate:
705  * @bin: #Gstbin to iterate
706  *
707  * Iterates over the elements in this bin.
708  *
709  * Returns: TRUE if the bin did something usefull. This value
710  *          can be used to determine it the bin is in EOS.
711  */
712 gboolean
713 gst_bin_iterate (GstBin *bin)
714 {
715   GstBinClass *oclass;
716   gboolean running = TRUE;
717
718   GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (bin));
719
720   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
721
722   if (oclass->iterate)
723     running = (oclass->iterate) (bin);
724
725   GST_DEBUG_LEAVE("(\"%s\") %d",GST_ELEMENT_NAME (bin), running);
726
727   if (!running) {
728     if (GST_STATE (bin) == GST_STATE_PLAYING && GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING) {
729       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "waiting for child shutdown after useless iteration\n");
730       //gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
731       gst_element_wait_state_change (GST_ELEMENT (bin));
732       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "child shutdown\n");
733     }
734   }
735
736   return running;
737 }
738
739 /* out internal element fired EOS, we decrement the number of pending EOS childs */
740 G_GNUC_UNUSED static void
741 gst_bin_received_eos (GstElement *element, GstBin *bin)
742 {
743   GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "child %s fired eos, pending %d", GST_ELEMENT_NAME (element),
744                   bin->num_eos_providers);
745
746   GST_LOCK (bin);
747   if (bin->num_eos_providers) {
748     bin->num_eos_providers--;
749     g_cond_signal (bin->eoscond);
750   }
751   GST_UNLOCK (bin);
752 }
753