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