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