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