seriously, using cvs over slow lines just sucks.
[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, const 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_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, 
900           "clock time %llu: setting element time to %llu", event_time, time);
901       element->base_time = event_time - time;
902       break;
903     default:
904       g_assert_not_reached ();
905       break;
906   }
907 }
908
909 /**
910  * gst_element_adjust_time:
911  * @element: element to adjust time on
912  * @difference: difference to adjust
913  *
914  * Adjusts the current time of the element by the specified difference. This 
915  * function can be used when handling discont events. You can only call this 
916  * function on an element with a clock in #GST_STATE_PAUSED or 
917  * #GST_STATE_PLAYING. It is more accurate than gst_element_set_time().
918  */
919 void
920 gst_element_adjust_time (GstElement *element, GstClockTimeDiff diff)
921 {
922   GstClockTime time;
923   
924   g_return_if_fail (GST_IS_ELEMENT (element));
925   g_return_if_fail (GST_IS_CLOCK (element->clock));
926   g_return_if_fail (element->current_state >= GST_STATE_PAUSED);
927
928   switch (element->current_state) {
929     case GST_STATE_PAUSED:
930       if (diff < 0 && element->base_time < abs (diff)) {
931         g_warning ("attempted to set the current time of element %s below 0",
932             GST_OBJECT_NAME (element));
933         element->base_time = 0;
934       } else {
935         element->base_time += diff;
936       }
937       break;
938     case GST_STATE_PLAYING:
939       time = gst_clock_get_time (element->clock);
940       if (time < element->base_time - diff) {
941         g_warning ("attempted to set the current time of element %s below 0",
942             GST_OBJECT_NAME (element));
943         element->base_time = time;
944       } else {
945         element->base_time -= diff;
946       }
947       break;
948     default:
949       g_assert_not_reached ();
950       break;
951   }
952 }
953
954 #undef GST_CAT_DEFAULT
955
956 #ifndef GST_DISABLE_INDEX
957 /**
958  * gst_element_is_indexable:
959  * @element: a #GstElement.
960  *
961  * Queries if the element can be indexed.
962  *
963  * Returns: TRUE if the element can be indexed.
964  */
965 gboolean
966 gst_element_is_indexable (GstElement *element)
967 {
968   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
969
970   return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
971 }
972
973 /**
974  * gst_element_set_index:
975  * @element: a #GstElement.
976  * @index: a #GstIndex.
977  *
978  * Set the specified GstIndex on the element.
979  */
980 void
981 gst_element_set_index (GstElement *element, GstIndex *index)
982 {
983   GstElementClass *oclass;
984
985   g_return_if_fail (GST_IS_ELEMENT (element));
986   g_return_if_fail (GST_IS_INDEX (index));
987
988   oclass = GST_ELEMENT_GET_CLASS (element);
989
990   if (oclass->set_index)
991     oclass->set_index (element, index);
992 }
993
994 /**
995  * gst_element_get_index:
996  * @element: a #GstElement.
997  *
998  * Gets the index from the element.
999  *
1000  * Returns: a #GstIndex or NULL when no index was set on the
1001  * element.
1002  */
1003 GstIndex*
1004 gst_element_get_index (GstElement *element)
1005 {
1006   GstElementClass *oclass;
1007
1008   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1009
1010   oclass = GST_ELEMENT_GET_CLASS (element);
1011
1012   if (oclass->get_index)
1013     return oclass->get_index (element);
1014
1015   return NULL;
1016 }
1017 #endif
1018
1019 /**
1020  * gst_element_release_locks:
1021  * @element: a #GstElement to release all locks on.
1022  *
1023  * Instruct the element to release all the locks it is holding, such as
1024  * blocking reads, waiting for the clock, ...
1025  *
1026  * Returns: TRUE if the locks could be released.
1027  */
1028 gboolean
1029 gst_element_release_locks (GstElement *element)
1030 {
1031   GstElementClass *oclass;
1032
1033   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1034
1035   oclass = GST_ELEMENT_GET_CLASS (element);
1036
1037   if (oclass->release_locks)
1038     return oclass->release_locks (element);
1039   
1040   return TRUE;
1041 }
1042
1043 /**
1044  * gst_element_add_pad:
1045  * @element: a #GstElement to add the pad to.
1046  * @pad: the #GstPad to add to the element.
1047  *
1048  * Add a pad (link point) to the element, setting the parent of the
1049  * pad to the element (and thus adding a reference).
1050  * Pads are automatically activated when the element is in state PLAYING.
1051  */
1052 void
1053 gst_element_add_pad (GstElement *element, GstPad *pad)
1054 {
1055   g_return_if_fail (GST_IS_ELEMENT (element));
1056   g_return_if_fail (GST_IS_PAD (pad));
1057
1058   /* first check to make sure the pad's parent is already set */
1059   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
1060
1061   /* then check to see if there's already a pad by that name here */
1062   g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
1063
1064   /* set the pad's parent */
1065   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
1066         GST_PAD_NAME (pad), GST_STR_NULL (GST_ELEMENT_NAME (element)));
1067   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
1068
1069   /* add it to the list */
1070   element->pads = g_list_append (element->pads, pad);
1071   element->numpads++;
1072   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
1073     element->numsrcpads++;
1074   else
1075     element->numsinkpads++;
1076
1077   /* activate element when we are playing */
1078   if (GST_STATE (element) == GST_STATE_PLAYING)
1079     gst_pad_set_active (pad, TRUE);
1080   
1081   /* emit the NEW_PAD signal */
1082   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
1083 }
1084
1085 /**
1086  * gst_element_remove_pad:
1087  * @element: a #GstElement to remove pad from.
1088  * @pad: the #GstPad to remove from the element.
1089  *
1090  * Remove a pad (link point) from the element.
1091  */
1092 void
1093 gst_element_remove_pad (GstElement *element, GstPad *pad)
1094 {
1095   g_return_if_fail (element != NULL);
1096   g_return_if_fail (GST_IS_ELEMENT (element));
1097   g_return_if_fail (pad != NULL);
1098   g_return_if_fail (GST_IS_PAD (pad));
1099
1100   g_return_if_fail (GST_PAD_PARENT (pad) == element);
1101
1102   /* check to see if the pad is still linked */
1103   /* FIXME: what if someone calls _remove_pad instead of 
1104     _remove_ghost_pad? */
1105   if (GST_IS_REAL_PAD (pad)) {
1106     if (GST_RPAD_PEER (pad) != NULL) {
1107       gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad)));
1108     }
1109   }
1110   
1111   /* remove it from the list */
1112   element->pads = g_list_remove (element->pads, pad);
1113   element->numpads--;
1114   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
1115     element->numsrcpads--;
1116   else
1117     element->numsinkpads--;
1118
1119   g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
1120
1121   gst_object_unparent (GST_OBJECT (pad));
1122 }
1123
1124 /**
1125  * gst_element_add_ghost_pad:
1126  * @element: a #GstElement to add the ghost pad to.
1127  * @pad: the #GstPad from which the new ghost pad will be created.
1128  * @name: the name of the new ghost pad.
1129  *
1130  * Creates a ghost pad from the given pad, and adds it to the list of pads
1131  * for this element.
1132  * 
1133  * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
1134  */
1135 GstPad *
1136 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
1137 {
1138   GstPad *ghostpad;
1139
1140   g_return_val_if_fail (element != NULL, NULL);
1141   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1142   g_return_val_if_fail (pad != NULL, NULL);
1143   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1144
1145   /* then check to see if there's already a pad by that name here */
1146   g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
1147
1148   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
1149              "creating new ghost pad called %s, from pad %s:%s",
1150              name, GST_DEBUG_PAD_NAME(pad));
1151   ghostpad = gst_ghost_pad_new (name, pad);
1152
1153   /* add it to the list */
1154   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
1155             name, GST_ELEMENT_NAME (element));
1156   element->pads = g_list_append (element->pads, ghostpad);
1157   element->numpads++;
1158   /* set the parent of the ghostpad */
1159   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
1160
1161   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
1162
1163   /* emit the NEW_GHOST_PAD signal */
1164   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
1165         
1166   return ghostpad;
1167 }
1168
1169 /**
1170  * gst_element_remove_ghost_pad:
1171  * @element: a #GstElement to remove the ghost pad from.
1172  * @pad: ghost #GstPad to remove.
1173  *
1174  * Removes a ghost pad from an element.
1175  */
1176 void
1177 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
1178 {
1179   g_return_if_fail (GST_IS_ELEMENT (element));
1180   g_return_if_fail (GST_IS_GHOST_PAD (pad));
1181
1182   /* FIXME this is redundant?
1183    * wingo 10-july-2001: I don't think so, you have to actually remove the pad
1184    * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
1185    * the real pad's ghost pad list
1186    */
1187   gst_object_ref (GST_OBJECT (pad));
1188   gst_element_remove_pad (element, pad);
1189   gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
1190   gst_object_unref (GST_OBJECT (pad));
1191 }
1192
1193
1194 /**
1195  * gst_element_get_pad:
1196  * @element: a #GstElement to find pad of.
1197  * @name: the name of the pad to retrieve.
1198  *
1199  * Retrieves a pad from the element by name.
1200  *
1201  * Returns: requested #GstPad if found, otherwise NULL.
1202  */
1203 GstPad*
1204 gst_element_get_pad (GstElement *element, const gchar *name)
1205 {
1206   GstPad *pad;
1207
1208   g_return_val_if_fail (element != NULL, NULL);
1209   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1210   g_return_val_if_fail (name != NULL, NULL);
1211
1212   pad = gst_element_get_static_pad (element, name);
1213   if (!pad) 
1214     pad = gst_element_get_request_pad (element, name);
1215
1216   return pad;
1217 }
1218
1219 /**
1220  * gst_element_get_static_pad:
1221  * @element: a #GstElement to find a static pad of.
1222  * @name: the name of the static #GstPad to retrieve.
1223  *
1224  * Retrieves a pad from the element by name. This version only retrieves
1225  * already-existing (i.e. 'static') pads.
1226  *
1227  * Returns: the requested #GstPad if found, otherwise NULL.
1228  */
1229 GstPad *
1230 gst_element_get_static_pad (GstElement *element, const gchar *name)
1231 {
1232   GList *walk;
1233   
1234   g_return_val_if_fail (element != NULL, NULL);
1235   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1236   g_return_val_if_fail (name != NULL, NULL);
1237
1238   walk = element->pads;
1239   while (walk) {
1240     GstPad *pad;
1241     
1242     pad = GST_PAD(walk->data);
1243     if (strcmp (GST_PAD_NAME(pad), name) == 0) {
1244       GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1245       return pad;
1246     }
1247     walk = g_list_next (walk);
1248   }
1249
1250   GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
1251   return NULL;
1252 }
1253
1254 /**
1255  * gst_element_get_request_pad:
1256  * @element: a #GstElement to find a request pad of.
1257  * @name: the name of the request #GstPad to retrieve.
1258  *
1259  * Retrieves a pad from the element by name. This version only retrieves
1260  * request pads.
1261  *
1262  * Returns: requested #GstPad if found, otherwise NULL.
1263  */
1264 GstPad*
1265 gst_element_get_request_pad (GstElement *element, const gchar *name)
1266 {
1267   GstPadTemplate *templ = NULL;
1268   GstPad *pad;
1269   const gchar *req_name = NULL;
1270   gboolean templ_found = FALSE;
1271   GList *list;
1272   gint n;
1273   const gchar *data;
1274   gchar *str, *endptr = NULL;
1275
1276   g_return_val_if_fail (element != NULL, NULL);
1277   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1278   g_return_val_if_fail (name != NULL, NULL);
1279
1280   if (strstr (name, "%")) {
1281     templ = gst_element_get_pad_template (element, name);
1282     req_name = NULL;
1283     if (templ)
1284       templ_found = TRUE;
1285   } else {
1286     list = gst_element_get_pad_template_list(element);
1287     while (!templ_found && list) {
1288       templ = (GstPadTemplate*) list->data;
1289       if (templ->presence == GST_PAD_REQUEST) {
1290         /* we know that %s and %d are the only possibilities because of sanity
1291            checks in gst_pad_template_new */
1292         GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
1293         if ((str = strchr (templ->name_template, '%')) &&
1294             strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
1295             strlen (name) > str - templ->name_template) {
1296           data = name + (str - templ->name_template);
1297           if (*(str+1) == 'd') {
1298             /* it's an int */
1299             n = (gint) strtol (data, &endptr, 10);
1300             if (endptr && *endptr == '\0') {
1301               templ_found = TRUE;
1302               req_name = name;
1303               break;
1304             }
1305           } else {
1306             /* it's a string */
1307             templ_found = TRUE;
1308             req_name = name;
1309             break;
1310           }
1311         }
1312       }
1313       list = list->next;
1314     }
1315   }
1316   
1317   if (!templ_found)
1318       return NULL;
1319   
1320   pad = gst_element_request_pad (element, templ, req_name);
1321   
1322   return pad;
1323 }
1324
1325 /**
1326  * gst_element_get_pad_list:
1327  * @element: a #GstElement to get pads of.
1328  *
1329  * Retrieves a list of the pads associated with the element.
1330  *
1331  * Returns: the #GList of pads.
1332  */
1333 const GList*
1334 gst_element_get_pad_list (GstElement *element)
1335 {
1336   g_return_val_if_fail (element != NULL, NULL);
1337   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1338
1339   /* return the list of pads */
1340   return element->pads;
1341 }
1342
1343 /**
1344  * gst_element_class_add_pad_template:
1345  * @klass: the #GstElementClass to add the pad template to.
1346  * @templ: a #GstPadTemplate to add to the element class.
1347  *
1348  * Adds a padtemplate to an element class. This is mainly used in the _base_init
1349  * functions of classes.
1350  */
1351 void
1352 gst_element_class_add_pad_template (GstElementClass *klass, 
1353                                     GstPadTemplate *templ)
1354 {
1355   GstPadTemplate *templ_copy;
1356
1357   g_return_if_fail (klass != NULL);
1358   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1359   g_return_if_fail (templ != NULL);
1360   g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1361   /* avoid registering pad templates with the same name */
1362   g_return_if_fail (gst_element_class_get_pad_template (klass, templ->name_template) == NULL);
1363   
1364   templ_copy = g_memdup(templ, sizeof(GstPadTemplate));
1365
1366   klass->padtemplates = g_list_append (klass->padtemplates, templ_copy);
1367   klass->numpadtemplates++;
1368 }
1369
1370 /**
1371  * gst_element_class_set_details:
1372  * @klass: class to set details for
1373  * @details: details to set
1374  *
1375  * Sets the detailed information for a #GstElementClass.
1376  * <note>This function is for use in _base_init functions only.</note>
1377  */
1378 void                    
1379 gst_element_class_set_details (GstElementClass *klass, const GstElementDetails *details)
1380 {
1381   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1382   g_return_if_fail (GST_IS_ELEMENT_DETAILS (details));
1383   
1384   __gst_element_details_set (&klass->details, details);
1385 }
1386
1387 /**
1388  * gst_element_class_get_pad_template_list:
1389  * @element: a #GstElementClass to get pad templates of.
1390  *
1391  * Retrieves a list of the pad templates associated with the element.
1392  *
1393  * Returns: the #GList of padtemplates.
1394  */
1395 GList*
1396 gst_element_class_get_pad_template_list (GstElementClass *element_class)
1397 {
1398   g_return_val_if_fail (element_class != NULL, NULL);
1399   g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
1400
1401   return element_class->padtemplates;
1402 }
1403
1404 /**
1405  * gst_element_class_get_pad_template:
1406  * @element: a #GstElementClass to get the pad template of.
1407  * @name: the name of the #GstPadTemplate to get.
1408  *
1409  * Retrieves a padtemplate from this element with the
1410  * given name.
1411  *
1412  * Returns: the #GstPadTemplate with the given name, or NULL if none was found. 
1413  * No unreferencing is necessary.
1414  */
1415 GstPadTemplate*
1416 gst_element_class_get_pad_template (GstElementClass *element_class, const gchar *name)
1417 {
1418   GList *padlist;
1419
1420   g_return_val_if_fail (element_class != NULL, NULL);
1421   g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
1422   g_return_val_if_fail (name != NULL, NULL);
1423
1424   padlist = gst_element_class_get_pad_template_list (element_class);
1425
1426   while (padlist) {
1427     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1428
1429     if (strcmp (padtempl->name_template, name) == 0)
1430       return padtempl;
1431
1432     padlist = g_list_next (padlist);
1433   }
1434
1435   return NULL;
1436 }
1437
1438 /**
1439  * gst_element_get_pad_template_list:
1440  * @element: a #GstElement to get pad templates of.
1441  *
1442  * Retrieves a list of the pad templates associated with the element.
1443  * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template_list).
1444  *
1445  * Returns: the #GList of padtemplates.
1446  */
1447 GList*
1448 gst_element_get_pad_template_list (GstElement *element)
1449 {
1450   g_return_val_if_fail (element != NULL, NULL);
1451   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1452
1453   return GST_ELEMENT_GET_CLASS (element)->padtemplates;
1454 }
1455
1456 /**
1457  * gst_element_get_pad_template:
1458  * @element: a #GstElement to get the pad template of.
1459  * @name: the name of the #GstPadTemplate to get.
1460  *
1461  * Retrieves a padtemplate from this element with the
1462  * given name.
1463  * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template).
1464  *
1465  * Returns: the #GstPadTemplate with the given name, or NULL if none was found. 
1466  * No unreferencing is necessary.
1467  */
1468 GstPadTemplate*
1469 gst_element_get_pad_template (GstElement *element, const gchar *name)
1470 {
1471   GList *padlist;
1472
1473   g_return_val_if_fail (element != NULL, NULL);
1474   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1475   g_return_val_if_fail (name != NULL, NULL);
1476
1477   padlist = gst_element_get_pad_template_list (element);
1478
1479   while (padlist) {
1480     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1481
1482     if (!strcmp (padtempl->name_template, name))
1483       return padtempl;
1484
1485     padlist = g_list_next (padlist);
1486   }
1487
1488   return NULL;
1489 }
1490
1491 /**
1492  * gst_element_get_compatible_pad_template:
1493  * @element: a #GstElement to get a compatible pad template for.
1494  * @compattempl: the #GstPadTemplate to find a compatible template for.
1495  *
1496  * Generates a pad template for this element compatible with the given
1497  * template (meaning it is able to link with it).
1498  *
1499  * Returns: the #GstPadTemplate of the element that is compatible with
1500  * the given GstPadTemplate, or NULL if none was found. No unreferencing
1501  * is necessary.
1502  */
1503 GstPadTemplate*
1504 gst_element_get_compatible_pad_template (GstElement *element,
1505                                          GstPadTemplate *compattempl)
1506 {
1507   GstPadTemplate *newtempl = NULL;
1508   GList *padlist;
1509
1510   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
1511
1512   g_return_val_if_fail (element != NULL, NULL);
1513   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1514   g_return_val_if_fail (compattempl != NULL, NULL);
1515
1516   padlist = gst_element_get_pad_template_list (element);
1517
1518   while (padlist) {
1519     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1520     gboolean comp = FALSE;
1521
1522     /* Ignore name
1523      * Ignore presence
1524      * Check direction (must be opposite)
1525      * Check caps
1526      */
1527     GST_CAT_DEBUG (GST_CAT_CAPS, "checking direction and caps");
1528     if (padtempl->direction == GST_PAD_SRC &&
1529       compattempl->direction == GST_PAD_SINK) {
1530       GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
1531       comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1532                                            GST_PAD_TEMPLATE_CAPS (padtempl));
1533       GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1534     } else if (padtempl->direction == GST_PAD_SINK &&
1535                compattempl->direction == GST_PAD_SRC) {
1536       GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
1537       comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1538                                            GST_PAD_TEMPLATE_CAPS (padtempl));
1539       GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1540     }
1541
1542     if (comp) {
1543       newtempl = padtempl;
1544       break;
1545     }
1546
1547     padlist = g_list_next (padlist);
1548   }
1549
1550   return newtempl;
1551 }
1552
1553 /**
1554  * gst_element_request_compatible_pad:
1555  * @element: a #GstElement to request a new pad from.
1556  * @templ: the #GstPadTemplate to which the new pad should be able to link.
1557  *
1558  * Requests a new pad from the element. The template will
1559  * be used to decide what type of pad to create. This function
1560  * is typically used for elements with a padtemplate with presence
1561  * GST_PAD_REQUEST.
1562  *
1563  * Returns: the new #GstPad that was created, or NULL if none could be created.
1564  */
1565 GstPad*
1566 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
1567 {
1568   GstPadTemplate *templ_new;
1569   GstPad *pad = NULL;
1570
1571   g_return_val_if_fail (element != NULL, NULL);
1572   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1573   g_return_val_if_fail (templ != NULL, NULL);
1574
1575   templ_new = gst_element_get_compatible_pad_template (element, templ);
1576   if (templ_new != NULL)
1577       pad = gst_element_request_pad (element, templ_new, NULL);
1578
1579   return pad;
1580 }
1581
1582
1583 /**
1584  * gst_element_get_compatible_pad_filtered:
1585  * @element: a #GstElement in which the pad should be found.
1586  * @pad: the #GstPad to find a compatible one for.
1587  * @filtercaps: the #GstCaps to use as a filter.
1588  *
1589  * Looks for an unlinked pad to which the given pad can link to.
1590  * It is not guaranteed that linking the pads will work, though
1591  * it should work in most cases.
1592  *
1593  * Returns: the #GstPad to which a link can be made.
1594  */
1595 GstPad*
1596 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
1597                                          const GstCaps *filtercaps)
1598 {
1599   const GList *pads;
1600   GstPadTemplate *templ;
1601   GstCaps *templcaps;
1602   GstPad *foundpad = NULL;
1603
1604   /* checks */
1605   g_return_val_if_fail (element != NULL, NULL);
1606   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1607   g_return_val_if_fail (pad != NULL, NULL);
1608   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1609
1610   GST_DEBUG ("finding pad in %s compatible with %s:%s",
1611         GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));    
1612
1613   /* let's use the real pad */
1614   pad = (GstPad *) GST_PAD_REALIZE (pad);
1615   g_return_val_if_fail (pad != NULL, NULL);
1616   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1617
1618   /* try to get an existing unlinked pad */
1619   pads = gst_element_get_pad_list (element);
1620   while (pads) {
1621     GstPad *current = GST_PAD (pads->data);
1622     if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
1623         gst_pad_can_link_filtered (pad, current, filtercaps)) {
1624       return current;
1625     }
1626     pads = g_list_next (pads);
1627   }
1628
1629   /* try to create a new one */
1630   /* requesting is a little crazy, we need a template. Let's create one */
1631   templcaps = gst_pad_get_caps (pad);
1632   if (filtercaps != NULL) {
1633     GstCaps *temp;
1634     temp = gst_caps_intersect (filtercaps, templcaps);
1635     gst_caps_free (templcaps);
1636     templcaps = temp;
1637   }
1638
1639   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
1640       GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
1641   foundpad = gst_element_request_compatible_pad (element, templ);
1642   gst_object_unref (GST_OBJECT (templ));
1643
1644   if (foundpad) return foundpad;
1645
1646   /* FIXME: this is broken, but it's in here so autoplugging elements
1647    * that don't have caps on their source padtemplates (spider) can
1648    * link... */
1649   //g_warning("got here");
1650   //if (filtercaps == NULL) {
1651     templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
1652         GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, gst_caps_new_any());
1653     foundpad = gst_element_request_compatible_pad (element, templ);
1654     gst_object_unref (GST_OBJECT (templ));
1655
1656     if (foundpad) return foundpad;
1657   //}
1658   
1659   GST_DEBUG_OBJECT (element, "Could not find a compatible pad to link to %s:%s",
1660       GST_DEBUG_PAD_NAME (pad));
1661
1662   return NULL;
1663 }
1664
1665 /**
1666  * gst_element_get_compatible_pad:
1667  * @element: a #GstElement in which the pad should be found.
1668  * @pad: the #GstPad to find a compatible one for.
1669  *
1670  * Looks for an unlinked pad to which the given pad can link to.
1671  * It is not guaranteed that linking the pads will work, though
1672  * it should work in most cases.
1673  *
1674  * Returns: the #GstPad to which a link can be made, or NULL if none
1675  * could be found.
1676  */
1677 GstPad*                 
1678 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
1679 {
1680   return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1681 }
1682
1683 /**
1684  * gst_element_link_pads_filtered:
1685  * @src: a #GstElement containing the source pad.
1686  * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
1687  * @dest: the #GstElement containing the destination pad.
1688  * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
1689  * @filtercaps: the #GstCaps to use as a filter.
1690  *
1691  * Links the two named pads of the source and destination elements.
1692  * Side effect is that if one of the pads has no parent, it becomes a
1693  * child of the parent of the other element.  If they have different
1694  * parents, the link fails.
1695  *
1696  * Returns: TRUE if the pads could be linked.
1697  */
1698 gboolean
1699 gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
1700                                 GstElement *dest, const gchar *destpadname,
1701                                 const GstCaps *filtercaps)
1702 {
1703   const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1704   GstPad *srcpad, *destpad;
1705   GstPadTemplate *srctempl, *desttempl;
1706
1707   /* checks */
1708   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1709   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1710
1711   GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "trying to link element %s:%s to element %s:%s",
1712             GST_ELEMENT_NAME (src), srcpadname ? srcpadname : "(any)", 
1713             GST_ELEMENT_NAME (dest), destpadname ? destpadname : "(any)");
1714
1715   /* now get the pads we're trying to link and a list of all remaining pads */
1716   if (srcpadname) {
1717     srcpad = gst_element_get_pad (src, srcpadname);
1718     if (!srcpad) {
1719       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (src), srcpadname);    
1720       return FALSE;
1721     } else {
1722       if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
1723         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad", GST_DEBUG_PAD_NAME (srcpad));    
1724         return FALSE;
1725       }
1726       if (GST_PAD_PEER (srcpad) != NULL) {
1727         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (srcpad));    
1728         return FALSE;
1729       }
1730     }    
1731     srcpads = NULL;
1732   } else {
1733     srcpads = gst_element_get_pad_list (src);
1734     srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
1735   }
1736   if (destpadname) {
1737     destpad = gst_element_get_pad (dest, destpadname);
1738     if (!destpad) {
1739       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (dest), destpadname);    
1740       return FALSE;
1741     } else {
1742       if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
1743         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad", GST_DEBUG_PAD_NAME (destpad));    
1744         return FALSE;
1745       }
1746       if (GST_PAD_PEER (destpad) != NULL) {
1747         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (destpad));    
1748         return FALSE;
1749       }
1750     }
1751     destpads = NULL;
1752   } else {
1753     destpads = gst_element_get_pad_list (dest);
1754     destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
1755   }
1756
1757   if (srcpadname && destpadname) {
1758     /* two explicitly specified pads */
1759     return gst_pad_link_filtered (srcpad, destpad, filtercaps);
1760   }
1761   if (srcpad) {
1762     /* loop through the allowed pads in the source, trying to find a
1763      * compatible destination pad */
1764     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "looping through allowed src and dest pads");
1765     do {
1766       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", 
1767                  GST_DEBUG_PAD_NAME (srcpad));
1768       if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1769           (GST_PAD_PEER (srcpad) == NULL)) {
1770         GstPad *temp = gst_element_get_compatible_pad_filtered (dest, srcpad, 
1771                                                                 filtercaps);
1772         if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) {
1773           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", 
1774                      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
1775           return TRUE;
1776         }
1777       }
1778       /* find a better way for this mess */
1779       if (srcpads) {
1780         srcpads = g_list_next (srcpads);
1781         if (srcpads)
1782           srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1783       }
1784     } while (srcpads);
1785   }
1786   if (srcpadname) {
1787     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s", 
1788                GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
1789     return FALSE;
1790   }
1791   if (destpad) {    
1792     /* loop through the existing pads in the destination */
1793     do {
1794       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s", 
1795                  GST_DEBUG_PAD_NAME (destpad));
1796       if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1797           (GST_PAD_PEER (destpad) == NULL)) {
1798         GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad, 
1799                                                           filtercaps);
1800         if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) {
1801           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", 
1802                      GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
1803           return TRUE;
1804         }
1805       }
1806       if (destpads) {
1807         destpads = g_list_next (destpads);
1808         if (destpads)
1809           destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1810       }
1811     } while (destpads);
1812   }
1813   if (destpadname) {
1814     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s", 
1815                GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
1816     return FALSE;
1817   }
1818
1819   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
1820              "we might have request pads on both sides, checking...");
1821   srctempls = gst_element_get_pad_template_list (src);
1822   desttempls = gst_element_get_pad_template_list (dest);
1823   
1824   if (srctempls && desttempls) {
1825     while (srctempls) {
1826       srctempl = (GstPadTemplate*) srctempls->data;
1827       if (srctempl->presence == GST_PAD_REQUEST) {
1828         for (l=desttempls; l; l=l->next) {
1829           desttempl = (GstPadTemplate*) l->data;
1830           if (desttempl->presence == GST_PAD_REQUEST && 
1831               desttempl->direction != srctempl->direction) {
1832             if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
1833                                               gst_pad_template_get_caps (desttempl))) {
1834               srcpad = gst_element_get_request_pad (src, 
1835                                                     srctempl->name_template);
1836               destpad = gst_element_get_request_pad (dest, 
1837                                                      desttempl->name_template);
1838               if (gst_pad_link_filtered (srcpad, destpad, filtercaps)) {
1839                 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
1840                            "linked pad %s:%s to pad %s:%s",
1841                            GST_DEBUG_PAD_NAME (srcpad), 
1842                            GST_DEBUG_PAD_NAME (destpad));
1843                 return TRUE;
1844               }
1845               /* it failed, so we release the request pads */
1846               gst_element_release_request_pad (src, srcpad);
1847               gst_element_release_request_pad (dest, destpad);
1848             }
1849           }
1850         }
1851       }
1852       srctempls = srctempls->next;
1853     }
1854   }
1855   
1856   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s", 
1857              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1858   return FALSE;  
1859 }
1860 /**
1861  * gst_element_link_filtered:
1862  * @src: a #GstElement containing the source pad.
1863  * @dest: the #GstElement containing the destination pad.
1864  * @filtercaps: the #GstCaps to use as a filter.
1865  *
1866  * Links the source to the destination element using the filtercaps.
1867  * The link must be from source to destination, the other
1868  * direction will not be tried.
1869  * The functions looks for existing pads that aren't linked yet.
1870  * It will use request pads if possible. But both pads will not be requested.
1871  * If multiple links are possible, only one is established.
1872  *
1873  * Returns: TRUE if the elements could be linked.
1874  */
1875 gboolean
1876 gst_element_link_filtered (GstElement *src, GstElement *dest,
1877                               const GstCaps *filtercaps)
1878 {
1879   return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
1880 }
1881
1882 /**
1883  * gst_element_link_many:
1884  * @element_1: the first #GstElement in the link chain.
1885  * @element_2: the second #GstElement in the link chain.
1886  * @...: the NULL-terminated list of elements to link in order.
1887  * 
1888  * Chain together a series of elements. Uses #gst_element_link.
1889  *
1890  * Returns: TRUE on success, FALSE otherwise.
1891  */
1892 gboolean
1893 gst_element_link_many (GstElement *element_1, GstElement *element_2, ...)
1894 {
1895   va_list args;
1896
1897   g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1898   g_return_val_if_fail (GST_IS_ELEMENT (element_1) && 
1899                         GST_IS_ELEMENT (element_2), FALSE);
1900
1901   va_start (args, element_2);
1902
1903   while (element_2) {
1904     if (!gst_element_link (element_1, element_2))
1905       return FALSE;
1906     
1907     element_1 = element_2;
1908     element_2 = va_arg (args, GstElement*);
1909   }
1910
1911   va_end (args);
1912   
1913   return TRUE;
1914 }
1915
1916 /**
1917  * gst_element_link:
1918  * @src: a #GstElement containing the source pad.
1919  * @dest: the #GstElement containing the destination pad.
1920  *
1921  * Links the source to the destination element.
1922  * The link must be from source to destination, the other
1923  * direction will not be tried.
1924  * The functions looks for existing pads and request pads that aren't
1925  * linked yet. If multiple links are possible, only one is
1926  * established.
1927  *
1928  * Returns: TRUE if the elements could be linked.
1929  */
1930 gboolean
1931 gst_element_link (GstElement *src, GstElement *dest)
1932 {
1933   return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
1934 }
1935
1936 /**
1937  * gst_element_link_pads:
1938  * @src: a #GstElement containing the source pad.
1939  * @srcpadname: the name of the #GstPad in the source element.
1940  * @dest: the #GstElement containing the destination pad.
1941  * @destpadname: the name of the #GstPad in destination element.
1942  *
1943  * Links the two named pads of the source and destination elements.
1944  * Side effect is that if one of the pads has no parent, it becomes a
1945  * child of the parent of the other element.  If they have different
1946  * parents, the link fails.
1947  *
1948  * Returns: TRUE if the pads could be linked.
1949  */
1950 gboolean
1951 gst_element_link_pads (GstElement *src, const gchar *srcpadname,
1952                           GstElement *dest, const gchar *destpadname)
1953 {
1954   return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1955 }
1956
1957 /**
1958  * gst_element_unlink_pads:
1959  * @src: a #GstElement containing the source pad.
1960  * @srcpadname: the name of the #GstPad in source element.
1961  * @dest: a #GstElement containing the destination pad.
1962  * @destpadname: the name of the #GstPad in destination element.
1963  *
1964  * Unlinks the two named pads of the source and destination elements.
1965  */
1966 void
1967 gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
1968                              GstElement *dest, const gchar *destpadname)
1969 {
1970   GstPad *srcpad,*destpad;
1971
1972   g_return_if_fail (src != NULL);
1973   g_return_if_fail (GST_IS_ELEMENT(src));
1974   g_return_if_fail (srcpadname != NULL);
1975   g_return_if_fail (dest != NULL);
1976   g_return_if_fail (GST_IS_ELEMENT(dest));
1977   g_return_if_fail (destpadname != NULL);
1978
1979   /* obtain the pads requested */
1980   srcpad = gst_element_get_pad (src, srcpadname);
1981   if (srcpad == NULL) {
1982     GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
1983     return;
1984   }
1985   destpad = gst_element_get_pad (dest, destpadname);
1986   if (srcpad == NULL) {
1987     GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"", destpadname);
1988     return;
1989   }
1990
1991   /* we're satisified they can be unlinked, let's do it */
1992   gst_pad_unlink (srcpad,destpad);
1993 }
1994
1995 /**
1996  * gst_element_unlink_many:
1997  * @element_1: the first #GstElement in the link chain.
1998  * @element_2: the second #GstElement in the link chain.
1999  * @...: the NULL-terminated list of elements to unlink in order.
2000  * 
2001  * Unlinks a series of elements. Uses #gst_element_unlink.
2002  */
2003 void
2004 gst_element_unlink_many (GstElement *element_1, GstElement *element_2, ...)
2005 {
2006   va_list args;
2007
2008   g_return_if_fail (element_1 != NULL && element_2 != NULL);
2009   g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
2010
2011   va_start (args, element_2);
2012
2013   while (element_2) {
2014     gst_element_unlink (element_1, element_2);
2015     
2016     element_1 = element_2;
2017     element_2 = va_arg (args, GstElement*);
2018   }
2019
2020   va_end (args);
2021 }
2022
2023 /**
2024  * gst_element_unlink:
2025  * @src: the source #GstElement to unlink.
2026  * @dest: the sink #GstElement to unlink.
2027  *
2028  * Unlinks all source pads of the source element with all sink pads
2029  * of the sink element to which they are linked.
2030  */
2031 void
2032 gst_element_unlink (GstElement *src, GstElement *dest)
2033 {
2034   const GList *srcpads;
2035   GstPad *pad;
2036
2037   g_return_if_fail (GST_IS_ELEMENT (src));
2038   g_return_if_fail (GST_IS_ELEMENT (dest));
2039
2040   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
2041              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
2042
2043   srcpads = gst_element_get_pad_list (src);
2044
2045   while (srcpads) {
2046     pad = GST_PAD (srcpads->data);
2047
2048     /* we only care about real src pads */
2049     if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
2050       GstPad *peerpad = GST_PAD_PEER (pad);
2051
2052       /* see if the pad is connected and is really a pad
2053        * of dest */
2054       if (peerpad && 
2055           (GST_OBJECT_PARENT (peerpad) == (GstObject*) dest)) 
2056       {
2057         gst_pad_unlink (pad, peerpad);
2058       }
2059     }
2060
2061     srcpads = g_list_next (srcpads);
2062   }
2063 }
2064
2065 static void
2066 gst_element_error_func (GstElement* element, GstElement *source,
2067                         GError *error, gchar *debug)
2068 {
2069   /* tell the parent */
2070   if (GST_OBJECT_PARENT (element)) {
2071     GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM, "forwarding error \"%s\" from %s to %s",
2072                    error->message, GST_ELEMENT_NAME (element),
2073                    GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
2074
2075     gst_object_ref (GST_OBJECT (element));
2076     g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)),
2077                    gst_element_signals[ERROR], 0, source, error, debug);
2078     gst_object_unref (GST_OBJECT (element));
2079     GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM, "forwarded error \"%s\" from %s to %s", 
2080                error->message, GST_ELEMENT_NAME (element), 
2081                GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
2082   }
2083 }
2084
2085 static GstPad*
2086 gst_element_get_random_pad (GstElement *element, GstPadDirection dir)
2087 {
2088   GList *pads = element->pads;
2089   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
2090   while (pads) {
2091     GstPad *pad = GST_PAD (pads->data);
2092
2093     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
2094                GST_DEBUG_PAD_NAME (pad));
2095
2096     if (GST_PAD_DIRECTION (pad) == dir) {
2097       if (GST_PAD_IS_LINKED (pad)) {
2098         return pad;
2099       }
2100       else {
2101         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
2102                    GST_DEBUG_PAD_NAME (pad));
2103       }
2104     }
2105     else {
2106       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
2107                  GST_DEBUG_PAD_NAME (pad));
2108     }
2109
2110     pads = g_list_next (pads);
2111   }
2112   return NULL;
2113 }
2114
2115 /**
2116  * gst_element_get_event_masks:
2117  * @element: a #GstElement to query
2118  *
2119  * Get an array of event masks from the element.
2120  * If the element doesn't 
2121  * implement an event masks function, the query will be forwarded
2122  * to a random linked sink pad.
2123  * 
2124  * Returns: An array of #GstEventMask elements.
2125  */
2126 const GstEventMask*
2127 gst_element_get_event_masks (GstElement *element)
2128 {
2129   GstElementClass *oclass;
2130
2131   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2132   
2133   oclass = GST_ELEMENT_GET_CLASS (element);
2134
2135   if (oclass->get_event_masks)
2136     return oclass->get_event_masks (element);
2137   else {
2138     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2139     if (pad)
2140       return gst_pad_get_event_masks (GST_PAD_PEER (pad));
2141   }
2142
2143   return FALSE;
2144 }
2145
2146 /**
2147  * gst_element_send_event:
2148  * @element: a #GstElement to send the event to.
2149  * @event: the #GstEvent to send to the element.
2150  *
2151  * Sends an event to an element. If the element doesn't
2152  * implement an event handler, the event will be forwarded
2153  * to a random sink pad.
2154  *
2155  * Returns: TRUE if the event was handled.
2156  */
2157 gboolean
2158 gst_element_send_event (GstElement *element, GstEvent *event)
2159 {
2160   GstElementClass *oclass;
2161
2162   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2163   g_return_val_if_fail (event != NULL, FALSE);
2164   
2165   oclass = GST_ELEMENT_GET_CLASS (element);
2166
2167   if (oclass->send_event)
2168     return oclass->send_event (element, event);
2169   else {
2170     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2171     if (pad) {
2172       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
2173                  GST_DEBUG_PAD_NAME (pad));
2174       return gst_pad_send_event (GST_PAD_PEER (pad), event);
2175     }
2176   }
2177   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
2178              GST_ELEMENT_NAME (element));
2179   return FALSE;
2180 }
2181
2182 /**
2183  * gst_element_seek:
2184  * @element: a #GstElement to send the event to.
2185  * @seek_type: the method to use for seeking.
2186  * @offset: the offset to seek to.
2187  *
2188  * Sends a seek event to an element.
2189  *
2190  * Returns: TRUE if the event was handled.
2191  */
2192 gboolean
2193 gst_element_seek (GstElement  *element,
2194                   GstSeekType  seek_type,
2195                   guint64      offset)
2196 {
2197   GstEvent *event = gst_event_new_seek (seek_type, offset);
2198
2199   return gst_element_send_event (element, event);
2200 }
2201
2202 /**
2203  * gst_element_get_query_types:
2204  * @element: a #GstElement to query
2205  *
2206  * Get an array of query types from the element.
2207  * If the element doesn't 
2208  * implement a query types function, the query will be forwarded
2209  * to a random sink pad.
2210  * 
2211  * Returns: An array of #GstQueryType elements.
2212  */
2213 const GstQueryType*
2214 gst_element_get_query_types (GstElement *element)
2215 {
2216   GstElementClass *oclass;
2217
2218   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2219   
2220   oclass = GST_ELEMENT_GET_CLASS (element);
2221
2222   if (oclass->get_query_types)
2223     return oclass->get_query_types (element);
2224   else {
2225     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2226     if (pad)
2227       return gst_pad_get_query_types (GST_PAD_PEER (pad));
2228   }
2229
2230   return FALSE;
2231 }
2232
2233 /**
2234  * gst_element_query:
2235  * @element: a #GstElement to perform the query on.
2236  * @type: the #GstQueryType.
2237  * @format: the #GstFormat pointer to hold the format of the result.
2238  * @value: the pointer to the value of the result.
2239  *
2240  * Performs a query on the given element. If the format is set
2241  * to GST_FORMAT_DEFAULT and this function returns TRUE, the 
2242  * format pointer will hold the default format.
2243  * For element that don't implement a query handler, this function
2244  * forwards the query to a random usable sinkpad of this element.
2245  * 
2246  * Returns: TRUE if the query could be performed.
2247  */
2248 gboolean
2249 gst_element_query (GstElement *element, GstQueryType type,
2250                    GstFormat *format, gint64 *value)
2251 {
2252   GstElementClass *oclass;
2253
2254   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2255   g_return_val_if_fail (format != NULL, FALSE);
2256   g_return_val_if_fail (value != NULL, FALSE);
2257
2258   oclass = GST_ELEMENT_GET_CLASS (element);
2259   
2260   if (oclass->query)
2261     return oclass->query (element, type, format, value);
2262   else {
2263     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC);
2264     if (pad)
2265       return gst_pad_query (pad, type, format, value);
2266     pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2267     if (pad)
2268       return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
2269   }
2270
2271   return FALSE;
2272 }
2273
2274 /**
2275  * gst_element_get_formats:
2276  * @element: a #GstElement to query
2277  *
2278  * Get an array of formst from the element.
2279  * If the element doesn't 
2280  * implement a formats function, the query will be forwarded
2281  * to a random sink pad.
2282  * 
2283  * Returns: An array of #GstFormat elements.
2284  */
2285 const GstFormat*
2286 gst_element_get_formats (GstElement *element)
2287 {
2288   GstElementClass *oclass;
2289
2290   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2291   
2292   oclass = GST_ELEMENT_GET_CLASS (element);
2293
2294   if (oclass->get_formats)
2295     return oclass->get_formats (element);
2296   else {
2297     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2298     if (pad)
2299       return gst_pad_get_formats (GST_PAD_PEER (pad));
2300   }
2301
2302   return FALSE;
2303 }
2304
2305 /**
2306  * gst_element_convert:
2307  * @element: a #GstElement to invoke the converter on.
2308  * @src_format: the source #GstFormat.
2309  * @src_value: the source value.
2310  * @dest_format: a pointer to the destination #GstFormat.
2311  * @dest_value: a pointer to the destination value.
2312  *
2313  * Invokes a conversion on the element.
2314  * If the element doesn't 
2315  * implement a convert function, the query will be forwarded
2316  * to a random sink pad.
2317  *
2318  * Returns: TRUE if the conversion could be performed.
2319  */
2320 gboolean
2321 gst_element_convert (GstElement *element,
2322                      GstFormat  src_format,  gint64  src_value,
2323                      GstFormat *dest_format, gint64 *dest_value)
2324 {
2325   GstElementClass *oclass;
2326
2327   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2328   g_return_val_if_fail (dest_format != NULL, FALSE);
2329   g_return_val_if_fail (dest_value != NULL, FALSE);
2330
2331   if (src_format == *dest_format) {
2332     *dest_value = src_value;
2333     return TRUE;
2334   }
2335
2336   oclass = GST_ELEMENT_GET_CLASS (element);
2337
2338   if (oclass->convert)
2339     return oclass->convert (element,
2340                             src_format, src_value, 
2341                             dest_format, dest_value);
2342   else {
2343     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2344     if (pad)
2345       return gst_pad_convert (GST_PAD_PEER (pad), 
2346                               src_format, src_value, 
2347                               dest_format, dest_value);
2348   }
2349
2350   return FALSE;
2351 }
2352
2353 /**
2354  * _gst_element_error_printf:
2355  * @format: the printf-like format to use, or NULL
2356  *
2357  * This function is only used internally by the #gst_element_error macro.
2358  *
2359  * Returns: a newly allocated string, or NULL if the format was NULL or ""
2360  */
2361 gchar *
2362 _gst_element_error_printf (const gchar *format, ...)
2363 {
2364   va_list args;
2365   gchar *buffer;
2366
2367   if (format == NULL) return NULL;
2368   if (format[0] == 0) return NULL;
2369
2370   va_start (args, format);
2371   buffer = g_strdup_vprintf (format, args);
2372   va_end (args);
2373   return buffer;
2374 }
2375
2376 /**
2377  * gst_element_error_full:
2378  * @element: a #GstElement with the error.
2379  * @domain: the GStreamer error domain this error belongs to.
2380  * @code: the error code belonging to the domain
2381  * @message: an allocated message to be used as a replacement for the default
2382  *           message connected to code, or NULL
2383  * debug: an allocated debug message to be used as a replacement for the
2384  *        default debugging information, or NULL
2385  *
2386  * Signals an error condition on an element.
2387  * This function is used internally by elements.
2388  * It results in the "error" signal.
2389  */
2390 void
2391 gst_element_error_full
2392 (GstElement *element, GQuark domain, gint code, gchar *message, gchar *debug,
2393  const gchar *file, const gchar *function, gint line)
2394 {
2395   GError *error = NULL;
2396   gchar *sent_message;
2397   gchar *sent_debug;
2398
2399   /* checks */
2400   g_return_if_fail (GST_IS_ELEMENT (element));
2401
2402   /* check if we send the given message or the default error message */
2403   if ((message == NULL) || (message[0] == 0))
2404   {
2405     /* we got this message from g_strdup_printf (""); */
2406     g_free (message);
2407     sent_message = gst_error_get_message (domain, code);
2408   }
2409   else
2410     sent_message = message;
2411
2412   if ((debug == NULL) || (debug[0] == 0))
2413   {
2414     /* we got this debug from g_strdup_printf (""); */
2415     g_free (debug);
2416     debug = NULL;
2417   }
2418  
2419   /* create error message */
2420   GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signaling error in %s: %s",
2421                 GST_ELEMENT_NAME (element),
2422                 sent_message);
2423   error = g_error_new (domain, code, sent_message);
2424
2425   /* if the element was already in error, stop now */
2426   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IN_ERROR)) {
2427     GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "recursive ERROR detected in %s",
2428                   GST_ELEMENT_NAME (element));
2429     g_free (sent_message);
2430     if (debug) g_free (debug);
2431     return;
2432   }
2433
2434   GST_FLAG_SET (element, GST_ELEMENT_IN_ERROR);
2435
2436   /* emit the signal, make sure the element stays available */
2437   gst_object_ref (GST_OBJECT (element));
2438   if (debug)
2439     sent_debug = g_strdup_printf ("%s(%d):%s:\n%s",
2440                                   file, line, function,
2441                                   debug ? debug : "");
2442   else
2443     sent_debug = NULL;
2444   g_free (debug);
2445   g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element,
2446                  error, sent_debug);
2447   GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signalled error in %s: %s",
2448                 GST_ELEMENT_NAME (element),
2449                 sent_message);
2450
2451  /* tell the scheduler */
2452   if (element->sched) {
2453     gst_scheduler_error (element->sched, element);
2454   }
2455
2456   if (GST_STATE (element) == GST_STATE_PLAYING) {
2457     GstElementStateReturn ret;
2458
2459     ret = gst_element_set_state (element, GST_STATE_PAUSED);
2460     if (ret != GST_STATE_SUCCESS) {
2461       g_warning ("could not PAUSE element \"%s\" after error, help!",
2462                  GST_ELEMENT_NAME (element));
2463     }
2464   }
2465
2466   GST_FLAG_UNSET (element, GST_ELEMENT_IN_ERROR);
2467
2468   /* cleanup */
2469   gst_object_unref (GST_OBJECT (element));
2470   g_free (sent_message);
2471   g_free (sent_debug);
2472   g_error_free (error);
2473 }
2474
2475 /**
2476  * gst_element_is_locked_state:
2477  * @element: a #GstElement.
2478  *
2479  * Checks if the state of an element is locked.
2480  * If the state of an element is locked, state changes of the parent don't 
2481  * affect the element.
2482  * This way you can leave currently unused elements inside bins. Just lock their
2483  * state before changing the state from #GST_STATE_NULL.
2484  *
2485  * Returns: TRUE, if the element's state is locked.
2486  */
2487 gboolean
2488 gst_element_is_locked_state (GstElement *element)
2489 {
2490   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2491
2492   return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE;
2493 }
2494 /**
2495  * gst_element_set_locked_state:
2496  * @element: a #GstElement
2497  * @locked_state: TRUE to lock the element's state
2498  *
2499  * Locks the state of an element, so state changes of the parent don't affect
2500  * this element anymore.
2501  */
2502 void
2503 gst_element_set_locked_state (GstElement *element, gboolean locked_state)
2504 {
2505   gboolean old;
2506
2507   g_return_if_fail (GST_IS_ELEMENT (element));
2508
2509   old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
2510
2511   if (old == locked_state)
2512     return;
2513
2514   if (locked_state) {
2515     GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s", 
2516                GST_ELEMENT_NAME (element));
2517     GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE);
2518   } else {
2519     GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s", 
2520                GST_ELEMENT_NAME (element));
2521     GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
2522   }
2523 }
2524 /**
2525  * gst_element_sync_state_with_parent:
2526  * @element: a #GstElement.
2527  *
2528  * Tries to change the state of the element to the same as its parent.
2529  * If this function returns FALSE, the state of element is undefined.
2530  *
2531  * Returns: TRUE, if the element's state could be synced to the parent's state.
2532  */
2533 gboolean
2534 gst_element_sync_state_with_parent (GstElement *element)
2535 {
2536   GstElement *parent;
2537
2538   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2539   parent = GST_ELEMENT (GST_ELEMENT_PARENT(element));
2540   g_return_val_if_fail (GST_IS_BIN (parent), FALSE);
2541   
2542   GST_CAT_DEBUG (GST_CAT_STATES, "syncing state of element %s (%s) to %s (%s)", 
2543              GST_ELEMENT_NAME (element), gst_element_state_get_name (GST_STATE (element)),
2544              GST_ELEMENT_NAME (parent), gst_element_state_get_name (GST_STATE (parent)));
2545   if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
2546     return FALSE;
2547   }
2548   return TRUE;
2549 }
2550 /**
2551  * gst_element_get_state:
2552  * @element: a #GstElement to get the state of.
2553  *
2554  * Gets the state of the element. 
2555  *
2556  * Returns: the #GstElementState of the element.
2557  */
2558 GstElementState
2559 gst_element_get_state (GstElement *element)
2560 {
2561   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2562
2563   return GST_STATE (element);
2564 }
2565
2566 /**
2567  * gst_element_wait_state_change:
2568  * @element: a #GstElement to wait for a state change on.
2569  *
2570  * Waits and blocks until the element changed its state.
2571  */
2572 void
2573 gst_element_wait_state_change (GstElement *element)
2574 {
2575   g_mutex_lock (element->state_mutex);
2576   g_cond_wait (element->state_cond, element->state_mutex);
2577   g_mutex_unlock (element->state_mutex);
2578 }
2579
2580 /**
2581  * gst_element_set_state:
2582  * @element: a #GstElement to change state of.
2583  * @state: the element's new #GstElementState.
2584  *
2585  * Sets the state of the element. This function will try to set the
2586  * requested state by going through all the intermediary states and calling
2587  * the class's state change function for each.
2588  *
2589  * Returns: TRUE if the state was successfully set.
2590  * (using #GstElementStateReturn).
2591  */
2592 GstElementStateReturn
2593 gst_element_set_state (GstElement *element, GstElementState state)
2594 {
2595   GstElementClass *oclass;
2596   GstElementState curpending;
2597   GstElementStateReturn return_val = GST_STATE_SUCCESS;
2598
2599   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2600
2601   /* start with the current state */
2602   curpending = GST_STATE(element);
2603
2604   if (state == curpending)
2605   {
2606     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2607                        "element is already in requested state %s",
2608                        gst_element_state_get_name (state));
2609     return (GST_STATE_SUCCESS);
2610   }
2611
2612   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s",
2613                      gst_element_state_get_name (curpending),
2614                      gst_element_state_get_name (state));
2615
2616   /* loop until the final requested state is set */
2617   while (GST_STATE (element) != state 
2618       && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2619     /* move the curpending state in the correct direction */
2620     if (curpending < state) 
2621       curpending <<= 1;
2622     else 
2623       curpending >>= 1;
2624
2625     /* set the pending state variable */
2626     /* FIXME: should probably check to see that we don't already have one */
2627     GST_STATE_PENDING (element) = curpending;
2628
2629     if (curpending != state) {
2630       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
2631                          "intermediate: setting state from %s to %s",
2632                          gst_element_state_get_name (GST_STATE (element)),
2633                          gst_element_state_get_name (curpending));
2634     }
2635
2636     /* call the state change function so it can set the state */
2637     oclass = GST_ELEMENT_GET_CLASS (element);
2638     if (oclass->change_state)
2639       return_val = (oclass->change_state) (element);
2640
2641     switch (return_val) {
2642       case GST_STATE_FAILURE:
2643         GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
2644                            "have failed change_state return");
2645         goto exit;
2646       case GST_STATE_ASYNC:
2647         GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
2648                            "element will change state async");
2649         goto exit;
2650       case GST_STATE_SUCCESS:
2651         /* Last thing we do is verify that a successful state change really
2652          * did change the state... */
2653         /* if it did not, this is an error - fix the element that does this */
2654         if (GST_STATE (element) != curpending) {
2655           g_warning ("element %s claimed state-change success,"
2656                      "but state didn't change to %s. State is %s (%s pending), fix the element",
2657                      GST_ELEMENT_NAME (element),
2658                      gst_element_state_get_name (curpending),
2659                      gst_element_state_get_name (GST_STATE (element)),
2660                      gst_element_state_get_name (GST_STATE_PENDING (element)));
2661           return_val = GST_STATE_FAILURE;
2662           goto exit;
2663         }
2664         break;
2665       default:
2666         /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2667         g_assert_not_reached ();
2668     }
2669   }
2670 exit:
2671
2672   return return_val;
2673 }
2674
2675 static gboolean
2676 gst_element_negotiate_pads (GstElement *element)
2677 {
2678   GList *pads = GST_ELEMENT_PADS (element);
2679
2680   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "negotiating pads");
2681
2682   while (pads) {
2683     GstPad *pad = GST_PAD (pads->data);
2684     GstRealPad *srcpad;
2685
2686     pads = g_list_next (pads);
2687     
2688     if (!GST_IS_REAL_PAD (pad))
2689       continue;
2690
2691     srcpad = GST_PAD_REALIZE (pad);
2692
2693     /* if we have a link on this pad and it doesn't have caps
2694      * allready, try to negotiate */
2695     if (GST_PAD_IS_LINKED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2696       GstRealPad *sinkpad;
2697       GstElementState otherstate;
2698       GstElement *parent;
2699       
2700       sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2701
2702       /* check the parent of the peer pad, if there is no parent do nothing */
2703       parent = GST_PAD_PARENT (sinkpad);
2704       if (!parent) 
2705         continue;
2706
2707       /* skips pads that were already negotiating */
2708       if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
2709           GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
2710         continue;
2711
2712       otherstate = GST_STATE (parent);
2713
2714       /* swap pads if needed */
2715       if (!GST_PAD_IS_SRC (srcpad)) {
2716         GstRealPad *temp;
2717
2718         temp = srcpad;
2719         srcpad = sinkpad;
2720         sinkpad = temp;
2721       }
2722
2723       /* only try to negotiate if the peer element is in PAUSED or higher too */
2724       if (otherstate >= GST_STATE_READY) {
2725         GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, 
2726                            "perform negotiate for %s:%s and %s:%s",
2727                            GST_DEBUG_PAD_NAME (srcpad), 
2728                            GST_DEBUG_PAD_NAME (sinkpad));
2729         if (gst_pad_renegotiate (pad) == GST_PAD_LINK_REFUSED)
2730           return FALSE;
2731       }
2732       else {
2733         GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, 
2734                            "not negotiating %s:%s and %s:%s, not in READY yet",
2735                            GST_DEBUG_PAD_NAME (srcpad), 
2736                            GST_DEBUG_PAD_NAME (sinkpad));
2737       }
2738     }
2739   }
2740
2741   return TRUE;
2742 }
2743
2744 static void
2745 gst_element_clear_pad_caps (GstElement *element)
2746 {
2747   GList *pads = GST_ELEMENT_PADS (element);
2748
2749   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "clearing pad caps");
2750
2751   while (pads) {
2752     GstPad *pad = GST_PAD (pads->data);
2753
2754     gst_pad_unnegotiate (pad);
2755
2756     pads = g_list_next (pads);
2757   }
2758 }
2759
2760 static void
2761 gst_element_pads_activate (GstElement *element, gboolean active)
2762 {
2763   GList *pads = element->pads;
2764
2765   while (pads) {
2766     GstPad *pad = GST_PAD (pads->data);
2767     pads = g_list_next (pads);
2768
2769     if (!GST_IS_REAL_PAD (pad))
2770       continue;
2771
2772     gst_pad_set_active (pad, active);
2773   }
2774 }
2775
2776 static GstElementStateReturn
2777 gst_element_change_state (GstElement *element)
2778 {
2779   GstElementState old_state;
2780   GstObject *parent;
2781   gint old_pending, old_transition;
2782
2783   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2784
2785   old_state = GST_STATE (element);
2786   old_pending = GST_STATE_PENDING (element);
2787   old_transition = GST_STATE_TRANSITION (element);
2788
2789   if (old_pending == GST_STATE_VOID_PENDING || 
2790       old_state == GST_STATE_PENDING (element)) {
2791     GST_CAT_INFO (GST_CAT_STATES, 
2792               "no state change needed for element %s (VOID_PENDING)", 
2793               GST_ELEMENT_NAME (element));
2794     return GST_STATE_SUCCESS;
2795   }
2796   
2797   GST_CAT_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x", 
2798             GST_ELEMENT_NAME (element),
2799             gst_element_state_get_name (old_state),
2800             gst_element_state_get_name (old_pending),
2801             old_transition);
2802
2803   /* we set the state change early for the negotiation functions */
2804   GST_STATE (element) = old_pending;
2805   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2806
2807   switch (old_transition) {
2808     case GST_STATE_PLAYING_TO_PAUSED:
2809       if (element->clock) {
2810         GstClockTime time = gst_clock_get_event_time (element->clock);
2811         g_assert (time >= element->base_time);
2812         element->base_time = time - element->base_time;
2813         GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
2814             G_GINT64_FORMAT, element->base_time);
2815       }
2816       gst_element_pads_activate (element, FALSE);
2817       break;
2818     case GST_STATE_PAUSED_TO_PLAYING:
2819       gst_element_pads_activate (element, TRUE);
2820       if (element->clock) {
2821         GstClockTime time = gst_clock_get_event_time (element->clock);
2822         element->base_time = time - element->base_time;
2823         GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
2824             G_GINT64_FORMAT, element->base_time);
2825       }
2826       break;
2827     /* if we are going to paused, we try to negotiate the pads */
2828     case GST_STATE_READY_TO_PAUSED:
2829       g_assert (element->base_time == 0);
2830       if (!gst_element_negotiate_pads (element)) 
2831         goto failure;
2832       break;
2833     /* going to the READY state clears all pad caps */
2834     /* FIXME: Why doesn't this happen on READY => NULL? -- Company */
2835     case GST_STATE_PAUSED_TO_READY:
2836       element->base_time = 0;
2837       gst_element_clear_pad_caps (element);
2838       break;
2839     default:
2840       break;
2841   }
2842
2843   parent = GST_ELEMENT_PARENT (element);
2844
2845   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2846                      "signaling state change from %s to %s",
2847                      gst_element_state_get_name (old_state),
2848                      gst_element_state_get_name (GST_STATE (element)));
2849
2850   /* tell the scheduler if we have one */
2851   if (element->sched) {
2852     if (gst_scheduler_state_transition (element->sched, element, 
2853                                         old_transition) != GST_STATE_SUCCESS) {
2854       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
2855                          "scheduler could not change state");
2856       goto failure;
2857     }
2858   }
2859
2860   /* tell our parent about the state change */
2861   if (parent && GST_IS_BIN (parent)) {
2862     gst_bin_child_state_change (GST_BIN (parent), old_state, 
2863                                 GST_STATE (element), element);
2864   }
2865   /* at this point the state of the element could have changed again */
2866
2867   g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2868                  0, old_state, GST_STATE (element));
2869
2870   /* signal the state change in case somebody is waiting for us */
2871   g_mutex_lock (element->state_mutex);
2872   g_cond_signal (element->state_cond);
2873   g_mutex_unlock (element->state_mutex);
2874
2875   return GST_STATE_SUCCESS;
2876
2877 failure:
2878   /* undo the state change */
2879   GST_STATE (element) = old_state;
2880   GST_STATE_PENDING (element) = old_pending;
2881
2882   return GST_STATE_FAILURE;
2883 }
2884
2885 /**
2886  * gst_element_get_factory:
2887  * @element: a #GstElement to request the element factory of.
2888  *
2889  * Retrieves the factory that was used to create this element.
2890  *
2891  * Returns: the #GstElementFactory used for creating this element.
2892  */
2893 GstElementFactory*
2894 gst_element_get_factory (GstElement *element)
2895 {
2896   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2897                                                                                 
2898   return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2899 }
2900
2901 static void
2902 gst_element_dispose (GObject *object)
2903 {
2904   GstElement *element = GST_ELEMENT (object);
2905   GList *pads;
2906   GstPad *pad;
2907
2908   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
2909
2910   gst_element_set_state (element, GST_STATE_NULL);
2911
2912   /* first we break all our links with the ouside */
2913   if (element->pads) {
2914     GList *orig;
2915     orig = pads = g_list_copy (element->pads);
2916     while (pads) {
2917       pad = GST_PAD (pads->data);
2918
2919       if (GST_PAD_PEER (pad)) {
2920         GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "unlinking pad '%s'",
2921                    GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2922         gst_pad_unlink (pad, GST_PAD (GST_PAD_PEER (pad)));
2923       }
2924       gst_element_remove_pad (element, pad);
2925
2926       pads = g_list_next (pads);
2927     }
2928     g_list_free (orig);
2929     g_list_free (element->pads);
2930     element->pads = NULL;
2931   }
2932
2933   element->numsrcpads = 0;
2934   element->numsinkpads = 0;
2935   element->numpads = 0;
2936   g_mutex_free (element->state_mutex);
2937   g_cond_free (element->state_cond);
2938
2939   if (element->prop_value_queue)
2940     g_async_queue_unref (element->prop_value_queue);
2941   element->prop_value_queue = NULL;
2942   if (element->property_mutex)
2943     g_mutex_free (element->property_mutex);
2944
2945   gst_object_replace ((GstObject **)&element->sched, NULL);
2946   gst_object_replace ((GstObject **)&element->clock, NULL);
2947
2948   G_OBJECT_CLASS (parent_class)->dispose (object);
2949 }
2950
2951 #ifndef GST_DISABLE_LOADSAVE
2952 /**
2953  * gst_element_save_thyself:
2954  * @element: a #GstElement to save.
2955  * @parent: the xml parent node.
2956  *
2957  * Saves the element as part of the given XML structure.
2958  *
2959  * Returns: the new #xmlNodePtr.
2960  */
2961 static xmlNodePtr
2962 gst_element_save_thyself (GstObject *object,
2963                           xmlNodePtr parent)
2964 {
2965   GList *pads;
2966   GstElementClass *oclass;
2967   GParamSpec **specs, *spec;
2968   gint nspecs, i;
2969   GValue value = { 0, };
2970   GstElement *element;
2971
2972   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2973
2974   element = GST_ELEMENT (object);
2975
2976   oclass = GST_ELEMENT_GET_CLASS (element);
2977
2978   xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2979
2980   if (oclass->elementfactory != NULL) {
2981     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2982
2983     xmlNewChild (parent, NULL, "type",
2984                  GST_PLUGIN_FEATURE (factory)->name);
2985   }
2986
2987 /* FIXME: what is this? */  
2988 /*  if (element->manager) */
2989 /*    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2990
2991   /* params */
2992   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2993   
2994   for (i=0; i<nspecs; i++) {
2995     spec = specs[i];
2996     if (spec->flags & G_PARAM_READABLE) {
2997       xmlNodePtr param;
2998       char *contents;
2999       
3000       g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
3001       
3002       g_object_get_property (G_OBJECT (element), spec->name, &value);
3003       param = xmlNewChild (parent, NULL, "param", NULL);
3004       xmlNewChild (param, NULL, "name", spec->name);
3005       
3006       if (G_IS_PARAM_SPEC_STRING (spec))
3007         contents = g_value_dup_string (&value);
3008       else if (G_IS_PARAM_SPEC_ENUM (spec))
3009         contents = g_strdup_printf ("%d", g_value_get_enum (&value));
3010       else if (G_IS_PARAM_SPEC_INT64 (spec))
3011         contents = g_strdup_printf ("%" G_GINT64_FORMAT,
3012                                     g_value_get_int64 (&value));
3013       else
3014         contents = g_strdup_value_contents (&value);
3015       
3016       xmlNewChild (param, NULL, "value", contents);
3017       g_free (contents);
3018       
3019       g_value_unset(&value);
3020     }
3021   }
3022
3023   pads = GST_ELEMENT_PADS (element);
3024
3025   while (pads) {
3026     GstPad *pad = GST_PAD (pads->data);
3027     /* figure out if it's a direct pad or a ghostpad */
3028     if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
3029       xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
3030       gst_object_save_thyself (GST_OBJECT (pad), padtag);
3031     }
3032     pads = g_list_next (pads);
3033   }
3034
3035   return parent;
3036 }
3037
3038 static void
3039 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
3040 {
3041   xmlNodePtr children;
3042   GstElement *element;
3043   gchar *name = NULL;
3044   gchar *value = NULL;
3045
3046   element = GST_ELEMENT (object);
3047   g_return_if_fail (element != NULL);
3048
3049   /* parameters */
3050   children = self->xmlChildrenNode;
3051   while (children) {
3052     if (!strcmp (children->name, "param")) {
3053       xmlNodePtr child = children->xmlChildrenNode;
3054
3055       while (child) {
3056         if (!strcmp (child->name, "name")) {
3057           name = xmlNodeGetContent (child);
3058         }
3059         else if (!strcmp (child->name, "value")) {
3060           value = xmlNodeGetContent (child);
3061         }
3062         child = child->next;
3063       }
3064       /* FIXME: can this just be g_object_set ? */
3065       gst_util_set_object_arg (G_OBJECT (element), name, value);
3066       /* g_object_set (G_OBJECT (element), name, value, NULL); */
3067     }
3068     children = children->next;
3069   }
3070   
3071   /* pads */
3072   children = self->xmlChildrenNode;
3073   while (children) {
3074     if (!strcmp (children->name, "pad")) {
3075       gst_pad_load_and_link (children, GST_OBJECT (element));
3076     }
3077     children = children->next;
3078   }
3079
3080   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
3081     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
3082 }
3083 #endif /* GST_DISABLE_LOADSAVE */
3084
3085 /**
3086  * gst_element_yield:
3087  * @element: a #GstElement to yield.
3088  *
3089  * Requests a yield operation for the element. The scheduler will typically
3090  * give control to another element.
3091  */
3092 void
3093 gst_element_yield (GstElement *element)
3094 {
3095   if (GST_ELEMENT_SCHED (element)) {
3096     gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
3097   }
3098 }
3099
3100 /**
3101  * gst_element_interrupt:
3102  * @element: a #GstElement to interrupt.
3103  *
3104  * Requests the scheduler of this element to interrupt the execution of
3105  * this element and scheduler another one.
3106  *
3107  * Returns: TRUE if the element should exit its chain/loop/get
3108  * function ASAP, depending on the scheduler implementation.
3109  */
3110 gboolean
3111 gst_element_interrupt (GstElement *element)
3112 {
3113   if (GST_ELEMENT_SCHED (element)) {
3114     return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
3115   }
3116   else 
3117     return TRUE;
3118 }
3119
3120 /**
3121  * gst_element_set_scheduler:
3122  * @element: a #GstElement to set the scheduler of.
3123  * @sched: the #GstScheduler to set.
3124  *
3125  * Sets the scheduler of the element.  For internal use only, unless you're
3126  * writing a new bin subclass.
3127  */
3128 void
3129 gst_element_set_scheduler (GstElement *element,
3130                        GstScheduler *sched)
3131 {
3132   g_return_if_fail (GST_IS_ELEMENT (element));
3133   
3134   GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
3135
3136   gst_object_replace ((GstObject **)&GST_ELEMENT_SCHED (element), GST_OBJECT (sched));
3137 }
3138
3139 /**
3140  * gst_element_get_scheduler:
3141  * @element: a #GstElement to get the scheduler of.
3142  *
3143  * Returns the scheduler of the element.
3144  *
3145  * Returns: the element's #GstScheduler.
3146  */
3147 GstScheduler*
3148 gst_element_get_scheduler (GstElement *element)
3149 {
3150   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
3151
3152   return GST_ELEMENT_SCHED (element);
3153 }
3154
3155 /**
3156  * gst_element_set_loop_function:
3157  * @element: a #GstElement to set the loop function of.
3158  * @loop: Pointer to #GstElementLoopFunction.
3159  *
3160  * This sets the loop function for the element.  The function pointed to
3161  * can deviate from the GstElementLoopFunction definition in type of
3162  * pointer only.
3163  *
3164  * NOTE: in order for this to take effect, the current loop function *must*
3165  * exit.  Assuming the loop function itself is the only one who will cause
3166  * a new loopfunc to be assigned, this should be no problem.
3167  */
3168 void
3169 gst_element_set_loop_function (GstElement *element,
3170                                GstElementLoopFunction loop)
3171 {
3172   gboolean need_notify = FALSE;
3173   
3174   g_return_if_fail (GST_IS_ELEMENT (element));
3175
3176   /* if the element changed from loop based to chain/get based
3177    * or vice versa, we need to inform the scheduler about that */
3178   if ((element->loopfunc == NULL && loop != NULL) ||
3179       (element->loopfunc != NULL && loop == NULL))
3180   {
3181     need_notify = TRUE;
3182   }
3183   
3184   /* set the loop function */
3185   element->loopfunc = loop;
3186
3187   if (need_notify) {
3188     /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
3189     GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
3190
3191     if (GST_ELEMENT_SCHED (element)) {
3192       gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
3193     }
3194   }
3195 }
3196 static inline void
3197 gst_element_emit_found_tag (GstElement* element, GstElement *source, const GstTagList *tag_list)
3198 {
3199   gst_object_ref (GST_OBJECT (element));
3200   g_signal_emit (element, gst_element_signals[FOUND_TAG], 0, source, tag_list);
3201   gst_object_unref (GST_OBJECT (element));
3202 }
3203 static void
3204 gst_element_found_tag_func (GstElement* element, GstElement *source, const GstTagList *tag_list)
3205 {
3206   /* tell the parent */
3207   if (GST_OBJECT_PARENT (element)) {
3208     GST_CAT_LOG_OBJECT (GST_CAT_EVENT, element, "forwarding tag event to %s", 
3209                GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
3210     gst_element_emit_found_tag (GST_ELEMENT (GST_OBJECT_PARENT (element)), source, tag_list);
3211   }  
3212 }
3213 /**
3214  * gst_element_found_tags:
3215  * @element: the element that found the tags
3216  * @tag_list: the found tags
3217  *
3218  * This function emits the found_tags signal. This is a recursive signal, so
3219  * every parent will emit that signal, too, before this function returns.
3220  * Only emit this signal, when you extracted these tags out of the data stream,
3221  * not when you handle an event.
3222  */
3223 void
3224 gst_element_found_tags (GstElement *element, const GstTagList *tag_list)
3225 {
3226   gst_element_emit_found_tag (element, element, tag_list);
3227 }
3228 /**
3229  * gst_element_found_tags_for_pad:
3230  * @element: element that found the tag
3231  * @pad: src pad the tags correspond to
3232  * @timestamp: time the tags were found
3233  * @list: the taglist
3234  *
3235  * This is a convenience routine for tag finding. Most of the time you only
3236  * want to push the found tags down one pad, in that case this function is for
3237  * you. It takes ownership of the taglist, emits the found-tag signal and pushes 
3238  * a tag event down the pad.
3239  */
3240 void
3241 gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp,
3242                                 GstTagList *list)
3243 {
3244   GstEvent *tag_event;
3245
3246   g_return_if_fail (GST_IS_ELEMENT (element));
3247   g_return_if_fail (GST_IS_REAL_PAD (pad));
3248   g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
3249   g_return_if_fail (element == GST_PAD_PARENT (pad));
3250   g_return_if_fail (list != NULL);
3251
3252   tag_event = gst_event_new_tag (list);
3253   GST_EVENT_TIMESTAMP (tag_event) = timestamp;
3254   gst_element_found_tags (element, gst_event_tag_get_list (tag_event));
3255   if (GST_PAD_IS_USABLE (pad)) {
3256     gst_pad_push (pad, GST_DATA (tag_event));
3257   } else {
3258     gst_data_unref (GST_DATA (tag_event));
3259   }
3260 }
3261
3262 static inline void
3263 gst_element_set_eos_recursive (GstElement *element)
3264 {
3265   /* this function is only called, when we were in PLAYING before. So every 
3266      parent that's PAUSED was PLAYING before. That means it has reached EOS. */
3267   GstElement *parent;
3268
3269   GST_CAT_DEBUG (GST_CAT_EVENT, "setting recursive EOS on %s", 
3270              GST_OBJECT_NAME (element));
3271   g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
3272
3273   if (!GST_OBJECT_PARENT (element))
3274     return;
3275   
3276   parent = GST_ELEMENT (GST_OBJECT_PARENT (element));
3277   if (GST_STATE (parent) == GST_STATE_PAUSED)
3278     gst_element_set_eos_recursive (parent);
3279 }
3280 /**
3281  * gst_element_set_eos:
3282  * @element: a #GstElement to set to the EOS state.
3283  *
3284  * Perform the actions needed to bring the element in the EOS state.
3285  */
3286 void
3287 gst_element_set_eos (GstElement *element)
3288 {
3289   g_return_if_fail (GST_IS_ELEMENT (element));
3290
3291   GST_CAT_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", 
3292              GST_OBJECT_NAME (element));
3293
3294   if (GST_STATE (element) == GST_STATE_PLAYING) {
3295     gst_element_set_state (element, GST_STATE_PAUSED);
3296     gst_element_set_eos_recursive (element);
3297   } else {
3298     g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
3299   }
3300 }
3301
3302
3303 /**
3304  * gst_element_state_get_name:
3305  * @state: a #GstElementState to get the name of.
3306  *
3307  * Gets a string representing the given state.
3308  *
3309  * Returns: a string with the name of the state.
3310  */
3311 const gchar*
3312 gst_element_state_get_name (GstElementState state) 
3313 {
3314   switch (state) {
3315 #ifdef GST_DEBUG_COLOR
3316     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
3317     case GST_STATE_NULL: return "\033[01;34mNULL\033[00m";break;
3318     case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
3319     case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
3320     case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
3321     default:
3322       /* This is a memory leak */
3323       return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
3324 #else
3325     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
3326     case GST_STATE_NULL: return "NULL";break;
3327     case GST_STATE_READY: return "READY";break;
3328     case GST_STATE_PLAYING: return "PLAYING";break;
3329     case GST_STATE_PAUSED: return "PAUSED";break;
3330     default: return "UNKNOWN!";
3331 #endif
3332   }
3333   return "";
3334 }
3335
3336 static void
3337 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name, 
3338                                 guint arg_id, GParamFlags flags)
3339 {
3340   GQuark prop_id = g_quark_from_string (prop_name);
3341   GParamSpec *pspec;
3342
3343   static GQuark fd_id = 0;
3344   static GQuark blocksize_id;
3345   static GQuark bytesperread_id;
3346   static GQuark dump_id;
3347   static GQuark filesize_id;
3348   static GQuark mmapsize_id;
3349   static GQuark location_id;
3350   static GQuark offset_id;
3351   static GQuark silent_id;
3352   static GQuark touch_id;
3353
3354   if (!fd_id) {
3355     fd_id = g_quark_from_static_string ("fd");
3356     blocksize_id = g_quark_from_static_string ("blocksize");
3357     bytesperread_id = g_quark_from_static_string ("bytesperread");
3358     dump_id = g_quark_from_static_string ("dump");
3359     filesize_id = g_quark_from_static_string ("filesize");
3360     mmapsize_id = g_quark_from_static_string ("mmapsize");
3361     location_id = g_quark_from_static_string ("location");
3362     offset_id = g_quark_from_static_string ("offset");
3363     silent_id = g_quark_from_static_string ("silent");
3364     touch_id = g_quark_from_static_string ("touch");
3365   }
3366
3367   if (prop_id == fd_id) {
3368     pspec = g_param_spec_int ("fd", "File-descriptor",
3369                               "File-descriptor for the file being read",
3370                               0, G_MAXINT, 0, flags);
3371   }
3372   else if (prop_id == blocksize_id) {
3373     pspec = g_param_spec_ulong ("blocksize", "Block Size",
3374                                 "Block size to read per buffer",
3375                                 0, G_MAXULONG, 4096, flags);
3376
3377   }
3378   else if (prop_id == bytesperread_id) {
3379     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
3380                               "Number of bytes to read per buffer",
3381                               G_MININT, G_MAXINT, 0, flags);
3382
3383   }
3384   else if (prop_id == dump_id) {
3385     pspec = g_param_spec_boolean ("dump", "Dump", 
3386                                   "Dump bytes to stdout", 
3387                                   FALSE, flags);
3388
3389   }
3390   else if (prop_id == filesize_id) {
3391     pspec = g_param_spec_int64 ("filesize", "File Size",
3392                                 "Size of the file being read",
3393                                 0, G_MAXINT64, 0, flags);
3394
3395   }
3396   else if (prop_id == mmapsize_id) {
3397     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
3398                                 "Size in bytes of mmap()d regions",
3399                                 0, G_MAXULONG, 4 * 1048576, flags);
3400
3401   }
3402   else if (prop_id == location_id) {
3403     pspec = g_param_spec_string ("location", "File Location",
3404                                  "Location of the file to read",
3405                                  NULL, flags);
3406
3407   }
3408   else if (prop_id == offset_id) {
3409     pspec = g_param_spec_int64 ("offset", "File Offset",
3410                                 "Byte offset of current read pointer",
3411                                 0, G_MAXINT64, 0, flags);
3412
3413   }
3414   else if (prop_id == silent_id) {
3415     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
3416                                   FALSE, flags);
3417
3418   }
3419   else if (prop_id == touch_id) {
3420     pspec = g_param_spec_boolean ("touch", "Touch read data",
3421                                   "Touch data to force disk read before "
3422                                   "push ()", TRUE, flags);
3423   }
3424   else {
3425     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
3426                prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
3427     pspec = NULL;
3428   }
3429
3430   if (pspec) {
3431     g_object_class_install_property (klass, arg_id, pspec);
3432   }
3433 }
3434
3435 /**
3436  * gst_element_class_install_std_props:
3437  * @klass: the #GstElementClass to add the properties to.
3438  * @first_name: the name of the first property.
3439  * in a NULL terminated
3440  * @...: the id and flags of the first property, followed by
3441  * further 'name', 'id', 'flags' triplets and terminated by NULL.
3442  * 
3443  * Adds a list of standardized properties with types to the @klass.
3444  * the id is for the property switch in your get_prop method, and
3445  * the flags determine readability / writeability.
3446  **/
3447 void
3448 gst_element_class_install_std_props (GstElementClass * klass, 
3449                                      const gchar *first_name, ...)
3450 {
3451   const char *name;
3452
3453   va_list args;
3454
3455   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
3456
3457   va_start (args, first_name);
3458
3459   name = first_name;
3460
3461   while (name) {
3462     int arg_id = va_arg (args, int);
3463     int flags = va_arg (args, int);
3464
3465     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
3466
3467     name = va_arg (args, char *);
3468   }
3469
3470   va_end (args);
3471 }
3472
3473 /**
3474  * gst_element_get_managing_bin:
3475  * @element: a #GstElement to get the managing bin of.
3476  * 
3477  * Gets the managing bin (a pipeline or a thread, for example) of an element.
3478  *
3479  * Returns: the #GstBin, or NULL on failure.
3480  **/
3481 GstBin*
3482 gst_element_get_managing_bin (GstElement *element)
3483 {
3484   GstBin *bin;
3485
3486   g_return_val_if_fail (element != NULL, NULL);
3487
3488   bin = GST_BIN (gst_object_get_parent (GST_OBJECT (element)));
3489
3490   while (bin && !GST_FLAG_IS_SET (GST_OBJECT (bin), GST_BIN_FLAG_MANAGER))
3491     bin = GST_BIN (gst_object_get_parent (GST_OBJECT (bin)));
3492   
3493   return bin;
3494 }