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