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