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