source: trunk/third/gstreamer/gst/gstelement.c @ 21448

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