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