gst_object_swap -> gst_object_replace as it's a better name. Wait for next commit...
[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   gst_object_replace ((GstObject **)&element->clock, (GstObject *)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 (link 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 (link 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 linked */
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 link 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 link.
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 unlinked pad to which the given pad can link to.
1322  * It is not guaranteed that linking the pads will work, though
1323  * it should work in most cases.
1324  *
1325  * Returns: the #GstPad to which a link 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 unlinked 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_link_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_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 link... */
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 unlinked pad to which the given pad can link to.
1391  * It is not guaranteed that linking the pads will work, though
1392  * it should work in most cases.
1393  *
1394  * Returns: the #GstPad to which a link 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_link_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  * Links the source to the destination element using the filtercaps.
1410  * The link must be from source to destination, the other
1411  * direction will not be tried.
1412  * The functions looks for existing pads that aren't linked yet.
1413  * It will use request pads if possible. But both pads will not be requested.
1414  * If multiple links are possible, only one is established.
1415  *
1416  * Returns: TRUE if the elements could be linked.
1417  */
1418 gboolean
1419 gst_element_link_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 link 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_link_filtered (srcpad, destpad, filtercaps)) {
1451           GST_DEBUG (GST_CAT_ELEMENT_PADS, "linked 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_link_filtered (srcpad, destpad, filtercaps)) {
1469           GST_DEBUG (GST_CAT_ELEMENT_PADS, "linked 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_link_filtered (srcpad, destpad, filtercaps)) {
1498                 GST_DEBUG (GST_CAT_ELEMENT_PADS, 
1499                            "linked 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 link possible from %s to %s", 
1514              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1515   return FALSE;  
1516 }
1517
1518 /**
1519  * gst_element_link_many:
1520  * @element_1: the first #GstElement in the link chain.
1521  * @element_2: the second #GstElement in the link chain.
1522  * @...: the NULL-terminated list of elements to link in order.
1523  * 
1524  * Chain together a series of elements. Uses #gst_element_link.
1525  *
1526  * Returns: TRUE on success, FALSE otherwise.
1527  */
1528 gboolean
1529 gst_element_link_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_link (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_link:
1554  * @src: a #GstElement containing the source pad.
1555  * @dest: the #GstElement containing the destination pad.
1556  *
1557  * Links the source to the destination element.
1558  * The link 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  * linked yet. If multiple links are possible, only one is
1562  * established.
1563  *
1564  * Returns: TRUE if the elements could be linked.
1565  */
1566 gboolean
1567 gst_element_link (GstElement *src, GstElement *dest)
1568 {
1569   return gst_element_link_filtered (src, dest, NULL);
1570 }
1571
1572 /**
1573  * gst_element_link_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  * Links 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 link fails.
1584  *
1585  * Returns: TRUE if the pads could be linked.
1586  */
1587 gboolean
1588 gst_element_link_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 linked, let's do it */
1614   return gst_pad_link_filtered (srcpad, destpad, filtercaps);
1615 }
1616
1617 /**
1618  * gst_element_link_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  * Links 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 link fails.
1628  *
1629  * Returns: TRUE if the pads could be linked.
1630  */
1631 gboolean
1632 gst_element_link_pads (GstElement *src, const gchar *srcpadname,
1633                           GstElement *dest, const gchar *destpadname)
1634 {
1635   return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1636 }
1637
1638 /**
1639  * gst_element_unlink_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  * Unlinks the two named pads of the source and destination elements.
1646  */
1647 void
1648 gst_element_unlink_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 unlinked, let's do it */
1673   gst_pad_unlink (srcpad,destpad);
1674 }
1675
1676 /**
1677  * gst_element_unlink_many:
1678  * @element_1: the first #GstElement in the link chain.
1679  * @element_2: the second #GstElement in the link chain.
1680  * @...: the NULL-terminated list of elements to unlink in order.
1681  * 
1682  * Unlinks a series of elements. Uses #gst_element_unlink.
1683  */
1684 void
1685 gst_element_unlink_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_unlink (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_unlink:
1706  * @src: the source #GstElement to unlink.
1707  * @dest: the sink #GstElement to unlink.
1708  *
1709  * Unlinks all source pads of the source element with all sink pads
1710  * of the sink element to which they are linked.
1711  */
1712 void
1713 gst_element_unlink (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, "unlinking \"%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_unlink (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_LINKED (pad)) {
1772         return pad;
1773       }
1774       else {
1775         GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
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 linked 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   if (GST_STATE (element) == GST_STATE_PLAYING)
2040     gst_element_set_state (element, GST_STATE_PAUSED);
2041
2042   /* cleanup */
2043   gst_object_unref (GST_OBJECT (element));
2044   g_free (string);
2045 }
2046
2047 /**
2048  * gst_element_get_state:
2049  * @element: a #GstElement to get the state of.
2050  *
2051  * Gets the state of the element. 
2052  *
2053  * Returns: the #GstElementState of the element.
2054  */
2055 GstElementState
2056 gst_element_get_state (GstElement *element)
2057 {
2058   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2059
2060   return GST_STATE (element);
2061 }
2062
2063 /**
2064  * gst_element_wait_state_change:
2065  * @element: a #GstElement to wait for a state change on.
2066  *
2067  * Waits and blocks until the element changed its state.
2068  */
2069 void
2070 gst_element_wait_state_change (GstElement *element)
2071 {
2072   g_mutex_lock (element->state_mutex);
2073   g_cond_wait (element->state_cond, element->state_mutex);
2074   g_mutex_unlock (element->state_mutex);
2075 }
2076
2077 /**
2078  * gst_element_set_state:
2079  * @element: a #GstElement to change state of.
2080  * @state: the element's new #GstElementState.
2081  *
2082  * Sets the state of the element. This function will try to set the
2083  * requested state by going through all the intermediary states and calling
2084  * the class's state change function for each.
2085  *
2086  * Returns: TRUE if the state was successfully set.
2087  * (using #GstElementStateReturn).
2088  */
2089 GstElementStateReturn
2090 gst_element_set_state (GstElement *element, GstElementState state)
2091 {
2092   GstElementClass *oclass;
2093   GstElementState curpending;
2094   GstElementStateReturn return_val = GST_STATE_SUCCESS;
2095
2096   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2097
2098   /* start with the current state */
2099   curpending = GST_STATE(element);
2100
2101   GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s",
2102                      gst_element_state_get_name (curpending),
2103                      gst_element_state_get_name (state));
2104
2105   /* loop until the final requested state is set */
2106   while (GST_STATE (element) != state 
2107       && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2108     /* move the curpending state in the correct direction */
2109     if (curpending < state) 
2110       curpending <<= 1;
2111     else 
2112       curpending >>= 1;
2113
2114     /* set the pending state variable */
2115     /* FIXME: should probably check to see that we don't already have one */
2116     GST_STATE_PENDING (element) = curpending;
2117
2118     if (curpending != state) {
2119       GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2120                          "intermediate: setting state from %s to %s",
2121                          gst_element_state_get_name (GST_STATE (element)),
2122                          gst_element_state_get_name (curpending));
2123     }
2124
2125     /* call the state change function so it can set the state */
2126     oclass = GST_ELEMENT_GET_CLASS (element);
2127     if (oclass->change_state)
2128       return_val = (oclass->change_state) (element);
2129
2130     switch (return_val) {
2131       case GST_STATE_FAILURE:
2132         GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2133                            "have failed change_state return");
2134         goto exit;
2135       case GST_STATE_ASYNC:
2136         GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2137                            "element will change state async");
2138         goto exit;
2139       case GST_STATE_SUCCESS:
2140         /* Last thing we do is verify that a successful state change really
2141          * did change the state... */
2142         if (GST_STATE (element) != curpending) {
2143           GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2144                              "element claimed state-change success,"
2145                              "but state didn't change %s, %s <-> %s",
2146                              gst_element_state_get_name (GST_STATE (element)),
2147                              gst_element_state_get_name (GST_STATE_PENDING (element)),
2148                              gst_element_state_get_name (curpending));
2149           return GST_STATE_FAILURE;
2150         }
2151         break;
2152       default:
2153         /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2154         g_assert_not_reached ();
2155     }
2156   }
2157 exit:
2158
2159   return return_val;
2160 }
2161
2162 static gboolean
2163 gst_element_negotiate_pads (GstElement *element)
2164 {
2165   GList *pads = GST_ELEMENT_PADS (element);
2166
2167   GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads");
2168
2169   while (pads) {
2170     GstPad *pad = GST_PAD (pads->data);
2171     GstRealPad *srcpad;
2172
2173     pads = g_list_next (pads);
2174     
2175     if (!GST_IS_REAL_PAD (pad))
2176       continue;
2177
2178     srcpad = GST_PAD_REALIZE (pad);
2179
2180     /* if we have a link on this pad and it doesn't have caps
2181      * allready, try to negotiate */
2182     if (GST_PAD_IS_LINKED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2183       GstRealPad *sinkpad;
2184       GstElementState otherstate;
2185       GstElement *parent;
2186       
2187       sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2188
2189       /* check the parent of the peer pad, if there is no parent do nothing */
2190       parent = GST_PAD_PARENT (sinkpad);
2191       if (!parent) 
2192         continue;
2193
2194       /* skips pads that were already negotiating */
2195       if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
2196           GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
2197         continue;
2198
2199       otherstate = GST_STATE (parent);
2200
2201       /* swap pads if needed */
2202       if (!GST_PAD_IS_SRC (srcpad)) {
2203         GstRealPad *temp;
2204
2205         temp = srcpad;
2206         srcpad = sinkpad;
2207         sinkpad = temp;
2208       }
2209
2210       /* only try to negotiate if the peer element is in PAUSED or higher too */
2211       if (otherstate >= GST_STATE_READY) {
2212         GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
2213                            "perform negotiate for %s:%s and %s:%s",
2214                            GST_DEBUG_PAD_NAME (srcpad), 
2215                            GST_DEBUG_PAD_NAME (sinkpad));
2216         if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
2217           return FALSE;
2218       }
2219       else {
2220         GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
2221                            "not negotiating %s:%s and %s:%s, not in READY yet",
2222                            GST_DEBUG_PAD_NAME (srcpad), 
2223                            GST_DEBUG_PAD_NAME (sinkpad));
2224       }
2225     }
2226   }
2227
2228   return TRUE;
2229 }
2230
2231 static void
2232 gst_element_clear_pad_caps (GstElement *element)
2233 {
2234   GList *pads = GST_ELEMENT_PADS (element);
2235
2236   GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps");
2237
2238   while (pads) {
2239     GstRealPad *pad = GST_PAD_REALIZE (pads->data);
2240
2241     gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
2242
2243     pads = g_list_next (pads);
2244   }
2245 }
2246
2247 static void
2248 gst_element_pads_activate (GstElement *element, gboolean active)
2249 {
2250   GList *pads = element->pads;
2251
2252   while (pads) {
2253     GstPad *pad = GST_PAD_CAST (pads->data);
2254     pads = g_list_next (pads);
2255
2256     if (!GST_IS_REAL_PAD (pad))
2257       continue;
2258
2259     gst_pad_set_active (pad, active);
2260   }
2261 }
2262
2263 static GstElementStateReturn
2264 gst_element_change_state (GstElement *element)
2265 {
2266   GstElementState old_state;
2267   GstObject *parent;
2268   gint old_pending, old_transition;
2269
2270   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2271
2272   old_state = GST_STATE (element);
2273   old_pending = GST_STATE_PENDING (element);
2274   old_transition = GST_STATE_TRANSITION (element);
2275
2276   if (old_pending == GST_STATE_VOID_PENDING || 
2277       old_state == GST_STATE_PENDING (element)) {
2278     GST_INFO (GST_CAT_STATES, 
2279               "no state change needed for element %s (VOID_PENDING)", 
2280               GST_ELEMENT_NAME (element));
2281     return GST_STATE_SUCCESS;
2282   }
2283   
2284   GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x", 
2285             GST_ELEMENT_NAME (element),
2286             gst_element_state_get_name (old_state),
2287             gst_element_state_get_name (old_pending),
2288             old_transition);
2289
2290   /* we set the state change early for the negotiation functions */
2291   GST_STATE (element) = old_pending;
2292   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2293
2294   switch (old_transition) {
2295     case GST_STATE_PLAYING_TO_PAUSED:
2296       gst_element_pads_activate (element, FALSE);
2297       break;
2298     case GST_STATE_PAUSED_TO_PLAYING:
2299       gst_element_pads_activate (element, TRUE);
2300       break;
2301     /* if we are going to paused, we try to negotiate the pads */
2302     case GST_STATE_READY_TO_PAUSED:
2303       if (!gst_element_negotiate_pads (element)) 
2304         goto failure;
2305       break;
2306     /* going to the READY state clears all pad caps */
2307     case GST_STATE_PAUSED_TO_READY:
2308       gst_element_clear_pad_caps (element);
2309       break;
2310     default:
2311       break;
2312   }
2313
2314   parent = GST_ELEMENT_PARENT (element);
2315
2316   GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2317                      "signaling state change from %s to %s",
2318                      gst_element_state_get_name (old_state),
2319                      gst_element_state_get_name (GST_STATE (element)));
2320
2321   /* tell the scheduler if we have one */
2322   if (element->sched) {
2323     if (gst_scheduler_state_transition (element->sched, element, 
2324                                         old_transition) != GST_STATE_SUCCESS) {
2325       GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
2326                          "scheduler could change state");
2327       goto failure;
2328     }
2329   }
2330
2331   g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2332                  0, old_state, GST_STATE (element));
2333
2334   /* tell our parent about the state change */
2335   if (parent && GST_IS_BIN (parent)) {
2336     gst_bin_child_state_change (GST_BIN (parent), old_state, 
2337                                 GST_STATE (element), element);
2338   }
2339
2340   /* signal the state change in case somebody is waiting for us */
2341   g_mutex_lock (element->state_mutex);
2342   g_cond_signal (element->state_cond);
2343   g_mutex_unlock (element->state_mutex);
2344
2345   return GST_STATE_SUCCESS;
2346
2347 failure:
2348   /* undo the state change */
2349   GST_STATE (element) = old_state;
2350   GST_STATE_PENDING (element) = old_pending;
2351
2352   return GST_STATE_FAILURE;
2353 }
2354
2355 /**
2356  * gst_element_get_factory:
2357  * @element: a #GstElement to request the element factory of.
2358  *
2359  * Retrieves the factory that was used to create this element.
2360  *
2361  * Returns: the #GstElementFactory used for creating this element.
2362  */
2363 GstElementFactory*
2364 gst_element_get_factory (GstElement *element)
2365 {
2366   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2367
2368   return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2369 }
2370
2371 static void
2372 gst_element_dispose (GObject *object)
2373 {
2374   GstElement *element = GST_ELEMENT (object);
2375   GList *pads;
2376   GstPad *pad;
2377
2378   GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose");
2379
2380   gst_element_set_state (element, GST_STATE_NULL);
2381
2382   /* first we break all our links with the ouside */
2383   if (element->pads) {
2384     GList *orig;
2385     orig = pads = g_list_copy (element->pads);
2386     while (pads) {
2387       pad = GST_PAD (pads->data);
2388
2389       if (GST_PAD_PEER (pad)) {
2390         GST_DEBUG (GST_CAT_REFCOUNTING, "unlinking pad '%s'",
2391                    GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2392         gst_pad_unlink (pad, GST_PAD (GST_PAD_PEER (pad)));
2393       }
2394       gst_element_remove_pad (element, pad);
2395
2396       pads = g_list_next (pads);
2397     }
2398     g_list_free (orig);
2399     g_list_free (element->pads);
2400     element->pads = NULL;
2401   }
2402
2403   element->numsrcpads = 0;
2404   element->numsinkpads = 0;
2405   element->numpads = 0;
2406   g_mutex_free (element->state_mutex);
2407   g_cond_free (element->state_cond);
2408
2409   if (element->prop_value_queue)
2410     g_async_queue_unref (element->prop_value_queue);
2411   element->prop_value_queue = NULL;
2412   if (element->property_mutex)
2413     g_mutex_free (element->property_mutex);
2414
2415   gst_object_replace ((GstObject **)&element->sched, NULL);
2416   gst_object_replace ((GstObject **)&element->clock, NULL);
2417
2418   G_OBJECT_CLASS (parent_class)->dispose (object);
2419 }
2420
2421 #ifndef GST_DISABLE_LOADSAVE
2422 /**
2423  * gst_element_save_thyself:
2424  * @element: a #GstElement to save.
2425  * @parent: the xml parent node.
2426  *
2427  * Saves the element as part of the given XML structure.
2428  *
2429  * Returns: the new #xmlNodePtr.
2430  */
2431 static xmlNodePtr
2432 gst_element_save_thyself (GstObject *object,
2433                           xmlNodePtr parent)
2434 {
2435   GList *pads;
2436   GstElementClass *oclass;
2437   GParamSpec **specs, *spec;
2438   gint nspecs, i;
2439   GValue value = { 0, };
2440   GstElement *element;
2441
2442   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2443
2444   element = GST_ELEMENT (object);
2445
2446   oclass = GST_ELEMENT_GET_CLASS (element);
2447
2448   xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2449
2450   if (oclass->elementfactory != NULL) {
2451     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2452
2453     xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
2454     xmlNewChild (parent, NULL, "version", factory->details->version);
2455   }
2456
2457 /* FIXME: what is this? */  
2458 /*  if (element->manager) */
2459 /*    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2460
2461   /* params */
2462   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2463   
2464   for (i=0; i<nspecs; i++) {
2465     spec = specs[i];
2466     if (spec->flags & G_PARAM_READABLE) {
2467       xmlNodePtr param;
2468       char *contents;
2469       
2470       g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
2471       
2472       g_object_get_property (G_OBJECT (element), spec->name, &value);
2473       param = xmlNewChild (parent, NULL, "param", NULL);
2474       xmlNewChild (param, NULL, "name", spec->name);
2475       
2476       if (G_IS_PARAM_SPEC_STRING (spec))
2477         contents = g_value_dup_string (&value);
2478       else if (G_IS_PARAM_SPEC_ENUM (spec))
2479         contents = g_strdup_printf ("%d", g_value_get_enum (&value));
2480       else if (G_IS_PARAM_SPEC_INT64 (spec))
2481         contents = g_strdup_printf ("%" G_GINT64_FORMAT,
2482                                     g_value_get_int64 (&value));
2483       else
2484         contents = g_strdup_value_contents (&value);
2485       
2486       xmlNewChild (param, NULL, "value", contents);
2487       g_free (contents);
2488       
2489       g_value_unset(&value);
2490     }
2491   }
2492
2493   pads = GST_ELEMENT_PADS (element);
2494
2495   while (pads) {
2496     GstPad *pad = GST_PAD (pads->data);
2497     /* figure out if it's a direct pad or a ghostpad */
2498     if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
2499       xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
2500       gst_object_save_thyself (GST_OBJECT (pad), padtag);
2501     }
2502     pads = g_list_next (pads);
2503   }
2504
2505   return parent;
2506 }
2507
2508 static void
2509 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
2510 {
2511   xmlNodePtr children;
2512   GstElement *element;
2513   gchar *name = NULL;
2514   gchar *value = NULL;
2515
2516   element = GST_ELEMENT (object);
2517   g_return_if_fail (element != NULL);
2518
2519   /* parameters */
2520   children = self->xmlChildrenNode;
2521   while (children) {
2522     if (!strcmp (children->name, "param")) {
2523       xmlNodePtr child = children->xmlChildrenNode;
2524
2525       while (child) {
2526         if (!strcmp (child->name, "name")) {
2527           name = xmlNodeGetContent (child);
2528         }
2529         else if (!strcmp (child->name, "value")) {
2530           value = xmlNodeGetContent (child);
2531         }
2532         child = child->next;
2533       }
2534       /* FIXME: can this just be g_object_set ? */
2535       gst_util_set_object_arg (G_OBJECT (element), name, value);
2536     }
2537     children = children->next;
2538   }
2539   
2540   /* pads */
2541   children = self->xmlChildrenNode;
2542   while (children) {
2543     if (!strcmp (children->name, "pad")) {
2544       gst_pad_load_and_link (children, GST_OBJECT (element));
2545     }
2546     children = children->next;
2547   }
2548
2549   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
2550     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
2551 }
2552 #endif /* GST_DISABLE_LOADSAVE */
2553
2554 /**
2555  * gst_element_yield:
2556  * @element: a #GstElement to yield.
2557  *
2558  * Requests a yield operation for the element. The scheduler will typically
2559  * give control to another element.
2560  */
2561 void
2562 gst_element_yield (GstElement *element)
2563 {
2564   if (GST_ELEMENT_SCHED (element)) {
2565     gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
2566   }
2567 }
2568
2569 /**
2570  * gst_element_interrupt:
2571  * @element: a #GstElement to interrupt.
2572  *
2573  * Requests the scheduler of this element to interrupt the execution of
2574  * this element and scheduler another one.
2575  *
2576  * Returns: TRUE if the element should exit its chain/loop/get
2577  * function ASAP, depending on the scheduler implementation.
2578  */
2579 gboolean
2580 gst_element_interrupt (GstElement *element)
2581 {
2582   if (GST_ELEMENT_SCHED (element)) {
2583     return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
2584   }
2585   else 
2586     return TRUE;
2587 }
2588
2589 /**
2590  * gst_element_set_scheduler:
2591  * @element: a #GstElement to set the scheduler of.
2592  * @sched: the #GstScheduler to set.
2593  *
2594  * Sets the scheduler of the element.  For internal use only, unless you're
2595  * writing a new bin subclass.
2596  */
2597 void
2598 gst_element_set_scheduler (GstElement *element,
2599                        GstScheduler *sched)
2600 {
2601   g_return_if_fail (GST_IS_ELEMENT (element));
2602   
2603   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
2604
2605   gst_object_replace ((GstObject **)&GST_ELEMENT_SCHED (element), GST_OBJECT (sched));
2606 }
2607
2608 /**
2609  * gst_element_get_scheduler:
2610  * @element: a #GstElement to get the scheduler of.
2611  *
2612  * Returns the scheduler of the element.
2613  *
2614  * Returns: the element's #GstScheduler.
2615  */
2616 GstScheduler*
2617 gst_element_get_scheduler (GstElement *element)
2618 {
2619   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2620
2621   return GST_ELEMENT_SCHED (element);
2622 }
2623
2624 /**
2625  * gst_element_set_loop_function:
2626  * @element: a #GstElement to set the loop function of.
2627  * @loop: Pointer to #GstElementLoopFunction.
2628  *
2629  * This sets the loop function for the element.  The function pointed to
2630  * can deviate from the GstElementLoopFunction definition in type of
2631  * pointer only.
2632  *
2633  * NOTE: in order for this to take effect, the current loop function *must*
2634  * exit.  Assuming the loop function itself is the only one who will cause
2635  * a new loopfunc to be assigned, this should be no problem.
2636  */
2637 void
2638 gst_element_set_loop_function (GstElement *element,
2639                                GstElementLoopFunction loop)
2640 {
2641   g_return_if_fail (GST_IS_ELEMENT (element));
2642
2643   /* set the loop function */
2644   element->loopfunc = loop;
2645
2646   /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
2647   GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
2648
2649   if (GST_ELEMENT_SCHED (element)) {
2650     gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
2651   }
2652 }
2653
2654 /**
2655  * gst_element_set_eos:
2656  * @element: a #GstElement to set to the EOS state.
2657  *
2658  * Perform the actions needed to bring the element in the EOS state.
2659  */
2660 void
2661 gst_element_set_eos (GstElement *element)
2662 {
2663   g_return_if_fail (GST_IS_ELEMENT (element));
2664
2665   GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", 
2666              GST_OBJECT_NAME (element));
2667
2668   gst_element_set_state (element, GST_STATE_PAUSED);
2669
2670   g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2671 }
2672
2673
2674 /**
2675  * gst_element_state_get_name:
2676  * @state: a #GstElementState to get the name of.
2677  *
2678  * Gets a string representing the given state.
2679  *
2680  * Returns: a string with the name of the state.
2681  */
2682 const gchar*
2683 gst_element_state_get_name (GstElementState state) 
2684 {
2685   switch (state) {
2686 #ifdef GST_DEBUG_COLOR
2687     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2688     case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
2689     case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
2690     case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
2691     case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
2692     default:
2693       /* This is a memory leak */
2694       return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
2695 #else
2696     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2697     case GST_STATE_NULL: return "NULL";break;
2698     case GST_STATE_READY: return "READY";break;
2699     case GST_STATE_PLAYING: return "PLAYING";break;
2700     case GST_STATE_PAUSED: return "PAUSED";break;
2701     default: return "UNKNOWN!";
2702 #endif
2703   }
2704   return "";
2705 }
2706
2707 static void
2708 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name, 
2709                                 guint arg_id, GParamFlags flags)
2710 {
2711   GQuark prop_id = g_quark_from_string (prop_name);
2712   GParamSpec *pspec;
2713
2714   static GQuark fd_id = 0;
2715   static GQuark blocksize_id;
2716   static GQuark bytesperread_id;
2717   static GQuark dump_id;
2718   static GQuark filesize_id;
2719   static GQuark mmapsize_id;
2720   static GQuark location_id;
2721   static GQuark offset_id;
2722   static GQuark silent_id;
2723   static GQuark touch_id;
2724
2725   if (!fd_id) {
2726     fd_id = g_quark_from_static_string ("fd");
2727     blocksize_id = g_quark_from_static_string ("blocksize");
2728     bytesperread_id = g_quark_from_static_string ("bytesperread");
2729     dump_id = g_quark_from_static_string ("dump");
2730     filesize_id = g_quark_from_static_string ("filesize");
2731     mmapsize_id = g_quark_from_static_string ("mmapsize");
2732     location_id = g_quark_from_static_string ("location");
2733     offset_id = g_quark_from_static_string ("offset");
2734     silent_id = g_quark_from_static_string ("silent");
2735     touch_id = g_quark_from_static_string ("touch");
2736   }
2737
2738   if (prop_id == fd_id) {
2739     pspec = g_param_spec_int ("fd", "File-descriptor",
2740                               "File-descriptor for the file being read",
2741                               0, G_MAXINT, 0, flags);
2742   }
2743   else if (prop_id == blocksize_id) {
2744     pspec = g_param_spec_ulong ("blocksize", "Block Size",
2745                                 "Block size to read per buffer",
2746                                 0, G_MAXULONG, 4096, flags);
2747
2748   }
2749   else if (prop_id == bytesperread_id) {
2750     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
2751                               "Number of bytes to read per buffer",
2752                               G_MININT, G_MAXINT, 0, flags);
2753
2754   }
2755   else if (prop_id == dump_id) {
2756     pspec = g_param_spec_boolean ("dump", "Dump", 
2757                                   "Dump bytes to stdout", 
2758                                   FALSE, flags);
2759
2760   }
2761   else if (prop_id == filesize_id) {
2762     pspec = g_param_spec_int64 ("filesize", "File Size",
2763                                 "Size of the file being read",
2764                                 0, G_MAXINT64, 0, flags);
2765
2766   }
2767   else if (prop_id == mmapsize_id) {
2768     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
2769                                 "Size in bytes of mmap()d regions",
2770                                 0, G_MAXULONG, 4 * 1048576, flags);
2771
2772   }
2773   else if (prop_id == location_id) {
2774     pspec = g_param_spec_string ("location", "File Location",
2775                                  "Location of the file to read",
2776                                  NULL, flags);
2777
2778   }
2779   else if (prop_id == offset_id) {
2780     pspec = g_param_spec_int64 ("offset", "File Offset",
2781                                 "Byte offset of current read pointer",
2782                                 0, G_MAXINT64, 0, flags);
2783
2784   }
2785   else if (prop_id == silent_id) {
2786     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
2787                                   FALSE, flags);
2788
2789   }
2790   else if (prop_id == touch_id) {
2791     pspec = g_param_spec_boolean ("touch", "Touch read data",
2792                                   "Touch data to force disk read before "
2793                                   "push ()", TRUE, flags);
2794   }
2795   else {
2796     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
2797                prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
2798     pspec = NULL;
2799   }
2800
2801   if (pspec) {
2802     g_object_class_install_property (klass, arg_id, pspec);
2803   }
2804 }
2805
2806 /**
2807  * gst_element_class_install_std_props:
2808  * @klass: the #GstElementClass to add the properties to.
2809  * @first_name: the name of the first property.
2810  * in a NULL terminated
2811  * @...: the id and flags of the first property, followed by
2812  * further 'name', 'id', 'flags' triplets and terminated by NULL.
2813  * 
2814  * Adds a list of standardized properties with types to the @klass.
2815  * the id is for the property switch in your get_prop method, and
2816  * the flags determine readability / writeability.
2817  **/
2818 void
2819 gst_element_class_install_std_props (GstElementClass * klass, 
2820                                      const gchar *first_name, ...)
2821 {
2822   const char *name;
2823
2824   va_list args;
2825
2826   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
2827
2828   va_start (args, first_name);
2829
2830   name = first_name;
2831
2832   while (name) {
2833     int arg_id = va_arg (args, int);
2834     int flags = va_arg (args, int);
2835
2836     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
2837
2838     name = va_arg (args, char *);
2839   }
2840
2841   va_end (args);
2842 }
2843
2844 /**
2845  * gst_element_get_managing_bin:
2846  * @element: a #GstElement to get the managing bin of.
2847  * 
2848  * Gets the managing bin (a pipeline or a thread, for example) of an element.
2849  *
2850  * Returns: the #GstBin, or NULL on failure.
2851  **/
2852 GstBin*
2853 gst_element_get_managing_bin (GstElement *element)
2854 {
2855   GstBin *bin;
2856
2857   g_return_val_if_fail (element != NULL, NULL);
2858
2859   bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
2860
2861   while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
2862     bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
2863   
2864   return bin;
2865 }