IS_USABLE is only for PLAYING elements
[platform/upstream/gstreamer.git] / gst / gstelement.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstelement.c: The base element, all elements derive from this
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 <glib.h>
25 #include <stdarg.h>
26 #include <gobject/gvaluecollector.h>
27 #include "gst_private.h"
28
29 #include "gstelement.h"
30 #include "gstextratypes.h"
31 #include "gstbin.h"
32 #include "gstscheduler.h"
33 #include "gstevent.h"
34 #include "gstutils.h"
35 #include "gstlog.h"
36
37 /* Element signals and args */
38 enum {
39   STATE_CHANGE,
40   NEW_PAD,
41   PAD_REMOVED,
42   ERROR,
43   EOS,
44   LAST_SIGNAL
45 };
46
47 enum {
48   ARG_0,
49   /* FILL ME */
50 };
51
52 static void                     gst_element_class_init          (GstElementClass *klass);
53 static void                     gst_element_init                (GstElement *element);
54 static void                     gst_element_base_class_init     (GstElementClass *klass);
55
56 static void                     gst_element_real_set_property   (GObject *object, guint prop_id, 
57                                                                  const GValue *value, GParamSpec *pspec);
58 static void                     gst_element_real_get_property   (GObject *object, guint prop_id, GValue *value, 
59                                                                  GParamSpec *pspec);
60
61 static void                     gst_element_dispose             (GObject *object);
62
63 static GstElementStateReturn    gst_element_change_state        (GstElement *element);
64 static void                     gst_element_error_func          (GstElement* element, GstElement *source, gchar *errormsg);
65
66 #ifndef GST_DISABLE_LOADSAVE
67 static xmlNodePtr               gst_element_save_thyself        (GstObject *object, xmlNodePtr parent);
68 static void                     gst_element_restore_thyself     (GstObject *parent, xmlNodePtr self);
69 #endif
70
71 GType _gst_element_type = 0;
72
73 static GstObjectClass *parent_class = NULL;
74 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
75
76 GType gst_element_get_type (void) 
77 {
78   if (!_gst_element_type) {
79     static const GTypeInfo element_info = {
80       sizeof(GstElementClass),
81       (GBaseInitFunc)gst_element_base_class_init,
82       NULL,
83       (GClassInitFunc)gst_element_class_init,
84       NULL,
85       NULL,
86       sizeof(GstElement),
87       0,
88       (GInstanceInitFunc)gst_element_init,
89       NULL
90     };
91     _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", 
92                           &element_info, G_TYPE_FLAG_ABSTRACT);
93   }
94   return _gst_element_type;
95 }
96
97 static void
98 gst_element_class_init (GstElementClass *klass)
99 {
100   GObjectClass *gobject_class;
101   GstObjectClass *gstobject_class;
102
103   gobject_class = (GObjectClass*) klass;
104   gstobject_class = (GstObjectClass*) klass;
105
106   parent_class = g_type_class_ref(GST_TYPE_OBJECT);
107
108   gst_element_signals[STATE_CHANGE] =
109     g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
110                   G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
111                   gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
112                   G_TYPE_INT, G_TYPE_INT);
113   gst_element_signals[NEW_PAD] =
114     g_signal_new ("new_pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
115                   G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
116                   gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
117                   G_TYPE_OBJECT);
118   gst_element_signals[PAD_REMOVED] =
119     g_signal_new ("pad_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
120                   G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
121                   gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
122                   G_TYPE_OBJECT);
123   gst_element_signals[ERROR] =
124     g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
125                   G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
126                   gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
127                   G_TYPE_OBJECT, G_TYPE_STRING);
128   gst_element_signals[EOS] =
129     g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
130                   G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
131                   gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
132
133   gobject_class->set_property           = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
134   gobject_class->get_property           = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
135
136   gobject_class->dispose                = GST_DEBUG_FUNCPTR (gst_element_dispose);
137
138 #ifndef GST_DISABLE_LOADSAVE
139   gstobject_class->save_thyself         = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
140   gstobject_class->restore_thyself      = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
141 #endif
142
143   klass->change_state                   = GST_DEBUG_FUNCPTR (gst_element_change_state);
144   klass->error                          = GST_DEBUG_FUNCPTR (gst_element_error_func);
145   klass->elementfactory                 = NULL;
146   klass->padtemplates                   = NULL;
147   klass->numpadtemplates                = 0;
148 }
149
150 static void
151 gst_element_base_class_init (GstElementClass *klass)
152 {
153   GObjectClass *gobject_class;
154
155   gobject_class = (GObjectClass*) klass;
156
157   gobject_class->set_property =         GST_DEBUG_FUNCPTR(gst_element_real_set_property);
158   gobject_class->get_property =         GST_DEBUG_FUNCPTR(gst_element_real_get_property);
159 }
160
161 static void
162 gst_element_init (GstElement *element)
163 {
164   element->current_state = GST_STATE_NULL;
165   element->pending_state = GST_STATE_VOID_PENDING;
166   element->numpads = 0;
167   element->numsrcpads = 0;
168   element->numsinkpads = 0;
169   element->pads = NULL;
170   element->loopfunc = NULL;
171   element->sched = NULL;
172   element->clock = NULL;
173   element->sched_private = NULL;
174   element->state_mutex = g_mutex_new ();
175   element->state_cond = g_cond_new ();
176 }
177
178 static void
179 gst_element_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
180 {
181   GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
182
183   if (oclass->set_property)
184     (oclass->set_property) (object, prop_id, value, pspec);
185 }
186
187 static void
188 gst_element_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
189 {
190   GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
191
192   if (oclass->get_property)
193     (oclass->get_property) (object, prop_id, value, pspec);
194 }
195
196 /** 
197  * gst_element_default_error:
198  * @object: a #GObject that signalled the error.
199  * @orig: the #GstObject that initiated the error.
200  * @error: the error message.
201  *
202  * Adds a default error signal callback to an
203  * element. The user data passed to the g_signal_connect is
204  * ignored.
205  * The default handler will simply print the error string 
206  * using g_print.
207  */
208 void
209 gst_element_default_error (GObject *object, GstObject *orig, gchar *error)
210
211   gchar *name = gst_object_get_path_string (orig);
212   g_print ("ERROR: %s: %s\n", name, error);
213   g_free (name);
214
215
216 typedef struct {
217   const GParamSpec *pspec;
218   GValue value;
219 } prop_value_t;
220
221 static void
222 element_set_property (GstElement *element, const GParamSpec *pspec, const GValue *value)
223 {
224   prop_value_t *prop_value = g_new0 (prop_value_t, 1);
225
226   prop_value->pspec = pspec;
227   prop_value->value = *value;
228
229   g_async_queue_push (element->prop_value_queue, prop_value);
230 }
231
232 static void
233 element_get_property (GstElement *element, const GParamSpec *pspec, GValue *value)
234 {
235   g_mutex_lock (element->property_mutex);
236   g_object_get_property ((GObject*)element, pspec->name, value);
237   g_mutex_unlock (element->property_mutex);
238 }
239
240 static void
241 gst_element_threadsafe_properties_pre_run (GstElement *element)
242 {
243   GST_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
244   g_mutex_lock (element->property_mutex);
245   gst_element_set_pending_properties (element);
246 }
247
248 static void
249 gst_element_threadsafe_properties_post_run (GstElement *element)
250 {
251   GST_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
252   g_mutex_unlock (element->property_mutex);
253 }
254
255 /**
256  * gst_element_enable_threadsafe_properties:
257  * @element: a #GstElement to enable threadsafe properties on.
258  *
259  * Installs an asynchronous queue, a mutex and pre- and post-run functions on
260  * this element so that properties on the element can be set in a 
261  * threadsafe way.
262  */
263 void
264 gst_element_enable_threadsafe_properties (GstElement *element)
265 {
266   g_return_if_fail (GST_IS_ELEMENT (element));
267   
268   GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
269   element->pre_run_func = gst_element_threadsafe_properties_pre_run;
270   element->post_run_func = gst_element_threadsafe_properties_post_run;
271   if (!element->prop_value_queue)
272     element->prop_value_queue = g_async_queue_new ();
273   if (!element->property_mutex)
274     element->property_mutex = g_mutex_new ();
275 }
276
277 /**
278  * gst_element_disable_threadsafe_properties:
279  * @element: a #GstElement to disable threadsafe properties on.
280  *
281  * Removes the threadsafe properties, post- and pre-run locks from
282  * this element.
283  */
284 void
285 gst_element_disable_threadsafe_properties (GstElement *element)
286 {
287   g_return_if_fail (GST_IS_ELEMENT (element));
288   
289   GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
290   element->pre_run_func = NULL;
291   element->post_run_func = NULL;
292   /* let's keep around that async queue */
293 }
294
295 /**
296  * gst_element_set_pending_properties:
297  * @element: a #GstElement to set the pending properties on.
298  *
299  * Sets all pending properties on the threadsafe properties enabled
300  * element.
301  */
302 void
303 gst_element_set_pending_properties (GstElement *element) 
304 {
305   prop_value_t *prop_value;
306
307   while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) {
308     g_object_set_property ((GObject*)element, prop_value->pspec->name, &prop_value->value);
309     g_value_unset (&prop_value->value);
310     g_free (prop_value);
311   }
312 }
313
314 /* following 6 functions taken mostly from gobject.c */
315
316 /**
317  * gst_element_set:
318  * @element: a #GstElement to set properties on.
319  * @first_property_name: the first property to set.
320  * @...: value of the first property, and more properties to set, ending
321  *       with NULL.
322  *
323  * Sets properties on an element. If the element uses threadsafe properties,
324  * they will be queued and set on the object when it is scheduled again.
325  */
326 void
327 gst_element_set (GstElement *element, const gchar *first_property_name, ...)
328 {
329   va_list var_args;
330   
331   g_return_if_fail (GST_IS_ELEMENT (element));
332   
333   va_start (var_args, first_property_name);
334   gst_element_set_valist (element, first_property_name, var_args);
335   va_end (var_args);
336 }
337
338 /**
339  * gst_element_get:
340  * @element: a #GstElement to get properties of.
341  * @first_property_name: the first property to get.
342  * @...: pointer to a variable to store the first property in, as well as 
343  * more properties to get, ending with NULL.
344  *
345  * Gets properties from an element. If the element uses threadsafe properties,
346  * the element will be locked before getting the given properties.
347  */
348 void
349 gst_element_get (GstElement *element, const gchar *first_property_name, ...)
350 {
351   va_list var_args;
352   
353   g_return_if_fail (GST_IS_ELEMENT (element));
354   
355   va_start (var_args, first_property_name);
356   gst_element_get_valist (element, first_property_name, var_args);
357   va_end (var_args);
358 }
359
360 /**
361  * gst_element_set_valist:
362  * @element: a #GstElement to set properties on.
363  * @first_property_name: the first property to set.
364  * @var_args: the var_args list of other properties to get.
365  *
366  * Sets properties on an element. If the element uses threadsafe properties,
367  * the property change will be put on the async queue.
368  */
369 void
370 gst_element_set_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
371 {
372   const gchar *name;
373   GObject *object;
374   
375   g_return_if_fail (GST_IS_ELEMENT (element));
376   
377   object = (GObject *) element;
378
379   GST_DEBUG (GST_CAT_PROPERTIES, 
380              "setting valist of properties starting with %s on element %s",
381              first_property_name, gst_element_get_name (element));
382
383   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
384     g_object_set_valist (object, first_property_name, var_args);
385     return;
386   }
387
388   g_object_ref (object);
389   
390   name = first_property_name;
391
392   while (name)
393     {
394       GValue value = { 0, };
395       GParamSpec *pspec;
396       gchar *error = NULL;
397       
398       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
399
400       if (!pspec)
401         {
402           g_warning ("%s: object class `%s' has no property named `%s'",
403                      G_STRLOC,
404                      G_OBJECT_TYPE_NAME (object),
405                      name);
406           break;
407         }
408       if (!(pspec->flags & G_PARAM_WRITABLE))
409         {
410           g_warning ("%s: property `%s' of object class `%s' is not writable",
411                      G_STRLOC,
412                      pspec->name,
413                      G_OBJECT_TYPE_NAME (object));
414           break;
415         }
416       
417       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
418       
419       G_VALUE_COLLECT (&value, var_args, 0, &error);
420       if (error)
421         {
422           g_warning ("%s: %s", G_STRLOC, error);
423           g_free (error);
424           
425           /* we purposely leak the value here, it might not be
426            * in a sane state if an error condition occoured
427            */
428           break;
429         }
430       
431       element_set_property (element, pspec, &value);
432       g_value_unset (&value);
433       
434       name = va_arg (var_args, gchar*);
435     }
436
437   g_object_unref (object);
438 }
439
440 /**
441  * gst_element_get_valist:
442  * @element: a #GstElement to get properties of.
443  * @first_property_name: the first property to get.
444  * @var_args: the var_args list of other properties to get.
445  *
446  * Gets properties from an element. If the element uses threadsafe properties,
447  * the element will be locked before getting the given properties.
448  */
449 void
450 gst_element_get_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
451 {
452   const gchar *name;
453   GObject *object;
454   
455   g_return_if_fail (GST_IS_ELEMENT (element));
456   
457   object = (GObject*)element;
458
459   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
460     g_object_get_valist (object, first_property_name, var_args);
461     return;
462   }
463
464   g_object_ref (object);
465   
466   name = first_property_name;
467   
468   while (name)
469     {
470       GValue value = { 0, };
471       GParamSpec *pspec;
472       gchar *error;
473       
474       pspec =  g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
475
476       if (!pspec)
477         {
478           g_warning ("%s: object class `%s' has no property named `%s'",
479                      G_STRLOC,
480                      G_OBJECT_TYPE_NAME (object),
481                      name);
482           break;
483         }
484       if (!(pspec->flags & G_PARAM_READABLE))
485         {
486           g_warning ("%s: property `%s' of object class `%s' is not readable",
487                      G_STRLOC,
488                      pspec->name,
489                      G_OBJECT_TYPE_NAME (object));
490           break;
491         }
492       
493       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
494       
495       element_get_property (element, pspec, &value);
496       
497       G_VALUE_LCOPY (&value, var_args, 0, &error);
498       if (error)
499         {
500           g_warning ("%s: %s", G_STRLOC, error);
501           g_free (error);
502           g_value_unset (&value);
503           break;
504         }
505       
506       g_value_unset (&value);
507       
508       name = va_arg (var_args, gchar*);
509     }
510   
511   g_object_unref (object);
512 }
513
514 /**
515  * gst_element_set_property:
516  * @element: a #GstElement to set properties on.
517  * @property_name: the first property to get.
518  * @value: the #GValue that holds the value to set.
519  *
520  * Sets a property on an element. If the element uses threadsafe properties,
521  * the property will be put on the async queue.
522  */
523 void
524 gst_element_set_property (GstElement *element, const gchar *property_name, 
525                           const GValue *value)
526 {
527   GParamSpec *pspec;
528   GObject *object;
529   
530   g_return_if_fail (GST_IS_ELEMENT (element));
531   g_return_if_fail (property_name != NULL);
532   g_return_if_fail (G_IS_VALUE (value));
533   
534   object = (GObject*) element;
535
536   GST_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
537              property_name, gst_element_get_name (element));
538   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
539     g_object_set_property (object, property_name, value);
540     return;
541   }
542
543   g_object_ref (object);
544   
545   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), 
546                                         property_name);
547   
548   if (!pspec)
549     g_warning ("%s: object class `%s' has no property named `%s'",
550                G_STRLOC,
551                G_OBJECT_TYPE_NAME (object),
552                property_name);
553   else
554     element_set_property (element, pspec, value);
555   
556   g_object_unref (object);
557 }
558   
559 /**
560  * gst_element_get_property:
561  * @element: a #GstElement to get properties of.
562  * @property_name: the first property to get.
563  * @value: the #GValue to store the property value in.
564  *
565  * Gets a property from an element. If the element uses threadsafe properties,
566  * the element will be locked before getting the given property.
567  */
568 void
569 gst_element_get_property (GstElement *element, const gchar *property_name, GValue *value)
570 {
571   GParamSpec *pspec;
572   GObject *object;
573   
574   g_return_if_fail (GST_IS_ELEMENT (element));
575   g_return_if_fail (property_name != NULL);
576   g_return_if_fail (G_IS_VALUE (value));
577   
578   object = (GObject*)element;
579
580   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
581     g_object_get_property (object, property_name, value);
582     return;
583   }
584
585   g_object_ref (object);
586   
587   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
588   
589   if (!pspec)
590     g_warning ("%s: object class `%s' has no property named `%s'",
591                G_STRLOC,
592                G_OBJECT_TYPE_NAME (object),
593                property_name);
594   else
595     {
596       GValue *prop_value, tmp_value = { 0, };
597       
598       /* auto-conversion of the callers value type
599        */
600       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
601         {
602           g_value_reset (value);
603           prop_value = value;
604         }
605       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
606         {
607           g_warning ("can't retrieve property `%s' of type `%s' as value of type `%s'",
608                      pspec->name,
609                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
610                      G_VALUE_TYPE_NAME (value));
611           g_object_unref (object);
612           return;
613         }
614       else
615         {
616           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
617           prop_value = &tmp_value;
618         }
619       element_get_property (element, pspec, prop_value);
620       if (prop_value != value)
621         {
622           g_value_transform (prop_value, value);
623           g_value_unset (&tmp_value);
624         }
625     }
626   
627   g_object_unref (object);
628 }
629
630 static GstPad*
631 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
632 {
633   GstPad *newpad = NULL;
634   GstElementClass *oclass;
635
636   oclass = GST_ELEMENT_GET_CLASS (element);
637
638   if (oclass->request_new_pad)
639     newpad = (oclass->request_new_pad)(element, templ, name);
640
641   return newpad;
642 }
643
644 /**
645  * gst_element_release_request_pad:
646  * @element: a #GstElement to release the request pad of.
647  * @pad: the #GstPad to release.
648  *
649  * Makes the element free the previously requested pad as obtained
650  * with gst_element_get_request_pad().
651  */
652 void
653 gst_element_release_request_pad (GstElement *element, GstPad *pad)
654 {
655   GstElementClass *oclass;
656
657   g_return_if_fail (GST_IS_ELEMENT (element));
658   g_return_if_fail (GST_IS_PAD (pad));
659
660   oclass = GST_ELEMENT_GET_CLASS (element);
661
662   if (oclass->release_pad)
663     (oclass->release_pad) (element, pad);
664 }
665
666 /**
667  * gst_element_requires_clock:
668  * @element: a #GstElement to query
669  *
670  * Query if the element requiresd a clock
671  *
672  * Returns: TRUE if the element requires a clock
673  */
674 gboolean
675 gst_element_requires_clock (GstElement *element)
676 {
677   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
678
679   return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL);
680 }
681
682 /**
683  * gst_element_provides_clock:
684  * @element: a #GstElement to query
685  *
686  * Query if the element provides a clock
687  *
688  * Returns: TRUE if the element provides a clock
689  */
690 gboolean
691 gst_element_provides_clock (GstElement *element)
692 {
693   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
694
695   return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL);
696 }
697
698 /**
699  * gst_element_set_clock:
700  * @element: a #GstElement to set the clock for.
701  * @clock: the #GstClock to set for the element.
702  *
703  * Sets the clock for the element.
704  */
705 void
706 gst_element_set_clock (GstElement *element, GstClock *clock)
707 {
708   GstElementClass *oclass;
709
710   g_return_if_fail (GST_IS_ELEMENT (element));
711
712   oclass = GST_ELEMENT_GET_CLASS (element);
713
714   if (oclass->set_clock)
715     oclass->set_clock (element, clock);
716
717   element->clock = clock;
718 }
719
720 /**
721  * gst_element_get_clock:
722  * @element: a #GstElement to get the clock of.
723  *
724  * Gets the clock of the element.
725  *
726  * Returns: the #GstClock of the element.
727  */
728 GstClock*
729 gst_element_get_clock (GstElement *element)
730 {
731   GstElementClass *oclass;
732
733   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
734
735   oclass = GST_ELEMENT_GET_CLASS (element);
736   
737   if (oclass->get_clock)
738     return oclass->get_clock (element);
739
740   return NULL;
741 }
742
743 /**
744  * gst_element_clock_wait:
745  * @element: a #GstElement.
746  * @id: the #GstClock to use.
747  * @jitter: the difference between requested time and actual time.
748  *
749  * Waits for a specific time on the clock.
750  *
751  * Returns: the #GstClockReturn result of the wait operation.
752  */
753 GstClockReturn
754 gst_element_clock_wait (GstElement *element, GstClockID id, GstClockTimeDiff *jitter)
755 {
756   GstClockReturn res;
757
758   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
759
760   if (GST_ELEMENT_SCHED (element)) {
761     res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id, jitter);
762   }
763   else 
764     res = GST_CLOCK_TIMEOUT;
765
766   return res;
767 }
768
769 /**
770  * gst_element_is_indexable:
771  * @element: a #GstElement.
772  *
773  * Queries if the element can be indexed/
774  *
775  * Returns: TRUE if the element can be indexed.
776  */
777 gboolean
778 gst_element_is_indexable (GstElement *element)
779 {
780   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
781
782   return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
783 }
784
785 /**
786  * gst_element_set_index:
787  * @element: a #GstElement.
788  * @index: a #GstIndex.
789  *
790  * Set the specified GstIndex on the element.
791  */
792 void
793 gst_element_set_index (GstElement *element, GstIndex *index)
794 {
795   GstElementClass *oclass;
796
797   g_return_if_fail (GST_IS_ELEMENT (element));
798   g_return_if_fail (GST_IS_INDEX (index));
799
800   oclass = GST_ELEMENT_GET_CLASS (element);
801
802   if (oclass->set_index)
803     oclass->set_index (element, index);
804 }
805
806 /**
807  * gst_element_get_index:
808  * @element: a #GstElement.
809  *
810  * Gets the index from the element.
811  *
812  * Returns: a #GstIndex or NULL when no index was set on the
813  * element.
814  */
815 GstIndex*
816 gst_element_get_index (GstElement *element)
817 {
818   GstElementClass *oclass;
819
820   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
821
822   oclass = GST_ELEMENT_GET_CLASS (element);
823
824   if (oclass->get_index)
825     return oclass->get_index (element);
826
827   return NULL;
828 }
829
830 /**
831  * gst_element_release_locks:
832  * @element: a #GstElement to release all locks on.
833  *
834  * Instruct the element to release all the locks it is holding, such as
835  * blocking reads, waiting for the clock, ...
836  *
837  * Returns: TRUE if the locks could be released.
838  */
839 gboolean
840 gst_element_release_locks (GstElement *element)
841 {
842   GstElementClass *oclass;
843
844   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
845
846   oclass = GST_ELEMENT_GET_CLASS (element);
847
848   if (oclass->release_locks)
849     return oclass->release_locks (element);
850   
851   return TRUE;
852 }
853
854 /**
855  * gst_element_add_pad:
856  * @element: a #GstElement to add the pad to.
857  * @pad: the #GstPad to add to the element.
858  *
859  * Add a pad (connection point) to the element, setting the parent of the
860  * pad to the element (and thus adding a reference).
861  */
862 void
863 gst_element_add_pad (GstElement *element, GstPad *pad)
864 {
865   g_return_if_fail (element != NULL);
866   g_return_if_fail (GST_IS_ELEMENT (element));
867   g_return_if_fail (pad != NULL);
868   g_return_if_fail (GST_IS_PAD (pad));
869
870   /* first check to make sure the pad's parent is already set */
871   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
872
873   /* then check to see if there's already a pad by that name here */
874   g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
875
876   /* set the pad's parent */
877   GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
878         GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
879   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
880
881   /* add it to the list */
882   element->pads = g_list_append (element->pads, pad);
883   element->numpads++;
884   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
885     element->numsrcpads++;
886   else
887     element->numsinkpads++;
888
889   /* emit the NEW_PAD signal */
890   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
891 }
892
893 /**
894  * gst_element_remove_pad:
895  * @element: a #GstElement to remove pad from.
896  * @pad: the #GstPad to remove from the element.
897  *
898  * Remove a pad (connection point) from the element.
899  */
900 void
901 gst_element_remove_pad (GstElement *element, GstPad *pad)
902 {
903   g_return_if_fail (element != NULL);
904   g_return_if_fail (GST_IS_ELEMENT (element));
905   g_return_if_fail (pad != NULL);
906   g_return_if_fail (GST_IS_PAD (pad));
907
908   g_return_if_fail (GST_PAD_PARENT (pad) == element);
909
910   /* check to see if the pad is still connected */
911   /* FIXME: what if someone calls _remove_pad instead of 
912     _remove_ghost_pad? */
913   if (GST_IS_REAL_PAD (pad)) {
914     g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
915   }
916   
917   /* remove it from the list */
918   element->pads = g_list_remove (element->pads, pad);
919   element->numpads--;
920   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
921     element->numsrcpads--;
922   else
923     element->numsinkpads--;
924
925   g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
926
927   gst_object_unparent (GST_OBJECT (pad));
928 }
929
930 /**
931  * gst_element_add_ghost_pad:
932  * @element: a #GstElement to add the ghost pad to.
933  * @pad: the #GstPad from which the new ghost pad will be created.
934  * @name: the name of the new ghost pad.
935  *
936  * Creates a ghost pad from the given pad, and adds it to the list of pads
937  * for this element.
938  * 
939  * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
940  */
941 GstPad *
942 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
943 {
944   GstPad *ghostpad;
945
946   g_return_val_if_fail (element != NULL, NULL);
947   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
948   g_return_val_if_fail (pad != NULL, NULL);
949   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
950
951   /* then check to see if there's already a pad by that name here */
952   g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
953
954   GST_DEBUG (GST_CAT_ELEMENT_PADS, 
955              "creating new ghost pad called %s, from pad %s:%s",
956              name, GST_DEBUG_PAD_NAME(pad));
957   ghostpad = gst_ghost_pad_new (name, pad);
958
959   /* add it to the list */
960   GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
961             name, GST_ELEMENT_NAME (element));
962   element->pads = g_list_append (element->pads, ghostpad);
963   element->numpads++;
964   /* set the parent of the ghostpad */
965   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
966
967   GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
968
969   /* emit the NEW_GHOST_PAD signal */
970   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
971         
972   return ghostpad;
973 }
974
975 /**
976  * gst_element_remove_ghost_pad:
977  * @element: a #GstElement to remove the ghost pad from.
978  * @pad: ghost #GstPad to remove.
979  *
980  * Removes a ghost pad from an element.
981  */
982 void
983 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
984 {
985   g_return_if_fail (element != NULL);
986   g_return_if_fail (GST_IS_ELEMENT (element));
987   g_return_if_fail (pad != NULL);
988   g_return_if_fail (GST_IS_GHOST_PAD (pad));
989
990   /* FIXME this is redundant?
991    * wingo 10-july-2001: I don't think so, you have to actually remove the pad
992    * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
993    * the real pad's ghost pad list
994    */
995   gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
996   gst_element_remove_pad (element, pad);
997 }
998
999
1000 /**
1001  * gst_element_get_pad:
1002  * @element: a #GstElement to find pad of.
1003  * @name: the name of the pad to retrieve.
1004  *
1005  * Retrieves a pad from the element by name.
1006  *
1007  * Returns: requested #GstPad if found, otherwise NULL.
1008  */
1009 GstPad*
1010 gst_element_get_pad (GstElement *element, const gchar *name)
1011 {
1012   GstPad *pad;
1013
1014   g_return_val_if_fail (element != NULL, NULL);
1015   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1016   g_return_val_if_fail (name != NULL, NULL);
1017
1018   pad = gst_element_get_static_pad (element, name);
1019   if (!pad) 
1020     pad = gst_element_get_request_pad (element, name);
1021
1022   return pad;
1023 }
1024
1025 /**
1026  * gst_element_get_static_pad:
1027  * @element: a #GstElement to find a static pad of.
1028  * @name: the name of the static #GstPad to retrieve.
1029  *
1030  * Retrieves a pad from the element by name. This version only retrieves
1031  * already-existing (i.e. 'static') pads.
1032  *
1033  * Returns: the requested #GstPad if found, otherwise NULL.
1034  */
1035 GstPad *
1036 gst_element_get_static_pad (GstElement *element, const gchar *name)
1037 {
1038   GList *walk;
1039   
1040   g_return_val_if_fail (element != NULL, NULL);
1041   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1042   g_return_val_if_fail (name != NULL, NULL);
1043
1044   walk = element->pads;
1045   while (walk) {
1046     GstPad *pad;
1047     
1048     pad = GST_PAD(walk->data);
1049     if (strcmp (GST_PAD_NAME(pad), name) == 0) {
1050       GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1051       return pad;
1052     }
1053     walk = g_list_next (walk);
1054   }
1055
1056   GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
1057   return NULL;
1058 }
1059
1060 /**
1061  * gst_element_get_request_pad:
1062  * @element: a #GstElement to find a request pad of.
1063  * @name: the name of the request #GstPad to retrieve.
1064  *
1065  * Retrieves a pad from the element by name. This version only retrieves
1066  * request pads.
1067  *
1068  * Returns: requested #GstPad if found, otherwise NULL.
1069  */
1070 GstPad*
1071 gst_element_get_request_pad (GstElement *element, const gchar *name)
1072 {
1073   GstPadTemplate *templ = NULL;
1074   GstPad *pad;
1075   const gchar *req_name = NULL;
1076   gboolean templ_found = FALSE;
1077   GList *list;
1078   gint n;
1079   const gchar *data;
1080   gchar *str, *endptr = NULL;
1081
1082   g_return_val_if_fail (element != NULL, NULL);
1083   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1084   g_return_val_if_fail (name != NULL, NULL);
1085
1086   if (strstr (name, "%")) {
1087     templ = gst_element_get_pad_template (element, name);
1088     req_name = NULL;
1089     if (templ)
1090       templ_found = TRUE;
1091   } else {
1092     list = gst_element_get_pad_template_list(element);
1093     while (!templ_found && list) {
1094       templ = (GstPadTemplate*) list->data;
1095       if (templ->presence == GST_PAD_REQUEST) {
1096         /* we know that %s and %d are the only possibilities because of sanity
1097            checks in gst_pad_template_new */
1098         GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
1099         if ((str = strchr (templ->name_template, '%')) &&
1100             strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
1101             strlen (name) > str - templ->name_template) {
1102           data = name + (str - templ->name_template);
1103           if (*(str+1) == 'd') {
1104             /* it's an int */
1105             n = (gint) strtol (data, &endptr, 10);
1106             if (endptr && *endptr == '\0') {
1107               templ_found = TRUE;
1108               req_name = name;
1109               break;
1110             }
1111           } else {
1112             /* it's a string */
1113             templ_found = TRUE;
1114             req_name = name;
1115             break;
1116           }
1117         }
1118       }
1119       list = list->next;
1120     }
1121   }
1122   
1123   if (!templ_found)
1124       return NULL;
1125   
1126   pad = gst_element_request_pad (element, templ, req_name);
1127   
1128   return pad;
1129 }
1130
1131 /**
1132  * gst_element_get_pad_list:
1133  * @element: a #GstElement to get pads of.
1134  *
1135  * Retrieves a list of the pads associated with the element.
1136  *
1137  * Returns: the #GList of pads.
1138  */
1139 const GList*
1140 gst_element_get_pad_list (GstElement *element)
1141 {
1142   g_return_val_if_fail (element != NULL, NULL);
1143   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1144
1145   /* return the list of pads */
1146   return element->pads;
1147 }
1148
1149 /**
1150  * gst_element_class_add_pad_template:
1151  * @klass: the #GstElementClass to add the pad template to.
1152  * @templ: a #GstPadTemplate to add to the element class.
1153  *
1154  * Adds a padtemplate to an element class. 
1155  * This is useful if you have derived a custom bin and wish to provide 
1156  * an on-request pad at runtime. Plug-in writers should use
1157  * gst_element_factory_add_pad_template instead.
1158  */
1159 void
1160 gst_element_class_add_pad_template (GstElementClass *klass, 
1161                                     GstPadTemplate *templ)
1162 {
1163   g_return_if_fail (klass != NULL);
1164   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1165   g_return_if_fail (templ != NULL);
1166   g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1167   
1168   klass->padtemplates = g_list_append (klass->padtemplates, templ);
1169   klass->numpadtemplates++;
1170 }
1171
1172 /**
1173  * gst_element_get_pad_template_list:
1174  * @element: a #GstElement to get pad templates of.
1175  *
1176  * Retrieves a list of the pad templates associated with the element.
1177  *
1178  * Returns: the #GList of padtemplates.
1179  */
1180 GList*
1181 gst_element_get_pad_template_list (GstElement *element)
1182 {
1183   g_return_val_if_fail (element != NULL, NULL);
1184   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1185
1186   return GST_ELEMENT_GET_CLASS (element)->padtemplates;
1187 }
1188
1189 /**
1190  * gst_element_get_pad_template:
1191  * @element: a #GstElement to get the pad template of.
1192  * @name: the name of the #GstPadTemplate to get.
1193  *
1194  * Retrieves a padtemplate from this element with the
1195  * given name.
1196  *
1197  * Returns: the #GstPadTemplate with the given name, or NULL if none was found. 
1198  * No unreferencing is necessary.
1199  */
1200 GstPadTemplate*
1201 gst_element_get_pad_template (GstElement *element, const gchar *name)
1202 {
1203   GList *padlist;
1204
1205   g_return_val_if_fail (element != NULL, NULL);
1206   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1207   g_return_val_if_fail (name != NULL, NULL);
1208
1209   padlist = gst_element_get_pad_template_list (element);
1210
1211   while (padlist) {
1212     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1213
1214     if (!strcmp (padtempl->name_template, name))
1215       return padtempl;
1216
1217     padlist = g_list_next (padlist);
1218   }
1219
1220   return NULL;
1221 }
1222
1223 /**
1224  * gst_element_get_compatible_pad_template:
1225  * @element: a #GstElement to get a compatible pad template for.
1226  * @compattempl: the #GstPadTemplate to find a compatible template for.
1227  *
1228  * Generates a pad template for this element compatible with the given
1229  * template (meaning it is able to connect with it).
1230  *
1231  * Returns: the #GstPadTemplate of the element that is compatible with
1232  * the given GstPadTemplate, or NULL if none was found. No unreferencing 
1233  * is necessary.
1234  */
1235 GstPadTemplate*
1236 gst_element_get_compatible_pad_template (GstElement *element, 
1237                                          GstPadTemplate *compattempl)
1238 {
1239   GstPadTemplate *newtempl = NULL;
1240   GList *padlist;
1241
1242   GST_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
1243
1244   g_return_val_if_fail (element != NULL, NULL);
1245   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1246   g_return_val_if_fail (compattempl != NULL, NULL);
1247
1248   padlist = gst_element_get_pad_template_list (element);
1249
1250   while (padlist) {
1251     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1252     gboolean comp = FALSE;
1253
1254     /* Ignore name
1255      * Ignore presence
1256      * Check direction (must be opposite)
1257      * Check caps
1258      */
1259     GST_DEBUG (GST_CAT_CAPS, "checking direction and caps");
1260     if (padtempl->direction == GST_PAD_SRC &&
1261       compattempl->direction == GST_PAD_SINK) {
1262       GST_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
1263       comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (padtempl),
1264                                            GST_PAD_TEMPLATE_CAPS (compattempl));
1265       GST_DEBUG(GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1266     } else if (padtempl->direction == GST_PAD_SINK &&
1267                compattempl->direction == GST_PAD_SRC) {
1268       GST_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
1269       comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1270                                            GST_PAD_TEMPLATE_CAPS (padtempl));
1271       GST_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1272     }
1273
1274     if (comp) {
1275       newtempl = padtempl;
1276       break;
1277     }
1278
1279     padlist = g_list_next (padlist);
1280   }
1281
1282   return newtempl;
1283 }
1284
1285 /**
1286  * gst_element_request_compatible_pad:
1287  * @element: a #GstElement to request a new pad from.
1288  * @templ: the #GstPadTemplate to which the new pad should be able to connect.
1289  *
1290  * Requests a new pad from the element. The template will
1291  * be used to decide what type of pad to create. This function
1292  * is typically used for elements with a padtemplate with presence
1293  * GST_PAD_REQUEST.
1294  *
1295  * Returns: the new #GstPad that was created, or NULL if none could be created.
1296  */
1297 GstPad*
1298 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
1299 {
1300   GstPadTemplate *templ_new;
1301   GstPad *pad = NULL;
1302
1303   g_return_val_if_fail (element != NULL, NULL);
1304   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1305   g_return_val_if_fail (templ != NULL, NULL);
1306
1307   templ_new = gst_element_get_compatible_pad_template (element, templ);
1308   if (templ_new != NULL)
1309       pad = gst_element_request_pad (element, templ_new, NULL);
1310
1311   return pad;
1312 }
1313
1314
1315 /**
1316  * gst_element_get_compatible_pad_filtered:
1317  * @element: a #GstElement in which the pad should be found.
1318  * @pad: the #GstPad to find a compatible one for.
1319  * @filtercaps: the #GstCaps to use as a filter.
1320  *
1321  * Looks for an unconnected pad to which the given pad can connect to.
1322  * It is not guaranteed that connecting the pads will work, though
1323  * it should work in most cases.
1324  *
1325  * Returns: the #GstPad to which a connection can be made.
1326  */
1327 GstPad*                 
1328 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad, 
1329                                          GstCaps *filtercaps)
1330 {
1331   const GList *pads;
1332   GstPadTemplate *templ;
1333   GstCaps *templcaps;
1334   GstPad *foundpad = NULL;
1335   
1336   /* checks */
1337   g_return_val_if_fail (element != NULL, NULL);
1338   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1339   g_return_val_if_fail (pad != NULL, NULL);
1340   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1341   
1342   /* let's use the real pad */
1343   pad = (GstPad *) GST_PAD_REALIZE (pad);
1344   g_return_val_if_fail (pad != NULL, NULL);
1345   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1346   
1347   /* try to get an existing unconnected pad */
1348   pads = gst_element_get_pad_list (element);
1349   while (pads) {
1350     GstPad *current = GST_PAD (pads->data);
1351     if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
1352         gst_pad_can_connect_filtered (pad, current, filtercaps)) {
1353       return current;
1354     }
1355     pads = g_list_next (pads);
1356   }
1357   
1358   /* try to create a new one */
1359   /* requesting is a little crazy, we need a template. Let's create one */
1360   if (filtercaps != NULL) {
1361     templcaps = gst_caps_intersect (filtercaps, (GstCaps *) GST_RPAD_CAPS (pad));
1362     if (templcaps == NULL)
1363       return NULL;
1364   } else {
1365     templcaps = gst_caps_copy (gst_pad_get_caps (pad));
1366   }
1367   
1368   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1369                                GST_PAD_ALWAYS, templcaps, NULL);
1370   foundpad = gst_element_request_compatible_pad (element, templ);
1371   gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
1372   
1373   /* FIXME: this is broken, but it's in here so autoplugging elements that don't
1374      have caps on their source padtemplates (spider) can connect... */
1375   if (!foundpad && !filtercaps) {
1376     templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1377                                  GST_PAD_ALWAYS, NULL, NULL);
1378     foundpad = gst_element_request_compatible_pad (element, templ);
1379     gst_object_unref (GST_OBJECT (templ));
1380   }
1381   
1382   return foundpad;
1383 }
1384
1385 /**
1386  * gst_element_get_compatible_pad:
1387  * @element: a #GstElement in which the pad should be found.
1388  * @pad: the #GstPad to find a compatible one for.
1389  *
1390  * Looks for an unconnected pad to which the given pad can connect to.
1391  * It is not guaranteed that connecting the pads will work, though
1392  * it should work in most cases.
1393  *
1394  * Returns: the #GstPad to which a connection can be made, or NULL if none
1395  * could be found.
1396  */
1397 GstPad*                 
1398 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
1399 {
1400   return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1401 }
1402
1403 /**
1404  * gst_element_connect_filtered:
1405  * @src: a #GstElement containing the source pad.
1406  * @dest: the #GstElement containing the destination pad.
1407  * @filtercaps: the #GstCaps to use as a filter.
1408  *
1409  * Connects the source to the destination element using the filtercaps.
1410  * The connection must be from source to destination, the other
1411  * direction will not be tried.
1412  * The functions looks for existing pads that aren't connected yet. 
1413  * It will use request pads if possible. But both pads will not be requested.
1414  * If multiple connections are possible, only one is established.
1415  *
1416  * Returns: TRUE if the elements could be connected.
1417  */
1418 gboolean
1419 gst_element_connect_filtered (GstElement *src, GstElement *dest, 
1420                               GstCaps *filtercaps)
1421 {
1422   const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1423   GstPad *srcpad, *destpad;
1424   GstPadTemplate *srctempl, *desttempl;
1425
1426   /* checks */
1427   g_return_val_if_fail (src != NULL, FALSE);
1428   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1429   g_return_val_if_fail (dest != NULL, FALSE);
1430   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1431
1432   GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying to connect element %s to element %s",
1433              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1434    
1435   srcpads = gst_element_get_pad_list (src);
1436   destpads = gst_element_get_pad_list (dest);
1437
1438   if (srcpads || destpads) {
1439     GST_DEBUG (GST_CAT_ELEMENT_PADS, "looping through src and dest pads");
1440     /* loop through the existing pads in the source, trying to find a
1441      * compatible destination pad */
1442     while (srcpads) {
1443       srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1444       GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", 
1445                  GST_DEBUG_PAD_NAME (srcpad));
1446       if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1447           (GST_PAD_PEER (srcpad) == NULL)) {
1448         destpad = gst_element_get_compatible_pad_filtered (dest, srcpad, 
1449                                                            filtercaps);
1450         if (destpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1451           GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", 
1452                      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1453           return TRUE;
1454         }
1455       }
1456       srcpads = g_list_next (srcpads);
1457     }
1458     
1459     /* loop through the existing pads in the destination */
1460     while (destpads) {
1461       destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1462       GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s", 
1463                  GST_DEBUG_PAD_NAME (destpad));
1464       if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1465           (GST_PAD_PEER (destpad) == NULL)) {
1466         srcpad = gst_element_get_compatible_pad_filtered (src, destpad, 
1467                                                           filtercaps);
1468         if (srcpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1469           GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", 
1470                      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1471           return TRUE;
1472         }
1473       }
1474       destpads = g_list_next (destpads);
1475     }
1476   }
1477
1478   GST_DEBUG (GST_CAT_ELEMENT_PADS, 
1479              "we might have request pads on both sides, checking...");
1480   srctempls = gst_element_get_pad_template_list (src);
1481   desttempls = gst_element_get_pad_template_list (dest);
1482   
1483   if (srctempls && desttempls) {
1484     while (srctempls) {
1485       srctempl = (GstPadTemplate*) srctempls->data;
1486       if (srctempl->presence == GST_PAD_REQUEST) {
1487         for (l=desttempls; l; l=l->next) {
1488           desttempl = (GstPadTemplate*) desttempls->data;
1489           if (desttempl->presence == GST_PAD_REQUEST && 
1490               desttempl->direction != srctempl->direction) {
1491             if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
1492                                               gst_pad_template_get_caps (desttempl))) {
1493               srcpad = gst_element_get_request_pad (src, 
1494                                                     srctempl->name_template);
1495               destpad = gst_element_get_request_pad (dest, 
1496                                                      desttempl->name_template);
1497               if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1498                 GST_DEBUG (GST_CAT_ELEMENT_PADS, 
1499                            "connected pad %s:%s to pad %s:%s",
1500                            GST_DEBUG_PAD_NAME (srcpad), 
1501                            GST_DEBUG_PAD_NAME (destpad));
1502                 return TRUE;
1503               }
1504               /* FIXME: we have extraneous request pads lying around */
1505             }
1506           }
1507         }
1508       }
1509       srctempls = srctempls->next;
1510     }
1511   }
1512   
1513   GST_DEBUG (GST_CAT_ELEMENT_PADS, "no connection possible from %s to %s", 
1514              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1515   return FALSE;  
1516 }
1517
1518 /**
1519  * gst_element_connect_many:
1520  * @element_1: the first #GstElement in the connection chain.
1521  * @element_2: the second #GstElement in the connection chain.
1522  * @...: the NULL-terminated list of elements to connect in order.
1523  * 
1524  * Chain together a series of elements. Uses #gst_element_connect.
1525  *
1526  * Returns: TRUE on success, FALSE otherwise.
1527  */
1528 gboolean
1529 gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
1530 {
1531   va_list args;
1532
1533   g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1534   g_return_val_if_fail (GST_IS_ELEMENT (element_1) && 
1535                         GST_IS_ELEMENT (element_2), FALSE);
1536
1537   va_start (args, element_2);
1538
1539   while (element_2) {
1540     if (!gst_element_connect (element_1, element_2))
1541       return FALSE;
1542     
1543     element_1 = element_2;
1544     element_2 = va_arg (args, GstElement*);
1545   }
1546
1547   va_end (args);
1548   
1549   return TRUE;
1550 }
1551
1552 /**
1553  * gst_element_connect:
1554  * @src: a #GstElement containing the source pad.
1555  * @dest: the #GstElement containing the destination pad.
1556  *
1557  * Connects the source to the destination element.
1558  * The connection must be from source to destination, the other
1559  * direction will not be tried.
1560  * The functions looks for existing pads and request pads that aren't
1561  * connected yet. If multiple connections are possible, only one is
1562  * established.
1563  *
1564  * Returns: TRUE if the elements could be connected.
1565  */
1566 gboolean
1567 gst_element_connect (GstElement *src, GstElement *dest)
1568 {
1569   return gst_element_connect_filtered (src, dest, NULL);
1570 }
1571
1572 /**
1573  * gst_element_connect_pads_filtered:
1574  * @src: a #GstElement containing the source pad.
1575  * @srcpadname: the name of the #GstPad in source element.
1576  * @dest: the #GstElement containing the destination pad.
1577  * @destpadname: the name of the #GstPad in destination element.
1578  * @filtercaps: the #GstCaps to use as a filter.
1579  *
1580  * Connects the two named pads of the source and destination elements.
1581  * Side effect is that if one of the pads has no parent, it becomes a
1582  * child of the parent of the other element.  If they have different
1583  * parents, the connection fails.
1584  *
1585  * Returns: TRUE if the pads could be connected.
1586  */
1587 gboolean
1588 gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
1589                                    GstElement *dest, const gchar *destpadname, 
1590                                    GstCaps *filtercaps)
1591 {
1592   GstPad *srcpad,*destpad;
1593
1594   g_return_val_if_fail (src != NULL, FALSE);
1595   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1596   g_return_val_if_fail (srcpadname != NULL, FALSE);
1597   g_return_val_if_fail (dest != NULL, FALSE);
1598   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1599   g_return_val_if_fail (destpadname != NULL, FALSE);
1600
1601   /* obtain the pads requested */
1602   srcpad = gst_element_get_pad (src, srcpadname);
1603   if (srcpad == NULL) {
1604     GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
1605     return FALSE;
1606   }
1607   destpad = gst_element_get_pad (dest, destpadname);
1608   if (srcpad == NULL) {
1609     GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
1610     return FALSE;
1611   }
1612
1613   /* we're satisified they can be connected, let's do it */
1614   return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
1615 }
1616
1617 /**
1618  * gst_element_connect_pads:
1619  * @src: a #GstElement containing the source pad.
1620  * @srcpadname: the name of the #GstPad in the source element.
1621  * @dest: the #GstElement containing the destination pad.
1622  * @destpadname: the name of the #GstPad in destination element.
1623  *
1624  * Connects the two named pads of the source and destination elements.
1625  * Side effect is that if one of the pads has no parent, it becomes a
1626  * child of the parent of the other element.  If they have different
1627  * parents, the connection fails.
1628  *
1629  * Returns: TRUE if the pads could be connected.
1630  */
1631 gboolean
1632 gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
1633                           GstElement *dest, const gchar *destpadname)
1634 {
1635   return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1636 }
1637
1638 /**
1639  * gst_element_disconnect_pads:
1640  * @src: a #GstElement containing the source pad.
1641  * @srcpadname: the name of the #GstPad in source element.
1642  * @dest: a #GstElement containing the destination pad.
1643  * @destpadname: the name of the #GstPad in destination element.
1644  *
1645  * Disconnects the two named pads of the source and destination elements.
1646  */
1647 void
1648 gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
1649                              GstElement *dest, const gchar *destpadname)
1650 {
1651   GstPad *srcpad,*destpad;
1652
1653   g_return_if_fail (src != NULL);
1654   g_return_if_fail (GST_IS_ELEMENT(src));
1655   g_return_if_fail (srcpadname != NULL);
1656   g_return_if_fail (dest != NULL);
1657   g_return_if_fail (GST_IS_ELEMENT(dest));
1658   g_return_if_fail (destpadname != NULL);
1659
1660   /* obtain the pads requested */
1661   srcpad = gst_element_get_pad (src, srcpadname);
1662   if (srcpad == NULL) {
1663     GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
1664     return;
1665   }
1666   destpad = gst_element_get_pad (dest, destpadname);
1667   if (srcpad == NULL) {
1668     GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
1669     return;
1670   }
1671
1672   /* we're satisified they can be disconnected, let's do it */
1673   gst_pad_disconnect(srcpad,destpad);
1674 }
1675
1676 /**
1677  * gst_element_disconnect_many:
1678  * @element_1: the first #GstElement in the connection chain.
1679  * @element_2: the second #GstElement in the connection chain.
1680  * @...: the NULL-terminated list of elements to disconnect in order.
1681  * 
1682  * Disconnects a series of elements. Uses #gst_element_disconnect.
1683  */
1684 void
1685 gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
1686 {
1687   va_list args;
1688
1689   g_return_if_fail (element_1 != NULL && element_2 != NULL);
1690   g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1691
1692   va_start (args, element_2);
1693
1694   while (element_2) {
1695     gst_element_disconnect (element_1, element_2);
1696     
1697     element_1 = element_2;
1698     element_2 = va_arg (args, GstElement*);
1699   }
1700
1701   va_end (args);
1702 }
1703
1704 /**
1705  * gst_element_disconnect:
1706  * @src: the source #GstElement to disconnect.
1707  * @dest: the sink #GstElement to disconnect.
1708  *
1709  * Disconnects all source pads of the source element with all sink pads
1710  * of the sink element to which they are connected.
1711  */
1712 void
1713 gst_element_disconnect (GstElement *src, GstElement *dest)
1714 {
1715   const GList *srcpads;
1716   GstPad *pad;
1717
1718   g_return_if_fail (GST_IS_ELEMENT (src));
1719   g_return_if_fail (GST_IS_ELEMENT (dest));
1720
1721   GST_DEBUG (GST_CAT_ELEMENT_PADS, "disconnecting \"%s\" and \"%s\"", 
1722              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1723
1724   srcpads = gst_element_get_pad_list (src);
1725
1726   while (srcpads) {
1727     pad = GST_PAD_CAST (srcpads->data);
1728     
1729     if (GST_IS_REAL_PAD (pad) && GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1730       GstPad *peerpad = GST_PAD_PEER (pad);
1731
1732       if (peerpad && 
1733           (GST_OBJECT_PARENT (GST_PAD_PEER (peerpad)) == (GstObject*) src)) {
1734         gst_pad_disconnect (pad, peerpad);
1735       }
1736     }
1737
1738     srcpads = g_list_next (srcpads);
1739   }
1740 }
1741
1742 static void
1743 gst_element_error_func (GstElement* element, GstElement *source, 
1744                         gchar *errormsg)
1745 {
1746   /* tell the parent */
1747   if (GST_OBJECT_PARENT (element)) {
1748     GST_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s", 
1749                errormsg, GST_ELEMENT_NAME (element), 
1750                GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
1751
1752     gst_object_ref (GST_OBJECT (element));
1753     g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)), 
1754                    gst_element_signals[ERROR], 0, source, errormsg);
1755     gst_object_unref (GST_OBJECT (element));
1756   }
1757 }
1758
1759 static GstPad*
1760 gst_element_get_random_pad (GstElement *element, GstPadDirection dir)
1761 {
1762   GList *pads = element->pads;
1763   GST_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
1764   while (pads) {
1765     GstPad *pad = GST_PAD_CAST (pads->data);
1766
1767     GST_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
1768                GST_DEBUG_PAD_NAME (pad));
1769
1770     if (GST_PAD_DIRECTION (pad) == dir) {
1771       if (GST_PAD_IS_CONNECTED (pad)) {
1772         return pad;
1773       }
1774       else {
1775         GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not connected",
1776                    GST_DEBUG_PAD_NAME (pad));
1777       }
1778     }
1779     else {
1780       GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
1781                  GST_DEBUG_PAD_NAME (pad));
1782     }
1783
1784     pads = g_list_next (pads);
1785   }
1786   return NULL;
1787 }
1788
1789 /**
1790  * gst_element_get_event_masks:
1791  * @element: a #GstElement to query
1792  *
1793  * Get an array of event masks from the element.
1794  * If the element doesn't 
1795  * implement an event masks function, the query will be forwarded
1796  * to a random connected sink pad.
1797  * 
1798  * Returns: An array of #GstEventMask elements.
1799  */
1800 const GstEventMask*
1801 gst_element_get_event_masks (GstElement *element)
1802 {
1803   GstElementClass *oclass;
1804
1805   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1806   
1807   oclass = GST_ELEMENT_GET_CLASS (element);
1808
1809   if (oclass->get_event_masks)
1810     return oclass->get_event_masks (element);
1811   else {
1812     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1813     if (pad)
1814       return gst_pad_get_event_masks (GST_PAD_PEER (pad));
1815   }
1816
1817   return FALSE;
1818 }
1819
1820 /**
1821  * gst_element_send_event:
1822  * @element: a #GstElement to send the event to.
1823  * @event: the #GstEvent to send to the element.
1824  *
1825  * Sends an event to an element. If the element doesn't
1826  * implement an event handler, the event will be forwarded
1827  * to a random sink pad.
1828  *
1829  * Returns: TRUE if the event was handled.
1830  */
1831 gboolean
1832 gst_element_send_event (GstElement *element, GstEvent *event)
1833 {
1834   GstElementClass *oclass;
1835
1836   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1837   g_return_val_if_fail (event != NULL, FALSE);
1838   
1839   oclass = GST_ELEMENT_GET_CLASS (element);
1840
1841   if (oclass->send_event)
1842     return oclass->send_event (element, event);
1843   else {
1844     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1845     if (pad) {
1846       GST_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
1847                  GST_DEBUG_PAD_NAME (pad));
1848       return gst_pad_send_event (GST_PAD_PEER (pad), event);
1849     }
1850   }
1851   GST_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
1852              GST_ELEMENT_NAME (element));
1853   return FALSE;
1854 }
1855
1856 /**
1857  * gst_element_get_query_types:
1858  * @element: a #GstElement to query
1859  *
1860  * Get an array of query types from the element.
1861  * If the element doesn't 
1862  * implement a query types function, the query will be forwarded
1863  * to a random sink pad.
1864  * 
1865  * Returns: An array of #GstQueryType elements.
1866  */
1867 const GstQueryType*
1868 gst_element_get_query_types (GstElement *element)
1869 {
1870   GstElementClass *oclass;
1871
1872   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1873   
1874   oclass = GST_ELEMENT_GET_CLASS (element);
1875
1876   if (oclass->get_query_types)
1877     return oclass->get_query_types (element);
1878   else {
1879     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1880     if (pad)
1881       return gst_pad_get_query_types (GST_PAD_PEER (pad));
1882   }
1883
1884   return FALSE;
1885 }
1886
1887 /**
1888  * gst_element_query:
1889  * @element: a #GstElement to perform the query on.
1890  * @type: the #GstQueryType.
1891  * @format: the #GstFormat pointer to hold the format of the result.
1892  * @value: the pointer to the value of the result.
1893  *
1894  * Performs a query on the given element. If the format is set
1895  * to GST_FORMAT_DEFAULT and this function returns TRUE, the 
1896  * format pointer will hold the default format.
1897  * For element that don't implement a query handler, this function
1898  * forwards the query to a random usable sinkpad of this element.
1899  * 
1900  * Returns: TRUE if the query could be performed.
1901  */
1902 gboolean
1903 gst_element_query (GstElement *element, GstQueryType type,
1904                    GstFormat *format, gint64 *value)
1905 {
1906   GstElementClass *oclass;
1907
1908   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1909   g_return_val_if_fail (format != NULL, FALSE);
1910   g_return_val_if_fail (value != NULL, FALSE);
1911
1912   oclass = GST_ELEMENT_GET_CLASS (element);
1913   
1914   if (oclass->query)
1915     return oclass->query (element, type, format, value);
1916   else {
1917     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1918     if (pad)
1919       return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
1920   }
1921
1922   return FALSE;
1923 }
1924
1925 /**
1926  * gst_element_get_formats:
1927  * @element: a #GstElement to query
1928  *
1929  * Get an array of formst from the element.
1930  * If the element doesn't 
1931  * implement a formats function, the query will be forwarded
1932  * to a random sink pad.
1933  * 
1934  * Returns: An array of #GstFormat elements.
1935  */
1936 const GstFormat*
1937 gst_element_get_formats (GstElement *element)
1938 {
1939   GstElementClass *oclass;
1940
1941   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1942   
1943   oclass = GST_ELEMENT_GET_CLASS (element);
1944
1945   if (oclass->get_formats)
1946     return oclass->get_formats (element);
1947   else {
1948     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1949     if (pad)
1950       return gst_pad_get_formats (GST_PAD_PEER (pad));
1951   }
1952
1953   return FALSE;
1954 }
1955
1956 /**
1957  * gst_element_convert:
1958  * @element: a #GstElement to invoke the converter on.
1959  * @src_format: the source #GstFormat.
1960  * @src_value: the source value.
1961  * @dest_format: a pointer to the destination #GstFormat.
1962  * @dest_value: a pointer to the destination value.
1963  *
1964  * Invokes a conversion on the element.
1965  * If the element doesn't 
1966  * implement a convert function, the query will be forwarded
1967  * to a random sink pad.
1968  *
1969  * Returns: TRUE if the conversion could be performed.
1970  */
1971 gboolean
1972 gst_element_convert (GstElement *element,
1973                      GstFormat  src_format,  gint64  src_value,
1974                      GstFormat *dest_format, gint64 *dest_value)
1975 {
1976   GstElementClass *oclass;
1977
1978   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1979   g_return_val_if_fail (dest_format != NULL, FALSE);
1980   g_return_val_if_fail (dest_value != NULL, FALSE);
1981
1982   if (src_format == *dest_format) {
1983     *dest_value = src_value;
1984     return TRUE;
1985   }
1986
1987   oclass = GST_ELEMENT_GET_CLASS (element);
1988
1989   if (oclass->convert)
1990     return oclass->convert (element,
1991                             src_format, src_value, 
1992                             dest_format, dest_value);
1993   else {
1994     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1995     if (pad)
1996       return gst_pad_convert (GST_PAD_PEER (pad), 
1997                               src_format, src_value, 
1998                               dest_format, dest_value);
1999   }
2000
2001   return FALSE;
2002 }
2003
2004 /**
2005  * gst_element_error:
2006  * @element: a #GstElement with the error.
2007  * @error: the printf-style string describing the error.
2008  * @...: the optional arguments for the string.
2009  *
2010  * signals an error condition on an element.
2011  * This function is used internally by elements.
2012  * It results in the "error" signal.
2013  */
2014 void
2015 gst_element_error (GstElement *element, const gchar *error, ...)
2016 {
2017   va_list var_args;
2018   gchar *string;
2019   
2020   /* checks */
2021   g_return_if_fail (GST_IS_ELEMENT (element));
2022   g_return_if_fail (error != NULL);
2023
2024   /* create error message */
2025   va_start (var_args, error);
2026   string = g_strdup_vprintf (error, var_args);
2027   va_end (var_args);
2028   GST_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
2029
2030   /* emit the signal, make sure the element stays available */
2031   gst_object_ref (GST_OBJECT (element));
2032   g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, string);
2033   
2034  /* tell the scheduler */
2035   if (element->sched) {
2036     gst_scheduler_error (element->sched, element); 
2037   } 
2038
2039   gst_element_set_state (element, GST_STATE_PAUSED);
2040
2041   /* cleanup */
2042   gst_object_unref (GST_OBJECT (element));
2043   g_free (string);
2044 }
2045
2046 /**
2047  * gst_element_get_state:
2048  * @element: a #GstElement to get the state of.
2049  *
2050  * Gets the state of the element. 
2051  *
2052  * Returns: the #GstElementState of the element.
2053  */
2054 GstElementState
2055 gst_element_get_state (GstElement *element)
2056 {
2057   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2058
2059   return GST_STATE (element);
2060 }
2061
2062 /**
2063  * gst_element_wait_state_change:
2064  * @element: a #GstElement to wait for a state change on.
2065  *
2066  * Waits and blocks until the element changed its state.
2067  */
2068 void
2069 gst_element_wait_state_change (GstElement *element)
2070 {
2071   g_mutex_lock (element->state_mutex);
2072   g_cond_wait (element->state_cond, element->state_mutex);
2073   g_mutex_unlock (element->state_mutex);
2074 }
2075
2076 /**
2077  * gst_element_set_state:
2078  * @element: a #GstElement to change state of.
2079  * @state: the element's new #GstElementState.
2080  *
2081  * Sets the state of the element. This function will try to set the
2082  * requested state by going through all the intermediary states and calling
2083  * the class's state change function for each.
2084  *
2085  * Returns: TRUE if the state was successfully set.
2086  * (using #GstElementStateReturn).
2087  */
2088 GstElementStateReturn
2089 gst_element_set_state (GstElement *element, GstElementState state)
2090 {
2091   GstElementClass *oclass;
2092   GstElementState curpending;
2093   GstElementStateReturn return_val = GST_STATE_SUCCESS;
2094
2095   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2096
2097   /* start with the current state */
2098   curpending = GST_STATE(element);
2099
2100   GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s",
2101                      gst_element_state_get_name (curpending),
2102                      gst_element_state_get_name (state));
2103
2104   /* loop until the final requested state is set */
2105   while (GST_STATE (element) != state 
2106       && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2107     /* move the curpending state in the correct direction */
2108     if (curpending < state) 
2109       curpending <<= 1;
2110     else 
2111       curpending >>= 1;
2112
2113     /* set the pending state variable */
2114     /* FIXME: should probably check to see that we don't already have one */
2115     GST_STATE_PENDING (element) = curpending;
2116
2117     if (curpending != state) {
2118       GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2119                          "intermediate: setting state from %s to %s",
2120                          gst_element_state_get_name (GST_STATE (element)),
2121                          gst_element_state_get_name (curpending));
2122     }
2123
2124     /* call the state change function so it can set the state */
2125     oclass = GST_ELEMENT_GET_CLASS (element);
2126     if (oclass->change_state)
2127       return_val = (oclass->change_state) (element);
2128
2129     switch (return_val) {
2130       case GST_STATE_FAILURE:
2131         GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2132                            "have failed change_state return");
2133         goto exit;
2134       case GST_STATE_ASYNC:
2135         GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2136                            "element will change state async");
2137         goto exit;
2138       case GST_STATE_SUCCESS:
2139         /* Last thing we do is verify that a successful state change really
2140          * did change the state... */
2141         if (GST_STATE (element) != curpending) {
2142           GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2143                              "element claimed state-change success,"
2144                              "but state didn't change %s, %s <-> %s",
2145                              gst_element_state_get_name (GST_STATE (element)),
2146                              gst_element_state_get_name (GST_STATE_PENDING (element)),
2147                              gst_element_state_get_name (curpending));
2148           return GST_STATE_FAILURE;
2149         }
2150         break;
2151       default:
2152         /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2153         g_assert_not_reached ();
2154     }
2155   }
2156 exit:
2157
2158   return return_val;
2159 }
2160
2161 static gboolean
2162 gst_element_negotiate_pads (GstElement *element)
2163 {
2164   GList *pads = GST_ELEMENT_PADS (element);
2165
2166   GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads");
2167
2168   while (pads) {
2169     GstPad *pad = GST_PAD (pads->data);
2170     GstRealPad *srcpad;
2171
2172     pads = g_list_next (pads);
2173     
2174     if (!GST_IS_REAL_PAD (pad))
2175       continue;
2176
2177     srcpad = GST_PAD_REALIZE (pad);
2178
2179     /* if we have a connection on this pad and it doesn't have caps
2180      * allready, try to negotiate */
2181     if (GST_PAD_IS_CONNECTED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2182       GstRealPad *sinkpad;
2183       GstElementState otherstate;
2184       GstElement *parent;
2185       
2186       sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2187
2188       /* check the parent of the peer pad, if there is no parent do nothing */
2189       parent = GST_PAD_PARENT (sinkpad);
2190       if (!parent) 
2191         continue;
2192
2193       otherstate = GST_STATE (parent);
2194
2195       /* swap pads if needed */
2196       if (!GST_PAD_IS_SRC (srcpad)) {
2197         GstRealPad *temp;
2198
2199         temp = srcpad;
2200         srcpad = sinkpad;
2201         sinkpad = temp;
2202       }
2203
2204       /* only try to negotiate if the peer element is in PAUSED or higher too */
2205       if (otherstate >= GST_STATE_READY) {
2206         GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
2207                            "perform negotiate for %s:%s and %s:%s",
2208                            GST_DEBUG_PAD_NAME (srcpad), 
2209                            GST_DEBUG_PAD_NAME (sinkpad));
2210         if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
2211           return FALSE;
2212       }
2213       else {
2214         GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
2215                            "not negotiating %s:%s and %s:%s, not in READY yet",
2216                            GST_DEBUG_PAD_NAME (srcpad), 
2217                            GST_DEBUG_PAD_NAME (sinkpad));
2218       }
2219     }
2220   }
2221
2222   return TRUE;
2223 }
2224
2225 static void
2226 gst_element_clear_pad_caps (GstElement *element)
2227 {
2228   GList *pads = GST_ELEMENT_PADS (element);
2229
2230   GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps");
2231
2232   while (pads) {
2233     GstRealPad *pad = GST_PAD_REALIZE (pads->data);
2234
2235     if (GST_PAD_CAPS (pad)) {
2236       GST_PAD_CAPS (pad) = NULL;
2237     }
2238     pads = g_list_next (pads);
2239   }
2240 }
2241
2242 static void
2243 gst_element_pads_activate (GstElement *element, gboolean active)
2244 {
2245   GList *pads = element->pads;
2246
2247   while (pads) {
2248     GstPad *pad = GST_PAD_CAST (pads->data);
2249     pads = g_list_next (pads);
2250
2251     if (!GST_IS_REAL_PAD (pad))
2252       continue;
2253
2254     gst_pad_set_active (pad, active);
2255   }
2256 }
2257
2258 static GstElementStateReturn
2259 gst_element_change_state (GstElement *element)
2260 {
2261   GstElementState old_state;
2262   GstObject *parent;
2263   gint old_pending, old_transition;
2264
2265   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2266
2267   old_state = GST_STATE (element);
2268   old_pending = GST_STATE_PENDING (element);
2269   old_transition = GST_STATE_TRANSITION (element);
2270
2271   if (old_pending == GST_STATE_VOID_PENDING || 
2272       old_state == GST_STATE_PENDING (element)) {
2273     GST_INFO (GST_CAT_STATES, 
2274               "no state change needed for element %s (VOID_PENDING)", 
2275               GST_ELEMENT_NAME (element));
2276     return GST_STATE_SUCCESS;
2277   }
2278   
2279   GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x", 
2280             GST_ELEMENT_NAME (element),
2281             gst_element_state_get_name (old_state),
2282             gst_element_state_get_name (old_pending),
2283             old_transition);
2284
2285   /* we set the state change early for the negotiation functions */
2286   GST_STATE (element) = old_pending;
2287   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2288
2289   switch (old_transition) {
2290     case GST_STATE_PLAYING_TO_PAUSED:
2291       gst_element_pads_activate (element, FALSE);
2292       break;
2293     case GST_STATE_PAUSED_TO_PLAYING:
2294       gst_element_pads_activate (element, TRUE);
2295       break;
2296     /* if we are going to paused, we try to negotiate the pads */
2297     case GST_STATE_READY_TO_PAUSED:
2298       if (!gst_element_negotiate_pads (element)) 
2299         goto failure;
2300       break;
2301     /* going to the READY state clears all pad caps */
2302     case GST_STATE_PAUSED_TO_READY:
2303       gst_element_clear_pad_caps (element);
2304       break;
2305     default:
2306       break;
2307   }
2308
2309   parent = GST_ELEMENT_PARENT (element);
2310
2311   GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2312                      "signaling state change from %s to %s",
2313                      gst_element_state_get_name (old_state),
2314                      gst_element_state_get_name (GST_STATE (element)));
2315
2316   /* tell the scheduler if we have one */
2317   if (element->sched) {
2318     if (gst_scheduler_state_transition (element->sched, element, 
2319                                         old_transition) != GST_STATE_SUCCESS) {
2320       goto failure;
2321     }
2322   }
2323
2324   g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2325                  0, old_state, GST_STATE (element));
2326
2327   /* tell our parent about the state change */
2328   if (parent && GST_IS_BIN (parent)) {
2329     gst_bin_child_state_change (GST_BIN (parent), old_state, 
2330                                 GST_STATE (element), element);
2331   }
2332
2333   /* signal the state change in case somebody is waiting for us */
2334   g_mutex_lock (element->state_mutex);
2335   g_cond_signal (element->state_cond);
2336   g_mutex_unlock (element->state_mutex);
2337
2338   return GST_STATE_SUCCESS;
2339
2340 failure:
2341   /* undo the state change */
2342   GST_STATE (element) = old_state;
2343   GST_STATE_PENDING (element) = old_pending;
2344
2345   return GST_STATE_FAILURE;
2346 }
2347
2348 /**
2349  * gst_element_get_factory:
2350  * @element: a #GstElement to request the element factory of.
2351  *
2352  * Retrieves the factory that was used to create this element.
2353  *
2354  * Returns: the #GstElementFactory used for creating this element.
2355  */
2356 GstElementFactory*
2357 gst_element_get_factory (GstElement *element)
2358 {
2359   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2360
2361   return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2362 }
2363
2364 static void
2365 gst_element_dispose (GObject *object)
2366 {
2367   GstElement *element = GST_ELEMENT (object);
2368   GList *pads;
2369   GstPad *pad;
2370   
2371   GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose");
2372
2373   gst_element_set_state (element, GST_STATE_NULL);
2374
2375   /* first we break all our connections with the ouside */
2376   if (element->pads) {
2377     GList *orig;
2378     orig = pads = g_list_copy (element->pads);
2379     while (pads) {
2380       pad = GST_PAD (pads->data);
2381
2382       if (GST_PAD_PEER (pad)) {
2383         GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'",
2384                    GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2385         gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
2386       }
2387       gst_element_remove_pad (element, pad);
2388
2389       pads = g_list_next (pads);
2390     }
2391     g_list_free (orig);
2392     g_list_free (element->pads);
2393     element->pads = NULL;
2394   }
2395
2396   element->numsrcpads = 0;
2397   element->numsinkpads = 0;
2398   element->numpads = 0;
2399   g_mutex_free (element->state_mutex);
2400   g_cond_free (element->state_cond);
2401
2402   if (element->prop_value_queue)
2403     g_async_queue_unref (element->prop_value_queue);
2404   element->prop_value_queue = NULL;
2405   if (element->property_mutex)
2406     g_mutex_free (element->property_mutex);
2407   
2408   G_OBJECT_CLASS (parent_class)->dispose (object);
2409 }
2410
2411 #ifndef GST_DISABLE_LOADSAVE
2412 /**
2413  * gst_element_save_thyself:
2414  * @element: a #GstElement to save.
2415  * @parent: the xml parent node.
2416  *
2417  * Saves the element as part of the given XML structure.
2418  *
2419  * Returns: the new #xmlNodePtr.
2420  */
2421 static xmlNodePtr
2422 gst_element_save_thyself (GstObject *object,
2423                           xmlNodePtr parent)
2424 {
2425   GList *pads;
2426   GstElementClass *oclass;
2427   GParamSpec **specs, *spec;
2428   gint nspecs, i;
2429   GValue value = { 0, };
2430   GstElement *element;
2431
2432   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2433
2434   element = GST_ELEMENT (object);
2435
2436   oclass = GST_ELEMENT_GET_CLASS (element);
2437
2438   xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2439
2440   if (oclass->elementfactory != NULL) {
2441     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2442
2443     xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
2444     xmlNewChild (parent, NULL, "version", factory->details->version);
2445   }
2446
2447 /* FIXME: what is this? */  
2448 /*  if (element->manager) */
2449 /*    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2450
2451   /* params */
2452   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2453   
2454   for (i=0; i<nspecs; i++) {
2455     spec = specs[i];
2456     if (spec->flags & G_PARAM_READABLE) {
2457       xmlNodePtr param;
2458       char *contents;
2459       
2460       g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
2461       
2462       g_object_get_property (G_OBJECT (element), spec->name, &value);
2463       param = xmlNewChild (parent, NULL, "param", NULL);
2464       xmlNewChild (param, NULL, "name", spec->name);
2465       
2466       if (G_IS_PARAM_SPEC_STRING (spec))
2467         contents = g_value_dup_string (&value);
2468       else if (G_IS_PARAM_SPEC_ENUM (spec))
2469         contents = g_strdup_printf ("%d", g_value_get_enum (&value));
2470       else if (G_IS_PARAM_SPEC_INT64 (spec))
2471         contents = g_strdup_printf ("%" G_GINT64_FORMAT,
2472                                     g_value_get_int64 (&value));
2473       else
2474         contents = g_strdup_value_contents (&value);
2475       
2476       xmlNewChild (param, NULL, "value", contents);
2477       g_free (contents);
2478       
2479       g_value_unset(&value);
2480     }
2481   }
2482
2483   pads = GST_ELEMENT_PADS (element);
2484
2485   while (pads) {
2486     GstPad *pad = GST_PAD (pads->data);
2487     /* figure out if it's a direct pad or a ghostpad */
2488     if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
2489       xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
2490       gst_object_save_thyself (GST_OBJECT (pad), padtag);
2491     }
2492     pads = g_list_next (pads);
2493   }
2494
2495   return parent;
2496 }
2497
2498 static void
2499 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
2500 {
2501   xmlNodePtr children;
2502   GstElement *element;
2503   gchar *name = NULL;
2504   gchar *value = NULL;
2505
2506   element = GST_ELEMENT (object);
2507   g_return_if_fail (element != NULL);
2508
2509   /* parameters */
2510   children = self->xmlChildrenNode;
2511   while (children) {
2512     if (!strcmp (children->name, "param")) {
2513       xmlNodePtr child = children->xmlChildrenNode;
2514
2515       while (child) {
2516         if (!strcmp (child->name, "name")) {
2517           name = xmlNodeGetContent (child);
2518         }
2519         else if (!strcmp (child->name, "value")) {
2520           value = xmlNodeGetContent (child);
2521         }
2522         child = child->next;
2523       }
2524       /* FIXME: can this just be g_object_set ? */
2525       gst_util_set_object_arg (G_OBJECT (element), name, value);
2526     }
2527     children = children->next;
2528   }
2529   
2530   /* pads */
2531   children = self->xmlChildrenNode;
2532   while (children) {
2533     if (!strcmp (children->name, "pad")) {
2534       gst_pad_load_and_connect (children, GST_OBJECT (element));
2535     }
2536     children = children->next;
2537   }
2538
2539   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
2540     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
2541 }
2542 #endif /* GST_DISABLE_LOADSAVE */
2543
2544 /**
2545  * gst_element_yield:
2546  * @element: a #GstElement to yield.
2547  *
2548  * Requests a yield operation for the element. The scheduler will typically
2549  * give control to another element.
2550  */
2551 void
2552 gst_element_yield (GstElement *element)
2553 {
2554   if (GST_ELEMENT_SCHED (element)) {
2555     gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
2556   }
2557 }
2558
2559 /**
2560  * gst_element_interrupt:
2561  * @element: a #GstElement to interrupt.
2562  *
2563  * Requests the scheduler of this element to interrupt the execution of
2564  * this element and scheduler another one.
2565  *
2566  * Returns: TRUE if the element should exit its chain/loop/get
2567  * function ASAP, depending on the scheduler implementation.
2568  */
2569 gboolean
2570 gst_element_interrupt (GstElement *element)
2571 {
2572   if (GST_ELEMENT_SCHED (element)) {
2573     return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
2574   }
2575   else 
2576     return FALSE;
2577 }
2578
2579 /**
2580  * gst_element_set_scheduler:
2581  * @element: a #GstElement to set the scheduler of.
2582  * @sched: the #GstScheduler to set.
2583  *
2584  * Sets the scheduler of the element.  For internal use only, unless you're
2585  * writing a new bin subclass.
2586  */
2587 void
2588 gst_element_set_scheduler (GstElement *element,
2589                        GstScheduler *sched)
2590 {
2591   g_return_if_fail (GST_IS_ELEMENT (element));
2592   
2593   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
2594
2595   GST_ELEMENT_SCHED (element) = sched;
2596 }
2597
2598 /**
2599  * gst_element_get_scheduler:
2600  * @element: a #GstElement to get the scheduler of.
2601  *
2602  * Returns the scheduler of the element.
2603  *
2604  * Returns: the element's #GstScheduler.
2605  */
2606 GstScheduler*
2607 gst_element_get_scheduler (GstElement *element)
2608 {
2609   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2610
2611   return GST_ELEMENT_SCHED (element);
2612 }
2613
2614 /**
2615  * gst_element_set_loop_function:
2616  * @element: a #GstElement to set the loop function of.
2617  * @loop: Pointer to #GstElementLoopFunction.
2618  *
2619  * This sets the loop function for the element.  The function pointed to
2620  * can deviate from the GstElementLoopFunction definition in type of
2621  * pointer only.
2622  *
2623  * NOTE: in order for this to take effect, the current loop function *must*
2624  * exit.  Assuming the loop function itself is the only one who will cause
2625  * a new loopfunc to be assigned, this should be no problem.
2626  */
2627 void
2628 gst_element_set_loop_function (GstElement *element,
2629                                GstElementLoopFunction loop)
2630 {
2631   g_return_if_fail (GST_IS_ELEMENT (element));
2632
2633   /* set the loop function */
2634   element->loopfunc = loop;
2635
2636   /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
2637   GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
2638
2639   if (GST_ELEMENT_SCHED (element)) {
2640     gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
2641   }
2642 }
2643
2644 /**
2645  * gst_element_set_eos:
2646  * @element: a #GstElement to set to the EOS state.
2647  *
2648  * Perform the actions needed to bring the element in the EOS state.
2649  */
2650 void
2651 gst_element_set_eos (GstElement *element)
2652 {
2653   g_return_if_fail (GST_IS_ELEMENT (element));
2654
2655   GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", 
2656              GST_OBJECT_NAME (element));
2657
2658   gst_element_set_state (element, GST_STATE_PAUSED);
2659
2660   g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2661 }
2662
2663
2664 /**
2665  * gst_element_state_get_name:
2666  * @state: a #GstElementState to get the name of.
2667  *
2668  * Gets a string representing the given state.
2669  *
2670  * Returns: a string with the name of the state.
2671  */
2672 const gchar*
2673 gst_element_state_get_name (GstElementState state) 
2674 {
2675   switch (state) {
2676 #ifdef GST_DEBUG_COLOR
2677     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2678     case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
2679     case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
2680     case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
2681     case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
2682     default:
2683       /* This is a memory leak */
2684       return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
2685 #else
2686     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2687     case GST_STATE_NULL: return "NULL";break;
2688     case GST_STATE_READY: return "READY";break;
2689     case GST_STATE_PLAYING: return "PLAYING";break;
2690     case GST_STATE_PAUSED: return "PAUSED";break;
2691     default: return "UNKNOWN!";
2692 #endif
2693   }
2694   return "";
2695 }
2696
2697 static void
2698 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name, 
2699                                 guint arg_id, GParamFlags flags)
2700 {
2701   GQuark prop_id = g_quark_from_string (prop_name);
2702   GParamSpec *pspec;
2703
2704   static GQuark fd_id = 0;
2705   static GQuark blocksize_id;
2706   static GQuark bytesperread_id;
2707   static GQuark dump_id;
2708   static GQuark filesize_id;
2709   static GQuark mmapsize_id;
2710   static GQuark location_id;
2711   static GQuark offset_id;
2712   static GQuark silent_id;
2713   static GQuark touch_id;
2714
2715   if (!fd_id) {
2716     fd_id = g_quark_from_static_string ("fd");
2717     blocksize_id = g_quark_from_static_string ("blocksize");
2718     bytesperread_id = g_quark_from_static_string ("bytesperread");
2719     dump_id = g_quark_from_static_string ("dump");
2720     filesize_id = g_quark_from_static_string ("filesize");
2721     mmapsize_id = g_quark_from_static_string ("mmapsize");
2722     location_id = g_quark_from_static_string ("location");
2723     offset_id = g_quark_from_static_string ("offset");
2724     silent_id = g_quark_from_static_string ("silent");
2725     touch_id = g_quark_from_static_string ("touch");
2726   }
2727
2728   if (prop_id == fd_id) {
2729     pspec = g_param_spec_int ("fd", "File-descriptor",
2730                               "File-descriptor for the file being read",
2731                               0, G_MAXINT, 0, flags);
2732   }
2733   else if (prop_id == blocksize_id) {
2734     pspec = g_param_spec_ulong ("blocksize", "Block Size",
2735                                 "Block size to read per buffer",
2736                                 0, G_MAXULONG, 4096, flags);
2737
2738   }
2739   else if (prop_id == bytesperread_id) {
2740     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
2741                               "Number of bytes to read per buffer",
2742                               G_MININT, G_MAXINT, 0, flags);
2743
2744   }
2745   else if (prop_id == dump_id) {
2746     pspec = g_param_spec_boolean ("dump", "Dump", 
2747                                   "Dump bytes to stdout", 
2748                                   FALSE, flags);
2749
2750   }
2751   else if (prop_id == filesize_id) {
2752     pspec = g_param_spec_int64 ("filesize", "File Size",
2753                                 "Size of the file being read",
2754                                 0, G_MAXINT64, 0, flags);
2755
2756   }
2757   else if (prop_id == mmapsize_id) {
2758     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
2759                                 "Size in bytes of mmap()d regions",
2760                                 0, G_MAXULONG, 4 * 1048576, flags);
2761
2762   }
2763   else if (prop_id == location_id) {
2764     pspec = g_param_spec_string ("location", "File Location",
2765                                  "Location of the file to read",
2766                                  NULL, flags);
2767
2768   }
2769   else if (prop_id == offset_id) {
2770     pspec = g_param_spec_int64 ("offset", "File Offset",
2771                                 "Byte offset of current read pointer",
2772                                 0, G_MAXINT64, 0, flags);
2773
2774   }
2775   else if (prop_id == silent_id) {
2776     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
2777                                   FALSE, flags);
2778
2779   }
2780   else if (prop_id == touch_id) {
2781     pspec = g_param_spec_boolean ("touch", "Touch read data",
2782                                   "Touch data to force disk read before "
2783                                   "push ()", TRUE, flags);
2784   }
2785   else {
2786     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
2787                prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
2788     pspec = NULL;
2789   }
2790
2791   if (pspec) {
2792     g_object_class_install_property (klass, arg_id, pspec);
2793   }
2794 }
2795
2796 /**
2797  * gst_element_class_install_std_props:
2798  * @klass: the #GstElementClass to add the properties to.
2799  * @first_name: the name of the first property.
2800  * in a NULL terminated
2801  * @...: the id and flags of the first property, followed by
2802  * further 'name', 'id', 'flags' triplets and terminated by NULL.
2803  * 
2804  * Adds a list of standardized properties with types to the @klass.
2805  * the id is for the property switch in your get_prop method, and
2806  * the flags determine readability / writeability.
2807  **/
2808 void
2809 gst_element_class_install_std_props (GstElementClass * klass, 
2810                                      const gchar *first_name, ...)
2811 {
2812   const char *name;
2813
2814   va_list args;
2815
2816   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
2817
2818   va_start (args, first_name);
2819
2820   name = first_name;
2821
2822   while (name) {
2823     int arg_id = va_arg (args, int);
2824     int flags = va_arg (args, int);
2825
2826     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
2827
2828     name = va_arg (args, char *);
2829   }
2830
2831   va_end (args);
2832 }
2833
2834 /**
2835  * gst_element_get_managing_bin:
2836  * @element: a #GstElement to get the managing bin of.
2837  * 
2838  * Gets the managing bin (a pipeline or a thread, for example) of an element.
2839  *
2840  * Returns: the #GstBin, or NULL on failure.
2841  **/
2842 GstBin*
2843 gst_element_get_managing_bin (GstElement *element)
2844 {
2845   GstBin *bin;
2846
2847   g_return_val_if_fail (element != NULL, NULL);
2848
2849   bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
2850
2851   while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
2852     bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
2853   
2854   return bin;
2855 }