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