5bfa479f51a3e6edf21c33c7f7e4bb3474396221
[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   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 (GstBin *bin, GstElementState old, GstElementState new, GstElement *child)
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   // FIXME, need to setup this array at add/remove time
388   if (i<0) {
389     GST_STATE_PENDING (bin) = GST_STATE_NULL;
390     gst_bin_change_state_norecurse (bin);
391   }
392           
393   GST_UNLOCK (bin);
394 }
395
396 static GstElementStateReturn
397 gst_bin_change_state (GstElement *element)
398 {
399   GstBin *bin;
400   GList *children;
401   GstElement *child;
402   GstElementStateReturn ret;
403   GstElementState old_state, pending;
404   gboolean have_async = FALSE;
405
406   g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
407
408   bin = GST_BIN (element);
409
410   old_state = GST_STATE (element);
411   pending = GST_STATE_PENDING (element);
412
413   GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
414                 gst_element_statename (old_state),
415                 gst_element_statename (pending));
416
417   children = bin->children;
418   while (children) {
419     child = GST_ELEMENT (children->data);
420     children = g_list_next (children);
421
422     switch (gst_element_set_state (child, pending)) {
423       case GST_STATE_FAILURE:
424         GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
425         GST_DEBUG (GST_CAT_STATES,"child '%s' failed to go to state %d(%s)\n", GST_ELEMENT_NAME (child),
426               pending, gst_element_statename (pending));
427
428         gst_element_set_state (child, old_state);
429         if (GST_ELEMENT_SCHED (child) == GST_ELEMENT_SCHED (element)) {
430           return GST_STATE_FAILURE;
431         }
432         break;
433       case GST_STATE_ASYNC:
434         GST_DEBUG (GST_CAT_STATES,"child '%s' is changing state asynchronously\n", GST_ELEMENT_NAME (child));
435         have_async = TRUE;
436         break;
437     }
438   }
439
440   GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s",
441                 gst_element_statename (old_state),
442                 gst_element_statename (pending));
443
444   if (have_async)
445     ret = GST_STATE_ASYNC;
446   else
447     ret = GST_STATE_SUCCESS;
448
449   return ret;
450 }
451
452
453 static GstElementStateReturn
454 gst_bin_change_state_norecurse (GstBin *bin)
455 {
456   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
457     GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
458     return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
459   } else
460     return GST_STATE_FAILURE;
461 }
462
463 static gboolean
464 gst_bin_change_state_type (GstBin *bin,
465                            GstElementState state,
466                            GType type)
467 {
468   GList *children;
469   GstElement *child;
470
471   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
472   g_return_val_if_fail (bin->numchildren != 0, FALSE);
473
474   children = bin->children;
475   while (children) {
476     child = GST_ELEMENT (children->data);
477     if (GST_IS_BIN (child)) {
478       if (!gst_bin_set_state_type (GST_BIN (child), state,type))
479         return FALSE;
480     } else if (G_TYPE_CHECK_INSTANCE_TYPE (child,type)) {
481       if (!gst_element_set_state (child,state))
482         return FALSE;
483     }
484     children = g_list_next (children);
485   }
486   if (type == GST_TYPE_BIN)
487     gst_element_set_state (GST_ELEMENT (bin), state);
488
489   return TRUE;
490 }
491
492 /**
493  * gst_bin_set_state_type:
494  * @bin: #GstBin to set the state
495  * @state: the new state to set the elements to
496  * @type: the type of elements to change
497  *
498  * Sets the state of only those objects of the given type.
499  *
500  * Returns: indication if the state change was successfull
501  */
502 gboolean
503 gst_bin_set_state_type (GstBin *bin,
504                         GstElementState state,
505                         GType type)
506 {
507   GstBinClass *oclass;
508
509   GST_DEBUG (GST_CAT_STATES,"gst_bin_set_state_type(\"%s\",%d,%d)\n",
510           GST_ELEMENT_NAME (bin), state,type);
511
512   g_return_val_if_fail (bin != NULL, FALSE);
513   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
514
515   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
516
517   if (oclass->change_state_type)
518     (oclass->change_state_type) (bin,state,type);
519   return TRUE;
520 }
521
522 static void
523 gst_bin_dispose (GObject *object)
524 {
525   GstBin *bin = GST_BIN (object);
526   GList *children, *orig;
527   GstElement *child;
528
529   GST_DEBUG (GST_CAT_REFCOUNTING,"dispose\n");
530
531   if (bin->children) {
532     orig = children = g_list_copy (bin->children);
533     while (children) {
534       child = GST_ELEMENT (children->data);
535       //gst_object_unref (GST_OBJECT (child));
536       //gst_object_unparent (GST_OBJECT (child));
537       gst_bin_remove (bin, child);
538       children = g_list_next (children);
539     }
540     g_list_free (orig);
541     g_list_free (bin->children);
542   }
543   bin->children = NULL;
544   bin->numchildren = 0;
545
546   g_cond_free (bin->eoscond);
547
548   G_OBJECT_CLASS (parent_class)->dispose (object);
549 }
550
551 /**
552  * gst_bin_get_by_name:
553  * @bin: #Gstbin to search
554  * @name: the element name to search for
555  *
556  * Get the element with the given name from this bin.
557  *
558  * Returns: the element with the given name
559  */
560 GstElement*
561 gst_bin_get_by_name (GstBin *bin,
562                      const gchar *name)
563 {
564   GList *children;
565   GstElement *child;
566
567   g_return_val_if_fail (bin != NULL, NULL);
568   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
569   g_return_val_if_fail (name != NULL, NULL);
570
571   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, bin, "looking up child element %s", name);
572
573   children = bin->children;
574   while (children) {
575     child = GST_ELEMENT (children->data);
576     if (!strcmp (GST_OBJECT_NAME(child),name))
577       return child;
578     if (GST_IS_BIN (child)) {
579       GstElement *res = gst_bin_get_by_name (GST_BIN (child), name);
580       if (res)
581         return res;
582     }
583     children = g_list_next (children);
584   }
585
586   return NULL;
587 }
588
589 /**
590  * gst_bin_get_by_name_recurse_up:
591  * @bin: #Gstbin to search
592  * @name: the element name to search for
593  *
594  * Get the element with the given name from this bin. If the
595  * element is not found, a recursion is performed on the parent bin.
596  *
597  * Returns: the element with the given name
598  */
599 GstElement*
600 gst_bin_get_by_name_recurse_up (GstBin *bin,
601                                 const gchar *name)
602 {
603   GstElement *result = NULL;
604   GstObject *parent;
605
606   g_return_val_if_fail (bin != NULL, NULL);
607   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
608   g_return_val_if_fail (name != NULL, NULL);
609
610   result = gst_bin_get_by_name (bin, name);
611
612   if (result)
613     return result;
614
615   parent = gst_object_get_parent (GST_OBJECT (bin));
616
617   if (parent && GST_IS_BIN (parent)) {
618     result = gst_bin_get_by_name_recurse_up (GST_BIN (parent), name);
619   }
620
621   return result;
622 }
623
624 /**
625  * gst_bin_get_list:
626  * @bin: #Gstbin to get the list from
627  *
628  * Get the list of elements in this bin.
629  *
630  * Returns: a GList of elements
631  */
632 GList*
633 gst_bin_get_list (GstBin *bin)
634 {
635   g_return_val_if_fail (bin != NULL, NULL);
636   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
637
638   return bin->children;
639 }
640
641 #ifndef GST_DISABLE_LOADSAVE
642 static xmlNodePtr
643 gst_bin_save_thyself (GstObject *object,
644                       xmlNodePtr parent)
645 {
646   GstBin *bin = GST_BIN (object);
647   xmlNodePtr childlist, elementnode;
648   GList *children;
649   GstElement *child;
650
651   if (GST_OBJECT_CLASS (parent_class)->save_thyself)
652     GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
653
654   childlist = xmlNewChild (parent, NULL, "children", NULL);
655
656   GST_INFO_ELEMENT (GST_CAT_XML, bin, "saving %d children", bin->numchildren);
657
658   children = bin->children;
659   while (children) {
660     child = GST_ELEMENT (children->data);
661     elementnode = xmlNewChild (childlist, NULL, "element", NULL);
662     gst_object_save_thyself (GST_OBJECT (child), elementnode);
663     children = g_list_next (children);
664   }
665   return childlist;
666 }
667
668 static void
669 gst_bin_restore_thyself (GstObject *object,
670                          xmlNodePtr self)
671 {
672   GstBin *bin = GST_BIN (object);
673   xmlNodePtr field = self->xmlChildrenNode;
674   xmlNodePtr childlist;
675
676   while (field) {
677     if (!strcmp (field->name, "children")) {
678       GST_INFO_ELEMENT (GST_CAT_XML, GST_ELEMENT (object), "loading children");
679       childlist = field->xmlChildrenNode;
680       while (childlist) {
681         if (!strcmp (childlist->name, "element")) {
682           GstElement *element = gst_element_restore_thyself (childlist, GST_OBJECT (bin));
683
684           gst_bin_add (bin, element);
685         }
686         childlist = childlist->next;
687       }
688     }
689
690     field = field->next;
691   }
692 }
693 #endif /* GST_DISABLE_LOADSAVE */
694
695 static gboolean
696 gst_bin_iterate_func (GstBin *bin)
697 {
698   // only iterate if this is the manager bin
699   if (GST_ELEMENT_SCHED(bin)->parent == GST_ELEMENT (bin)) {
700     return gst_scheduler_iterate (GST_ELEMENT_SCHED(bin));
701   } else {
702     g_warning ("bin \"%d\" can't be iterated on!\n", GST_ELEMENT_NAME (bin));
703   }
704
705   return FALSE;
706 }
707
708 /**
709  * gst_bin_iterate:
710  * @bin: #Gstbin to iterate
711  *
712  * Iterates over the elements in this bin.
713  *
714  * Returns: TRUE if the bin did something usefull. This value
715  *          can be used to determine it the bin is in EOS.
716  */
717 gboolean
718 gst_bin_iterate (GstBin *bin)
719 {
720   GstBinClass *oclass;
721   gboolean running = TRUE;
722
723   GST_DEBUG_ENTER("(\"%s\")",GST_ELEMENT_NAME (bin));
724
725   oclass = GST_BIN_CLASS (G_OBJECT_GET_CLASS(bin));
726
727   if (oclass->iterate)
728     running = (oclass->iterate) (bin);
729
730   GST_DEBUG_LEAVE("(\"%s\") %d",GST_ELEMENT_NAME (bin), running);
731
732   if (!running) {
733     if (GST_STATE (bin) == GST_STATE_PLAYING && GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING) {
734       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "waiting for child shutdown after useless iteration\n");
735       //gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
736       gst_element_wait_state_change (GST_ELEMENT (bin));
737       GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, bin, "child shutdown\n");
738     }
739   }
740
741   return running;
742 }
743
744 /* out internal element fired EOS, we decrement the number of pending EOS childs */
745 G_GNUC_UNUSED static void
746 gst_bin_received_eos (GstElement *element, GstBin *bin)
747 {
748   GST_INFO_ELEMENT (GST_CAT_PLANNING, bin, "child %s fired eos, pending %d", GST_ELEMENT_NAME (element),
749                   bin->num_eos_providers);
750
751   GST_LOCK (bin);
752   if (bin->num_eos_providers) {
753     bin->num_eos_providers--;
754     g_cond_signal (bin->eoscond);
755   }
756   GST_UNLOCK (bin);
757 }
758