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