bcd27f3a4e1ffd07a19e346f35d1a8fb4424facd
[platform/upstream/gstreamer.git] / gst / gstbin.c
1 /* GStreamer
2  *
3  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
4  *                    2004 Wim Taymans <wim@fluendo.com>
5  *
6  * gstbin.c: GstBin container object and support code
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * MT safe.
24  */
25
26 #include "gst_private.h"
27
28 #include "gstevent.h"
29 #include "gstbin.h"
30 #include "gstmarshal.h"
31 #include "gstxml.h"
32 #include "gstinfo.h"
33 #include "gsterror.h"
34
35 #include "gstscheduler.h"
36 #include "gstindex.h"
37 #include "gstutils.h"
38
39 GST_DEBUG_CATEGORY_STATIC (bin_debug);
40 #define GST_CAT_DEFAULT bin_debug
41 #define GST_LOG_BIN_CONTENTS(bin, text) GST_LOG_OBJECT ((bin), \
42         text ": %d elements: %u PLAYING, %u PAUSED, %u READY, %u NULL, own state: %s", \
43         (bin)->numchildren, (guint) (bin)->child_states[3], \
44         (guint) (bin)->child_states[2], (bin)->child_states[1], \
45         (bin)->child_states[0], gst_element_state_get_name (GST_STATE (bin)))
46
47
48 static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
49     "Generic/Bin",
50     "Simple container object",
51     "Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
52
53 GType _gst_bin_type = 0;
54
55 static void gst_bin_dispose (GObject * object);
56
57 static GstElementStateReturn gst_bin_change_state (GstElement * element);
58 static GstElementStateReturn gst_bin_get_state (GstElement * element,
59     GstElementState * state, GstElementState * pending, GTimeVal * timeout);
60
61 static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
62 static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
63
64 #ifndef GST_DISABLE_INDEX
65 static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
66 #endif
67 static GstClock *gst_bin_get_clock_func (GstElement * element);
68 static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
69
70 static void gst_bin_set_manager (GstElement * element, GstPipeline * manager);
71 static void gst_bin_set_bus (GstElement * element, GstBus * bus);
72 static void gst_bin_set_scheduler (GstElement * element, GstScheduler * sched);
73
74 static gboolean gst_bin_send_event (GstElement * element, GstEvent * event);
75 static gboolean gst_bin_query (GstElement * element, GstQuery * query);
76
77 #ifndef GST_DISABLE_LOADSAVE
78 static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
79 static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
80 #endif
81
82 static gint bin_element_is_sink (GstElement * child, GstBin * bin);
83
84 /* Bin signals and args */
85 enum
86 {
87   ELEMENT_ADDED,
88   ELEMENT_REMOVED,
89   LAST_SIGNAL
90 };
91
92 enum
93 {
94   ARG_0
95       /* FILL ME */
96 };
97
98 static void gst_bin_base_init (gpointer g_class);
99 static void gst_bin_class_init (GstBinClass * klass);
100 static void gst_bin_init (GstBin * bin);
101
102 static GstElementClass *parent_class = NULL;
103 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
104
105 /**
106  * gst_bin_get_type:
107  *
108  * Returns: the type of #GstBin
109  */
110 GType
111 gst_bin_get_type (void)
112 {
113   if (!_gst_bin_type) {
114     static const GTypeInfo bin_info = {
115       sizeof (GstBinClass),
116       gst_bin_base_init,
117       NULL,
118       (GClassInitFunc) gst_bin_class_init,
119       NULL,
120       NULL,
121       sizeof (GstBin),
122       0,
123       (GInstanceInitFunc) gst_bin_init,
124       NULL
125     };
126
127     _gst_bin_type =
128         g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
129
130     GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
131         "debugging info for the 'bin' container element");
132   }
133   return _gst_bin_type;
134 }
135
136 static void
137 gst_bin_base_init (gpointer g_class)
138 {
139   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
140
141   gst_element_class_set_details (gstelement_class, &gst_bin_details);
142 }
143
144 static void
145 gst_bin_class_init (GstBinClass * klass)
146 {
147   GObjectClass *gobject_class;
148   GstObjectClass *gstobject_class;
149   GstElementClass *gstelement_class;
150
151   gobject_class = (GObjectClass *) klass;
152   gstobject_class = (GstObjectClass *) klass;
153   gstelement_class = (GstElementClass *) klass;
154
155   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
156
157   gst_bin_signals[ELEMENT_ADDED] =
158       g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
159       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
160       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
161   gst_bin_signals[ELEMENT_REMOVED] =
162       g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
163       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
164       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
165
166   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
167
168 #ifndef GST_DISABLE_LOADSAVE
169   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
170   gstobject_class->restore_thyself =
171       GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
172 #endif
173
174   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
175   gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state);
176 #ifndef GST_DISABLE_INDEX
177   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
178 #endif
179   gstelement_class->get_clock = GST_DEBUG_FUNCPTR (gst_bin_get_clock_func);
180   gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func);
181   gstelement_class->set_manager = GST_DEBUG_FUNCPTR (gst_bin_set_manager);
182   gstelement_class->set_bus = GST_DEBUG_FUNCPTR (gst_bin_set_bus);
183   gstelement_class->set_scheduler = GST_DEBUG_FUNCPTR (gst_bin_set_scheduler);
184
185   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_bin_send_event);
186   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_bin_query);
187
188   klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
189   klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
190 }
191
192 static void
193 gst_bin_init (GstBin * bin)
194 {
195   bin->numchildren = 0;
196   bin->children = NULL;
197   bin->children_cookie = 0;
198 }
199
200 /**
201  * gst_bin_new:
202  * @name: name of new bin
203  *
204  * Create a new bin with given name.
205  *
206  * Returns: new bin
207  */
208 GstElement *
209 gst_bin_new (const gchar * name)
210 {
211   return gst_element_factory_make ("bin", name);
212 }
213
214 /* set the index on all elements in this bin
215  *
216  * MT safe
217  */
218 #ifndef GST_DISABLE_INDEX
219 static void
220 gst_bin_set_index_func (GstElement * element, GstIndex * index)
221 {
222   GstBin *bin;
223   GList *children;
224
225   bin = GST_BIN (element);
226
227   GST_LOCK (bin);
228   for (children = bin->children; children; children = g_list_next (children)) {
229     GstElement *child = GST_ELEMENT (children->data);
230
231     gst_element_set_index (child, index);
232   }
233   GST_UNLOCK (bin);
234 }
235 #endif
236
237 /* set the clock on all elements in this bin
238  *
239  * MT safe
240  */
241 static void
242 gst_bin_set_clock_func (GstElement * element, GstClock * clock)
243 {
244   GList *children;
245   GstBin *bin;
246
247   bin = GST_BIN (element);
248
249   GST_LOCK (bin);
250   for (children = bin->children; children; children = g_list_next (children)) {
251     GstElement *child = GST_ELEMENT (children->data);
252
253     gst_element_set_clock (child, clock);
254   }
255   GST_UNLOCK (bin);
256 }
257
258 /* get the clock for this bin by asking all of the children in this bin
259  *
260  * MT safe
261  */
262 static GstClock *
263 gst_bin_get_clock_func (GstElement * element)
264 {
265   GstClock *result = NULL;
266   GstBin *bin;
267   GList *children;
268
269   bin = GST_BIN (element);
270
271   GST_LOCK (bin);
272   for (children = bin->children; children; children = g_list_next (children)) {
273     GstElement *child = GST_ELEMENT (children->data);
274
275     result = gst_element_get_clock (child);
276     if (result)
277       break;
278   }
279   GST_UNLOCK (bin);
280
281   return result;
282 }
283
284 /* set the bus on all of the children in this bin
285  *
286  * MT safe
287  */
288 static void
289 gst_bin_set_bus (GstElement * element, GstBus * bus)
290 {
291   GList *children;
292   GstBin *bin;
293
294   bin = GST_BIN (element);
295
296   parent_class->set_bus (element, bus);
297
298   GST_LOCK (bin);
299   for (children = bin->children; children; children = g_list_next (children)) {
300     GstElement *child = GST_ELEMENT (children->data);
301
302     gst_element_set_bus (child, bus);
303   }
304   GST_UNLOCK (bin);
305 }
306
307 /* set the scheduler on all of the children in this bin
308  *
309  * MT safe
310  */
311 static void
312 gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
313 {
314   GList *children;
315   GstBin *bin;
316
317   bin = GST_BIN (element);
318
319   parent_class->set_scheduler (element, sched);
320
321   GST_LOCK (bin);
322   for (children = bin->children; children; children = g_list_next (children)) {
323     GstElement *child = GST_ELEMENT (children->data);
324
325     gst_element_set_scheduler (child, sched);
326   }
327   GST_UNLOCK (bin);
328 }
329
330 /* set the manager on all of the children in this bin
331  *
332  * MT safe
333  */
334 static void
335 gst_bin_set_manager (GstElement * element, GstPipeline * manager)
336 {
337   GstBin *bin = GST_BIN (element);
338   GList *kids;
339   GstElement *kid;
340
341   GST_ELEMENT_CLASS (parent_class)->set_manager (element, manager);
342
343   GST_LOCK (element);
344   for (kids = bin->children; kids != NULL; kids = kids->next) {
345     kid = GST_ELEMENT (kids->data);
346     gst_element_set_manager (kid, manager);
347   }
348   GST_UNLOCK (element);
349 }
350
351 /* add an element to this bin
352  *
353  * MT safe
354  */
355 static gboolean
356 gst_bin_add_func (GstBin * bin, GstElement * element)
357 {
358   gchar *elem_name;
359
360   /* we obviously can't add ourself to ourself */
361   if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
362     goto adding_itself;
363
364   /* get the element name to make sure it is unique in this bin, FIXME, another
365    * thread can change the name after the unlock. */
366   GST_LOCK (element);
367   elem_name = g_strdup (GST_ELEMENT_NAME (element));
368   GST_UNLOCK (element);
369
370   GST_LOCK (bin);
371
372   /* then check to see if the element's name is already taken in the bin,
373    * we can safely take the lock here. This check is probably bogus because
374    * you can safely change the element name after adding it to the bin. */
375   if (G_UNLIKELY (gst_object_check_uniqueness (bin->children,
376               elem_name) == FALSE))
377     goto duplicate_name;
378
379   /* set the element's parent and add the element to the bin's list of children */
380   if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (element),
381               GST_OBJECT_CAST (bin))))
382     goto had_parent;
383
384   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK))
385     GST_FLAG_SET (bin, GST_ELEMENT_IS_SINK);
386
387   bin->children = g_list_prepend (bin->children, element);
388   bin->numchildren++;
389   bin->children_cookie++;
390
391   gst_element_set_manager (element, GST_ELEMENT (bin)->manager);
392   gst_element_set_bus (element, GST_ELEMENT (bin)->bus);
393   gst_element_set_scheduler (element, GST_ELEMENT_SCHEDULER (bin));
394   gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
395
396   GST_UNLOCK (bin);
397
398   GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
399       elem_name);
400   g_free (elem_name);
401
402   g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
403
404   return TRUE;
405
406   /* ERROR handling here */
407 adding_itself:
408   {
409     GST_LOCK (bin);
410     g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
411     GST_UNLOCK (bin);
412     return FALSE;
413   }
414 duplicate_name:
415   {
416     g_warning ("Name %s is not unique in bin %s, not adding",
417         elem_name, GST_ELEMENT_NAME (bin));
418     GST_UNLOCK (bin);
419     g_free (elem_name);
420     return FALSE;
421   }
422 had_parent:
423   {
424     g_warning ("Element %s already has parent", elem_name);
425     GST_UNLOCK (bin);
426     g_free (elem_name);
427     return FALSE;
428   }
429 }
430
431 /**
432  * gst_bin_add:
433  * @bin: #GstBin to add element to
434  * @element: #GstElement to add to bin
435  *
436  * Adds the given element to the bin.  Sets the element's parent, and thus
437  * takes ownership of the element. An element can only be added to one bin.
438  *
439  * MT safe.
440  *
441  * Returns: TRUE if the element could be added, FALSE on wrong parameters or
442  * the bin does not want to accept the element.
443  */
444 gboolean
445 gst_bin_add (GstBin * bin, GstElement * element)
446 {
447   GstBinClass *bclass;
448   gboolean result;
449
450   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
451   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
452
453   bclass = GST_BIN_GET_CLASS (bin);
454
455   if (G_UNLIKELY (bclass->add_element == NULL))
456     goto no_function;
457
458   GST_CAT_DEBUG (GST_CAT_PARENTAGE, "adding element %s to bin %s",
459       GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
460
461   result = bclass->add_element (bin, element);
462
463   return result;
464
465   /* ERROR handling */
466 no_function:
467   {
468     g_warning ("adding elements to bin %s is not supported",
469         GST_ELEMENT_NAME (bin));
470     return FALSE;
471   }
472 }
473
474 /* remove an element from the bin
475  *
476  * MT safe
477  */
478 static gboolean
479 gst_bin_remove_func (GstBin * bin, GstElement * element)
480 {
481   gchar *elem_name;
482
483   /* grab element name so we can print it */
484   GST_LOCK (element);
485   elem_name = g_strdup (GST_ELEMENT_NAME (element));
486   GST_UNLOCK (element);
487
488   GST_LOCK (bin);
489   /* the element must be in the bin's list of children */
490   if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
491     goto not_in_bin;
492
493   /* now remove the element from the list of elements */
494   bin->children = g_list_remove (bin->children, element);
495   bin->numchildren--;
496   bin->children_cookie++;
497
498   /* check if we a sink */
499   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK)) {
500     GList *other_sink;
501
502     /* check if we removed the last sink */
503     other_sink = g_list_find_custom (bin->children,
504         bin, (GCompareFunc) bin_element_is_sink);
505     if (!other_sink) {
506       /* yups, we're not a sink anymore */
507       GST_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK);
508     }
509   }
510
511   GST_UNLOCK (bin);
512
513   GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
514       elem_name);
515   g_free (elem_name);
516
517   gst_element_set_manager (element, NULL);
518   gst_element_set_bus (element, NULL);
519   gst_element_set_scheduler (element, NULL);
520
521   /* unlock any waiters for the state change. It is possible that
522    * we are waiting for an ASYNC state change on this element. The
523    * element cannot be added to another bin yet as it is not yet
524    * unparented. */
525   GST_STATE_LOCK (element);
526   GST_STATE_BROADCAST (element);
527   GST_STATE_UNLOCK (element);
528
529   /* we ref here because after the _unparent() the element can be disposed
530    * and we still need it to fire a signal. */
531   gst_object_ref (GST_OBJECT_CAST (element));
532   gst_object_unparent (GST_OBJECT_CAST (element));
533
534   g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
535   /* element is really out of our control now */
536   gst_object_unref (GST_OBJECT_CAST (element));
537
538   return TRUE;
539
540   /* ERROR handling */
541 not_in_bin:
542   {
543     g_warning ("Element %s is not in bin %s", elem_name,
544         GST_ELEMENT_NAME (bin));
545     GST_UNLOCK (bin);
546     g_free (elem_name);
547     return FALSE;
548   }
549 }
550
551 /**
552  * gst_bin_remove:
553  * @bin: #GstBin to remove element from
554  * @element: #GstElement to remove
555  *
556  * Remove the element from its associated bin, unparenting it as well.
557  * Unparenting the element means that the element will be dereferenced,
558  * so if the bin holds the only reference to the element, the element
559  * will be freed in the process of removing it from the bin.  If you
560  * want the element to still exist after removing, you need to call
561  * #gst_object_ref before removing it from the bin.
562  *
563  * MT safe.
564  *
565  * Returns: TRUE if the element could be removed, FALSE on wrong parameters or
566  * the bin does not want to remove the element.
567  */
568 gboolean
569 gst_bin_remove (GstBin * bin, GstElement * element)
570 {
571   GstBinClass *bclass;
572   gboolean result;
573
574   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
575   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
576
577   bclass = GST_BIN_GET_CLASS (bin);
578
579   if (G_UNLIKELY (bclass->remove_element == NULL))
580     goto no_function;
581
582   GST_CAT_DEBUG (GST_CAT_PARENTAGE, "removing element %s from bin %s",
583       GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
584
585   result = bclass->remove_element (bin, element);
586
587   return result;
588
589   /* ERROR handling */
590 no_function:
591   {
592     g_warning ("removing elements from bin %s is not supported",
593         GST_ELEMENT_NAME (bin));
594     return FALSE;
595   }
596 }
597
598 static GstIteratorItem
599 iterate_child (GstIterator * it, GstElement * child)
600 {
601   gst_object_ref (GST_OBJECT (child));
602   return GST_ITERATOR_ITEM_PASS;
603 }
604
605 /**
606  * gst_bin_iterate_elements:
607  * @bin: #Gstbin to iterate the elements of
608  *
609  * Get an iterator for the elements in this bin.
610  * Each element will have its refcount increased, so unref
611  * after use.
612  *
613  * MT safe.
614  *
615  * Returns: a #GstIterator of #GstElements. gst_iterator_free after
616  * use. returns NULL when passing bad parameters.
617  */
618 GstIterator *
619 gst_bin_iterate_elements (GstBin * bin)
620 {
621   GstIterator *result;
622
623   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
624
625   GST_LOCK (bin);
626   /* add ref because the iterator refs the bin. When the iterator
627    * is freed it will unref the bin again using the provided dispose
628    * function. */
629   gst_object_ref (GST_OBJECT (bin));
630   result = gst_iterator_new_list (GST_GET_LOCK (bin),
631       &bin->children_cookie,
632       &bin->children,
633       bin,
634       (GstIteratorItemFunction) iterate_child,
635       (GstIteratorDisposeFunction) gst_object_unref);
636   GST_UNLOCK (bin);
637
638   return result;
639 }
640
641 static GstIteratorItem
642 iterate_child_recurse (GstIterator * it, GstElement * child)
643 {
644   gst_object_ref (GST_OBJECT (child));
645   if (GST_IS_BIN (child)) {
646     GstIterator *other = gst_bin_iterate_recurse (GST_BIN (child));
647
648     gst_iterator_push (it, other);
649   }
650   return GST_ITERATOR_ITEM_PASS;
651 }
652
653 /**
654  * gst_bin_iterate_recurse:
655  * @bin: #Gstbin to iterate the elements of
656  *
657  * Get an iterator for the elements in this bin.
658  * Each element will have its refcount increased, so unref
659  * after use. This iterator recurses into GstBin children.
660  *
661  * MT safe.
662  *
663  * Returns: a #GstIterator of #GstElements. gst_iterator_free after
664  * use. returns NULL when passing bad parameters.
665  */
666 GstIterator *
667 gst_bin_iterate_recurse (GstBin * bin)
668 {
669   GstIterator *result;
670
671   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
672
673   GST_LOCK (bin);
674   /* add ref because the iterator refs the bin. When the iterator
675    * is freed it will unref the bin again using the provided dispose
676    * function. */
677   gst_object_ref (GST_OBJECT (bin));
678   result = gst_iterator_new_list (GST_GET_LOCK (bin),
679       &bin->children_cookie,
680       &bin->children,
681       bin,
682       (GstIteratorItemFunction) iterate_child_recurse,
683       (GstIteratorDisposeFunction) gst_object_unref);
684   GST_UNLOCK (bin);
685
686   return result;
687 }
688
689 /* returns 0 when TRUE because this is a GCompareFunc */
690 /* MT safe */
691 static gint
692 bin_element_is_sink (GstElement * child, GstBin * bin)
693 {
694   gboolean is_sink;
695
696   /* we lock the child here for the remainder of the function to
697    * get its name safely. */
698   GST_LOCK (child);
699   is_sink = GST_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
700   GST_UNLOCK (child);
701
702   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
703       "child %s %s sink", GST_OBJECT_NAME (child), is_sink ? "is" : "is not");
704
705   return is_sink ? 0 : 1;
706 }
707
708 static gboolean
709 has_ancestor (GstObject * object, GstObject * ancestor)
710 {
711   GstObject *parent;
712   gboolean result = FALSE;
713
714   if (object == NULL)
715     return FALSE;
716
717   if (object == ancestor)
718     return TRUE;
719
720   parent = gst_object_get_parent (object);
721   result = has_ancestor (parent, ancestor);
722   if (parent)
723     gst_object_unref (GST_OBJECT_CAST (parent));
724
725   return result;
726 }
727
728 /* returns 0 when TRUE because this is a GCompareFunc.
729  * This function returns elements that have no connected srcpads and
730  * are therefore not reachable from a real sink. */
731 /* MT safe */
732 static gint
733 bin_element_is_semi_sink (GstElement * child, GstBin * bin)
734 {
735   int ret = 1;
736
737   /* we lock the child here for the remainder of the function to
738    * get its pads and name safely. */
739   GST_LOCK (child);
740
741   /* check if this is a sink element, these are the elements
742    * without (linked) source pads. */
743   if (child->numsrcpads == 0) {
744     /* shortcut */
745     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
746         "adding child %s as sink", GST_OBJECT_NAME (child));
747     ret = 0;
748   } else {
749     /* loop over all pads, try to figure out if this element
750      * is a semi sink because it has no linked source pads */
751     GList *pads;
752     gboolean connected_src = FALSE;
753
754     for (pads = child->srcpads; pads; pads = g_list_next (pads)) {
755       GstPad *peer;
756
757       if ((peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)))) {
758         connected_src =
759             has_ancestor (GST_OBJECT_CAST (peer), GST_OBJECT_CAST (bin));
760         gst_object_unref (GST_OBJECT_CAST (peer));
761         if (connected_src) {
762           break;
763         }
764       }
765     }
766     if (connected_src) {
767       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
768           "not adding child %s as sink: linked source pads",
769           GST_OBJECT_NAME (child));
770     } else {
771       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
772           "adding child %s as sink since it has unlinked source pads in this bin",
773           GST_OBJECT_NAME (child));
774       ret = 0;
775     }
776   }
777   GST_UNLOCK (child);
778
779   return ret;
780 }
781
782 static gint
783 sink_iterator_filter (GstElement * child, GstBin * bin)
784 {
785   if (bin_element_is_sink (child, bin) == 0) {
786     /* returns 0 because this is a GCompareFunc */
787     return 0;
788   } else {
789     /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
790        through */
791     gst_object_unref ((GstObject *) child);
792     return 1;
793   }
794 }
795
796 /**
797  * gst_bin_iterate_sinks:
798  * @bin: #Gstbin to iterate on
799  *
800  * Get an iterator for the sink elements in this bin.
801  * Each element will have its refcount increased, so unref
802  * after use.
803  *
804  * The sink elements are those without any linked srcpads.
805  *
806  * MT safe.
807  *
808  * Returns: a #GstIterator of #GstElements. gst_iterator_free after use.
809  */
810 GstIterator *
811 gst_bin_iterate_sinks (GstBin * bin)
812 {
813   GstIterator *children;
814   GstIterator *result;
815
816   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
817
818   children = gst_bin_iterate_elements (bin);
819   result = gst_iterator_filter (children,
820       (GCompareFunc) sink_iterator_filter, bin);
821
822   return result;
823 }
824
825 /* 2 phases:
826  *  1) check state of all children with 0 timeout to find ERROR and
827  *     NO_PREROLL elements. return if found.
828  *  2) perform full blocking wait with requested timeout.
829  *
830  * 2) cannot be performed when 1) returns results as the sinks might
831  *    not be able to complete the state change making 2) block forever.
832  *
833  * MT safe
834  */
835 static GstElementStateReturn
836 gst_bin_get_state (GstElement * element, GstElementState * state,
837     GstElementState * pending, GTimeVal * timeout)
838 {
839   GstBin *bin = GST_BIN (element);
840   GstElementStateReturn ret = GST_STATE_SUCCESS;
841   GList *children;
842   guint32 children_cookie;
843   gboolean zero_timeout;
844   gboolean have_no_preroll;
845
846   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "getting state");
847
848   zero_timeout = timeout != NULL && timeout->tv_sec == 0
849       && timeout->tv_usec == 0;
850
851   /* lock bin, no element can be added or removed between going into
852    * the quick scan and the blocking wait. */
853   GST_LOCK (bin);
854
855 restart:
856   have_no_preroll = FALSE;
857
858   /* if we have a non zero timeout we must make sure not to block
859    * on the sinks when we have NO_PREROLL elements. This is why we do
860    * a quick check if there are still NO_PREROLL elements. We also
861    * catch the error elements this way. */
862   if (!zero_timeout) {
863     GTimeVal tv;
864     gboolean have_async = FALSE;
865
866     GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "checking for NO_PREROLL");
867     /* use 0 timeout so we don't block on the sinks */
868     GST_TIME_TO_TIMEVAL (0, tv);
869     children = bin->children;
870     children_cookie = bin->children_cookie;
871     while (children) {
872       GstElement *child = GST_ELEMENT_CAST (children->data);
873
874       gst_object_ref (GST_OBJECT_CAST (child));
875       /* now we release the lock to enter a non blocking wait. We 
876        * release the lock anyway since we can. */
877       GST_UNLOCK (bin);
878
879       ret = gst_element_get_state (child, NULL, NULL, &tv);
880
881       gst_object_unref (GST_OBJECT_CAST (child));
882
883       /* now grab the lock to iterate to the next child */
884       GST_LOCK (bin);
885       if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
886         /* child added/removed during state change, restart. We need
887          * to restart with the quick check as a no-preroll element could
888          * have been added here and we don't want to block on sinks then.*/
889         goto restart;
890       }
891
892       switch (ret) {
893           /* report FAILURE or NO_PREROLL immediatly */
894         case GST_STATE_FAILURE:
895           goto done;
896         case GST_STATE_NO_PREROLL:
897           /* we have to continue scanning as there might be
898            * ERRORS too */
899           have_no_preroll = TRUE;
900           break;
901         case GST_STATE_ASYNC:
902           have_async = TRUE;
903           break;
904         default:
905           break;
906       }
907       children = g_list_next (children);
908     }
909     /* if we get here, we have no FAILURES, check for any NO_PREROLL
910      * elements then. */
911     if (have_no_preroll) {
912       ret = GST_STATE_NO_PREROLL;
913       goto done;
914     }
915
916     /* if we get here, no NO_PREROLL elements are in the pipeline */
917     GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "no NO_PREROLL elements");
918
919     /* if no ASYNC elements exist we don't even have to poll with a
920      * timeout again */
921     if (!have_async) {
922       ret = GST_STATE_SUCCESS;
923       goto done;
924     }
925   }
926
927   /* next we poll all children for their state to see if one of them
928    * is still busy with its state change. We did not release the bin lock
929    * yet so the elements are the same as the ones from the quick scan. */
930   children = bin->children;
931   children_cookie = bin->children_cookie;
932   while (children) {
933     GstElement *child = GST_ELEMENT_CAST (children->data);
934
935     gst_object_ref (GST_OBJECT_CAST (child));
936     /* now we release the lock to enter the potentialy blocking wait */
937     GST_UNLOCK (bin);
938
939     /* ret is ASYNC if some child is still performing the state change
940      * ater the timeout. */
941     ret = gst_element_get_state (child, NULL, NULL, timeout);
942
943     gst_object_unref (GST_OBJECT_CAST (child));
944
945     /* now grab the lock to iterate to the next child */
946     GST_LOCK (bin);
947     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
948       /* child added/removed during state change, restart. We need
949        * to restart with the quick check as a no-preroll element could
950        * have been added here and we don't want to block on sinks then.*/
951       goto restart;
952     }
953
954     switch (ret) {
955       case GST_STATE_SUCCESS:
956         break;
957       case GST_STATE_FAILURE:
958       case GST_STATE_NO_PREROLL:
959         /* report FAILURE and NO_PREROLL immediatly */
960         goto done;
961         break;
962       case GST_STATE_ASYNC:
963         /* since we checked for non prerollable elements before,
964          * the first ASYNC return is the real return value */
965         if (!zero_timeout)
966           goto done;
967         break;
968       default:
969         g_assert_not_reached ();
970     }
971     children = g_list_next (children);
972   }
973   /* if we got here, all elements can do preroll */
974   have_no_preroll = FALSE;
975
976 done:
977   GST_UNLOCK (bin);
978
979   /* now we can take the state lock, it is possible that new elements
980    * are added now and we still report the old state. No problem though as
981    * the return is still consistent, the effect is as if the element was
982    * added after this function completed. */
983   GST_STATE_LOCK (bin);
984   switch (ret) {
985     case GST_STATE_SUCCESS:
986       /* we can commit the state */
987       gst_element_commit_state (element);
988       break;
989     case GST_STATE_FAILURE:
990       /* some element failed, abort the state change */
991       gst_element_abort_state (element);
992       break;
993     default:
994       /* other cases are just passed along */
995       break;
996   }
997
998   /* and report the state if needed */
999   if (state)
1000     *state = GST_STATE (element);
1001   if (pending)
1002     *pending = GST_STATE_PENDING (element);
1003
1004   GST_STATE_NO_PREROLL (element) = have_no_preroll;
1005
1006   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1007       "state current: %s, pending: %s, error: %d, no_preroll: %d, result: %d",
1008       gst_element_state_get_name (GST_STATE (element)),
1009       gst_element_state_get_name (GST_STATE_PENDING (element)),
1010       GST_STATE_ERROR (element), GST_STATE_NO_PREROLL (element), ret);
1011
1012   GST_STATE_UNLOCK (bin);
1013
1014   return ret;
1015 }
1016
1017 static void
1018 append_child (gpointer child, GQueue * queue)
1019 {
1020   g_queue_push_tail (queue, child);
1021 }
1022
1023 /**
1024  * gst_bin_iterate_state_order:
1025  * @bin: #Gstbin to iterate on
1026  *
1027  * Get an iterator for the elements in this bin in the order
1028  * in which a state change should be performed on them. This 
1029  * means that first the sinks and then the other elements will
1030  * be returned.
1031  * Each element will have its refcount increased, so unref
1032  * after use.
1033  *
1034  * MT safe.
1035  *
1036  * Returns: a #GstIterator of #GstElements. gst_iterator_free after use.
1037  */
1038 GstIterator *
1039 gst_bin_iterate_state_order (GstBin * bin)
1040 {
1041   GstIterator *result;
1042
1043   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1044
1045   result = NULL;
1046
1047   return result;
1048 }
1049
1050 /* this function is called with the STATE_LOCK held. It works
1051  * as follows:
1052  *
1053  * 1) put all sink elements on the queue.
1054  * 2) put all semisink elements on the queue.
1055  * 3) change state of elements in queue, put linked elements to queue.
1056  * 4) while queue not empty goto 3)
1057  *
1058  * This will effectively change the state of all elements in the bin
1059  * from the sinks to the sources. We have to change the states this
1060  * way so that when a source element pushes data, the downstream element
1061  * is in the right state to receive the data.
1062  *
1063  * MT safe.
1064  */
1065 static GstElementStateReturn
1066 gst_bin_change_state (GstElement * element)
1067 {
1068   GstBin *bin;
1069   GstElementStateReturn ret;
1070   GstElementState old_state, pending;
1071   gboolean have_async = FALSE;
1072   gboolean have_no_preroll = FALSE;
1073   GList *children;
1074   guint32 children_cookie;
1075   GQueue *elem_queue;           /* list of elements waiting for a state change */
1076   GQueue *semi_queue;           /* list of elements with no connected srcpads */
1077   GQueue *temp;                 /* queue of leftovers */
1078
1079   bin = GST_BIN (element);
1080
1081   /* we don't need to take the STATE_LOCK, it is already taken */
1082   old_state = GST_STATE (element);
1083   pending = GST_STATE_PENDING (element);
1084
1085   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1086       "changing state of children from %s to %s",
1087       gst_element_state_get_name (old_state),
1088       gst_element_state_get_name (pending));
1089
1090   if (pending == GST_STATE_VOID_PENDING)
1091     return GST_STATE_SUCCESS;
1092
1093   /* all elements added to these queues should have their refcount
1094    * incremented */
1095   elem_queue = g_queue_new ();
1096   semi_queue = g_queue_new ();
1097   temp = g_queue_new ();
1098
1099   /* first step, find all sink elements, these are the elements
1100    * without (linked) source pads. */
1101   GST_LOCK (bin);
1102 restart:
1103   children = bin->children;
1104   children_cookie = bin->children_cookie;
1105   while (children) {
1106     GstElement *child = GST_ELEMENT_CAST (children->data);
1107
1108     gst_object_ref (GST_OBJECT_CAST (child));
1109     GST_UNLOCK (bin);
1110
1111     if (bin_element_is_sink (child, bin) == 0) {
1112       g_queue_push_tail (elem_queue, child);
1113     } else if (bin_element_is_semi_sink (child, bin) == 0) {
1114       g_queue_push_tail (semi_queue, child);
1115     } else {
1116       g_queue_push_tail (temp, child);
1117     }
1118
1119     GST_LOCK (bin);
1120     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
1121       /* undo what we had */
1122       g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
1123       g_queue_foreach (semi_queue, (GFunc) gst_object_unref, NULL);
1124       g_queue_foreach (temp, (GFunc) gst_object_unref, NULL);
1125       while (g_queue_pop_head (elem_queue));
1126       while (g_queue_pop_head (semi_queue));
1127       while (g_queue_pop_head (temp));
1128       goto restart;
1129     }
1130
1131     children = g_list_next (children);
1132   }
1133   GST_UNLOCK (bin);
1134
1135   /* now change state for semi sink elements first so add them in
1136    * front of the other elements */
1137   g_queue_foreach (temp, (GFunc) append_child, semi_queue);
1138   g_queue_free (temp);
1139
1140   /* can be the case for a bin like ( identity ) */
1141   if (g_queue_is_empty (elem_queue) && !g_queue_is_empty (semi_queue)) {
1142     GQueue *q = elem_queue;
1143
1144     elem_queue = semi_queue;
1145     semi_queue = q;
1146   }
1147
1148   /* second step, change state of elements in the queue */
1149   while (!g_queue_is_empty (elem_queue)) {
1150     GstElement *qelement;
1151     GList *pads;
1152     gboolean locked;
1153
1154     /* take element */
1155     qelement = g_queue_pop_head (elem_queue);
1156     /* we don't need it in the semi_queue anymore */
1157     g_queue_remove_all (semi_queue, qelement);
1158
1159     /* if queue is empty now, continue with a non-sink */
1160     if (g_queue_is_empty (elem_queue)) {
1161       GstElement *non_sink;
1162
1163       GST_DEBUG ("sinks and upstream elements exhausted");
1164       non_sink = g_queue_pop_head (semi_queue);
1165       if (non_sink) {
1166         GST_DEBUG ("found lefover non-sink %s", GST_OBJECT_NAME (non_sink));
1167         g_queue_push_tail (elem_queue, non_sink);
1168       }
1169     }
1170
1171     /* queue all elements connected to the sinkpads of this element */
1172     GST_LOCK (qelement);
1173     pads = qelement->sinkpads;
1174     while (pads) {
1175       GstPad *pad = GST_PAD_CAST (pads->data);
1176       GstPad *peer;
1177
1178       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1179           "found sinkpad %s:%s", GST_DEBUG_PAD_NAME (pad));
1180
1181       peer = gst_pad_get_peer (pad);
1182       if (peer) {
1183         GstElement *peer_elem;
1184
1185         peer_elem = gst_pad_get_parent (peer);
1186
1187         if (peer_elem) {
1188           GstObject *parent;
1189
1190           /* see if this element is in the bin we are currently handling */
1191           parent = gst_object_get_parent (GST_OBJECT_CAST (peer_elem));
1192           if (parent && parent == GST_OBJECT_CAST (bin)) {
1193             GList *oldelem;
1194
1195             GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1196                 "adding element %s to queue", GST_ELEMENT_NAME (peer_elem));
1197
1198             /* make sure we don't have duplicates */
1199             while ((oldelem = g_queue_find (semi_queue, peer_elem))) {
1200               gst_object_unref (GST_OBJECT (peer_elem));
1201               g_queue_delete_link (semi_queue, oldelem);
1202             }
1203             while ((oldelem = g_queue_find (elem_queue, peer_elem))) {
1204               gst_object_unref (GST_OBJECT (peer_elem));
1205               g_queue_delete_link (elem_queue, oldelem);
1206             }
1207             /* was reffed before pushing on the queue by the
1208              * gst_object_get_parent() call we used to get the element. */
1209             g_queue_push_tail (elem_queue, peer_elem);
1210           } else {
1211             GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1212                 "not adding element %s to queue, it is in another bin",
1213                 GST_ELEMENT_NAME (peer_elem));
1214             gst_object_unref (GST_OBJECT_CAST (peer_elem));
1215           }
1216           if (parent) {
1217             gst_object_unref (parent);
1218           }
1219         }
1220         gst_object_unref (GST_OBJECT_CAST (peer));
1221       } else {
1222         GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1223             "pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
1224       }
1225       pads = g_list_next (pads);
1226     }
1227     /* peel off the locked flag and release the element lock */
1228     locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE);
1229     GST_UNLOCK (qelement);
1230
1231     if (G_UNLIKELY (locked))
1232       goto next_element;
1233
1234     qelement->base_time = element->base_time;
1235     ret = gst_element_set_state (qelement, pending);
1236     switch (ret) {
1237       case GST_STATE_SUCCESS:
1238         GST_CAT_DEBUG (GST_CAT_STATES,
1239             "child '%s' changed state to %d(%s) successfully",
1240             GST_ELEMENT_NAME (qelement), pending,
1241             gst_element_state_get_name (pending));
1242         break;
1243       case GST_STATE_ASYNC:
1244         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1245             "child '%s' is changing state asynchronously",
1246             GST_ELEMENT_NAME (qelement));
1247         have_async = TRUE;
1248         break;
1249       case GST_STATE_FAILURE:
1250         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1251             "child '%s' failed to go to state %d(%s)",
1252             GST_ELEMENT_NAME (qelement),
1253             pending, gst_element_state_get_name (pending));
1254         ret = GST_STATE_FAILURE;
1255         /* release refcount of element we popped off the queue */
1256         gst_object_unref (GST_OBJECT (qelement));
1257         goto exit;
1258       case GST_STATE_NO_PREROLL:
1259         GST_CAT_DEBUG (GST_CAT_STATES,
1260             "child '%s' changed state to %d(%s) successfully without preroll",
1261             GST_ELEMENT_NAME (qelement), pending,
1262             gst_element_state_get_name (pending));
1263         have_no_preroll = TRUE;
1264         break;
1265       default:
1266         g_assert_not_reached ();
1267         break;
1268     }
1269   next_element:
1270     gst_object_unref (GST_OBJECT (qelement));
1271   }
1272
1273   if (have_no_preroll) {
1274     ret = GST_STATE_NO_PREROLL;
1275   } else if (have_async) {
1276     ret = GST_STATE_ASYNC;
1277   } else {
1278     if ((ret = parent_class->change_state (element)) == GST_STATE_SUCCESS) {
1279       /* we can commit the state change now */
1280       gst_element_commit_state (element);
1281     }
1282   }
1283
1284   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1285       "done changing bin's state from %s to %s, now in %s",
1286       gst_element_state_get_name (old_state),
1287       gst_element_state_get_name (pending),
1288       gst_element_state_get_name (GST_STATE (element)));
1289
1290 exit:
1291   /* release refcounts in queue, should normally be empty unless we
1292    * had an error. */
1293   g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
1294   g_queue_free (elem_queue);
1295   g_queue_foreach (semi_queue, (GFunc) gst_object_unref, NULL);
1296   g_queue_free (semi_queue);
1297
1298   return ret;
1299 }
1300
1301 static void
1302 gst_bin_dispose (GObject * object)
1303 {
1304   GstBin *bin = GST_BIN (object);
1305
1306   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
1307
1308   /* ref to not hit 0 again */
1309   gst_object_ref (GST_OBJECT (object));
1310
1311   while (bin->children) {
1312     gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
1313   }
1314   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose no children");
1315   g_assert (bin->children == NULL);
1316   g_assert (bin->numchildren == 0);
1317
1318   G_OBJECT_CLASS (parent_class)->dispose (object);
1319 }
1320
1321 /*
1322  * This function is a utility event handler for seek events.
1323  * It will send the event to all sinks.
1324  * Applications are free to override this behaviour and
1325  * implement their own seek handler, but this will work for
1326  * pretty much all cases in practice.
1327  */
1328 static gboolean
1329 gst_bin_send_event (GstElement * element, GstEvent * event)
1330 {
1331   GstBin *bin = GST_BIN (element);
1332   GstIterator *iter;
1333   gboolean res = TRUE;
1334   gboolean done = FALSE;
1335
1336   iter = gst_bin_iterate_sinks (bin);
1337   GST_DEBUG_OBJECT (bin, "Sending event to sink children");
1338
1339   while (!done) {
1340     gpointer data;
1341
1342     switch (gst_iterator_next (iter, &data)) {
1343       case GST_ITERATOR_OK:
1344       {
1345         GstElement *sink;
1346
1347         gst_event_ref (event);
1348         sink = GST_ELEMENT_CAST (data);
1349         res &= gst_element_send_event (sink, event);
1350         gst_object_unref (GST_OBJECT (sink));
1351         break;
1352       }
1353       case GST_ITERATOR_RESYNC:
1354         gst_iterator_resync (iter);
1355         res = TRUE;
1356         break;
1357       default:
1358       case GST_ITERATOR_DONE:
1359         done = TRUE;
1360         break;
1361     }
1362   }
1363   gst_iterator_free (iter);
1364   gst_event_unref (event);
1365
1366   return res;
1367 }
1368
1369 static gboolean
1370 gst_bin_query (GstElement * element, GstQuery * query)
1371 {
1372   GstBin *bin = GST_BIN (element);
1373   GstIterator *iter;
1374   gboolean res = FALSE, done = FALSE;
1375
1376   iter = gst_bin_iterate_sinks (bin);
1377   GST_DEBUG_OBJECT (bin, "Sending event to sink children");
1378
1379   while (!(res || done)) {
1380     gpointer data;
1381
1382     switch (gst_iterator_next (iter, &data)) {
1383       case GST_ITERATOR_OK:
1384       {
1385         GstElement *sink;
1386
1387         sink = GST_ELEMENT_CAST (data);
1388         res = gst_element_query (sink, query);
1389         gst_object_unref (GST_OBJECT (sink));
1390         break;
1391       }
1392       case GST_ITERATOR_RESYNC:
1393         gst_iterator_resync (iter);
1394         break;
1395       default:
1396       case GST_ITERATOR_DONE:
1397         done = TRUE;
1398         break;
1399     }
1400   }
1401   gst_iterator_free (iter);
1402
1403   return res;
1404 }
1405
1406 static gint
1407 compare_name (GstElement * element, const gchar * name)
1408 {
1409   gint eq;
1410
1411   GST_LOCK (element);
1412   eq = strcmp (GST_ELEMENT_NAME (element), name);
1413   GST_UNLOCK (element);
1414
1415   if (eq != 0) {
1416     gst_object_unref (GST_OBJECT (element));
1417   }
1418   return eq;
1419 }
1420
1421 /**
1422  * gst_bin_get_by_name:
1423  * @bin: #Gstbin to search
1424  * @name: the element name to search for
1425  *
1426  * Get the element with the given name from this bin. This
1427  * function recurses into subbins.
1428  *
1429  * MT safe.
1430  *
1431  * Returns: the element with the given name. Returns NULL if the
1432  * element is not found or when bad parameters were given. Unref after
1433  * use.
1434  */
1435 GstElement *
1436 gst_bin_get_by_name (GstBin * bin, const gchar * name)
1437 {
1438   GstIterator *children;
1439   GstIterator *result;
1440
1441   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1442
1443   GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
1444       GST_ELEMENT_NAME (bin), name);
1445
1446   children = gst_bin_iterate_recurse (bin);
1447   result = gst_iterator_find_custom (children,
1448       (GCompareFunc) compare_name, (gpointer) name);
1449   gst_iterator_free (children);
1450
1451   return GST_ELEMENT_CAST (result);
1452 }
1453
1454 /**
1455  * gst_bin_get_by_name_recurse_up:
1456  * @bin: #Gstbin to search
1457  * @name: the element name to search for
1458  *
1459  * MT safe.
1460  *
1461  * Get the element with the given name from this bin. If the
1462  * element is not found, a recursion is performed on the parent bin.
1463  *
1464  * Returns: the element with the given name or NULL when the element
1465  * was not found or bad parameters were given. Unref after use.
1466  */
1467 GstElement *
1468 gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
1469 {
1470   GstElement *result;
1471
1472   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1473   g_return_val_if_fail (name != NULL, NULL);
1474
1475   result = gst_bin_get_by_name (bin, name);
1476
1477   if (!result) {
1478     GstObject *parent;
1479
1480     parent = gst_object_get_parent (GST_OBJECT_CAST (bin));
1481     if (parent) {
1482       if (GST_IS_BIN (parent)) {
1483         result = gst_bin_get_by_name_recurse_up (GST_BIN_CAST (parent), name);
1484       }
1485       gst_object_unref (parent);
1486     }
1487   }
1488
1489   return result;
1490 }
1491
1492 static gint
1493 compare_interface (GstElement * element, gpointer interface)
1494 {
1495   gint ret;
1496
1497   if (G_TYPE_CHECK_INSTANCE_TYPE (element, GPOINTER_TO_INT (interface))) {
1498     ret = 0;
1499   } else {
1500     /* we did not find the element, need to release the ref
1501      * added by the iterator */
1502     gst_object_unref (GST_OBJECT (element));
1503     ret = 1;
1504   }
1505   return ret;
1506 }
1507
1508 /**
1509  * gst_bin_get_by_interface:
1510  * @bin: bin to find element in
1511  * @interface: interface to be implemented by interface
1512  *
1513  * Looks for the first element inside the bin that implements the given
1514  * interface. If such an element is found, it returns the element. You can
1515  * cast this element to the given interface afterwards.
1516  * If you want all elements that implement the interface, use
1517  * gst_bin_iterate_all_by_interface(). The function recurses inside bins.
1518  *
1519  * MT safe.
1520  *
1521  * Returns: An #GstElement inside the bin implementing the interface.
1522  *          Unref after use.
1523  */
1524 GstElement *
1525 gst_bin_get_by_interface (GstBin * bin, GType interface)
1526 {
1527   GstIterator *children;
1528   GstIterator *result;
1529
1530   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1531
1532   children = gst_bin_iterate_recurse (bin);
1533   result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
1534       GINT_TO_POINTER (interface));
1535   gst_iterator_free (children);
1536
1537   return GST_ELEMENT_CAST (result);
1538 }
1539
1540 /**
1541  * gst_bin_get_all_by_interface:
1542  * @bin: bin to find elements in
1543  * @interface: interface to be implemented by interface
1544  *
1545  * Looks for all elements inside the bin that implements the given
1546  * interface. You can safely cast all returned elements to the given interface.
1547  * The function recurses bins inside bins. The iterator will return a series
1548  * of #GstElement that should be unreffed after use.
1549  *
1550  * MT safe.
1551  *
1552  * Returns: A #GstIterator for the elements inside the bin implementing the
1553  *          given interface.
1554  */
1555 GstIterator *
1556 gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)
1557 {
1558   GstIterator *children;
1559   GstIterator *result;
1560
1561   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1562
1563   children = gst_bin_iterate_recurse (bin);
1564   result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
1565       GINT_TO_POINTER (interface));
1566
1567   return result;
1568 }
1569
1570 #ifndef GST_DISABLE_LOADSAVE
1571 static xmlNodePtr
1572 gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
1573 {
1574   GstBin *bin = GST_BIN (object);
1575   xmlNodePtr childlist, elementnode;
1576   GList *children;
1577   GstElement *child;
1578
1579   if (GST_OBJECT_CLASS (parent_class)->save_thyself)
1580     GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
1581
1582   childlist = xmlNewChild (parent, NULL, (xmlChar *) "children", NULL);
1583
1584   GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
1585       GST_ELEMENT_NAME (bin), bin->numchildren);
1586
1587   children = bin->children;
1588   while (children) {
1589     child = GST_ELEMENT (children->data);
1590     elementnode = xmlNewChild (childlist, NULL, (xmlChar *) "element", NULL);
1591     gst_object_save_thyself (GST_OBJECT (child), elementnode);
1592     children = g_list_next (children);
1593   }
1594   return childlist;
1595 }
1596
1597 static void
1598 gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
1599 {
1600   GstBin *bin = GST_BIN (object);
1601   xmlNodePtr field = self->xmlChildrenNode;
1602   xmlNodePtr childlist;
1603
1604   while (field) {
1605     if (!strcmp ((char *) field->name, "children")) {
1606       GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
1607           GST_ELEMENT_NAME (object));
1608       childlist = field->xmlChildrenNode;
1609       while (childlist) {
1610         if (!strcmp ((char *) childlist->name, "element")) {
1611           GstElement *element =
1612               gst_xml_make_element (childlist, GST_OBJECT (bin));
1613
1614           /* it had to be parented to find the pads, now we ref and unparent so
1615            * we can add it to the bin */
1616           gst_object_ref (GST_OBJECT (element));
1617           gst_object_unparent (GST_OBJECT (element));
1618
1619           gst_bin_add (bin, element);
1620         }
1621         childlist = childlist->next;
1622       }
1623     }
1624
1625     field = field->next;
1626   }
1627   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
1628     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
1629 }
1630 #endif /* GST_DISABLE_LOADSAVE */