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