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