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