gst-indent run on core
[platform/upstream/gstreamer.git] / gst / gstelement.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstelement.c: The base element, all elements derive from this
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <glib.h>
24 #include <stdarg.h>
25 #include <gobject/gvaluecollector.h>
26 #include "gst_private.h"
27
28 #include "gstelement.h"
29 #include "gstbin.h"
30 #include "gstmarshal.h"
31 #include "gsterror.h"
32 #include "gstscheduler.h"
33 #include "gstevent.h"
34 #include "gstutils.h"
35 #include "gstinfo.h"
36 #include "gst-i18n-lib.h"
37
38 /* Element signals and args */
39 enum
40 {
41   STATE_CHANGE,
42   NEW_PAD,
43   PAD_REMOVED,
44   ERROR,
45   EOS,
46   FOUND_TAG,
47   /* add more above */
48   LAST_SIGNAL
49 };
50
51 enum
52 {
53   ARG_0
54       /* FILL ME */
55 };
56
57 extern void __gst_element_details_clear (GstElementDetails * dp);
58 extern void __gst_element_details_copy (GstElementDetails * dest,
59     const GstElementDetails * src);
60
61 static void gst_element_class_init (GstElementClass * klass);
62 static void gst_element_init (GstElement * element);
63 static void gst_element_base_class_init (gpointer g_class);
64 static void gst_element_base_class_finalize (gpointer g_class);
65
66 static void gst_element_real_set_property (GObject * object, guint prop_id,
67     const GValue * value, GParamSpec * pspec);
68 static void gst_element_real_get_property (GObject * object, guint prop_id,
69     GValue * value, GParamSpec * pspec);
70
71 static void gst_element_dispose (GObject * object);
72
73 static GstElementStateReturn gst_element_change_state (GstElement * element);
74 static void gst_element_error_func (GstElement * element, GstElement * source,
75     GError * error, gchar * debug);
76 static void gst_element_found_tag_func (GstElement * element,
77     GstElement * source, const GstTagList * tag_list);
78
79 #ifndef GST_DISABLE_LOADSAVE
80 static xmlNodePtr gst_element_save_thyself (GstObject * object,
81     xmlNodePtr parent);
82 static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
83 #endif
84
85 GType _gst_element_type = 0;
86
87 static GstObjectClass *parent_class = NULL;
88 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
89
90 GType
91 gst_element_get_type (void)
92 {
93   if (!_gst_element_type) {
94     static const GTypeInfo element_info = {
95       sizeof (GstElementClass),
96       gst_element_base_class_init,
97       gst_element_base_class_finalize,
98       (GClassInitFunc) gst_element_class_init,
99       NULL,
100       NULL,
101       sizeof (GstElement),
102       0,
103       (GInstanceInitFunc) gst_element_init,
104       NULL
105     };
106     _gst_element_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement",
107         &element_info, G_TYPE_FLAG_ABSTRACT);
108   }
109   return _gst_element_type;
110 }
111
112 static void
113 gst_element_class_init (GstElementClass * klass)
114 {
115   GObjectClass *gobject_class;
116   GstObjectClass *gstobject_class;
117
118   gobject_class = (GObjectClass *) klass;
119   gstobject_class = (GstObjectClass *) klass;
120
121   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
122
123   gst_element_signals[STATE_CHANGE] =
124       g_signal_new ("state-change", G_TYPE_FROM_CLASS (klass),
125       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, state_change), NULL,
126       NULL, gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
127   gst_element_signals[NEW_PAD] =
128       g_signal_new ("new-pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
129       G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
130       gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
131   gst_element_signals[PAD_REMOVED] =
132       g_signal_new ("pad-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
133       G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
134       gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
135   gst_element_signals[ERROR] =
136       g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
137       G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
138       gst_marshal_VOID__OBJECT_OBJECT_STRING, G_TYPE_NONE, 3, GST_TYPE_ELEMENT,
139       GST_TYPE_G_ERROR, G_TYPE_STRING);
140   gst_element_signals[EOS] =
141       g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
142       G_STRUCT_OFFSET (GstElementClass, eos), NULL, NULL,
143       gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
144   gst_element_signals[FOUND_TAG] =
145       g_signal_new ("found-tag", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
146       G_STRUCT_OFFSET (GstElementClass, found_tag), NULL, NULL,
147       gst_marshal_VOID__OBJECT_BOXED, G_TYPE_NONE, 2, GST_TYPE_ELEMENT,
148       GST_TYPE_TAG_LIST);
149
150   gobject_class->set_property =
151       GST_DEBUG_FUNCPTR (gst_element_real_set_property);
152   gobject_class->get_property =
153       GST_DEBUG_FUNCPTR (gst_element_real_get_property);
154
155   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
156
157 #ifndef GST_DISABLE_LOADSAVE
158   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
159   gstobject_class->restore_thyself =
160       GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
161 #endif
162
163   klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
164   klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
165   klass->found_tag = GST_DEBUG_FUNCPTR (gst_element_found_tag_func);
166   klass->numpadtemplates = 0;
167
168   klass->elementfactory = NULL;
169 }
170
171 static void
172 gst_element_base_class_init (gpointer g_class)
173 {
174   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
175   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
176
177
178   gobject_class->set_property =
179       GST_DEBUG_FUNCPTR (gst_element_real_set_property);
180   gobject_class->get_property =
181       GST_DEBUG_FUNCPTR (gst_element_real_get_property);
182
183   memset (&element_class->details, 0, sizeof (GstElementDetails));
184   element_class->padtemplates = NULL;
185 }
186
187 static void
188 gst_element_base_class_finalize (gpointer g_class)
189 {
190   GstElementClass *klass = GST_ELEMENT_CLASS (g_class);
191
192   g_list_foreach (klass->padtemplates, (GFunc) g_object_unref, NULL);
193   g_list_free (klass->padtemplates);
194   __gst_element_details_clear (&klass->details);
195 }
196
197 static void
198 gst_element_init (GstElement * element)
199 {
200   element->current_state = GST_STATE_NULL;
201   element->pending_state = GST_STATE_VOID_PENDING;
202   element->numpads = 0;
203   element->numsrcpads = 0;
204   element->numsinkpads = 0;
205   element->pads = NULL;
206   element->loopfunc = NULL;
207   element->sched = NULL;
208   element->clock = NULL;
209   element->sched_private = NULL;
210   element->state_mutex = g_mutex_new ();
211   element->state_cond = g_cond_new ();
212 }
213
214 static void
215 gst_element_real_set_property (GObject * object, guint prop_id,
216     const GValue * value, GParamSpec * pspec)
217 {
218   GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
219
220   if (oclass->set_property)
221     (oclass->set_property) (object, prop_id, value, pspec);
222 }
223
224 static void
225 gst_element_real_get_property (GObject * object, guint prop_id, GValue * value,
226     GParamSpec * pspec)
227 {
228   GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
229
230   if (oclass->get_property)
231     (oclass->get_property) (object, prop_id, value, pspec);
232 }
233
234 /** 
235  * gst_element_default_error:
236  * @object: a #GObject that signalled the error.
237  * @orig: the #GstObject that initiated the error.
238  * @error: the GError.
239  * @debug: an additional debug information string, or NULL.
240  *
241  * A default error signal callback to attach to an element.
242  * The user data passed to the g_signal_connect is ignored.
243  *
244  * The default handler will simply print the error string using g_print.
245  */
246 void
247 gst_element_default_error (GObject * object, GstObject * source, GError * error,
248     gchar * debug)
249 {
250   gchar *name = gst_object_get_path_string (source);
251
252   g_print (_("ERROR: from element %s: %s\n"), name, error->message);
253   if (debug)
254     g_print (_("Additional debug info:\n%s\n"), debug);
255
256   g_free (name);
257 }
258
259 typedef struct
260 {
261   const GParamSpec *pspec;
262   GValue value;
263 } prop_value_t;
264
265 static void
266 element_set_property (GstElement * element, const GParamSpec * pspec,
267     const GValue * value)
268 {
269   prop_value_t *prop_value = g_new0 (prop_value_t, 1);
270
271   prop_value->pspec = pspec;
272   prop_value->value = *value;
273
274   g_async_queue_push (element->prop_value_queue, prop_value);
275 }
276
277 static void
278 element_get_property (GstElement * element, const GParamSpec * pspec,
279     GValue * value)
280 {
281   g_mutex_lock (element->property_mutex);
282   g_object_get_property ((GObject *) element, pspec->name, value);
283   g_mutex_unlock (element->property_mutex);
284 }
285
286 static void
287 gst_element_threadsafe_properties_pre_run (GstElement * element)
288 {
289   GST_DEBUG ("locking element %s", GST_OBJECT_NAME (element));
290   g_mutex_lock (element->property_mutex);
291   gst_element_set_pending_properties (element);
292 }
293
294 static void
295 gst_element_threadsafe_properties_post_run (GstElement * element)
296 {
297   GST_DEBUG ("unlocking element %s", GST_OBJECT_NAME (element));
298   g_mutex_unlock (element->property_mutex);
299 }
300
301 /**
302  * gst_element_enable_threadsafe_properties:
303  * @element: a #GstElement to enable threadsafe properties on.
304  *
305  * Installs an asynchronous queue, a mutex and pre- and post-run functions on
306  * this element so that properties on the element can be set in a 
307  * threadsafe way.
308  */
309 void
310 gst_element_enable_threadsafe_properties (GstElement * element)
311 {
312   g_return_if_fail (GST_IS_ELEMENT (element));
313
314   GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
315   element->pre_run_func = gst_element_threadsafe_properties_pre_run;
316   element->post_run_func = gst_element_threadsafe_properties_post_run;
317   if (!element->prop_value_queue)
318     element->prop_value_queue = g_async_queue_new ();
319   if (!element->property_mutex)
320     element->property_mutex = g_mutex_new ();
321 }
322
323 /**
324  * gst_element_disable_threadsafe_properties:
325  * @element: a #GstElement to disable threadsafe properties on.
326  *
327  * Removes the threadsafe properties, post- and pre-run locks from
328  * this element.
329  */
330 void
331 gst_element_disable_threadsafe_properties (GstElement * element)
332 {
333   g_return_if_fail (GST_IS_ELEMENT (element));
334
335   GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
336   element->pre_run_func = NULL;
337   element->post_run_func = NULL;
338   /* let's keep around that async queue */
339 }
340
341 /**
342  * gst_element_set_pending_properties:
343  * @element: a #GstElement to set the pending properties on.
344  *
345  * Sets all pending properties on the threadsafe properties enabled
346  * element.
347  */
348 void
349 gst_element_set_pending_properties (GstElement * element)
350 {
351   prop_value_t *prop_value;
352
353   while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) {
354     g_object_set_property ((GObject *) element, prop_value->pspec->name,
355         &prop_value->value);
356     g_value_unset (&prop_value->value);
357     g_free (prop_value);
358   }
359 }
360
361 /* following 6 functions taken mostly from gobject.c */
362
363 /**
364  * gst_element_set:
365  * @element: a #GstElement to set properties on.
366  * @first_property_name: the first property to set.
367  * @...: value of the first property, and more properties to set, ending
368  *       with NULL.
369  *
370  * Sets properties on an element. If the element uses threadsafe properties,
371  * they will be queued and set on the object when it is scheduled again.
372  */
373 void
374 gst_element_set (GstElement * element, const gchar * first_property_name, ...)
375 {
376   va_list var_args;
377
378   g_return_if_fail (GST_IS_ELEMENT (element));
379
380   va_start (var_args, first_property_name);
381   gst_element_set_valist (element, first_property_name, var_args);
382   va_end (var_args);
383 }
384
385 /**
386  * gst_element_get:
387  * @element: a #GstElement to get properties of.
388  * @first_property_name: the first property to get.
389  * @...: pointer to a variable to store the first property in, as well as 
390  * more properties to get, ending with NULL.
391  *
392  * Gets properties from an element. If the element uses threadsafe properties,
393  * the element will be locked before getting the given properties.
394  */
395 void
396 gst_element_get (GstElement * element, const gchar * first_property_name, ...)
397 {
398   va_list var_args;
399
400   g_return_if_fail (GST_IS_ELEMENT (element));
401
402   va_start (var_args, first_property_name);
403   gst_element_get_valist (element, first_property_name, var_args);
404   va_end (var_args);
405 }
406
407 /**
408  * gst_element_set_valist:
409  * @element: a #GstElement to set properties on.
410  * @first_property_name: the first property to set.
411  * @var_args: the var_args list of other properties to get.
412  *
413  * Sets properties on an element. If the element uses threadsafe properties,
414  * the property change will be put on the async queue.
415  */
416 void
417 gst_element_set_valist (GstElement * element, const gchar * first_property_name,
418     va_list var_args)
419 {
420   const gchar *name;
421   GObject *object;
422
423   g_return_if_fail (GST_IS_ELEMENT (element));
424
425   object = (GObject *) element;
426
427   GST_CAT_DEBUG (GST_CAT_PROPERTIES,
428       "setting valist of properties starting with %s on element %s",
429       first_property_name, gst_element_get_name (element));
430
431   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
432     g_object_set_valist (object, first_property_name, var_args);
433     return;
434   }
435
436   g_object_ref (object);
437
438   name = first_property_name;
439
440   while (name) {
441     GValue value = { 0, };
442     GParamSpec *pspec;
443     gchar *error = NULL;
444
445     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
446
447     if (!pspec) {
448       g_warning ("%s: object class `%s' has no property named `%s'",
449           G_STRLOC, G_OBJECT_TYPE_NAME (object), name);
450       break;
451     }
452     if (!(pspec->flags & G_PARAM_WRITABLE)) {
453       g_warning ("%s: property `%s' of object class `%s' is not writable",
454           G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object));
455       break;
456     }
457
458     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
459
460     G_VALUE_COLLECT (&value, var_args, 0, &error);
461     if (error) {
462       g_warning ("%s: %s", G_STRLOC, error);
463       g_free (error);
464
465       /* we purposely leak the value here, it might not be
466        * in a sane state if an error condition occoured
467        */
468       break;
469     }
470
471     element_set_property (element, pspec, &value);
472     g_value_unset (&value);
473
474     name = va_arg (var_args, gchar *);
475   }
476
477   g_object_unref (object);
478 }
479
480 /**
481  * gst_element_get_valist:
482  * @element: a #GstElement to get properties of.
483  * @first_property_name: the first property to get.
484  * @var_args: the var_args list of other properties to get.
485  *
486  * Gets properties from an element. If the element uses threadsafe properties,
487  * the element will be locked before getting the given properties.
488  */
489 void
490 gst_element_get_valist (GstElement * element, const gchar * first_property_name,
491     va_list var_args)
492 {
493   const gchar *name;
494   GObject *object;
495
496   g_return_if_fail (GST_IS_ELEMENT (element));
497
498   object = (GObject *) element;
499
500   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
501     g_object_get_valist (object, first_property_name, var_args);
502     return;
503   }
504
505   g_object_ref (object);
506
507   name = first_property_name;
508
509   while (name) {
510     GValue value = { 0, };
511     GParamSpec *pspec;
512     gchar *error;
513
514     pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
515
516     if (!pspec) {
517       g_warning ("%s: object class `%s' has no property named `%s'",
518           G_STRLOC, G_OBJECT_TYPE_NAME (object), name);
519       break;
520     }
521     if (!(pspec->flags & G_PARAM_READABLE)) {
522       g_warning ("%s: property `%s' of object class `%s' is not readable",
523           G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object));
524       break;
525     }
526
527     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
528
529     element_get_property (element, pspec, &value);
530
531     G_VALUE_LCOPY (&value, var_args, 0, &error);
532     if (error) {
533       g_warning ("%s: %s", G_STRLOC, error);
534       g_free (error);
535       g_value_unset (&value);
536       break;
537     }
538
539     g_value_unset (&value);
540
541     name = va_arg (var_args, gchar *);
542   }
543
544   g_object_unref (object);
545 }
546
547 /**
548  * gst_element_set_property:
549  * @element: a #GstElement to set properties on.
550  * @property_name: the first property to get.
551  * @value: the #GValue that holds the value to set.
552  *
553  * Sets a property on an element. If the element uses threadsafe properties,
554  * the property will be put on the async queue.
555  */
556 void
557 gst_element_set_property (GstElement * element, const gchar * property_name,
558     const GValue * value)
559 {
560   GParamSpec *pspec;
561   GObject *object;
562
563   g_return_if_fail (GST_IS_ELEMENT (element));
564   g_return_if_fail (property_name != NULL);
565   g_return_if_fail (G_IS_VALUE (value));
566
567   object = (GObject *) element;
568
569   GST_CAT_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
570       property_name, gst_element_get_name (element));
571   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
572     g_object_set_property (object, property_name, value);
573     return;
574   }
575
576   g_object_ref (object);
577
578   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
579       property_name);
580
581   if (!pspec)
582     g_warning ("%s: object class `%s' has no property named `%s'",
583         G_STRLOC, G_OBJECT_TYPE_NAME (object), property_name);
584   else
585     element_set_property (element, pspec, value);
586
587   g_object_unref (object);
588 }
589
590 /**
591  * gst_element_get_property:
592  * @element: a #GstElement to get properties of.
593  * @property_name: the first property to get.
594  * @value: the #GValue to store the property value in.
595  *
596  * Gets a property from an element. If the element uses threadsafe properties,
597  * the element will be locked before getting the given property.
598  */
599 void
600 gst_element_get_property (GstElement * element, const gchar * property_name,
601     GValue * value)
602 {
603   GParamSpec *pspec;
604   GObject *object;
605
606   g_return_if_fail (GST_IS_ELEMENT (element));
607   g_return_if_fail (property_name != NULL);
608   g_return_if_fail (G_IS_VALUE (value));
609
610   object = (GObject *) element;
611
612   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
613     g_object_get_property (object, property_name, value);
614     return;
615   }
616
617   g_object_ref (object);
618
619   pspec =
620       g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
621
622   if (!pspec)
623     g_warning ("%s: object class `%s' has no property named `%s'",
624         G_STRLOC, G_OBJECT_TYPE_NAME (object), property_name);
625   else {
626     GValue *prop_value, tmp_value = { 0, };
627
628     /* auto-conversion of the callers value type
629      */
630     if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec)) {
631       g_value_reset (value);
632       prop_value = value;
633     } else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec),
634             G_VALUE_TYPE (value))) {
635       g_warning
636           ("can't retrieve property `%s' of type `%s' as value of type `%s'",
637           pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
638           G_VALUE_TYPE_NAME (value));
639       g_object_unref (object);
640       return;
641     } else {
642       g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
643       prop_value = &tmp_value;
644     }
645     element_get_property (element, pspec, prop_value);
646     if (prop_value != value) {
647       g_value_transform (prop_value, value);
648       g_value_unset (&tmp_value);
649     }
650   }
651
652   g_object_unref (object);
653 }
654
655 static GstPad *
656 gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
657     const gchar * name)
658 {
659   GstPad *newpad = NULL;
660   GstElementClass *oclass;
661
662   oclass = GST_ELEMENT_GET_CLASS (element);
663
664   if (oclass->request_new_pad)
665     newpad = (oclass->request_new_pad) (element, templ, name);
666
667   return newpad;
668 }
669
670 /**
671  * gst_element_release_request_pad:
672  * @element: a #GstElement to release the request pad of.
673  * @pad: the #GstPad to release.
674  *
675  * Makes the element free the previously requested pad as obtained
676  * with gst_element_get_request_pad().
677  */
678 void
679 gst_element_release_request_pad (GstElement * element, GstPad * pad)
680 {
681   GstElementClass *oclass;
682
683   g_return_if_fail (GST_IS_ELEMENT (element));
684   g_return_if_fail (GST_IS_PAD (pad));
685
686   oclass = GST_ELEMENT_GET_CLASS (element);
687
688   if (oclass->release_pad)
689     (oclass->release_pad) (element, pad);
690 }
691
692 /**
693  * gst_element_requires_clock:
694  * @element: a #GstElement to query
695  *
696  * Query if the element requiresd a clock
697  *
698  * Returns: TRUE if the element requires a clock
699  */
700 gboolean
701 gst_element_requires_clock (GstElement * element)
702 {
703   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
704
705   return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL);
706 }
707
708 /**
709  * gst_element_provides_clock:
710  * @element: a #GstElement to query
711  *
712  * Query if the element provides a clock
713  *
714  * Returns: TRUE if the element provides a clock
715  */
716 gboolean
717 gst_element_provides_clock (GstElement * element)
718 {
719   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
720
721   return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL);
722 }
723
724 /**
725  * gst_element_set_clock:
726  * @element: a #GstElement to set the clock for.
727  * @clock: the #GstClock to set for the element.
728  *
729  * Sets the clock for the element.
730  */
731 void
732 gst_element_set_clock (GstElement * element, GstClock * clock)
733 {
734   GstElementClass *oclass;
735
736   g_return_if_fail (GST_IS_ELEMENT (element));
737
738   oclass = GST_ELEMENT_GET_CLASS (element);
739
740   if (oclass->set_clock)
741     oclass->set_clock (element, clock);
742
743   gst_object_replace ((GstObject **) & element->clock, (GstObject *) clock);
744 }
745
746 /**
747  * gst_element_get_clock:
748  * @element: a #GstElement to get the clock of.
749  *
750  * Gets the clock of the element.
751  *
752  * Returns: the #GstClock of the element.
753  */
754 GstClock *
755 gst_element_get_clock (GstElement * element)
756 {
757   GstElementClass *oclass;
758
759   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
760
761   oclass = GST_ELEMENT_GET_CLASS (element);
762
763   if (oclass->get_clock)
764     return oclass->get_clock (element);
765
766   return NULL;
767 }
768
769 /**
770  * gst_element_clock_wait:
771  * @element: a #GstElement.
772  * @id: the #GstClock to use.
773  * @jitter: the difference between requested time and actual time.
774  *
775  * Waits for a specific time on the clock.
776  *
777  * Returns: the #GstClockReturn result of the wait operation.
778  */
779 GstClockReturn
780 gst_element_clock_wait (GstElement * element, GstClockID id,
781     GstClockTimeDiff * jitter)
782 {
783   GstClockReturn res;
784
785   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
786
787   if (GST_ELEMENT_SCHED (element)) {
788     GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on scheduler clock");
789     res =
790         gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id,
791         jitter);
792   } else {
793     GST_CAT_DEBUG (GST_CAT_CLOCK, "no scheduler, returning GST_CLOCK_TIMEOUT");
794     res = GST_CLOCK_TIMEOUT;
795   }
796
797   return res;
798 }
799
800 #undef GST_CAT_DEFAULT
801 #define GST_CAT_DEFAULT GST_CAT_CLOCK
802 /**
803  * gst_element_get_time:
804  * @element: element to query
805  *
806  * Query the element's time. The element must use 
807  * 
808  * Returns: the current time of the element or #GST_CLOCK_TIME_NONE when there
809  *          is no time available.
810  */
811 GstClockTime
812 gst_element_get_time (GstElement * element)
813 {
814   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);
815
816   if (element->clock == NULL) {
817     GST_WARNING_OBJECT (element, "element queries time but has no clock");
818     return GST_CLOCK_TIME_NONE;
819   }
820   switch (element->current_state) {
821     case GST_STATE_NULL:
822     case GST_STATE_READY:
823       return GST_CLOCK_TIME_NONE;
824     case GST_STATE_PAUSED:
825       return element->base_time;
826     case GST_STATE_PLAYING:
827       return gst_clock_get_time (element->clock) - element->base_time;
828     default:
829       g_assert_not_reached ();
830       return GST_CLOCK_TIME_NONE;
831   }
832 }
833
834 /**
835  * gst_element_wait:
836  * @element: element that should wait
837  * @timestamp: wait until this time has arrived
838  *
839  * Waits until the given time has arrived. When this function returns successfully, 
840  * the time specified in the timestamp has passed.
841  * <note>This function can only be called on elements in #GST_STATE_PLAYING</note>
842  *
843  * Returns: TRUE on success
844  */
845 gboolean
846 gst_element_wait (GstElement * element, GstClockTime timestamp)
847 {
848   GstClockID id;
849   GstClockReturn ret;
850
851   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
852   g_return_val_if_fail (GST_IS_CLOCK (element->clock), FALSE);
853   g_return_val_if_fail (element->current_state == GST_STATE_PLAYING, FALSE);
854   g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
855
856   /* shortcut when we're already late... */
857   if (gst_element_get_time (element) >= timestamp) {
858     GST_INFO_OBJECT (element, "called gst_element_wait and was late");
859     return TRUE;
860   }
861
862   id = gst_clock_new_single_shot_id (element->clock,
863       element->base_time + timestamp);
864   ret = gst_element_clock_wait (element, id, NULL);
865   gst_clock_id_free (id);
866
867   return ret == GST_CLOCK_STOPPED;
868 }
869
870 /**
871  * gst_element_set_time:
872  * @element: element to set time on
873  * @time: time to set
874  *
875  * Sets the current time of the element. This function can be used when handling
876  * discont events. You can only call this function on an element with a clock in
877  * #GST_STATE_PAUSED or #GST_STATE_PLAYING. You might want to have a look at 
878  * gst_element_adjust_time(), if you want to adjust by a difference as that is
879  * more accurate.
880  */
881 void
882 gst_element_set_time (GstElement * element, GstClockTime time)
883 {
884   GstClockTime event_time;
885
886   g_return_if_fail (GST_IS_ELEMENT (element));
887   g_return_if_fail (GST_IS_CLOCK (element->clock));
888   g_return_if_fail (element->current_state >= GST_STATE_PAUSED);
889
890   switch (element->current_state) {
891     case GST_STATE_PAUSED:
892       element->base_time = time;
893       break;
894     case GST_STATE_PLAYING:
895       event_time = gst_clock_get_event_time (element->clock);
896       GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element,
897           "clock time %llu: setting element time to %llu", event_time, time);
898       element->base_time = event_time - time;
899       break;
900     default:
901       g_assert_not_reached ();
902       break;
903   }
904 }
905
906 /**
907  * gst_element_adjust_time:
908  * @element: element to adjust time on
909  * @difference: difference to adjust
910  *
911  * Adjusts the current time of the element by the specified difference. This 
912  * function can be used when handling discont events. You can only call this 
913  * function on an element with a clock in #GST_STATE_PAUSED or 
914  * #GST_STATE_PLAYING. It is more accurate than gst_element_set_time().
915  */
916 void
917 gst_element_adjust_time (GstElement * element, GstClockTimeDiff diff)
918 {
919   GstClockTime time;
920
921   g_return_if_fail (GST_IS_ELEMENT (element));
922   g_return_if_fail (GST_IS_CLOCK (element->clock));
923   g_return_if_fail (element->current_state >= GST_STATE_PAUSED);
924
925   switch (element->current_state) {
926     case GST_STATE_PAUSED:
927       if (diff < 0 && element->base_time < abs (diff)) {
928         g_warning ("attempted to set the current time of element %s below 0",
929             GST_OBJECT_NAME (element));
930         element->base_time = 0;
931       } else {
932         element->base_time += diff;
933       }
934       break;
935     case GST_STATE_PLAYING:
936       time = gst_clock_get_time (element->clock);
937       if (time < element->base_time - diff) {
938         g_warning ("attempted to set the current time of element %s below 0",
939             GST_OBJECT_NAME (element));
940         element->base_time = time;
941       } else {
942         element->base_time -= diff;
943       }
944       break;
945     default:
946       g_assert_not_reached ();
947       break;
948   }
949 }
950
951 #undef GST_CAT_DEFAULT
952
953 #ifndef GST_DISABLE_INDEX
954 /**
955  * gst_element_is_indexable:
956  * @element: a #GstElement.
957  *
958  * Queries if the element can be indexed.
959  *
960  * Returns: TRUE if the element can be indexed.
961  */
962 gboolean
963 gst_element_is_indexable (GstElement * element)
964 {
965   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
966
967   return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
968 }
969
970 /**
971  * gst_element_set_index:
972  * @element: a #GstElement.
973  * @index: a #GstIndex.
974  *
975  * Set the specified GstIndex on the element.
976  */
977 void
978 gst_element_set_index (GstElement * element, GstIndex * index)
979 {
980   GstElementClass *oclass;
981
982   g_return_if_fail (GST_IS_ELEMENT (element));
983   g_return_if_fail (GST_IS_INDEX (index));
984
985   oclass = GST_ELEMENT_GET_CLASS (element);
986
987   if (oclass->set_index)
988     oclass->set_index (element, index);
989 }
990
991 /**
992  * gst_element_get_index:
993  * @element: a #GstElement.
994  *
995  * Gets the index from the element.
996  *
997  * Returns: a #GstIndex or NULL when no index was set on the
998  * element.
999  */
1000 GstIndex *
1001 gst_element_get_index (GstElement * element)
1002 {
1003   GstElementClass *oclass;
1004
1005   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1006
1007   oclass = GST_ELEMENT_GET_CLASS (element);
1008
1009   if (oclass->get_index)
1010     return oclass->get_index (element);
1011
1012   return NULL;
1013 }
1014 #endif
1015
1016 /**
1017  * gst_element_release_locks:
1018  * @element: a #GstElement to release all locks on.
1019  *
1020  * Instruct the element to release all the locks it is holding, such as
1021  * blocking reads, waiting for the clock, ...
1022  *
1023  * Returns: TRUE if the locks could be released.
1024  */
1025 gboolean
1026 gst_element_release_locks (GstElement * element)
1027 {
1028   GstElementClass *oclass;
1029
1030   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1031
1032   oclass = GST_ELEMENT_GET_CLASS (element);
1033
1034   if (oclass->release_locks)
1035     return oclass->release_locks (element);
1036
1037   return TRUE;
1038 }
1039
1040 /**
1041  * gst_element_add_pad:
1042  * @element: a #GstElement to add the pad to.
1043  * @pad: the #GstPad to add to the element.
1044  *
1045  * Adds a pad (link point) to @element. @pad's parent will be set to @element;
1046  * see gst_object_set_parent() for refcounting information.
1047  *
1048  * Pads are automatically activated when the element is in state PLAYING.
1049  */
1050 void
1051 gst_element_add_pad (GstElement * element, GstPad * pad)
1052 {
1053   g_return_if_fail (GST_IS_ELEMENT (element));
1054   g_return_if_fail (GST_IS_PAD (pad));
1055
1056   /* first check to make sure the pad hasn't already been added to another
1057    * element */
1058   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
1059
1060   /* then check to see if there's already a pad by that name here */
1061   g_return_if_fail (gst_object_check_uniqueness (element->pads,
1062           GST_PAD_NAME (pad)) == TRUE);
1063
1064   GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
1065       GST_STR_NULL (GST_OBJECT_NAME (pad)));
1066
1067   /* set the pad's parent */
1068   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
1069
1070   /* add it to the list */
1071   element->pads = g_list_append (element->pads, pad);
1072   element->numpads++;
1073
1074   switch (gst_pad_get_direction (pad)) {
1075     case GST_PAD_SRC:
1076       element->numsrcpads++;
1077       break;
1078     case GST_PAD_SINK:
1079       element->numsinkpads++;
1080       break;
1081     default:
1082       /* can happen for ghost pads */
1083       break;
1084   }
1085
1086   /* activate element when we are playing */
1087   if (GST_STATE (element) == GST_STATE_PLAYING)
1088     gst_pad_set_active (pad, TRUE);
1089
1090   /* emit the NEW_PAD signal */
1091   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
1092 }
1093
1094 /**
1095  * gst_element_add_ghost_pad:
1096  * @element: a #GstElement to add the ghost pad to.
1097  * @pad: the #GstPad from which the new ghost pad will be created.
1098  * @name: the name of the new ghost pad, or NULL to assign a unique name
1099  * automatically.
1100  *
1101  * Creates a ghost pad from @pad, and adds it to @element via
1102  * gst_element_add_pad().
1103  * 
1104  * Returns: the added ghost #GstPad, or NULL on error.
1105  */
1106 GstPad *
1107 gst_element_add_ghost_pad (GstElement * element, GstPad * pad,
1108     const gchar * name)
1109 {
1110   GstPad *ghostpad;
1111
1112   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1113   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1114
1115   /* then check to see if there's already a pad by that name here */
1116   g_return_val_if_fail (gst_object_check_uniqueness (element->pads,
1117           name) == TRUE, NULL);
1118
1119   ghostpad = gst_ghost_pad_new (name, pad);
1120
1121   gst_element_add_pad (element, ghostpad);
1122
1123   return ghostpad;
1124 }
1125
1126 /**
1127  * gst_element_remove_pad:
1128  * @element: a #GstElement to remove pad from.
1129  * @pad: the #GstPad to remove from the element.
1130  *
1131  * Removes @pad from @element. @pad will be destroyed if it has not been
1132  * referenced elsewhere.
1133  */
1134 void
1135 gst_element_remove_pad (GstElement * element, GstPad * pad)
1136 {
1137   g_return_if_fail (element != NULL);
1138   g_return_if_fail (GST_IS_ELEMENT (element));
1139   g_return_if_fail (pad != NULL);
1140   g_return_if_fail (GST_IS_PAD (pad));
1141
1142   g_return_if_fail (GST_PAD_PARENT (pad) == element);
1143
1144   if (GST_IS_REAL_PAD (pad)) {
1145     /* unlink if necessary */
1146     if (GST_RPAD_PEER (pad) != NULL) {
1147       gst_pad_unlink (pad, GST_PAD (GST_RPAD_PEER (pad)));
1148     }
1149     gst_caps_replace (&GST_RPAD_EXPLICIT_CAPS (pad), NULL);
1150   } else if (GST_IS_GHOST_PAD (pad)) {
1151     g_object_set (pad, "real-pad", NULL, NULL);
1152   }
1153
1154   /* remove it from the list */
1155   element->pads = g_list_remove (element->pads, pad);
1156   element->numpads--;
1157   switch (gst_pad_get_direction (pad)) {
1158     case GST_PAD_SRC:
1159       element->numsrcpads--;
1160       break;
1161     case GST_PAD_SINK:
1162       element->numsinkpads--;
1163       break;
1164     default:
1165       /* can happen for ghost pads */
1166       break;
1167   }
1168
1169   g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
1170
1171   gst_object_unparent (GST_OBJECT (pad));
1172 }
1173
1174 /**
1175  * gst_element_remove_ghost_pad:
1176  * @element: a #GstElement to remove the ghost pad from.
1177  * @pad: ghost #GstPad to remove.
1178  *
1179  * Removes a ghost pad from an element. Deprecated, use gst_element_remove_pad()
1180  * instead.
1181  */
1182 void
1183 gst_element_remove_ghost_pad (GstElement * element, GstPad * pad)
1184 {
1185   g_return_if_fail (GST_IS_ELEMENT (element));
1186   g_return_if_fail (GST_IS_GHOST_PAD (pad));
1187
1188   g_warning ("gst_element_remove_ghost_pad is deprecated.\n"
1189       "Use gst_element_remove_pad instead.");
1190
1191   gst_element_remove_pad (element, pad);
1192 }
1193
1194
1195 /**
1196  * gst_element_get_pad:
1197  * @element: a #GstElement.
1198  * @name: the name of the pad to retrieve.
1199  *
1200  * Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
1201  * first, then gst_element_get_request_pad().
1202  *
1203  * Returns: the #GstPad if found, otherwise %NULL.
1204  */
1205 GstPad *
1206 gst_element_get_pad (GstElement * element, const gchar * name)
1207 {
1208   GstPad *pad;
1209
1210   g_return_val_if_fail (element != NULL, NULL);
1211   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1212   g_return_val_if_fail (name != NULL, NULL);
1213
1214   pad = gst_element_get_static_pad (element, name);
1215   if (!pad)
1216     pad = gst_element_get_request_pad (element, name);
1217
1218   return pad;
1219 }
1220
1221 /**
1222  * gst_element_get_static_pad:
1223  * @element: a #GstElement to find a static pad of.
1224  * @name: the name of the static #GstPad to retrieve.
1225  *
1226  * Retrieves a pad from @element by name. This version only retrieves
1227  * already-existing (i.e. 'static') pads.
1228  *
1229  * Returns: the requested #GstPad if found, otherwise NULL.
1230  */
1231 GstPad *
1232 gst_element_get_static_pad (GstElement * element, const gchar * name)
1233 {
1234   GList *walk;
1235
1236   g_return_val_if_fail (element != NULL, NULL);
1237   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1238   g_return_val_if_fail (name != NULL, NULL);
1239
1240   walk = element->pads;
1241   while (walk) {
1242     GstPad *pad;
1243
1244     pad = GST_PAD (walk->data);
1245     if (strcmp (GST_PAD_NAME (pad), name) == 0) {
1246       GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s",
1247           GST_DEBUG_PAD_NAME (pad));
1248       return pad;
1249     }
1250     walk = g_list_next (walk);
1251   }
1252
1253   GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"",
1254       name, GST_OBJECT_NAME (element));
1255   return NULL;
1256 }
1257
1258 /**
1259  * gst_element_get_request_pad:
1260  * @element: a #GstElement to find a request pad of.
1261  * @name: the name of the request #GstPad to retrieve.
1262  *
1263  * Retrieves a pad from the element by name. This version only retrieves
1264  * request pads.
1265  *
1266  * Returns: requested #GstPad if found, otherwise NULL.
1267  */
1268 GstPad *
1269 gst_element_get_request_pad (GstElement * element, const gchar * name)
1270 {
1271   GstPadTemplate *templ = NULL;
1272   GstPad *pad;
1273   const gchar *req_name = NULL;
1274   gboolean templ_found = FALSE;
1275   GList *list;
1276   gint n;
1277   const gchar *data;
1278   gchar *str, *endptr = NULL;
1279
1280   g_return_val_if_fail (element != NULL, NULL);
1281   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1282   g_return_val_if_fail (name != NULL, NULL);
1283
1284   if (strstr (name, "%")) {
1285     templ = gst_element_get_pad_template (element, name);
1286     req_name = NULL;
1287     if (templ)
1288       templ_found = TRUE;
1289   } else {
1290     list = gst_element_get_pad_template_list (element);
1291     while (!templ_found && list) {
1292       templ = (GstPadTemplate *) list->data;
1293       if (templ->presence == GST_PAD_REQUEST) {
1294         /* Because of sanity checks in gst_pad_template_new(), we know that %s
1295            and %d, occurring at the end of the name_template, are the only
1296            possibilities. */
1297         GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name,
1298             templ->name_template);
1299         if ((str = strchr (templ->name_template, '%'))
1300             && strncmp (templ->name_template, name,
1301                 str - templ->name_template) == 0
1302             && strlen (name) > str - templ->name_template) {
1303           data = name + (str - templ->name_template);
1304           if (*(str + 1) == 'd') {
1305             /* it's an int */
1306             n = (gint) strtol (data, &endptr, 10);
1307             if (endptr && *endptr == '\0') {
1308               templ_found = TRUE;
1309               req_name = name;
1310               break;
1311             }
1312           } else {
1313             /* it's a string */
1314             templ_found = TRUE;
1315             req_name = name;
1316             break;
1317           }
1318         }
1319       }
1320       list = list->next;
1321     }
1322   }
1323
1324   if (!templ_found)
1325     return NULL;
1326
1327   pad = gst_element_request_pad (element, templ, req_name);
1328
1329   return pad;
1330 }
1331
1332 /**
1333  * gst_element_get_pad_list:
1334  * @element: a #GstElement to get pads of.
1335  *
1336  * Retrieves a list of @element's pads. The list must not be modified by the
1337  * calling code.
1338  *
1339  * Returns: the #GList of pads.
1340  */
1341 const GList *
1342 gst_element_get_pad_list (GstElement * element)
1343 {
1344   g_return_val_if_fail (element != NULL, NULL);
1345   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1346
1347   /* return the list of pads */
1348   return element->pads;
1349 }
1350
1351 /**
1352  * gst_element_class_add_pad_template:
1353  * @klass: the #GstElementClass to add the pad template to.
1354  * @templ: a #GstPadTemplate to add to the element class.
1355  *
1356  * Adds a padtemplate to an element class. This is mainly used in the _base_init
1357  * functions of classes.
1358  */
1359 void
1360 gst_element_class_add_pad_template (GstElementClass * klass,
1361     GstPadTemplate * templ)
1362 {
1363   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1364   g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1365
1366   /* avoid registering pad templates with the same name */
1367   g_return_if_fail (gst_element_class_get_pad_template (klass,
1368           templ->name_template) == NULL);
1369
1370   klass->padtemplates = g_list_append (klass->padtemplates,
1371       gst_object_ref (GST_OBJECT (templ)));
1372   klass->numpadtemplates++;
1373 }
1374
1375 /**
1376  * gst_element_class_set_details:
1377  * @klass: class to set details for
1378  * @details: details to set
1379  *
1380  * Sets the detailed information for a #GstElementClass.
1381  * <note>This function is for use in _base_init functions only.</note>
1382  */
1383 void
1384 gst_element_class_set_details (GstElementClass * klass,
1385     const GstElementDetails * details)
1386 {
1387   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1388   g_return_if_fail (GST_IS_ELEMENT_DETAILS (details));
1389
1390   __gst_element_details_copy (&klass->details, details);
1391 }
1392
1393 /**
1394  * gst_element_class_get_pad_template_list:
1395  * @element_class: a #GstElementClass to get pad templates of.
1396  *
1397  * Retrieves a list of the pad templates associated with @element_class. The
1398  * list must not be modified by the calling code.
1399  *
1400  * Returns: the #GList of padtemplates.
1401  */
1402 GList *
1403 gst_element_class_get_pad_template_list (GstElementClass * element_class)
1404 {
1405   g_return_val_if_fail (element_class != NULL, NULL);
1406   g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
1407
1408   return element_class->padtemplates;
1409 }
1410
1411 /**
1412  * gst_element_class_get_pad_template:
1413  * @element_class: a #GstElementClass to get the pad template of.
1414  * @name: the name of the #GstPadTemplate to get.
1415  *
1416  * Retrieves a padtemplate from @element_class with the given name.
1417  *
1418  * Returns: the #GstPadTemplate with the given name, or NULL if none was found. 
1419  * No unreferencing is necessary.
1420  */
1421 GstPadTemplate *
1422 gst_element_class_get_pad_template (GstElementClass * element_class,
1423     const gchar * name)
1424 {
1425   GList *padlist;
1426
1427   g_return_val_if_fail (element_class != NULL, NULL);
1428   g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
1429   g_return_val_if_fail (name != NULL, NULL);
1430
1431   padlist = gst_element_class_get_pad_template_list (element_class);
1432
1433   while (padlist) {
1434     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
1435
1436     if (strcmp (padtempl->name_template, name) == 0)
1437       return padtempl;
1438
1439     padlist = g_list_next (padlist);
1440   }
1441
1442   return NULL;
1443 }
1444
1445 /**
1446  * gst_element_get_pad_template_list:
1447  * @element: a #GstElement to get pad templates of.
1448  *
1449  * Retrieves a list of the pad templates associated with the element.
1450  * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template_list).
1451  *
1452  * Returns: the #GList of padtemplates.
1453  */
1454 GList *
1455 gst_element_get_pad_template_list (GstElement * element)
1456 {
1457   g_return_val_if_fail (element != NULL, NULL);
1458   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1459
1460   return GST_ELEMENT_GET_CLASS (element)->padtemplates;
1461 }
1462
1463 /**
1464  * gst_element_get_pad_template:
1465  * @element: a #GstElement to get the pad template of.
1466  * @name: the name of the #GstPadTemplate to get.
1467  *
1468  * Retrieves a padtemplate from this element with the
1469  * given name.
1470  * (FIXME: Should be deprecated in favor of gst_element_class_get_pad_template).
1471  *
1472  * Returns: the #GstPadTemplate with the given name, or NULL if none was found. 
1473  * No unreferencing is necessary.
1474  */
1475 GstPadTemplate *
1476 gst_element_get_pad_template (GstElement * element, const gchar * name)
1477 {
1478   g_return_val_if_fail (element != NULL, NULL);
1479   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1480   g_return_val_if_fail (name != NULL, NULL);
1481
1482   return gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (element),
1483       name);
1484 }
1485
1486 /**
1487  * gst_element_get_compatible_pad_template:
1488  * @element: a #GstElement to get a compatible pad template for.
1489  * @compattempl: the #GstPadTemplate to find a compatible template for.
1490  *
1491  * Retrieves a pad template from @element that is compatible with @compattempl.
1492  * Pads from compatible templates can be linked together.
1493  *
1494  * Returns: a compatible #GstPadTemplate, or NULL if none was found. No
1495  * unreferencing is necessary.
1496  */
1497 GstPadTemplate *
1498 gst_element_get_compatible_pad_template (GstElement * element,
1499     GstPadTemplate * compattempl)
1500 {
1501   GstPadTemplate *newtempl = NULL;
1502   GList *padlist;
1503
1504   g_return_val_if_fail (element != NULL, NULL);
1505   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1506   g_return_val_if_fail (compattempl != NULL, NULL);
1507
1508   padlist = gst_element_get_pad_template_list (element);
1509
1510   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1511       "Looking for a suitable pad template...");
1512
1513   while (padlist) {
1514     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
1515     GstCaps *intersection;
1516
1517     /* Ignore name
1518      * Ignore presence
1519      * Check direction (must be opposite)
1520      * Check caps
1521      */
1522     if (padtempl->direction != compattempl->direction) {
1523       GST_CAT_DEBUG (GST_CAT_CAPS,
1524           "compatible direction: found %s pad template \"%s\"",
1525           padtempl->direction == GST_PAD_SRC ? "src" : "sink",
1526           padtempl->name_template);
1527
1528       intersection = gst_caps_intersect (GST_PAD_TEMPLATE_CAPS (compattempl),
1529           GST_PAD_TEMPLATE_CAPS (padtempl));
1530
1531       GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible",
1532           (intersection ? "" : "not "));
1533
1534       if (!gst_caps_is_empty (intersection))
1535         newtempl = padtempl;
1536       gst_caps_free (intersection);
1537       if (newtempl)
1538         break;
1539     }
1540
1541     padlist = g_list_next (padlist);
1542   }
1543
1544   return newtempl;
1545 }
1546
1547 /**
1548  * gst_element_get_pad_from_template:
1549  * @element: a #GstElement.
1550  * @templ: a #GstPadTemplate belonging to @element.
1551  *
1552  * Gets a pad from @element described by @templ. If the presence of @templ is
1553  * #GST_PAD_REQUEST, requests a new pad. Can return %NULL for #GST_PAD_SOMETIMES
1554  * templates.
1555  *
1556  * Returns: the #GstPad, or NULL if one could not be found or created.
1557  */
1558 static GstPad *
1559 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
1560 {
1561   GstPad *ret = NULL;
1562   GstPadPresence presence;
1563
1564   /* If this function is ever exported, we need check the validity of `element'
1565    * and `templ', and to make sure the template actually belongs to the
1566    * element. */
1567
1568   presence = GST_PAD_TEMPLATE_PRESENCE (templ);
1569
1570   switch (presence) {
1571     case GST_PAD_ALWAYS:
1572     case GST_PAD_SOMETIMES:
1573       ret = gst_element_get_static_pad (element, templ->name_template);
1574       if (!ret && presence == GST_PAD_ALWAYS)
1575         g_warning
1576             ("Element %s has an ALWAYS template %s, but no pad of the same name",
1577             GST_OBJECT_NAME (element), templ->name_template);
1578       break;
1579
1580     case GST_PAD_REQUEST:
1581       ret = gst_element_request_pad (element, templ, NULL);
1582       break;
1583   }
1584
1585   return ret;
1586 }
1587
1588 /**
1589  * gst_element_request_compatible_pad:
1590  * @element: a #GstElement.
1591  * @templ: the #GstPadTemplate to which the new pad should be able to link.
1592  *
1593  * Requests a pad from @element. The returned pad should be unlinked and
1594  * compatible with @templ. Might return an existing pad, or request a new one.
1595  *
1596  * Returns: a #GstPad, or %NULL if one could not be found or created.
1597  */
1598 GstPad *
1599 gst_element_request_compatible_pad (GstElement * element,
1600     GstPadTemplate * templ)
1601 {
1602   GstPadTemplate *templ_new;
1603   GstPad *pad = NULL;
1604
1605   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1606   g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL);
1607
1608   /* FIXME: should really loop through the templates, testing each for
1609      compatibility and pad availability. */
1610   templ_new = gst_element_get_compatible_pad_template (element, templ);
1611   if (templ_new)
1612     pad = gst_element_get_pad_from_template (element, templ_new);
1613
1614   /* This can happen for non-request pads. No need to unref. */
1615   if (pad && GST_PAD_PEER (pad))
1616     pad = NULL;
1617
1618   return pad;
1619 }
1620
1621 /**
1622  * gst_element_get_compatible_pad_filtered:
1623  * @element: a #GstElement in which the pad should be found.
1624  * @pad: the #GstPad to find a compatible one for.
1625  * @filtercaps: the #GstCaps to use as a filter.
1626  *
1627  * Looks for an unlinked pad to which the given pad can link. It is not
1628  * guaranteed that linking the pads will work, though it should work in most
1629  * cases.
1630  *
1631  * Returns: the #GstPad to which a link can be made, or %NULL if one cannot be
1632  * found.
1633  */
1634 GstPad *
1635 gst_element_get_compatible_pad_filtered (GstElement * element, GstPad * pad,
1636     const GstCaps * filtercaps)
1637 {
1638   const GList *pads;
1639   GstPadTemplate *templ;
1640   GstCaps *templcaps;
1641   GstPad *foundpad = NULL;
1642
1643   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1644   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1645
1646   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1647       "finding pad in %s compatible with %s:%s", GST_ELEMENT_NAME (element),
1648       GST_DEBUG_PAD_NAME (pad));
1649
1650   /* let's use the real pad */
1651   pad = (GstPad *) GST_PAD_REALIZE (pad);
1652   g_return_val_if_fail (pad != NULL, NULL);
1653   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1654
1655   /* try to get an existing unlinked pad */
1656   pads = gst_element_get_pad_list (element);
1657   while (pads) {
1658     GstPad *current = GST_PAD (pads->data);
1659
1660     if (GST_PAD_PEER (current) == NULL &&
1661         gst_pad_can_link_filtered (pad, current, filtercaps)) {
1662       return current;
1663     }
1664     pads = g_list_next (pads);
1665   }
1666
1667   /* try to create a new one */
1668   /* requesting is a little crazy, we need a template. Let's create one */
1669   templcaps = gst_pad_get_caps (pad);
1670   if (filtercaps != NULL) {
1671     GstCaps *temp;
1672
1673     temp = gst_caps_intersect (filtercaps, templcaps);
1674     gst_caps_free (templcaps);
1675     templcaps = temp;
1676   }
1677
1678   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
1679       GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
1680   foundpad = gst_element_request_compatible_pad (element, templ);
1681   gst_object_unref (GST_OBJECT (templ));
1682
1683   if (foundpad)
1684     return foundpad;
1685
1686   GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element,
1687       "Could not find a compatible pad to link to %s:%s",
1688       GST_DEBUG_PAD_NAME (pad));
1689
1690   return NULL;
1691 }
1692
1693 /**
1694  * gst_element_get_compatible_pad:
1695  * @element: a #GstElement in which the pad should be found.
1696  * @pad: the #GstPad to find a compatible one for.
1697  *
1698  * Looks for an unlinked pad to which the given pad can link to.
1699  * It is not guaranteed that linking the pads will work, though
1700  * it should work in most cases.
1701  *
1702  * Returns: the #GstPad to which a link can be made, or %NULL if one
1703  * could not be found.
1704  */
1705 GstPad *
1706 gst_element_get_compatible_pad (GstElement * element, GstPad * pad)
1707 {
1708   return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1709 }
1710
1711 /**
1712  * gst_element_link_pads_filtered:
1713  * @src: a #GstElement containing the source pad.
1714  * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
1715  * @dest: the #GstElement containing the destination pad.
1716  * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
1717  * @filtercaps: the #GstCaps to use as a filter.
1718  *
1719  * Links the two named pads of the source and destination elements.
1720  * Side effect is that if one of the pads has no parent, it becomes a
1721  * child of the parent of the other element.  If they have different
1722  * parents, the link fails.
1723  *
1724  * Returns: TRUE if the pads could be linked, FALSE otherwise.
1725  */
1726 gboolean
1727 gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
1728     GstElement * dest, const gchar * destpadname, const GstCaps * filtercaps)
1729 {
1730   const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1731   GstPad *srcpad, *destpad;
1732   GstPadTemplate *srctempl, *desttempl;
1733
1734   /* checks */
1735   g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1736   g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1737
1738   GST_CAT_INFO (GST_CAT_ELEMENT_PADS,
1739       "trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),
1740       srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),
1741       destpadname ? destpadname : "(any)");
1742
1743   /* now get the pads we're trying to link and a list of all remaining pads */
1744   if (srcpadname) {
1745     srcpad = gst_element_get_pad (src, srcpadname);
1746     if (!srcpad) {
1747       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
1748           GST_ELEMENT_NAME (src), srcpadname);
1749       return FALSE;
1750     } else {
1751       if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
1752         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",
1753             GST_DEBUG_PAD_NAME (srcpad));
1754         return FALSE;
1755       }
1756       if (GST_PAD_PEER (srcpad) != NULL) {
1757         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
1758             GST_DEBUG_PAD_NAME (srcpad));
1759         return FALSE;
1760       }
1761     }
1762     srcpads = NULL;
1763   } else {
1764     srcpads = gst_element_get_pad_list (src);
1765     srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
1766   }
1767   if (destpadname) {
1768     destpad = gst_element_get_pad (dest, destpadname);
1769     if (!destpad) {
1770       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",
1771           GST_ELEMENT_NAME (dest), destpadname);
1772       return FALSE;
1773     } else {
1774       if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {
1775         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",
1776             GST_DEBUG_PAD_NAME (destpad));
1777         return FALSE;
1778       }
1779       if (GST_PAD_PEER (destpad) != NULL) {
1780         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",
1781             GST_DEBUG_PAD_NAME (destpad));
1782         return FALSE;
1783       }
1784     }
1785     destpads = NULL;
1786   } else {
1787     destpads = gst_element_get_pad_list (dest);
1788     destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
1789   }
1790
1791   if (srcpadname && destpadname) {
1792     /* two explicitly specified pads */
1793     return gst_pad_link_filtered (srcpad, destpad, filtercaps);
1794   }
1795   if (srcpad) {
1796     /* loop through the allowed pads in the source, trying to find a
1797      * compatible destination pad */
1798     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1799         "looping through allowed src and dest pads");
1800     do {
1801       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
1802           GST_DEBUG_PAD_NAME (srcpad));
1803       if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1804           (GST_PAD_PEER (srcpad) == NULL)) {
1805         GstPad *temp = gst_element_get_compatible_pad_filtered (dest, srcpad,
1806             filtercaps);
1807
1808         if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) {
1809           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
1810               GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
1811           return TRUE;
1812         }
1813       }
1814       /* find a better way for this mess */
1815       if (srcpads) {
1816         srcpads = g_list_next (srcpads);
1817         if (srcpads)
1818           srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1819       }
1820     } while (srcpads);
1821   }
1822   if (srcpadname) {
1823     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
1824         GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
1825     return FALSE;
1826   }
1827   if (destpad) {
1828     /* loop through the existing pads in the destination */
1829     do {
1830       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
1831           GST_DEBUG_PAD_NAME (destpad));
1832       if ((GST_PAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1833           (GST_PAD_PEER (destpad) == NULL)) {
1834         GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad,
1835             filtercaps);
1836
1837         if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) {
1838           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
1839               GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
1840           return TRUE;
1841         }
1842       }
1843       if (destpads) {
1844         destpads = g_list_next (destpads);
1845         if (destpads)
1846           destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1847       }
1848     } while (destpads);
1849   }
1850   if (destpadname) {
1851     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
1852         GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
1853     return FALSE;
1854   }
1855
1856   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1857       "we might have request pads on both sides, checking...");
1858   srctempls = gst_element_get_pad_template_list (src);
1859   desttempls = gst_element_get_pad_template_list (dest);
1860
1861   if (srctempls && desttempls) {
1862     while (srctempls) {
1863       srctempl = (GstPadTemplate *) srctempls->data;
1864       if (srctempl->presence == GST_PAD_REQUEST) {
1865         for (l = desttempls; l; l = l->next) {
1866           desttempl = (GstPadTemplate *) l->data;
1867           if (desttempl->presence == GST_PAD_REQUEST &&
1868               desttempl->direction != srctempl->direction) {
1869             if (gst_caps_is_always_compatible (gst_pad_template_get_caps
1870                     (srctempl), gst_pad_template_get_caps (desttempl))) {
1871               srcpad =
1872                   gst_element_get_request_pad (src, srctempl->name_template);
1873               destpad =
1874                   gst_element_get_request_pad (dest, desttempl->name_template);
1875               if (gst_pad_link_filtered (srcpad, destpad, filtercaps)) {
1876                 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1877                     "linked pad %s:%s to pad %s:%s",
1878                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1879                 return TRUE;
1880               }
1881               /* it failed, so we release the request pads */
1882               gst_element_release_request_pad (src, srcpad);
1883               gst_element_release_request_pad (dest, destpad);
1884             }
1885           }
1886         }
1887       }
1888       srctempls = srctempls->next;
1889     }
1890   }
1891
1892   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
1893       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1894   return FALSE;
1895 }
1896
1897 /**
1898  * gst_element_link_filtered:
1899  * @src: a #GstElement containing the source pad.
1900  * @dest: the #GstElement containing the destination pad.
1901  * @filtercaps: the #GstCaps to use as a filter.
1902  *
1903  * Links @src to @dest, filtered by @filtercaps. The link must be from source to
1904  * destination; the other direction will not be tried. The function looks for
1905  * existing pads that aren't linked yet. It will request new pads if necessary.
1906  * If multiple links are possible, only one is established.
1907  *
1908  * Returns: TRUE if the elements could be linked, FALSE otherwise.
1909  */
1910 gboolean
1911 gst_element_link_filtered (GstElement * src, GstElement * dest,
1912     const GstCaps * filtercaps)
1913 {
1914   return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
1915 }
1916
1917 /**
1918  * gst_element_link_many:
1919  * @element_1: the first #GstElement in the link chain.
1920  * @element_2: the second #GstElement in the link chain.
1921  * @...: the NULL-terminated list of elements to link in order.
1922  * 
1923  * Chain together a series of elements. Uses gst_element_link().
1924  *
1925  * Returns: TRUE on success, FALSE otherwise.
1926  */
1927 gboolean
1928 gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)
1929 {
1930   va_list args;
1931
1932   g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1933   g_return_val_if_fail (GST_IS_ELEMENT (element_1) &&
1934       GST_IS_ELEMENT (element_2), FALSE);
1935
1936   va_start (args, element_2);
1937
1938   while (element_2) {
1939     if (!gst_element_link (element_1, element_2))
1940       return FALSE;
1941
1942     element_1 = element_2;
1943     element_2 = va_arg (args, GstElement *);
1944   }
1945
1946   va_end (args);
1947
1948   return TRUE;
1949 }
1950
1951 /**
1952  * gst_element_link:
1953  * @src: a #GstElement containing the source pad.
1954  * @dest: the #GstElement containing the destination pad.
1955  *
1956  * Links @src to @dest with no filter caps. See gst_element_link_filtered() for
1957  * more information.
1958  *
1959  * Returns: TRUE if the elements could be linked, FALSE otherwise.
1960  */
1961 gboolean
1962 gst_element_link (GstElement * src, GstElement * dest)
1963 {
1964   return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
1965 }
1966
1967 /**
1968  * gst_element_link_pads:
1969  * @src: a #GstElement containing the source pad.
1970  * @srcpadname: the name of the #GstPad in the source element.
1971  * @dest: the #GstElement containing the destination pad.
1972  * @destpadname: the name of the #GstPad in destination element.
1973  *
1974  * Links the two named pads of the source and destination elements.
1975  * Side effect is that if one of the pads has no parent, it becomes a
1976  * child of the parent of the other element.  If they have different
1977  * parents, the link fails.
1978  *
1979  * Returns: TRUE if the pads could be linked, FALSE otherwise.
1980  */
1981 gboolean
1982 gst_element_link_pads (GstElement * src, const gchar * srcpadname,
1983     GstElement * dest, const gchar * destpadname)
1984 {
1985   return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname,
1986       NULL);
1987 }
1988
1989 /**
1990  * gst_element_unlink_pads:
1991  * @src: a #GstElement containing the source pad.
1992  * @srcpadname: the name of the #GstPad in source element.
1993  * @dest: a #GstElement containing the destination pad.
1994  * @destpadname: the name of the #GstPad in destination element.
1995  *
1996  * Unlinks the two named pads of the source and destination elements.
1997  */
1998 void
1999 gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
2000     GstElement * dest, const gchar * destpadname)
2001 {
2002   GstPad *srcpad, *destpad;
2003
2004   g_return_if_fail (src != NULL);
2005   g_return_if_fail (GST_IS_ELEMENT (src));
2006   g_return_if_fail (srcpadname != NULL);
2007   g_return_if_fail (dest != NULL);
2008   g_return_if_fail (GST_IS_ELEMENT (dest));
2009   g_return_if_fail (destpadname != NULL);
2010
2011   /* obtain the pads requested */
2012   srcpad = gst_element_get_pad (src, srcpadname);
2013   if (srcpad == NULL) {
2014     GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
2015     return;
2016   }
2017   destpad = gst_element_get_pad (dest, destpadname);
2018   if (srcpad == NULL) {
2019     GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
2020         destpadname);
2021     return;
2022   }
2023
2024   /* we're satisified they can be unlinked, let's do it */
2025   gst_pad_unlink (srcpad, destpad);
2026 }
2027
2028 /**
2029  * gst_element_unlink_many:
2030  * @element_1: the first #GstElement in the link chain.
2031  * @element_2: the second #GstElement in the link chain.
2032  * @...: the NULL-terminated list of elements to unlink in order.
2033  * 
2034  * Unlinks a series of elements. Uses gst_element_unlink().
2035  */
2036 void
2037 gst_element_unlink_many (GstElement * element_1, GstElement * element_2, ...)
2038 {
2039   va_list args;
2040
2041   g_return_if_fail (element_1 != NULL && element_2 != NULL);
2042   g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
2043
2044   va_start (args, element_2);
2045
2046   while (element_2) {
2047     gst_element_unlink (element_1, element_2);
2048
2049     element_1 = element_2;
2050     element_2 = va_arg (args, GstElement *);
2051   }
2052
2053   va_end (args);
2054 }
2055
2056 /**
2057  * gst_element_unlink:
2058  * @src: the source #GstElement to unlink.
2059  * @dest: the sink #GstElement to unlink.
2060  *
2061  * Unlinks all source pads of the source element with all sink pads
2062  * of the sink element to which they are linked.
2063  */
2064 void
2065 gst_element_unlink (GstElement * src, GstElement * dest)
2066 {
2067   const GList *srcpads;
2068   GstPad *pad;
2069
2070   g_return_if_fail (GST_IS_ELEMENT (src));
2071   g_return_if_fail (GST_IS_ELEMENT (dest));
2072
2073   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
2074       GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
2075
2076   srcpads = gst_element_get_pad_list (src);
2077
2078   while (srcpads) {
2079     pad = GST_PAD (srcpads->data);
2080
2081     /* we only care about real src pads */
2082     if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
2083       GstPad *peerpad = GST_PAD_PEER (pad);
2084
2085       /* see if the pad is connected and is really a pad
2086        * of dest */
2087       if (peerpad && (GST_OBJECT_PARENT (peerpad) == (GstObject *) dest)) {
2088         gst_pad_unlink (pad, peerpad);
2089       }
2090     }
2091
2092     srcpads = g_list_next (srcpads);
2093   }
2094 }
2095
2096 static void
2097 gst_element_error_func (GstElement * element, GstElement * source,
2098     GError * error, gchar * debug)
2099 {
2100   /* tell the parent */
2101   if (GST_OBJECT_PARENT (element)) {
2102     GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM,
2103         "forwarding error \"%s\" from %s to %s", error->message,
2104         GST_ELEMENT_NAME (element),
2105         GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
2106
2107     gst_object_ref (GST_OBJECT (element));
2108     g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)),
2109         gst_element_signals[ERROR], 0, source, error, debug);
2110     gst_object_unref (GST_OBJECT (element));
2111     GST_CAT_DEBUG (GST_CAT_ERROR_SYSTEM, "forwarded error \"%s\" from %s to %s",
2112         error->message, GST_ELEMENT_NAME (element),
2113         GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
2114   }
2115 }
2116
2117 static GstPad *
2118 gst_element_get_random_pad (GstElement * element, GstPadDirection dir)
2119 {
2120   GList *pads = element->pads;
2121
2122   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
2123   while (pads) {
2124     GstPad *pad = GST_PAD (pads->data);
2125
2126     GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
2127         GST_DEBUG_PAD_NAME (pad));
2128
2129     if (GST_PAD_DIRECTION (pad) == dir) {
2130       if (GST_PAD_IS_LINKED (pad)) {
2131         return pad;
2132       } else {
2133         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
2134             GST_DEBUG_PAD_NAME (pad));
2135       }
2136     } else {
2137       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
2138           GST_DEBUG_PAD_NAME (pad));
2139     }
2140
2141     pads = g_list_next (pads);
2142   }
2143   return NULL;
2144 }
2145
2146 /**
2147  * gst_element_get_event_masks:
2148  * @element: a #GstElement to query
2149  *
2150  * Get an array of event masks from the element.
2151  * If the element doesn't 
2152  * implement an event masks function, the query will be forwarded
2153  * to a random linked sink pad.
2154  * 
2155  * Returns: An array of #GstEventMask elements.
2156  */
2157 const GstEventMask *
2158 gst_element_get_event_masks (GstElement * element)
2159 {
2160   GstElementClass *oclass;
2161
2162   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2163
2164   oclass = GST_ELEMENT_GET_CLASS (element);
2165
2166   if (oclass->get_event_masks)
2167     return oclass->get_event_masks (element);
2168   else {
2169     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2170
2171     if (pad)
2172       return gst_pad_get_event_masks (GST_PAD_PEER (pad));
2173   }
2174
2175   return FALSE;
2176 }
2177
2178 /**
2179  * gst_element_send_event:
2180  * @element: a #GstElement to send the event to.
2181  * @event: the #GstEvent to send to the element.
2182  *
2183  * Sends an event to an element. If the element doesn't
2184  * implement an event handler, the event will be forwarded
2185  * to a random sink pad.
2186  *
2187  * Returns: TRUE if the event was handled.
2188  */
2189 gboolean
2190 gst_element_send_event (GstElement * element, GstEvent * event)
2191 {
2192   GstElementClass *oclass;
2193
2194   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2195   g_return_val_if_fail (event != NULL, FALSE);
2196
2197   oclass = GST_ELEMENT_GET_CLASS (element);
2198
2199   if (oclass->send_event)
2200     return oclass->send_event (element, event);
2201   else {
2202     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2203
2204     if (pad) {
2205       GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
2206           GST_DEBUG_PAD_NAME (pad));
2207       return gst_pad_send_event (GST_PAD_PEER (pad), event);
2208     }
2209   }
2210   GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
2211       GST_ELEMENT_NAME (element));
2212   return FALSE;
2213 }
2214
2215 /**
2216  * gst_element_seek:
2217  * @element: a #GstElement to send the event to.
2218  * @seek_type: the method to use for seeking.
2219  * @offset: the offset to seek to.
2220  *
2221  * Sends a seek event to an element.
2222  *
2223  * Returns: TRUE if the event was handled.
2224  */
2225 gboolean
2226 gst_element_seek (GstElement * element, GstSeekType seek_type, guint64 offset)
2227 {
2228   GstEvent *event = gst_event_new_seek (seek_type, offset);
2229
2230   return gst_element_send_event (element, event);
2231 }
2232
2233 /**
2234  * gst_element_get_query_types:
2235  * @element: a #GstElement to query
2236  *
2237  * Get an array of query types from the element.
2238  * If the element doesn't 
2239  * implement a query types function, the query will be forwarded
2240  * to a random sink pad.
2241  * 
2242  * Returns: An array of #GstQueryType elements.
2243  */
2244 const GstQueryType *
2245 gst_element_get_query_types (GstElement * element)
2246 {
2247   GstElementClass *oclass;
2248
2249   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2250
2251   oclass = GST_ELEMENT_GET_CLASS (element);
2252
2253   if (oclass->get_query_types)
2254     return oclass->get_query_types (element);
2255   else {
2256     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2257
2258     if (pad)
2259       return gst_pad_get_query_types (GST_PAD_PEER (pad));
2260   }
2261
2262   return FALSE;
2263 }
2264
2265 /**
2266  * gst_element_query:
2267  * @element: a #GstElement to perform the query on.
2268  * @type: the #GstQueryType.
2269  * @format: the #GstFormat pointer to hold the format of the result.
2270  * @value: the pointer to the value of the result.
2271  *
2272  * Performs a query on the given element. If the format is set
2273  * to GST_FORMAT_DEFAULT and this function returns TRUE, the 
2274  * format pointer will hold the default format.
2275  * For element that don't implement a query handler, this function
2276  * forwards the query to a random usable sinkpad of this element.
2277  * 
2278  * Returns: TRUE if the query could be performed.
2279  */
2280 gboolean
2281 gst_element_query (GstElement * element, GstQueryType type,
2282     GstFormat * format, gint64 * value)
2283 {
2284   GstElementClass *oclass;
2285
2286   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2287   g_return_val_if_fail (format != NULL, FALSE);
2288   g_return_val_if_fail (value != NULL, FALSE);
2289
2290   oclass = GST_ELEMENT_GET_CLASS (element);
2291
2292   if (oclass->query)
2293     return oclass->query (element, type, format, value);
2294   else {
2295     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SRC);
2296
2297     if (pad)
2298       return gst_pad_query (pad, type, format, value);
2299     pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2300     if (pad)
2301       return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
2302   }
2303
2304   return FALSE;
2305 }
2306
2307 /**
2308  * gst_element_get_formats:
2309  * @element: a #GstElement to query
2310  *
2311  * Get an array of formst from the element.
2312  * If the element doesn't 
2313  * implement a formats function, the query will be forwarded
2314  * to a random sink pad.
2315  * 
2316  * Returns: An array of #GstFormat elements.
2317  */
2318 const GstFormat *
2319 gst_element_get_formats (GstElement * element)
2320 {
2321   GstElementClass *oclass;
2322
2323   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2324
2325   oclass = GST_ELEMENT_GET_CLASS (element);
2326
2327   if (oclass->get_formats)
2328     return oclass->get_formats (element);
2329   else {
2330     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2331
2332     if (pad)
2333       return gst_pad_get_formats (GST_PAD_PEER (pad));
2334   }
2335
2336   return FALSE;
2337 }
2338
2339 /**
2340  * gst_element_convert:
2341  * @element: a #GstElement to invoke the converter on.
2342  * @src_format: the source #GstFormat.
2343  * @src_value: the source value.
2344  * @dest_format: a pointer to the destination #GstFormat.
2345  * @dest_value: a pointer to the destination value.
2346  *
2347  * Invokes a conversion on the element.
2348  * If the element doesn't 
2349  * implement a convert function, the query will be forwarded
2350  * to a random sink pad.
2351  *
2352  * Returns: TRUE if the conversion could be performed.
2353  */
2354 gboolean
2355 gst_element_convert (GstElement * element,
2356     GstFormat src_format, gint64 src_value,
2357     GstFormat * dest_format, gint64 * dest_value)
2358 {
2359   GstElementClass *oclass;
2360
2361   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2362   g_return_val_if_fail (dest_format != NULL, FALSE);
2363   g_return_val_if_fail (dest_value != NULL, FALSE);
2364
2365   if (src_format == *dest_format) {
2366     *dest_value = src_value;
2367     return TRUE;
2368   }
2369
2370   oclass = GST_ELEMENT_GET_CLASS (element);
2371
2372   if (oclass->convert)
2373     return oclass->convert (element,
2374         src_format, src_value, dest_format, dest_value);
2375   else {
2376     GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2377
2378     if (pad)
2379       return gst_pad_convert (GST_PAD_PEER (pad),
2380           src_format, src_value, dest_format, dest_value);
2381   }
2382
2383   return FALSE;
2384 }
2385
2386 /**
2387  * _gst_element_error_printf:
2388  * @format: the printf-like format to use, or NULL
2389  *
2390  * This function is only used internally by the #gst_element_error macro.
2391  *
2392  * Returns: a newly allocated string, or NULL if the format was NULL or ""
2393  */
2394 gchar *
2395 _gst_element_error_printf (const gchar * format, ...)
2396 {
2397   va_list args;
2398   gchar *buffer;
2399
2400   if (format == NULL)
2401     return NULL;
2402   if (format[0] == 0)
2403     return NULL;
2404
2405   va_start (args, format);
2406   buffer = g_strdup_vprintf (format, args);
2407   va_end (args);
2408   return buffer;
2409 }
2410
2411 /**
2412  * gst_element_error_full:
2413  * @element: a #GstElement with the error.
2414  * @domain: the GStreamer error domain this error belongs to.
2415  * @code: the error code belonging to the domain
2416  * @message: an allocated message to be used as a replacement for the default
2417  *           message connected to code, or NULL
2418  * debug: an allocated debug message to be used as a replacement for the
2419  *        default debugging information, or NULL
2420  *
2421  * Signals an error condition on an element.
2422  * This function is used internally by elements.
2423  * It results in the "error" signal.
2424  */
2425 void gst_element_error_full
2426     (GstElement * element, GQuark domain, gint code, gchar * message,
2427     gchar * debug, const gchar * file, const gchar * function, gint line)
2428 {
2429   GError *error = NULL;
2430   gchar *name;
2431   gchar *sent_message;
2432   gchar *sent_debug;
2433
2434   /* checks */
2435   g_return_if_fail (GST_IS_ELEMENT (element));
2436
2437   /* check if we send the given message or the default error message */
2438   if ((message == NULL) || (message[0] == 0)) {
2439     /* we got this message from g_strdup_printf (""); */
2440     g_free (message);
2441     sent_message = gst_error_get_message (domain, code);
2442   } else
2443     sent_message = message;
2444
2445   if ((debug == NULL) || (debug[0] == 0)) {
2446     /* we got this debug from g_strdup_printf (""); */
2447     g_free (debug);
2448     debug = NULL;
2449   }
2450
2451   /* create error message */
2452   GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signaling error in %s: %s",
2453       GST_ELEMENT_NAME (element), sent_message);
2454   error = g_error_new (domain, code, sent_message);
2455
2456   /* if the element was already in error, stop now */
2457   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IN_ERROR)) {
2458     GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "recursive ERROR detected in %s",
2459         GST_ELEMENT_NAME (element));
2460     g_free (sent_message);
2461     if (debug)
2462       g_free (debug);
2463     return;
2464   }
2465
2466   GST_FLAG_SET (element, GST_ELEMENT_IN_ERROR);
2467
2468   /* emit the signal, make sure the element stays available */
2469   gst_object_ref (GST_OBJECT (element));
2470   name = gst_object_get_path_string (GST_OBJECT (element));
2471   if (debug)
2472     sent_debug = g_strdup_printf ("%s(%d): %s: %s:\n%s",
2473         file, line, function, name, debug ? debug : "");
2474   else
2475     sent_debug = NULL;
2476   g_free (debug);
2477   g_free (name);
2478   g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element,
2479       error, sent_debug);
2480   GST_CAT_INFO (GST_CAT_ERROR_SYSTEM, "signalled error in %s: %s",
2481       GST_ELEMENT_NAME (element), sent_message);
2482
2483   /* tell the scheduler */
2484   if (element->sched) {
2485     gst_scheduler_error (element->sched, element);
2486   }
2487
2488   if (GST_STATE (element) == GST_STATE_PLAYING) {
2489     GstElementStateReturn ret;
2490
2491     ret = gst_element_set_state (element, GST_STATE_PAUSED);
2492     if (ret != GST_STATE_SUCCESS) {
2493       g_warning ("could not PAUSE element \"%s\" after error, help!",
2494           GST_ELEMENT_NAME (element));
2495     }
2496   }
2497
2498   GST_FLAG_UNSET (element, GST_ELEMENT_IN_ERROR);
2499
2500   /* cleanup */
2501   gst_object_unref (GST_OBJECT (element));
2502   g_free (sent_message);
2503   g_free (sent_debug);
2504   g_error_free (error);
2505 }
2506
2507 /**
2508  * gst_element_is_locked_state:
2509  * @element: a #GstElement.
2510  *
2511  * Checks if the state of an element is locked.
2512  * If the state of an element is locked, state changes of the parent don't 
2513  * affect the element.
2514  * This way you can leave currently unused elements inside bins. Just lock their
2515  * state before changing the state from #GST_STATE_NULL.
2516  *
2517  * Returns: TRUE, if the element's state is locked.
2518  */
2519 gboolean
2520 gst_element_is_locked_state (GstElement * element)
2521 {
2522   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2523
2524   return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE;
2525 }
2526
2527 /**
2528  * gst_element_set_locked_state:
2529  * @element: a #GstElement
2530  * @locked_state: TRUE to lock the element's state
2531  *
2532  * Locks the state of an element, so state changes of the parent don't affect
2533  * this element anymore.
2534  */
2535 void
2536 gst_element_set_locked_state (GstElement * element, gboolean locked_state)
2537 {
2538   gboolean old;
2539
2540   g_return_if_fail (GST_IS_ELEMENT (element));
2541
2542   old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
2543
2544   if (old == locked_state)
2545     return;
2546
2547   if (locked_state) {
2548     GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s",
2549         GST_ELEMENT_NAME (element));
2550     GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE);
2551   } else {
2552     GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s",
2553         GST_ELEMENT_NAME (element));
2554     GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
2555   }
2556 }
2557
2558 /**
2559  * gst_element_sync_state_with_parent:
2560  * @element: a #GstElement.
2561  *
2562  * Tries to change the state of the element to the same as its parent.
2563  * If this function returns FALSE, the state of element is undefined.
2564  *
2565  * Returns: TRUE, if the element's state could be synced to the parent's state.
2566  */
2567 gboolean
2568 gst_element_sync_state_with_parent (GstElement * element)
2569 {
2570   GstElement *parent;
2571
2572   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2573   parent = GST_ELEMENT (GST_ELEMENT_PARENT (element));
2574   g_return_val_if_fail (GST_IS_BIN (parent), FALSE);
2575
2576   GST_CAT_DEBUG (GST_CAT_STATES, "syncing state of element %s (%s) to %s (%s)",
2577       GST_ELEMENT_NAME (element),
2578       gst_element_state_get_name (GST_STATE (element)),
2579       GST_ELEMENT_NAME (parent),
2580       gst_element_state_get_name (GST_STATE (parent)));
2581   if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
2582     return FALSE;
2583   }
2584   return TRUE;
2585 }
2586
2587 /**
2588  * gst_element_get_state:
2589  * @element: a #GstElement to get the state of.
2590  *
2591  * Gets the state of the element. 
2592  *
2593  * Returns: the #GstElementState of the element.
2594  */
2595 GstElementState
2596 gst_element_get_state (GstElement * element)
2597 {
2598   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2599
2600   return GST_STATE (element);
2601 }
2602
2603 /**
2604  * gst_element_wait_state_change:
2605  * @element: a #GstElement to wait for a state change on.
2606  *
2607  * Waits and blocks until the element changed its state.
2608  */
2609 void
2610 gst_element_wait_state_change (GstElement * element)
2611 {
2612   g_mutex_lock (element->state_mutex);
2613   g_cond_wait (element->state_cond, element->state_mutex);
2614   g_mutex_unlock (element->state_mutex);
2615 }
2616
2617 /**
2618  * gst_element_set_state:
2619  * @element: a #GstElement to change state of.
2620  * @state: the element's new #GstElementState.
2621  *
2622  * Sets the state of the element. This function will try to set the
2623  * requested state by going through all the intermediary states and calling
2624  * the class's state change function for each.
2625  *
2626  * Returns: TRUE if the state was successfully set.
2627  * (using #GstElementStateReturn).
2628  */
2629 GstElementStateReturn
2630 gst_element_set_state (GstElement * element, GstElementState state)
2631 {
2632   GstElementClass *oclass;
2633   GstElementState curpending;
2634   GstElementStateReturn return_val = GST_STATE_SUCCESS;
2635
2636   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2637
2638   /* start with the current state */
2639   curpending = GST_STATE (element);
2640
2641   if (state == curpending) {
2642     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2643         "element is already in requested state %s",
2644         gst_element_state_get_name (state));
2645     return (GST_STATE_SUCCESS);
2646   }
2647
2648   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s",
2649       gst_element_state_get_name (curpending),
2650       gst_element_state_get_name (state));
2651
2652   /* loop until the final requested state is set */
2653   while (GST_STATE (element) != state
2654       && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2655     /* move the curpending state in the correct direction */
2656     if (curpending < state)
2657       curpending <<= 1;
2658     else
2659       curpending >>= 1;
2660
2661     /* set the pending state variable */
2662     /* FIXME: should probably check to see that we don't already have one */
2663     GST_STATE_PENDING (element) = curpending;
2664
2665     if (curpending != state) {
2666       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2667           "intermediate: setting state from %s to %s",
2668           gst_element_state_get_name (GST_STATE (element)),
2669           gst_element_state_get_name (curpending));
2670     }
2671
2672     /* call the state change function so it can set the state */
2673     oclass = GST_ELEMENT_GET_CLASS (element);
2674     if (oclass->change_state)
2675       return_val = (oclass->change_state) (element);
2676
2677     switch (return_val) {
2678       case GST_STATE_FAILURE:
2679         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
2680             "have failed change_state return");
2681         goto exit;
2682       case GST_STATE_ASYNC:
2683         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
2684             "element will change state async");
2685         goto exit;
2686       case GST_STATE_SUCCESS:
2687         /* Last thing we do is verify that a successful state change really
2688          * did change the state... */
2689         /* if it did not, this is an error - fix the element that does this */
2690         if (GST_STATE (element) != curpending) {
2691           g_warning ("element %s claimed state-change success,"
2692               "but state didn't change to %s. State is %s (%s pending), fix the element",
2693               GST_ELEMENT_NAME (element),
2694               gst_element_state_get_name (curpending),
2695               gst_element_state_get_name (GST_STATE (element)),
2696               gst_element_state_get_name (GST_STATE_PENDING (element)));
2697           return_val = GST_STATE_FAILURE;
2698           goto exit;
2699         }
2700         break;
2701       default:
2702         /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2703         g_assert_not_reached ();
2704     }
2705   }
2706 exit:
2707
2708   return return_val;
2709 }
2710
2711 static gboolean
2712 gst_element_negotiate_pads (GstElement * element)
2713 {
2714   GList *pads = GST_ELEMENT_PADS (element);
2715
2716   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "negotiating pads");
2717
2718   while (pads) {
2719     GstPad *pad = GST_PAD (pads->data);
2720     GstRealPad *srcpad;
2721
2722     pads = g_list_next (pads);
2723
2724     if (!GST_IS_REAL_PAD (pad))
2725       continue;
2726
2727     srcpad = GST_PAD_REALIZE (pad);
2728
2729     /* if we have a link on this pad and it doesn't have caps
2730      * allready, try to negotiate */
2731     if (GST_PAD_IS_LINKED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2732       GstRealPad *sinkpad;
2733       GstElementState otherstate;
2734       GstElement *parent;
2735
2736       sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2737
2738       /* check the parent of the peer pad, if there is no parent do nothing */
2739       parent = GST_PAD_PARENT (sinkpad);
2740       if (!parent)
2741         continue;
2742
2743       /* skips pads that were already negotiating */
2744       if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
2745           GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
2746         continue;
2747
2748       otherstate = GST_STATE (parent);
2749
2750       /* swap pads if needed */
2751       if (!GST_PAD_IS_SRC (srcpad)) {
2752         GstRealPad *temp;
2753
2754         temp = srcpad;
2755         srcpad = sinkpad;
2756         sinkpad = temp;
2757       }
2758
2759       /* only try to negotiate if the peer element is in PAUSED or higher too */
2760       if (otherstate >= GST_STATE_READY) {
2761         GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element,
2762             "perform negotiate for %s:%s and %s:%s",
2763             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
2764         if (gst_pad_renegotiate (pad) == GST_PAD_LINK_REFUSED)
2765           return FALSE;
2766       } else {
2767         GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element,
2768             "not negotiating %s:%s and %s:%s, not in READY yet",
2769             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
2770       }
2771     }
2772   }
2773
2774   return TRUE;
2775 }
2776
2777 static void
2778 gst_element_clear_pad_caps (GstElement * element)
2779 {
2780   GList *pads = GST_ELEMENT_PADS (element);
2781
2782   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "clearing pad caps");
2783
2784   while (pads) {
2785     GstPad *pad = GST_PAD (pads->data);
2786
2787     gst_pad_unnegotiate (pad);
2788     if (GST_IS_REAL_PAD (pad)) {
2789       gst_caps_replace (&GST_RPAD_EXPLICIT_CAPS (pad), NULL);
2790     }
2791
2792     pads = g_list_next (pads);
2793   }
2794 }
2795
2796 static void
2797 gst_element_pads_activate (GstElement * element, gboolean active)
2798 {
2799   GList *pads = element->pads;
2800
2801   while (pads) {
2802     GstPad *pad = GST_PAD (pads->data);
2803
2804     pads = g_list_next (pads);
2805
2806     if (!GST_IS_REAL_PAD (pad))
2807       continue;
2808
2809     gst_pad_set_active (pad, active);
2810   }
2811 }
2812
2813 static GstElementStateReturn
2814 gst_element_change_state (GstElement * element)
2815 {
2816   GstElementState old_state;
2817   GstObject *parent;
2818   gint old_pending, old_transition;
2819
2820   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2821
2822   old_state = GST_STATE (element);
2823   old_pending = GST_STATE_PENDING (element);
2824   old_transition = GST_STATE_TRANSITION (element);
2825
2826   if (old_pending == GST_STATE_VOID_PENDING ||
2827       old_state == GST_STATE_PENDING (element)) {
2828     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2829         "element is already in the %s state",
2830         gst_element_state_get_name (old_state));
2831     return GST_STATE_SUCCESS;
2832   }
2833
2834   GST_CAT_LOG_OBJECT (GST_CAT_STATES, element,
2835       "default handler sets state from %s to %s %04x",
2836       gst_element_state_get_name (old_state),
2837       gst_element_state_get_name (old_pending), old_transition);
2838
2839   /* we set the state change early for the negotiation functions */
2840   GST_STATE (element) = old_pending;
2841   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2842
2843   switch (old_transition) {
2844     case GST_STATE_PLAYING_TO_PAUSED:
2845       if (element->clock) {
2846         GstClockTime time = gst_clock_get_event_time (element->clock);
2847
2848         g_assert (time >= element->base_time);
2849         element->base_time = time - element->base_time;
2850         GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
2851             G_GINT64_FORMAT, element->base_time);
2852       }
2853       gst_element_pads_activate (element, FALSE);
2854       break;
2855     case GST_STATE_PAUSED_TO_PLAYING:
2856       gst_element_pads_activate (element, TRUE);
2857       if (element->clock) {
2858         GstClockTime time = gst_clock_get_event_time (element->clock);
2859
2860         element->base_time = time - element->base_time;
2861         GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
2862             G_GINT64_FORMAT, element->base_time);
2863       }
2864       break;
2865       /* if we are going to paused, we try to negotiate the pads */
2866     case GST_STATE_READY_TO_PAUSED:
2867       g_assert (element->base_time == 0);
2868       if (!gst_element_negotiate_pads (element))
2869         goto failure;
2870       break;
2871       /* going to the READY state clears all pad caps */
2872       /* FIXME: Why doesn't this happen on READY => NULL? -- Company */
2873     case GST_STATE_PAUSED_TO_READY:
2874       element->base_time = 0;
2875       gst_element_clear_pad_caps (element);
2876       break;
2877     default:
2878       break;
2879   }
2880
2881   parent = GST_ELEMENT_PARENT (element);
2882
2883   GST_CAT_LOG_OBJECT (GST_CAT_STATES, element,
2884       "signaling state change from %s to %s",
2885       gst_element_state_get_name (old_state),
2886       gst_element_state_get_name (GST_STATE (element)));
2887
2888   /* tell the scheduler if we have one */
2889   if (element->sched) {
2890     if (gst_scheduler_state_transition (element->sched, element,
2891             old_transition) != GST_STATE_SUCCESS) {
2892       GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
2893           "scheduler could not change state");
2894       goto failure;
2895     }
2896   }
2897
2898   /* tell our parent about the state change */
2899   if (parent && GST_IS_BIN (parent)) {
2900     gst_bin_child_state_change (GST_BIN (parent), old_state,
2901         GST_STATE (element), element);
2902   }
2903   /* at this point the state of the element could have changed again */
2904
2905   g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2906       0, old_state, GST_STATE (element));
2907
2908   /* signal the state change in case somebody is waiting for us */
2909   g_mutex_lock (element->state_mutex);
2910   g_cond_signal (element->state_cond);
2911   g_mutex_unlock (element->state_mutex);
2912
2913   return GST_STATE_SUCCESS;
2914
2915 failure:
2916   /* undo the state change */
2917   GST_STATE (element) = old_state;
2918   GST_STATE_PENDING (element) = old_pending;
2919
2920   return GST_STATE_FAILURE;
2921 }
2922
2923 /**
2924  * gst_element_get_factory:
2925  * @element: a #GstElement to request the element factory of.
2926  *
2927  * Retrieves the factory that was used to create this element.
2928  *
2929  * Returns: the #GstElementFactory used for creating this element.
2930  */
2931 GstElementFactory *
2932 gst_element_get_factory (GstElement * element)
2933 {
2934   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2935
2936   return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2937 }
2938
2939 static void
2940 gst_element_dispose (GObject * object)
2941 {
2942   GstElement *element = GST_ELEMENT (object);
2943   GList *pads;
2944   GstPad *pad;
2945
2946   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
2947
2948   gst_element_set_state (element, GST_STATE_NULL);
2949
2950   /* first we break all our links with the ouside */
2951   if (element->pads) {
2952     GList *orig;
2953
2954     orig = pads = g_list_copy (element->pads);
2955     while (pads) {
2956       pad = GST_PAD (pads->data);
2957
2958       if (GST_PAD_PEER (pad)) {
2959         GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "unlinking pad '%s'",
2960             GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2961         gst_pad_unlink (pad, GST_PAD (GST_PAD_PEER (pad)));
2962       }
2963       gst_element_remove_pad (element, pad);
2964
2965       pads = g_list_next (pads);
2966     }
2967     g_list_free (orig);
2968     g_list_free (element->pads);
2969     element->pads = NULL;
2970   }
2971
2972   element->numsrcpads = 0;
2973   element->numsinkpads = 0;
2974   element->numpads = 0;
2975   if (element->state_mutex)
2976     g_mutex_free (element->state_mutex);
2977   element->state_mutex = NULL;
2978   if (element->state_cond)
2979     g_cond_free (element->state_cond);
2980   element->state_cond = NULL;
2981
2982   if (element->prop_value_queue)
2983     g_async_queue_unref (element->prop_value_queue);
2984   element->prop_value_queue = NULL;
2985   if (element->property_mutex)
2986     g_mutex_free (element->property_mutex);
2987   element->property_mutex = NULL;
2988
2989   gst_object_replace ((GstObject **) & element->sched, NULL);
2990   gst_object_replace ((GstObject **) & element->clock, NULL);
2991
2992   G_OBJECT_CLASS (parent_class)->dispose (object);
2993 }
2994
2995 #ifndef GST_DISABLE_LOADSAVE
2996 /**
2997  * gst_element_save_thyself:
2998  * @element: a #GstElement to save.
2999  * @parent: the xml parent node.
3000  *
3001  * Saves the element as part of the given XML structure.
3002  *
3003  * Returns: the new #xmlNodePtr.
3004  */
3005 static xmlNodePtr
3006 gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
3007 {
3008   GList *pads;
3009   GstElementClass *oclass;
3010   GParamSpec **specs, *spec;
3011   gint nspecs, i;
3012   GValue value = { 0, };
3013   GstElement *element;
3014
3015   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
3016
3017   element = GST_ELEMENT (object);
3018
3019   oclass = GST_ELEMENT_GET_CLASS (element);
3020
3021   xmlNewChild (parent, NULL, "name", GST_ELEMENT_NAME (element));
3022
3023   if (oclass->elementfactory != NULL) {
3024     GstElementFactory *factory = (GstElementFactory *) oclass->elementfactory;
3025
3026     xmlNewChild (parent, NULL, "type", GST_PLUGIN_FEATURE (factory)->name);
3027   }
3028
3029 /* FIXME: what is this? */
3030 /*  if (element->manager) */
3031 /*    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
3032
3033   /* params */
3034   specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
3035
3036   for (i = 0; i < nspecs; i++) {
3037     spec = specs[i];
3038     if (spec->flags & G_PARAM_READABLE) {
3039       xmlNodePtr param;
3040       char *contents;
3041
3042       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec));
3043
3044       g_object_get_property (G_OBJECT (element), spec->name, &value);
3045       param = xmlNewChild (parent, NULL, "param", NULL);
3046       xmlNewChild (param, NULL, "name", spec->name);
3047
3048       if (G_IS_PARAM_SPEC_STRING (spec))
3049         contents = g_value_dup_string (&value);
3050       else if (G_IS_PARAM_SPEC_ENUM (spec))
3051         contents = g_strdup_printf ("%d", g_value_get_enum (&value));
3052       else if (G_IS_PARAM_SPEC_INT64 (spec))
3053         contents = g_strdup_printf ("%" G_GINT64_FORMAT,
3054             g_value_get_int64 (&value));
3055       else
3056         contents = g_strdup_value_contents (&value);
3057
3058       xmlNewChild (param, NULL, "value", contents);
3059       g_free (contents);
3060
3061       g_value_unset (&value);
3062     }
3063   }
3064
3065   pads = GST_ELEMENT_PADS (element);
3066
3067   while (pads) {
3068     GstPad *pad = GST_PAD (pads->data);
3069
3070     /* figure out if it's a direct pad or a ghostpad */
3071     if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
3072       xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
3073
3074       gst_object_save_thyself (GST_OBJECT (pad), padtag);
3075     }
3076     pads = g_list_next (pads);
3077   }
3078
3079   return parent;
3080 }
3081
3082 static void
3083 gst_element_restore_thyself (GstObject * object, xmlNodePtr self)
3084 {
3085   xmlNodePtr children;
3086   GstElement *element;
3087   gchar *name = NULL;
3088   gchar *value = NULL;
3089
3090   element = GST_ELEMENT (object);
3091   g_return_if_fail (element != NULL);
3092
3093   /* parameters */
3094   children = self->xmlChildrenNode;
3095   while (children) {
3096     if (!strcmp (children->name, "param")) {
3097       xmlNodePtr child = children->xmlChildrenNode;
3098
3099       while (child) {
3100         if (!strcmp (child->name, "name")) {
3101           name = xmlNodeGetContent (child);
3102         } else if (!strcmp (child->name, "value")) {
3103           value = xmlNodeGetContent (child);
3104         }
3105         child = child->next;
3106       }
3107       /* FIXME: can this just be g_object_set ? */
3108       gst_util_set_object_arg (G_OBJECT (element), name, value);
3109       /* g_object_set (G_OBJECT (element), name, value, NULL); */
3110     }
3111     children = children->next;
3112   }
3113
3114   /* pads */
3115   children = self->xmlChildrenNode;
3116   while (children) {
3117     if (!strcmp (children->name, "pad")) {
3118       gst_pad_load_and_link (children, GST_OBJECT (element));
3119     }
3120     children = children->next;
3121   }
3122
3123   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
3124     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
3125 }
3126 #endif /* GST_DISABLE_LOADSAVE */
3127
3128 /**
3129  * gst_element_yield:
3130  * @element: a #GstElement to yield.
3131  *
3132  * Requests a yield operation for the element. The scheduler will typically
3133  * give control to another element.
3134  */
3135 void
3136 gst_element_yield (GstElement * element)
3137 {
3138   if (GST_ELEMENT_SCHED (element)) {
3139     gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
3140   }
3141 }
3142
3143 /**
3144  * gst_element_interrupt:
3145  * @element: a #GstElement to interrupt.
3146  *
3147  * Requests the scheduler of this element to interrupt the execution of
3148  * this element and scheduler another one.
3149  *
3150  * Returns: TRUE if the element should exit its chain/loop/get
3151  * function ASAP, depending on the scheduler implementation.
3152  */
3153 gboolean
3154 gst_element_interrupt (GstElement * element)
3155 {
3156   if (GST_ELEMENT_SCHED (element)) {
3157     return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
3158   } else
3159     return TRUE;
3160 }
3161
3162 /**
3163  * gst_element_set_scheduler:
3164  * @element: a #GstElement to set the scheduler of.
3165  * @sched: the #GstScheduler to set.
3166  *
3167  * Sets the scheduler of the element.  For internal use only, unless you're
3168  * writing a new bin subclass.
3169  */
3170 void
3171 gst_element_set_scheduler (GstElement * element, GstScheduler * sched)
3172 {
3173   g_return_if_fail (GST_IS_ELEMENT (element));
3174
3175   GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",
3176       sched);
3177
3178   gst_object_replace ((GstObject **) & GST_ELEMENT_SCHED (element),
3179       GST_OBJECT (sched));
3180 }
3181
3182 /**
3183  * gst_element_get_scheduler:
3184  * @element: a #GstElement to get the scheduler of.
3185  *
3186  * Returns the scheduler of the element.
3187  *
3188  * Returns: the element's #GstScheduler.
3189  */
3190 GstScheduler *
3191 gst_element_get_scheduler (GstElement * element)
3192 {
3193   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
3194
3195   return GST_ELEMENT_SCHED (element);
3196 }
3197
3198 /**
3199  * gst_element_set_loop_function:
3200  * @element: a #GstElement to set the loop function of.
3201  * @loop: Pointer to #GstElementLoopFunction.
3202  *
3203  * This sets the loop function for the element.  The function pointed to
3204  * can deviate from the GstElementLoopFunction definition in type of
3205  * pointer only.
3206  *
3207  * NOTE: in order for this to take effect, the current loop function *must*
3208  * exit.  Assuming the loop function itself is the only one who will cause
3209  * a new loopfunc to be assigned, this should be no problem.
3210  */
3211 void
3212 gst_element_set_loop_function (GstElement * element,
3213     GstElementLoopFunction loop)
3214 {
3215   gboolean need_notify = FALSE;
3216
3217   g_return_if_fail (GST_IS_ELEMENT (element));
3218
3219   /* if the element changed from loop based to chain/get based
3220    * or vice versa, we need to inform the scheduler about that */
3221   if ((element->loopfunc == NULL && loop != NULL) ||
3222       (element->loopfunc != NULL && loop == NULL)) {
3223     need_notify = TRUE;
3224   }
3225
3226   /* set the loop function */
3227   element->loopfunc = loop;
3228
3229   if (need_notify) {
3230     /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
3231     GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
3232
3233     if (GST_ELEMENT_SCHED (element)) {
3234       gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
3235     }
3236   }
3237 }
3238 static inline void
3239 gst_element_emit_found_tag (GstElement * element, GstElement * source,
3240     const GstTagList * tag_list)
3241 {
3242   gst_object_ref (GST_OBJECT (element));
3243   g_signal_emit (element, gst_element_signals[FOUND_TAG], 0, source, tag_list);
3244   gst_object_unref (GST_OBJECT (element));
3245 }
3246 static void
3247 gst_element_found_tag_func (GstElement * element, GstElement * source,
3248     const GstTagList * tag_list)
3249 {
3250   /* tell the parent */
3251   if (GST_OBJECT_PARENT (element)) {
3252     GST_CAT_LOG_OBJECT (GST_CAT_EVENT, element, "forwarding tag event to %s",
3253         GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
3254     gst_element_emit_found_tag (GST_ELEMENT (GST_OBJECT_PARENT (element)),
3255         source, tag_list);
3256   }
3257 }
3258
3259 /**
3260  * gst_element_found_tags:
3261  * @element: the element that found the tags
3262  * @tag_list: the found tags
3263  *
3264  * This function emits the found_tags signal. This is a recursive signal, so
3265  * every parent will emit that signal, too, before this function returns.
3266  * Only emit this signal, when you extracted these tags out of the data stream,
3267  * not when you handle an event.
3268  */
3269 void
3270 gst_element_found_tags (GstElement * element, const GstTagList * tag_list)
3271 {
3272   gst_element_emit_found_tag (element, element, tag_list);
3273 }
3274
3275 /**
3276  * gst_element_found_tags_for_pad:
3277  * @element: element that found the tag
3278  * @pad: src pad the tags correspond to
3279  * @timestamp: time the tags were found
3280  * @list: the taglist
3281  *
3282  * This is a convenience routine for tag finding. Most of the time you only
3283  * want to push the found tags down one pad, in that case this function is for
3284  * you. It takes ownership of the taglist, emits the found-tag signal and pushes 
3285  * a tag event down the pad.
3286  * <note>This function may not be used in a #GstPadGetFunction, because it calls 
3287  * gst_pad_push(). In those functions, call gst_element_found_tags(), create a 
3288  * tag event with gst_event_new_tag() and return that from your 
3289  * #GstPadGetFunction.</note>
3290  */
3291 void
3292 gst_element_found_tags_for_pad (GstElement * element, GstPad * pad,
3293     GstClockTime timestamp, GstTagList * list)
3294 {
3295   GstEvent *tag_event;
3296
3297   g_return_if_fail (GST_IS_ELEMENT (element));
3298   g_return_if_fail (GST_IS_REAL_PAD (pad));
3299   g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
3300   g_return_if_fail (element == GST_PAD_PARENT (pad));
3301   g_return_if_fail (list != NULL);
3302
3303   tag_event = gst_event_new_tag (list);
3304   GST_EVENT_TIMESTAMP (tag_event) = timestamp;
3305   gst_element_found_tags (element, gst_event_tag_get_list (tag_event));
3306   if (GST_PAD_IS_USABLE (pad)) {
3307     gst_pad_push (pad, GST_DATA (tag_event));
3308   } else {
3309     gst_data_unref (GST_DATA (tag_event));
3310   }
3311 }
3312
3313 static inline void
3314 gst_element_set_eos_recursive (GstElement * element)
3315 {
3316   /* this function is only called, when we were in PLAYING before. So every 
3317      parent that's PAUSED was PLAYING before. That means it has reached EOS. */
3318   GstElement *parent;
3319
3320   GST_CAT_DEBUG (GST_CAT_EVENT, "setting recursive EOS on %s",
3321       GST_OBJECT_NAME (element));
3322   g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
3323
3324   if (!GST_OBJECT_PARENT (element))
3325     return;
3326
3327   parent = GST_ELEMENT (GST_OBJECT_PARENT (element));
3328   if (GST_STATE (parent) == GST_STATE_PAUSED)
3329     gst_element_set_eos_recursive (parent);
3330 }
3331
3332 /**
3333  * gst_element_set_eos:
3334  * @element: a #GstElement to set to the EOS state.
3335  *
3336  * Perform the actions needed to bring the element in the EOS state.
3337  */
3338 void
3339 gst_element_set_eos (GstElement * element)
3340 {
3341   g_return_if_fail (GST_IS_ELEMENT (element));
3342
3343   GST_CAT_DEBUG (GST_CAT_EVENT, "setting EOS on element %s",
3344       GST_OBJECT_NAME (element));
3345
3346   if (GST_STATE (element) == GST_STATE_PLAYING) {
3347     gst_element_set_state (element, GST_STATE_PAUSED);
3348     gst_element_set_eos_recursive (element);
3349   } else {
3350     g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
3351   }
3352 }
3353
3354
3355 /**
3356  * gst_element_state_get_name:
3357  * @state: a #GstElementState to get the name of.
3358  *
3359  * Gets a string representing the given state.
3360  *
3361  * Returns: a string with the name of the state.
3362  */
3363 const gchar *
3364 gst_element_state_get_name (GstElementState state)
3365 {
3366   switch (state) {
3367 #ifdef GST_DEBUG_COLOR
3368     case GST_STATE_VOID_PENDING:
3369       return "NONE_PENDING";
3370       break;
3371     case GST_STATE_NULL:
3372       return "\033[01;34mNULL\033[00m";
3373       break;
3374     case GST_STATE_READY:
3375       return "\033[01;31mREADY\033[00m";
3376       break;
3377     case GST_STATE_PLAYING:
3378       return "\033[01;32mPLAYING\033[00m";
3379       break;
3380     case GST_STATE_PAUSED:
3381       return "\033[01;33mPAUSED\033[00m";
3382       break;
3383     default:
3384       /* This is a memory leak */
3385       return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
3386 #else
3387     case GST_STATE_VOID_PENDING:
3388       return "NONE_PENDING";
3389       break;
3390     case GST_STATE_NULL:
3391       return "NULL";
3392       break;
3393     case GST_STATE_READY:
3394       return "READY";
3395       break;
3396     case GST_STATE_PLAYING:
3397       return "PLAYING";
3398       break;
3399     case GST_STATE_PAUSED:
3400       return "PAUSED";
3401       break;
3402     default:
3403       return "UNKNOWN!";
3404 #endif
3405   }
3406   return "";
3407 }
3408
3409 static void
3410 gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name,
3411     guint arg_id, GParamFlags flags)
3412 {
3413   GQuark prop_id = g_quark_from_string (prop_name);
3414   GParamSpec *pspec;
3415
3416   static GQuark fd_id = 0;
3417   static GQuark blocksize_id;
3418   static GQuark bytesperread_id;
3419   static GQuark dump_id;
3420   static GQuark filesize_id;
3421   static GQuark mmapsize_id;
3422   static GQuark location_id;
3423   static GQuark offset_id;
3424   static GQuark silent_id;
3425   static GQuark touch_id;
3426
3427   if (!fd_id) {
3428     fd_id = g_quark_from_static_string ("fd");
3429     blocksize_id = g_quark_from_static_string ("blocksize");
3430     bytesperread_id = g_quark_from_static_string ("bytesperread");
3431     dump_id = g_quark_from_static_string ("dump");
3432     filesize_id = g_quark_from_static_string ("filesize");
3433     mmapsize_id = g_quark_from_static_string ("mmapsize");
3434     location_id = g_quark_from_static_string ("location");
3435     offset_id = g_quark_from_static_string ("offset");
3436     silent_id = g_quark_from_static_string ("silent");
3437     touch_id = g_quark_from_static_string ("touch");
3438   }
3439
3440   if (prop_id == fd_id) {
3441     pspec = g_param_spec_int ("fd", "File-descriptor",
3442         "File-descriptor for the file being read", 0, G_MAXINT, 0, flags);
3443   } else if (prop_id == blocksize_id) {
3444     pspec = g_param_spec_ulong ("blocksize", "Block Size",
3445         "Block size to read per buffer", 0, G_MAXULONG, 4096, flags);
3446
3447   } else if (prop_id == bytesperread_id) {
3448     pspec = g_param_spec_int ("bytesperread", "Bytes per read",
3449         "Number of bytes to read per buffer", G_MININT, G_MAXINT, 0, flags);
3450
3451   } else if (prop_id == dump_id) {
3452     pspec = g_param_spec_boolean ("dump", "Dump",
3453         "Dump bytes to stdout", FALSE, flags);
3454
3455   } else if (prop_id == filesize_id) {
3456     pspec = g_param_spec_int64 ("filesize", "File Size",
3457         "Size of the file being read", 0, G_MAXINT64, 0, flags);
3458
3459   } else if (prop_id == mmapsize_id) {
3460     pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
3461         "Size in bytes of mmap()d regions", 0, G_MAXULONG, 4 * 1048576, flags);
3462
3463   } else if (prop_id == location_id) {
3464     pspec = g_param_spec_string ("location", "File Location",
3465         "Location of the file to read", NULL, flags);
3466
3467   } else if (prop_id == offset_id) {
3468     pspec = g_param_spec_int64 ("offset", "File Offset",
3469         "Byte offset of current read pointer", 0, G_MAXINT64, 0, flags);
3470
3471   } else if (prop_id == silent_id) {
3472     pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
3473         FALSE, flags);
3474
3475   } else if (prop_id == touch_id) {
3476     pspec = g_param_spec_boolean ("touch", "Touch read data",
3477         "Touch data to force disk read before " "push ()", TRUE, flags);
3478   } else {
3479     g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
3480         prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
3481     pspec = NULL;
3482   }
3483
3484   if (pspec) {
3485     g_object_class_install_property (klass, arg_id, pspec);
3486   }
3487 }
3488
3489 /**
3490  * gst_element_class_install_std_props:
3491  * @klass: the #GstElementClass to add the properties to.
3492  * @first_name: the name of the first property.
3493  * in a NULL terminated
3494  * @...: the id and flags of the first property, followed by
3495  * further 'name', 'id', 'flags' triplets and terminated by NULL.
3496  * 
3497  * Adds a list of standardized properties with types to the @klass.
3498  * the id is for the property switch in your get_prop method, and
3499  * the flags determine readability / writeability.
3500  **/
3501 void
3502 gst_element_class_install_std_props (GstElementClass * klass,
3503     const gchar * first_name, ...)
3504 {
3505   const char *name;
3506
3507   va_list args;
3508
3509   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
3510
3511   va_start (args, first_name);
3512
3513   name = first_name;
3514
3515   while (name) {
3516     int arg_id = va_arg (args, int);
3517     int flags = va_arg (args, int);
3518
3519     gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id,
3520         flags);
3521
3522     name = va_arg (args, char *);
3523   }
3524
3525   va_end (args);
3526 }
3527
3528 /**
3529  * gst_element_get_managing_bin:
3530  * @element: a #GstElement to get the managing bin of.
3531  * 
3532  * Gets the managing bin (a pipeline or a thread, for example) of an element.
3533  *
3534  * Returns: the #GstBin, or NULL on failure.
3535  **/
3536 GstBin *
3537 gst_element_get_managing_bin (GstElement * element)
3538 {
3539   GstBin *bin;
3540
3541   g_return_val_if_fail (element != NULL, NULL);
3542
3543   bin = GST_BIN (gst_object_get_parent (GST_OBJECT (element)));
3544
3545   while (bin && !GST_FLAG_IS_SET (GST_OBJECT (bin), GST_BIN_FLAG_MANAGER))
3546     bin = GST_BIN (gst_object_get_parent (GST_OBJECT (bin)));
3547
3548   return bin;
3549 }