1 /* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 *
5 * gstelement.c: The base element, all elements derive from this
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
23 /* #define GST_DEBUG_ENABLED */
24 #include <glib.h>
25 #include <stdarg.h>
26 #include <gobject/gvaluecollector.h>
27 #include "gst_private.h"
29 #include "gstelement.h"
30 #include "gstextratypes.h"
31 #include "gstbin.h"
32 #include "gstscheduler.h"
33 #include "gstevent.h"
34 #include "gstutils.h"
35 #include "gstlog.h"
37 /* Element signals and args */
38 enum {
39 STATE_CHANGE,
40 NEW_PAD,
41 PAD_REMOVED,
42 ERROR,
43 EOS,
44 LAST_SIGNAL
45 };
47 enum {
48 ARG_0,
49 /* FILL ME */
50 };
52 static void gst_element_class_init (GstElementClass *klass);
53 static void gst_element_init (GstElement *element);
54 static void gst_element_base_class_init (GstElementClass *klass);
56 static void gst_element_real_set_property (GObject *object, guint prop_id,
57 const GValue *value, GParamSpec *pspec);
58 static void gst_element_real_get_property (GObject *object, guint prop_id, GValue *value,
59 GParamSpec *pspec);
61 static void gst_element_dispose (GObject *object);
63 static GstElementStateReturn gst_element_change_state (GstElement *element);
64 static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg);
66 #ifndef GST_DISABLE_LOADSAVE
67 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
68 static void gst_element_restore_thyself (GstObject *parent, xmlNodePtr self);
69 #endif
71 GType _gst_element_type = 0;
73 static GstObjectClass *parent_class = NULL;
74 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
76 GType gst_element_get_type (void)
77 {
78 if (!_gst_element_type) {
79 static const GTypeInfo element_info = {
80 sizeof(GstElementClass),
81 (GBaseInitFunc)gst_element_base_class_init,
82 NULL,
83 (GClassInitFunc)gst_element_class_init,
84 NULL,
85 NULL,
86 sizeof(GstElement),
87 0,
88 (GInstanceInitFunc)gst_element_init,
89 NULL
90 };
91 _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement",
92 &element_info, G_TYPE_FLAG_ABSTRACT);
93 }
94 return _gst_element_type;
95 }
97 static void
98 gst_element_class_init (GstElementClass *klass)
99 {
100 GObjectClass *gobject_class;
101 GstObjectClass *gstobject_class;
103 gobject_class = (GObjectClass*) klass;
104 gstobject_class = (GstObjectClass*) klass;
106 parent_class = g_type_class_ref(GST_TYPE_OBJECT);
108 gst_element_signals[STATE_CHANGE] =
109 g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
110 G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
111 gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
112 G_TYPE_INT, G_TYPE_INT);
113 gst_element_signals[NEW_PAD] =
114 g_signal_new ("new_pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
115 G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
116 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
117 G_TYPE_OBJECT);
118 gst_element_signals[PAD_REMOVED] =
119 g_signal_new ("pad_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
120 G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
121 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
122 G_TYPE_OBJECT);
123 gst_element_signals[ERROR] =
124 g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
125 G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
126 gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
127 G_TYPE_OBJECT, G_TYPE_STRING);
128 gst_element_signals[EOS] =
129 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
130 G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
131 gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
133 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
134 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
136 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
138 #ifndef GST_DISABLE_LOADSAVE
139 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
140 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
141 #endif
143 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
144 klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
145 klass->elementfactory = NULL;
146 klass->padtemplates = NULL;
147 klass->numpadtemplates = 0;
148 }
150 static void
151 gst_element_base_class_init (GstElementClass *klass)
152 {
153 GObjectClass *gobject_class;
155 gobject_class = (GObjectClass*) klass;
157 gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_real_set_property);
158 gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_real_get_property);
159 }
161 static void
162 gst_element_init (GstElement *element)
163 {
164 element->current_state = GST_STATE_NULL;
165 element->pending_state = GST_STATE_VOID_PENDING;
166 element->numpads = 0;
167 element->numsrcpads = 0;
168 element->numsinkpads = 0;
169 element->pads = NULL;
170 element->loopfunc = NULL;
171 element->sched = NULL;
172 element->clock = NULL;
173 element->sched_private = NULL;
174 element->state_mutex = g_mutex_new ();
175 element->state_cond = g_cond_new ();
176 }
178 static void
179 gst_element_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
180 {
181 GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
183 if (oclass->set_property)
184 (oclass->set_property) (object, prop_id, value, pspec);
185 }
187 static void
188 gst_element_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
189 {
190 GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
192 if (oclass->get_property)
193 (oclass->get_property) (object, prop_id, value, pspec);
194 }
196 /**
197 * gst_element_default_error:
198 * @object: a #GObject that signalled the error.
199 * @orig: the #GstObject that initiated the error.
200 * @error: the error message.
201 *
202 * Adds a default error signal callback to an
203 * element. The user data passed to the g_signal_connect is
204 * ignored.
205 * The default handler will simply print the error string
206 * using g_print.
207 */
208 void
209 gst_element_default_error (GObject *object, GstObject *orig, gchar *error)
210 {
211 gchar *name = gst_object_get_path_string (orig);
212 g_print ("ERROR: %s: %s\n", name, error);
213 g_free (name);
214 }
216 typedef struct {
217 const GParamSpec *pspec;
218 GValue value;
219 } prop_value_t;
221 static void
222 element_set_property (GstElement *element, const GParamSpec *pspec, const GValue *value)
223 {
224 prop_value_t *prop_value = g_new0 (prop_value_t, 1);
226 prop_value->pspec = pspec;
227 prop_value->value = *value;
229 g_async_queue_push (element->prop_value_queue, prop_value);
230 }
232 static void
233 element_get_property (GstElement *element, const GParamSpec *pspec, GValue *value)
234 {
235 g_mutex_lock (element->property_mutex);
236 g_object_get_property ((GObject*)element, pspec->name, value);
237 g_mutex_unlock (element->property_mutex);
238 }
240 static void
241 gst_element_threadsafe_properties_pre_run (GstElement *element)
242 {
243 GST_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
244 g_mutex_lock (element->property_mutex);
245 gst_element_set_pending_properties (element);
246 }
248 static void
249 gst_element_threadsafe_properties_post_run (GstElement *element)
250 {
251 GST_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
252 g_mutex_unlock (element->property_mutex);
253 }
255 /**
256 * gst_element_enable_threadsafe_properties:
257 * @element: a #GstElement to enable threadsafe properties on.
258 *
259 * Installs an asynchronous queue, a mutex and pre- and post-run functions on
260 * this element so that properties on the element can be set in a
261 * threadsafe way.
262 */
263 void
264 gst_element_enable_threadsafe_properties (GstElement *element)
265 {
266 g_return_if_fail (GST_IS_ELEMENT (element));
268 GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
269 element->pre_run_func = gst_element_threadsafe_properties_pre_run;
270 element->post_run_func = gst_element_threadsafe_properties_post_run;
271 if (!element->prop_value_queue)
272 element->prop_value_queue = g_async_queue_new ();
273 if (!element->property_mutex)
274 element->property_mutex = g_mutex_new ();
275 }
277 /**
278 * gst_element_disable_threadsafe_properties:
279 * @element: a #GstElement to disable threadsafe properties on.
280 *
281 * Removes the threadsafe properties, post- and pre-run locks from
282 * this element.
283 */
284 void
285 gst_element_disable_threadsafe_properties (GstElement *element)
286 {
287 g_return_if_fail (GST_IS_ELEMENT (element));
289 GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
290 element->pre_run_func = NULL;
291 element->post_run_func = NULL;
292 /* let's keep around that async queue */
293 }
295 /**
296 * gst_element_set_pending_properties:
297 * @element: a #GstElement to set the pending properties on.
298 *
299 * Sets all pending properties on the threadsafe properties enabled
300 * element.
301 */
302 void
303 gst_element_set_pending_properties (GstElement *element)
304 {
305 prop_value_t *prop_value;
307 while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) {
308 g_object_set_property ((GObject*)element, prop_value->pspec->name, &prop_value->value);
309 g_value_unset (&prop_value->value);
310 g_free (prop_value);
311 }
312 }
314 /* following 6 functions taken mostly from gobject.c */
316 /**
317 * gst_element_set:
318 * @element: a #GstElement to set properties on.
319 * @first_property_name: the first property to set.
320 * @...: value of the first property, and more properties to set, ending
321 * with NULL.
322 *
323 * Sets properties on an element. If the element uses threadsafe properties,
324 * they will be queued and set on the object when it is scheduled again.
325 */
326 void
327 gst_element_set (GstElement *element, const gchar *first_property_name, ...)
328 {
329 va_list var_args;
331 g_return_if_fail (GST_IS_ELEMENT (element));
333 va_start (var_args, first_property_name);
334 gst_element_set_valist (element, first_property_name, var_args);
335 va_end (var_args);
336 }
338 /**
339 * gst_element_get:
340 * @element: a #GstElement to get properties of.
341 * @first_property_name: the first property to get.
342 * @...: pointer to a variable to store the first property in, as well as
343 * more properties to get, ending with NULL.
344 *
345 * Gets properties from an element. If the element uses threadsafe properties,
346 * the element will be locked before getting the given properties.
347 */
348 void
349 gst_element_get (GstElement *element, const gchar *first_property_name, ...)
350 {
351 va_list var_args;
353 g_return_if_fail (GST_IS_ELEMENT (element));
355 va_start (var_args, first_property_name);
356 gst_element_get_valist (element, first_property_name, var_args);
357 va_end (var_args);
358 }
360 /**
361 * gst_element_set_valist:
362 * @element: a #GstElement to set properties on.
363 * @first_property_name: the first property to set.
364 * @var_args: the var_args list of other properties to get.
365 *
366 * Sets properties on an element. If the element uses threadsafe properties,
367 * the property change will be put on the async queue.
368 */
369 void
370 gst_element_set_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
371 {
372 const gchar *name;
373 GObject *object;
375 g_return_if_fail (GST_IS_ELEMENT (element));
377 object = (GObject *) element;
379 GST_DEBUG (GST_CAT_PROPERTIES,
380 "setting valist of properties starting with %s on element %s",
381 first_property_name, gst_element_get_name (element));
383 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
384 g_object_set_valist (object, first_property_name, var_args);
385 return;
386 }
388 g_object_ref (object);
390 name = first_property_name;
392 while (name)
393 {
394 GValue value = { 0, };
395 GParamSpec *pspec;
396 gchar *error = NULL;
398 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
400 if (!pspec)
401 {
402 g_warning ("%s: object class `%s' has no property named `%s'",
403 G_STRLOC,
404 G_OBJECT_TYPE_NAME (object),
405 name);
406 break;
407 }
408 if (!(pspec->flags & G_PARAM_WRITABLE))
409 {
410 g_warning ("%s: property `%s' of object class `%s' is not writable",
411 G_STRLOC,
412 pspec->name,
413 G_OBJECT_TYPE_NAME (object));
414 break;
415 }
417 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
419 G_VALUE_COLLECT (&value, var_args, 0, &error);
420 if (error)
421 {
422 g_warning ("%s: %s", G_STRLOC, error);
423 g_free (error);
425 /* we purposely leak the value here, it might not be
426 * in a sane state if an error condition occoured
427 */
428 break;
429 }
431 element_set_property (element, pspec, &value);
432 g_value_unset (&value);
434 name = va_arg (var_args, gchar*);
435 }
437 g_object_unref (object);
438 }
440 /**
441 * gst_element_get_valist:
442 * @element: a #GstElement to get properties of.
443 * @first_property_name: the first property to get.
444 * @var_args: the var_args list of other properties to get.
445 *
446 * Gets properties from an element. If the element uses threadsafe properties,
447 * the element will be locked before getting the given properties.
448 */
449 void
450 gst_element_get_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
451 {
452 const gchar *name;
453 GObject *object;
455 g_return_if_fail (GST_IS_ELEMENT (element));
457 object = (GObject*)element;
459 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
460 g_object_get_valist (object, first_property_name, var_args);
461 return;
462 }
464 g_object_ref (object);
466 name = first_property_name;
468 while (name)
469 {
470 GValue value = { 0, };
471 GParamSpec *pspec;
472 gchar *error;
474 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
476 if (!pspec)
477 {
478 g_warning ("%s: object class `%s' has no property named `%s'",
479 G_STRLOC,
480 G_OBJECT_TYPE_NAME (object),
481 name);
482 break;
483 }
484 if (!(pspec->flags & G_PARAM_READABLE))
485 {
486 g_warning ("%s: property `%s' of object class `%s' is not readable",
487 G_STRLOC,
488 pspec->name,
489 G_OBJECT_TYPE_NAME (object));
490 break;
491 }
493 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
495 element_get_property (element, pspec, &value);
497 G_VALUE_LCOPY (&value, var_args, 0, &error);
498 if (error)
499 {
500 g_warning ("%s: %s", G_STRLOC, error);
501 g_free (error);
502 g_value_unset (&value);
503 break;
504 }
506 g_value_unset (&value);
508 name = va_arg (var_args, gchar*);
509 }
511 g_object_unref (object);
512 }
514 /**
515 * gst_element_set_property:
516 * @element: a #GstElement to set properties on.
517 * @property_name: the first property to get.
518 * @value: the #GValue that holds the value to set.
519 *
520 * Sets a property on an element. If the element uses threadsafe properties,
521 * the property will be put on the async queue.
522 */
523 void
524 gst_element_set_property (GstElement *element, const gchar *property_name,
525 const GValue *value)
526 {
527 GParamSpec *pspec;
528 GObject *object;
530 g_return_if_fail (GST_IS_ELEMENT (element));
531 g_return_if_fail (property_name != NULL);
532 g_return_if_fail (G_IS_VALUE (value));
534 object = (GObject*) element;
536 GST_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
537 property_name, gst_element_get_name (element));
538 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
539 g_object_set_property (object, property_name, value);
540 return;
541 }
543 g_object_ref (object);
545 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
546 property_name);
548 if (!pspec)
549 g_warning ("%s: object class `%s' has no property named `%s'",
550 G_STRLOC,
551 G_OBJECT_TYPE_NAME (object),
552 property_name);
553 else
554 element_set_property (element, pspec, value);
556 g_object_unref (object);
557 }
559 /**
560 * gst_element_get_property:
561 * @element: a #GstElement to get properties of.
562 * @property_name: the first property to get.
563 * @value: the #GValue to store the property value in.
564 *
565 * Gets a property from an element. If the element uses threadsafe properties,
566 * the element will be locked before getting the given property.
567 */
568 void
569 gst_element_get_property (GstElement *element, const gchar *property_name, GValue *value)
570 {
571 GParamSpec *pspec;
572 GObject *object;
574 g_return_if_fail (GST_IS_ELEMENT (element));
575 g_return_if_fail (property_name != NULL);
576 g_return_if_fail (G_IS_VALUE (value));
578 object = (GObject*)element;
580 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
581 g_object_get_property (object, property_name, value);
582 return;
583 }
585 g_object_ref (object);
587 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
589 if (!pspec)
590 g_warning ("%s: object class `%s' has no property named `%s'",
591 G_STRLOC,
592 G_OBJECT_TYPE_NAME (object),
593 property_name);
594 else
595 {
596 GValue *prop_value, tmp_value = { 0, };
598 /* auto-conversion of the callers value type
599 */
600 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
601 {
602 g_value_reset (value);
603 prop_value = value;
604 }
605 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
606 {
607 g_warning ("can't retrieve property `%s' of type `%s' as value of type `%s'",
608 pspec->name,
609 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
610 G_VALUE_TYPE_NAME (value));
611 g_object_unref (object);
612 return;
613 }
614 else
615 {
616 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
617 prop_value = &tmp_value;
618 }
619 element_get_property (element, pspec, prop_value);
620 if (prop_value != value)
621 {
622 g_value_transform (prop_value, value);
623 g_value_unset (&tmp_value);
624 }
625 }
627 g_object_unref (object);
628 }
630 static GstPad*
631 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
632 {
633 GstPad *newpad = NULL;
634 GstElementClass *oclass;
636 oclass = GST_ELEMENT_GET_CLASS (element);
638 if (oclass->request_new_pad)
639 newpad = (oclass->request_new_pad)(element, templ, name);
641 return newpad;
642 }
644 /**
645 * gst_element_release_request_pad:
646 * @element: a #GstElement to release the request pad of.
647 * @pad: the #GstPad to release.
648 *
649 * Makes the element free the previously requested pad as obtained
650 * with gst_element_get_request_pad().
651 */
652 void
653 gst_element_release_request_pad (GstElement *element, GstPad *pad)
654 {
655 GstElementClass *oclass;
657 g_return_if_fail (GST_IS_ELEMENT (element));
658 g_return_if_fail (GST_IS_PAD (pad));
660 oclass = GST_ELEMENT_GET_CLASS (element);
662 if (oclass->release_pad)
663 (oclass->release_pad) (element, pad);
664 }
666 /**
667 * gst_element_requires_clock:
668 * @element: a #GstElement to query
669 *
670 * Query if the element requiresd a clock
671 *
672 * Returns: TRUE if the element requires a clock
673 */
674 gboolean
675 gst_element_requires_clock (GstElement *element)
676 {
677 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
679 return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL);
680 }
682 /**
683 * gst_element_provides_clock:
684 * @element: a #GstElement to query
685 *
686 * Query if the element provides a clock
687 *
688 * Returns: TRUE if the element provides a clock
689 */
690 gboolean
691 gst_element_provides_clock (GstElement *element)
692 {
693 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
695 return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL);
696 }
698 /**
699 * gst_element_set_clock:
700 * @element: a #GstElement to set the clock for.
701 * @clock: the #GstClock to set for the element.
702 *
703 * Sets the clock for the element.
704 */
705 void
706 gst_element_set_clock (GstElement *element, GstClock *clock)
707 {
708 GstElementClass *oclass;
710 g_return_if_fail (GST_IS_ELEMENT (element));
712 oclass = GST_ELEMENT_GET_CLASS (element);
714 if (oclass->set_clock)
715 oclass->set_clock (element, clock);
717 element->clock = clock;
718 }
720 /**
721 * gst_element_get_clock:
722 * @element: a #GstElement to get the clock of.
723 *
724 * Gets the clock of the element.
725 *
726 * Returns: the #GstClock of the element.
727 */
728 GstClock*
729 gst_element_get_clock (GstElement *element)
730 {
731 GstElementClass *oclass;
733 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
735 oclass = GST_ELEMENT_GET_CLASS (element);
737 if (oclass->get_clock)
738 return oclass->get_clock (element);
740 return NULL;
741 }
743 /**
744 * gst_element_clock_wait:
745 * @element: a #GstElement.
746 * @id: the #GstClock to use.
747 * @jitter: the difference between requested time and actual time.
748 *
749 * Waits for a specific time on the clock.
750 *
751 * Returns: the #GstClockReturn result of the wait operation.
752 */
753 GstClockReturn
754 gst_element_clock_wait (GstElement *element, GstClockID id, GstClockTimeDiff *jitter)
755 {
756 GstClockReturn res;
758 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
760 if (GST_ELEMENT_SCHED (element)) {
761 res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id, jitter);
762 }
763 else
764 res = GST_CLOCK_TIMEOUT;
766 return res;
767 }
769 /**
770 * gst_element_is_indexable:
771 * @element: a #GstElement.
772 *
773 * Queries if the element can be indexed/
774 *
775 * Returns: TRUE if the element can be indexed.
776 */
777 gboolean
778 gst_element_is_indexable (GstElement *element)
779 {
780 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
782 return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
783 }
785 /**
786 * gst_element_set_index:
787 * @element: a #GstElement.
788 * @index: a #GstIndex.
789 *
790 * Set the specified GstIndex on the element.
791 */
792 void
793 gst_element_set_index (GstElement *element, GstIndex *index)
794 {
795 GstElementClass *oclass;
797 g_return_if_fail (GST_IS_ELEMENT (element));
798 g_return_if_fail (GST_IS_INDEX (index));
800 oclass = GST_ELEMENT_GET_CLASS (element);
802 if (oclass->set_index)
803 oclass->set_index (element, index);
804 }
806 /**
807 * gst_element_get_index:
808 * @element: a #GstElement.
809 *
810 * Gets the index from the element.
811 *
812 * Returns: a #GstIndex or NULL when no index was set on the
813 * element.
814 */
815 GstIndex*
816 gst_element_get_index (GstElement *element)
817 {
818 GstElementClass *oclass;
820 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
822 oclass = GST_ELEMENT_GET_CLASS (element);
824 if (oclass->get_index)
825 return oclass->get_index (element);
827 return NULL;
828 }
830 /**
831 * gst_element_release_locks:
832 * @element: a #GstElement to release all locks on.
833 *
834 * Instruct the element to release all the locks it is holding, such as
835 * blocking reads, waiting for the clock, ...
836 *
837 * Returns: TRUE if the locks could be released.
838 */
839 gboolean
840 gst_element_release_locks (GstElement *element)
841 {
842 GstElementClass *oclass;
844 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
846 oclass = GST_ELEMENT_GET_CLASS (element);
848 if (oclass->release_locks)
849 return oclass->release_locks (element);
851 return TRUE;
852 }
854 /**
855 * gst_element_add_pad:
856 * @element: a #GstElement to add the pad to.
857 * @pad: the #GstPad to add to the element.
858 *
859 * Add a pad (connection point) to the element, setting the parent of the
860 * pad to the element (and thus adding a reference).
861 */
862 void
863 gst_element_add_pad (GstElement *element, GstPad *pad)
864 {
865 g_return_if_fail (element != NULL);
866 g_return_if_fail (GST_IS_ELEMENT (element));
867 g_return_if_fail (pad != NULL);
868 g_return_if_fail (GST_IS_PAD (pad));
870 /* first check to make sure the pad's parent is already set */
871 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
873 /* then check to see if there's already a pad by that name here */
874 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
876 /* set the pad's parent */
877 GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
878 GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
879 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
881 /* add it to the list */
882 element->pads = g_list_append (element->pads, pad);
883 element->numpads++;
884 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
885 element->numsrcpads++;
886 else
887 element->numsinkpads++;
889 /* emit the NEW_PAD signal */
890 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
891 }
893 /**
894 * gst_element_remove_pad:
895 * @element: a #GstElement to remove pad from.
896 * @pad: the #GstPad to remove from the element.
897 *
898 * Remove a pad (connection point) from the element.
899 */
900 void
901 gst_element_remove_pad (GstElement *element, GstPad *pad)
902 {
903 g_return_if_fail (element != NULL);
904 g_return_if_fail (GST_IS_ELEMENT (element));
905 g_return_if_fail (pad != NULL);
906 g_return_if_fail (GST_IS_PAD (pad));
908 g_return_if_fail (GST_PAD_PARENT (pad) == element);
910 /* check to see if the pad is still connected */
911 /* FIXME: what if someone calls _remove_pad instead of
912 _remove_ghost_pad? */
913 if (GST_IS_REAL_PAD (pad)) {
914 g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
915 }
917 /* remove it from the list */
918 element->pads = g_list_remove (element->pads, pad);
919 element->numpads--;
920 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
921 element->numsrcpads--;
922 else
923 element->numsinkpads--;
925 g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
927 gst_object_unparent (GST_OBJECT (pad));
928 }
930 /**
931 * gst_element_add_ghost_pad:
932 * @element: a #GstElement to add the ghost pad to.
933 * @pad: the #GstPad from which the new ghost pad will be created.
934 * @name: the name of the new ghost pad.
935 *
936 * Creates a ghost pad from the given pad, and adds it to the list of pads
937 * for this element.
938 *
939 * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
940 */
941 GstPad *
942 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
943 {
944 GstPad *ghostpad;
946 g_return_val_if_fail (element != NULL, NULL);
947 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
948 g_return_val_if_fail (pad != NULL, NULL);
949 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
951 /* then check to see if there's already a pad by that name here */
952 g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
954 GST_DEBUG (GST_CAT_ELEMENT_PADS,
955 "creating new ghost pad called %s, from pad %s:%s",
956 name, GST_DEBUG_PAD_NAME(pad));
957 ghostpad = gst_ghost_pad_new (name, pad);
959 /* add it to the list */
960 GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
961 name, GST_ELEMENT_NAME (element));
962 element->pads = g_list_append (element->pads, ghostpad);
963 element->numpads++;
964 /* set the parent of the ghostpad */
965 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
967 GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
969 /* emit the NEW_GHOST_PAD signal */
970 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
972 return ghostpad;
973 }
975 /**
976 * gst_element_remove_ghost_pad:
977 * @element: a #GstElement to remove the ghost pad from.
978 * @pad: ghost #GstPad to remove.
979 *
980 * Removes a ghost pad from an element.
981 */
982 void
983 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
984 {
985 g_return_if_fail (element != NULL);
986 g_return_if_fail (GST_IS_ELEMENT (element));
987 g_return_if_fail (pad != NULL);
988 g_return_if_fail (GST_IS_GHOST_PAD (pad));
990 /* FIXME this is redundant?
991 * wingo 10-july-2001: I don't think so, you have to actually remove the pad
992 * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
993 * the real pad's ghost pad list
994 */
995 gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
996 gst_element_remove_pad (element, pad);
997 }
1000 /**
1001 * gst_element_get_pad:
1002 * @element: a #GstElement to find pad of.
1003 * @name: the name of the pad to retrieve.
1004 *
1005 * Retrieves a pad from the element by name.
1006 *
1007 * Returns: requested #GstPad if found, otherwise NULL.
1008 */
1009 GstPad*
1010 gst_element_get_pad (GstElement *element, const gchar *name)
1011 {
1012 GstPad *pad;
1014 g_return_val_if_fail (element != NULL, NULL);
1015 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1016 g_return_val_if_fail (name != NULL, NULL);
1018 pad = gst_element_get_static_pad (element, name);
1019 if (!pad)
1020 pad = gst_element_get_request_pad (element, name);
1022 return pad;
1023 }
1025 /**
1026 * gst_element_get_static_pad:
1027 * @element: a #GstElement to find a static pad of.
1028 * @name: the name of the static #GstPad to retrieve.
1029 *
1030 * Retrieves a pad from the element by name. This version only retrieves
1031 * already-existing (i.e. 'static') pads.
1032 *
1033 * Returns: the requested #GstPad if found, otherwise NULL.
1034 */
1035 GstPad *
1036 gst_element_get_static_pad (GstElement *element, const gchar *name)
1037 {
1038 GList *walk;
1040 g_return_val_if_fail (element != NULL, NULL);
1041 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1042 g_return_val_if_fail (name != NULL, NULL);
1044 walk = element->pads;
1045 while (walk) {
1046 GstPad *pad;
1048 pad = GST_PAD(walk->data);
1049 if (strcmp (GST_PAD_NAME(pad), name) == 0) {
1050 GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1051 return pad;
1052 }
1053 walk = g_list_next (walk);
1054 }
1056 GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
1057 return NULL;
1058 }
1060 /**
1061 * gst_element_get_request_pad:
1062 * @element: a #GstElement to find a request pad of.
1063 * @name: the name of the request #GstPad to retrieve.
1064 *
1065 * Retrieves a pad from the element by name. This version only retrieves
1066 * request pads.
1067 *
1068 * Returns: requested #GstPad if found, otherwise NULL.
1069 */
1070 GstPad*
1071 gst_element_get_request_pad (GstElement *element, const gchar *name)
1072 {
1073 GstPadTemplate *templ = NULL;
1074 GstPad *pad;
1075 const gchar *req_name = NULL;
1076 gboolean templ_found = FALSE;
1077 GList *list;
1078 gint n;
1079 const gchar *data;
1080 gchar *str, *endptr = NULL;
1082 g_return_val_if_fail (element != NULL, NULL);
1083 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1084 g_return_val_if_fail (name != NULL, NULL);
1086 if (strstr (name, "%")) {
1087 templ = gst_element_get_pad_template (element, name);
1088 req_name = NULL;
1089 if (templ)
1090 templ_found = TRUE;
1091 } else {
1092 list = gst_element_get_pad_template_list(element);
1093 while (!templ_found && list) {
1094 templ = (GstPadTemplate*) list->data;
1095 if (templ->presence == GST_PAD_REQUEST) {
1096 /* we know that %s and %d are the only possibilities because of sanity
1097 checks in gst_pad_template_new */
1098 GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
1099 if ((str = strchr (templ->name_template, '%')) &&
1100 strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
1101 strlen (name) > str - templ->name_template) {
1102 data = name + (str - templ->name_template);
1103 if (*(str+1) == 'd') {
1104 /* it's an int */
1105 n = (gint) strtol (data, &endptr, 10);
1106 if (endptr && *endptr == '\0') {
1107 templ_found = TRUE;
1108 req_name = name;
1109 break;
1110 }
1111 } else {
1112 /* it's a string */
1113 templ_found = TRUE;
1114 req_name = name;
1115 break;
1116 }
1117 }
1118 }
1119 list = list->next;
1120 }
1121 }
1123 if (!templ_found)
1124 return NULL;
1126 pad = gst_element_request_pad (element, templ, req_name);
1128 return pad;
1129 }
1131 /**
1132 * gst_element_get_pad_list:
1133 * @element: a #GstElement to get pads of.
1134 *
1135 * Retrieves a list of the pads associated with the element.
1136 *
1137 * Returns: the #GList of pads.
1138 */
1139 const GList*
1140 gst_element_get_pad_list (GstElement *element)
1141 {
1142 g_return_val_if_fail (element != NULL, NULL);
1143 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1145 /* return the list of pads */
1146 return element->pads;
1147 }
1149 /**
1150 * gst_element_class_add_pad_template:
1151 * @klass: the #GstElementClass to add the pad template to.
1152 * @templ: a #GstPadTemplate to add to the element class.
1153 *
1154 * Adds a padtemplate to an element class.
1155 * This is useful if you have derived a custom bin and wish to provide
1156 * an on-request pad at runtime. Plug-in writers should use
1157 * gst_element_factory_add_pad_template instead.
1158 */
1159 void
1160 gst_element_class_add_pad_template (GstElementClass *klass,
1161 GstPadTemplate *templ)
1162 {
1163 g_return_if_fail (klass != NULL);
1164 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1165 g_return_if_fail (templ != NULL);
1166 g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1168 klass->padtemplates = g_list_append (klass->padtemplates, templ);
1169 klass->numpadtemplates++;
1170 }
1172 /**
1173 * gst_element_get_pad_template_list:
1174 * @element: a #GstElement to get pad templates of.
1175 *
1176 * Retrieves a list of the pad templates associated with the element.
1177 *
1178 * Returns: the #GList of padtemplates.
1179 */
1180 GList*
1181 gst_element_get_pad_template_list (GstElement *element)
1182 {
1183 g_return_val_if_fail (element != NULL, NULL);
1184 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1186 return GST_ELEMENT_GET_CLASS (element)->padtemplates;
1187 }
1189 /**
1190 * gst_element_get_pad_template:
1191 * @element: a #GstElement to get the pad template of.
1192 * @name: the name of the #GstPadTemplate to get.
1193 *
1194 * Retrieves a padtemplate from this element with the
1195 * given name.
1196 *
1197 * Returns: the #GstPadTemplate with the given name, or NULL if none was found.
1198 * No unreferencing is necessary.
1199 */
1200 GstPadTemplate*
1201 gst_element_get_pad_template (GstElement *element, const gchar *name)
1202 {
1203 GList *padlist;
1205 g_return_val_if_fail (element != NULL, NULL);
1206 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1207 g_return_val_if_fail (name != NULL, NULL);
1209 padlist = gst_element_get_pad_template_list (element);
1211 while (padlist) {
1212 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1214 if (!strcmp (padtempl->name_template, name))
1215 return padtempl;
1217 padlist = g_list_next (padlist);
1218 }
1220 return NULL;
1221 }
1223 /**
1224 * gst_element_get_compatible_pad_template:
1225 * @element: a #GstElement to get a compatible pad template for.
1226 * @compattempl: the #GstPadTemplate to find a compatible template for.
1227 *
1228 * Generates a pad template for this element compatible with the given
1229 * template (meaning it is able to connect with it).
1230 *
1231 * Returns: the #GstPadTemplate of the element that is compatible with
1232 * the given GstPadTemplate, or NULL if none was found. No unreferencing
1233 * is necessary.
1234 */
1235 GstPadTemplate*
1236 gst_element_get_compatible_pad_template (GstElement *element,
1237 GstPadTemplate *compattempl)
1238 {
1239 GstPadTemplate *newtempl = NULL;
1240 GList *padlist;
1242 GST_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
1244 g_return_val_if_fail (element != NULL, NULL);
1245 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1246 g_return_val_if_fail (compattempl != NULL, NULL);
1248 padlist = gst_element_get_pad_template_list (element);
1250 while (padlist) {
1251 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1252 gboolean comp = FALSE;
1254 /* Ignore name
1255 * Ignore presence
1256 * Check direction (must be opposite)
1257 * Check caps
1258 */
1259 GST_DEBUG (GST_CAT_CAPS, "checking direction and caps");
1260 if (padtempl->direction == GST_PAD_SRC &&
1261 compattempl->direction == GST_PAD_SINK) {
1262 GST_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
1263 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (padtempl),
1264 GST_PAD_TEMPLATE_CAPS (compattempl));
1265 GST_DEBUG(GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1266 } else if (padtempl->direction == GST_PAD_SINK &&
1267 compattempl->direction == GST_PAD_SRC) {
1268 GST_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
1269 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1270 GST_PAD_TEMPLATE_CAPS (padtempl));
1271 GST_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1272 }
1274 if (comp) {
1275 newtempl = padtempl;
1276 break;
1277 }
1279 padlist = g_list_next (padlist);
1280 }
1282 return newtempl;
1283 }
1285 /**
1286 * gst_element_request_compatible_pad:
1287 * @element: a #GstElement to request a new pad from.
1288 * @templ: the #GstPadTemplate to which the new pad should be able to connect.
1289 *
1290 * Requests a new pad from the element. The template will
1291 * be used to decide what type of pad to create. This function
1292 * is typically used for elements with a padtemplate with presence
1293 * GST_PAD_REQUEST.
1294 *
1295 * Returns: the new #GstPad that was created, or NULL if none could be created.
1296 */
1297 GstPad*
1298 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
1299 {
1300 GstPadTemplate *templ_new;
1301 GstPad *pad = NULL;
1303 g_return_val_if_fail (element != NULL, NULL);
1304 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1305 g_return_val_if_fail (templ != NULL, NULL);
1307 templ_new = gst_element_get_compatible_pad_template (element, templ);
1308 if (templ_new != NULL)
1309 pad = gst_element_request_pad (element, templ_new, NULL);
1311 return pad;
1312 }
1315 /**
1316 * gst_element_get_compatible_pad_filtered:
1317 * @element: a #GstElement in which the pad should be found.
1318 * @pad: the #GstPad to find a compatible one for.
1319 * @filtercaps: the #GstCaps to use as a filter.
1320 *
1321 * Looks for an unconnected pad to which the given pad can connect to.
1322 * It is not guaranteed that connecting the pads will work, though
1323 * it should work in most cases.
1324 *
1325 * Returns: the #GstPad to which a connection can be made.
1326 */
1327 GstPad*
1328 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
1329 GstCaps *filtercaps)
1330 {
1331 const GList *pads;
1332 GstPadTemplate *templ;
1333 GstCaps *templcaps;
1334 GstPad *foundpad = NULL;
1336 /* checks */
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 (pad != NULL, NULL);
1340 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1342 /* let's use the real pad */
1343 pad = (GstPad *) GST_PAD_REALIZE (pad);
1344 g_return_val_if_fail (pad != NULL, NULL);
1345 g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1347 /* try to get an existing unconnected pad */
1348 pads = gst_element_get_pad_list (element);
1349 while (pads) {
1350 GstPad *current = GST_PAD (pads->data);
1351 if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
1352 gst_pad_can_connect_filtered (pad, current, filtercaps)) {
1353 return current;
1354 }
1355 pads = g_list_next (pads);
1356 }
1358 /* try to create a new one */
1359 /* requesting is a little crazy, we need a template. Let's create one */
1360 if (filtercaps != NULL) {
1361 templcaps = gst_caps_intersect (filtercaps, (GstCaps *) GST_RPAD_CAPS (pad));
1362 if (templcaps == NULL)
1363 return NULL;
1364 } else {
1365 templcaps = gst_caps_copy (gst_pad_get_caps (pad));
1366 }
1368 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1369 GST_PAD_ALWAYS, templcaps, NULL);
1370 foundpad = gst_element_request_compatible_pad (element, templ);
1371 gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
1373 /* FIXME: this is broken, but it's in here so autoplugging elements that don't
1374 have caps on their source padtemplates (spider) can connect... */
1375 if (!foundpad && !filtercaps) {
1376 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1377 GST_PAD_ALWAYS, NULL, NULL);
1378 foundpad = gst_element_request_compatible_pad (element, templ);
1379 gst_object_unref (GST_OBJECT (templ));
1380 }
1382 return foundpad;
1383 }
1385 /**
1386 * gst_element_get_compatible_pad:
1387 * @element: a #GstElement in which the pad should be found.
1388 * @pad: the #GstPad to find a compatible one for.
1389 *
1390 * Looks for an unconnected pad to which the given pad can connect to.
1391 * It is not guaranteed that connecting the pads will work, though
1392 * it should work in most cases.
1393 *
1394 * Returns: the #GstPad to which a connection can be made, or NULL if none
1395 * could be found.
1396 */
1397 GstPad*
1398 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
1399 {
1400 return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1401 }
1403 /**
1404 * gst_element_connect_filtered:
1405 * @src: a #GstElement containing the source pad.
1406 * @dest: the #GstElement containing the destination pad.
1407 * @filtercaps: the #GstCaps to use as a filter.
1408 *
1409 * Connects the source to the destination element using the filtercaps.
1410 * The connection must be from source to destination, the other
1411 * direction will not be tried.
1412 * The functions looks for existing pads that aren't connected yet.
1413 * It will use request pads if possible. But both pads will not be requested.
1414 * If multiple connections are possible, only one is established.
1415 *
1416 * Returns: TRUE if the elements could be connected.
1417 */
1418 gboolean
1419 gst_element_connect_filtered (GstElement *src, GstElement *dest,
1420 GstCaps *filtercaps)
1421 {
1422 const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1423 GstPad *srcpad, *destpad;
1424 GstPadTemplate *srctempl, *desttempl;
1426 /* checks */
1427 g_return_val_if_fail (src != NULL, FALSE);
1428 g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1429 g_return_val_if_fail (dest != NULL, FALSE);
1430 g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1432 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying to connect element %s to element %s",
1433 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1435 srcpads = gst_element_get_pad_list (src);
1436 destpads = gst_element_get_pad_list (dest);
1438 if (srcpads || destpads) {
1439 GST_DEBUG (GST_CAT_ELEMENT_PADS, "looping through src and dest pads");
1440 /* loop through the existing pads in the source, trying to find a
1441 * compatible destination pad */
1442 while (srcpads) {
1443 srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1444 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
1445 GST_DEBUG_PAD_NAME (srcpad));
1446 if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1447 (GST_PAD_PEER (srcpad) == NULL)) {
1448 destpad = gst_element_get_compatible_pad_filtered (dest, srcpad,
1449 filtercaps);
1450 if (destpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1451 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
1452 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1453 return TRUE;
1454 }
1455 }
1456 srcpads = g_list_next (srcpads);
1457 }
1459 /* loop through the existing pads in the destination */
1460 while (destpads) {
1461 destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1462 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
1463 GST_DEBUG_PAD_NAME (destpad));
1464 if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1465 (GST_PAD_PEER (destpad) == NULL)) {
1466 srcpad = gst_element_get_compatible_pad_filtered (src, destpad,
1467 filtercaps);
1468 if (srcpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1469 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
1470 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1471 return TRUE;
1472 }
1473 }
1474 destpads = g_list_next (destpads);
1475 }
1476 }
1478 GST_DEBUG (GST_CAT_ELEMENT_PADS,
1479 "we might have request pads on both sides, checking...");
1480 srctempls = gst_element_get_pad_template_list (src);
1481 desttempls = gst_element_get_pad_template_list (dest);
1483 if (srctempls && desttempls) {
1484 while (srctempls) {
1485 srctempl = (GstPadTemplate*) srctempls->data;
1486 if (srctempl->presence == GST_PAD_REQUEST) {
1487 for (l=desttempls; l; l=l->next) {
1488 desttempl = (GstPadTemplate*) desttempls->data;
1489 if (desttempl->presence == GST_PAD_REQUEST &&
1490 desttempl->direction != srctempl->direction) {
1491 if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
1492 gst_pad_template_get_caps (desttempl))) {
1493 srcpad = gst_element_get_request_pad (src,
1494 srctempl->name_template);
1495 destpad = gst_element_get_request_pad (dest,
1496 desttempl->name_template);
1497 if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1498 GST_DEBUG (GST_CAT_ELEMENT_PADS,
1499 "connected pad %s:%s to pad %s:%s",
1500 GST_DEBUG_PAD_NAME (srcpad),
1501 GST_DEBUG_PAD_NAME (destpad));
1502 return TRUE;
1503 }
1504 /* FIXME: we have extraneous request pads lying around */
1505 }
1506 }
1507 }
1508 }
1509 srctempls = srctempls->next;
1510 }
1511 }
1513 GST_DEBUG (GST_CAT_ELEMENT_PADS, "no connection possible from %s to %s",
1514 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1515 return FALSE;
1516 }
1518 /**
1519 * gst_element_connect_many:
1520 * @element_1: the first #GstElement in the connection chain.
1521 * @element_2: the second #GstElement in the connection chain.
1522 * @...: the NULL-terminated list of elements to connect in order.
1523 *
1524 * Chain together a series of elements. Uses #gst_element_connect.
1525 *
1526 * Returns: TRUE on success, FALSE otherwise.
1527 */
1528 gboolean
1529 gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
1530 {
1531 va_list args;
1533 g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1534 g_return_val_if_fail (GST_IS_ELEMENT (element_1) &&
1535 GST_IS_ELEMENT (element_2), FALSE);
1537 va_start (args, element_2);
1539 while (element_2) {
1540 if (!gst_element_connect (element_1, element_2))
1541 return FALSE;
1543 element_1 = element_2;
1544 element_2 = va_arg (args, GstElement*);
1545 }
1547 va_end (args);
1549 return TRUE;
1550 }
1552 /**
1553 * gst_element_connect:
1554 * @src: a #GstElement containing the source pad.
1555 * @dest: the #GstElement containing the destination pad.
1556 *
1557 * Connects the source to the destination element.
1558 * The connection must be from source to destination, the other
1559 * direction will not be tried.
1560 * The functions looks for existing pads and request pads that aren't
1561 * connected yet. If multiple connections are possible, only one is
1562 * established.
1563 *
1564 * Returns: TRUE if the elements could be connected.
1565 */
1566 gboolean
1567 gst_element_connect (GstElement *src, GstElement *dest)
1568 {
1569 return gst_element_connect_filtered (src, dest, NULL);
1570 }
1572 /**
1573 * gst_element_connect_pads_filtered:
1574 * @src: a #GstElement containing the source pad.
1575 * @srcpadname: the name of the #GstPad in source element.
1576 * @dest: the #GstElement containing the destination pad.
1577 * @destpadname: the name of the #GstPad in destination element.
1578 * @filtercaps: the #GstCaps to use as a filter.
1579 *
1580 * Connects the two named pads of the source and destination elements.
1581 * Side effect is that if one of the pads has no parent, it becomes a
1582 * child of the parent of the other element. If they have different
1583 * parents, the connection fails.
1584 *
1585 * Returns: TRUE if the pads could be connected.
1586 */
1587 gboolean
1588 gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
1589 GstElement *dest, const gchar *destpadname,
1590 GstCaps *filtercaps)
1591 {
1592 GstPad *srcpad,*destpad;
1594 g_return_val_if_fail (src != NULL, FALSE);
1595 g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1596 g_return_val_if_fail (srcpadname != NULL, FALSE);
1597 g_return_val_if_fail (dest != NULL, FALSE);
1598 g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1599 g_return_val_if_fail (destpadname != NULL, FALSE);
1601 /* obtain the pads requested */
1602 srcpad = gst_element_get_pad (src, srcpadname);
1603 if (srcpad == NULL) {
1604 GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
1605 return FALSE;
1606 }
1607 destpad = gst_element_get_pad (dest, destpadname);
1608 if (srcpad == NULL) {
1609 GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
1610 return FALSE;
1611 }
1613 /* we're satisified they can be connected, let's do it */
1614 return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
1615 }
1617 /**
1618 * gst_element_connect_pads:
1619 * @src: a #GstElement containing the source pad.
1620 * @srcpadname: the name of the #GstPad in the source element.
1621 * @dest: the #GstElement containing the destination pad.
1622 * @destpadname: the name of the #GstPad in destination element.
1623 *
1624 * Connects the two named pads of the source and destination elements.
1625 * Side effect is that if one of the pads has no parent, it becomes a
1626 * child of the parent of the other element. If they have different
1627 * parents, the connection fails.
1628 *
1629 * Returns: TRUE if the pads could be connected.
1630 */
1631 gboolean
1632 gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
1633 GstElement *dest, const gchar *destpadname)
1634 {
1635 return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1636 }
1638 /**
1639 * gst_element_disconnect_pads:
1640 * @src: a #GstElement containing the source pad.
1641 * @srcpadname: the name of the #GstPad in source element.
1642 * @dest: a #GstElement containing the destination pad.
1643 * @destpadname: the name of the #GstPad in destination element.
1644 *
1645 * Disconnects the two named pads of the source and destination elements.
1646 */
1647 void
1648 gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
1649 GstElement *dest, const gchar *destpadname)
1650 {
1651 GstPad *srcpad,*destpad;
1653 g_return_if_fail (src != NULL);
1654 g_return_if_fail (GST_IS_ELEMENT(src));
1655 g_return_if_fail (srcpadname != NULL);
1656 g_return_if_fail (dest != NULL);
1657 g_return_if_fail (GST_IS_ELEMENT(dest));
1658 g_return_if_fail (destpadname != NULL);
1660 /* obtain the pads requested */
1661 srcpad = gst_element_get_pad (src, srcpadname);
1662 if (srcpad == NULL) {
1663 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
1664 return;
1665 }
1666 destpad = gst_element_get_pad (dest, destpadname);
1667 if (srcpad == NULL) {
1668 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
1669 return;
1670 }
1672 /* we're satisified they can be disconnected, let's do it */
1673 gst_pad_disconnect(srcpad,destpad);
1674 }
1676 /**
1677 * gst_element_disconnect_many:
1678 * @element_1: the first #GstElement in the connection chain.
1679 * @element_2: the second #GstElement in the connection chain.
1680 * @...: the NULL-terminated list of elements to disconnect in order.
1681 *
1682 * Disconnects a series of elements. Uses #gst_element_disconnect.
1683 */
1684 void
1685 gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
1686 {
1687 va_list args;
1689 g_return_if_fail (element_1 != NULL && element_2 != NULL);
1690 g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1692 va_start (args, element_2);
1694 while (element_2) {
1695 gst_element_disconnect (element_1, element_2);
1697 element_1 = element_2;
1698 element_2 = va_arg (args, GstElement*);
1699 }
1701 va_end (args);
1702 }
1704 /**
1705 * gst_element_disconnect:
1706 * @src: the source #GstElement to disconnect.
1707 * @dest: the sink #GstElement to disconnect.
1708 *
1709 * Disconnects all source pads of the source element with all sink pads
1710 * of the sink element to which they are connected.
1711 */
1712 void
1713 gst_element_disconnect (GstElement *src, GstElement *dest)
1714 {
1715 const GList *srcpads;
1716 GstPad *pad;
1718 g_return_if_fail (GST_IS_ELEMENT (src));
1719 g_return_if_fail (GST_IS_ELEMENT (dest));
1721 GST_DEBUG (GST_CAT_ELEMENT_PADS, "disconnecting \"%s\" and \"%s\"",
1722 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1724 srcpads = gst_element_get_pad_list (src);
1726 while (srcpads) {
1727 pad = GST_PAD_CAST (srcpads->data);
1729 if (GST_IS_REAL_PAD (pad) && GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1730 GstPad *peerpad = GST_PAD_PEER (pad);
1732 if (peerpad &&
1733 (GST_OBJECT_PARENT (GST_PAD_PEER (peerpad)) == (GstObject*) src)) {
1734 gst_pad_disconnect (pad, peerpad);
1735 }
1736 }
1738 srcpads = g_list_next (srcpads);
1739 }
1740 }
1742 static void
1743 gst_element_error_func (GstElement* element, GstElement *source,
1744 gchar *errormsg)
1745 {
1746 /* tell the parent */
1747 if (GST_OBJECT_PARENT (element)) {
1748 GST_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s",
1749 errormsg, GST_ELEMENT_NAME (element),
1750 GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
1752 gst_object_ref (GST_OBJECT (element));
1753 g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)),
1754 gst_element_signals[ERROR], 0, source, errormsg);
1755 gst_object_unref (GST_OBJECT (element));
1756 }
1757 }
1759 static GstPad*
1760 gst_element_get_random_pad (GstElement *element, GstPadDirection dir)
1761 {
1762 GList *pads = element->pads;
1763 GST_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
1764 while (pads) {
1765 GstPad *pad = GST_PAD_CAST (pads->data);
1767 GST_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
1768 GST_DEBUG_PAD_NAME (pad));
1770 if (GST_PAD_DIRECTION (pad) == dir) {
1771 if (GST_PAD_IS_CONNECTED (pad)) {
1772 return pad;
1773 }
1774 else {
1775 GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not connected",
1776 GST_DEBUG_PAD_NAME (pad));
1777 }
1778 }
1779 else {
1780 GST_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
1781 GST_DEBUG_PAD_NAME (pad));
1782 }
1784 pads = g_list_next (pads);
1785 }
1786 return NULL;
1787 }
1789 /**
1790 * gst_element_get_event_masks:
1791 * @element: a #GstElement to query
1792 *
1793 * Get an array of event masks from the element.
1794 * If the element doesn't
1795 * implement an event masks function, the query will be forwarded
1796 * to a random connected sink pad.
1797 *
1798 * Returns: An array of #GstEventMask elements.
1799 */
1800 const GstEventMask*
1801 gst_element_get_event_masks (GstElement *element)
1802 {
1803 GstElementClass *oclass;
1805 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1807 oclass = GST_ELEMENT_GET_CLASS (element);
1809 if (oclass->get_event_masks)
1810 return oclass->get_event_masks (element);
1811 else {
1812 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1813 if (pad)
1814 return gst_pad_get_event_masks (GST_PAD_PEER (pad));
1815 }
1817 return FALSE;
1818 }
1820 /**
1821 * gst_element_send_event:
1822 * @element: a #GstElement to send the event to.
1823 * @event: the #GstEvent to send to the element.
1824 *
1825 * Sends an event to an element. If the element doesn't
1826 * implement an event handler, the event will be forwarded
1827 * to a random sink pad.
1828 *
1829 * Returns: TRUE if the event was handled.
1830 */
1831 gboolean
1832 gst_element_send_event (GstElement *element, GstEvent *event)
1833 {
1834 GstElementClass *oclass;
1836 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1837 g_return_val_if_fail (event != NULL, FALSE);
1839 oclass = GST_ELEMENT_GET_CLASS (element);
1841 if (oclass->send_event)
1842 return oclass->send_event (element, event);
1843 else {
1844 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1845 if (pad) {
1846 GST_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
1847 GST_DEBUG_PAD_NAME (pad));
1848 return gst_pad_send_event (GST_PAD_PEER (pad), event);
1849 }
1850 }
1851 GST_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
1852 GST_ELEMENT_NAME (element));
1853 return FALSE;
1854 }
1856 /**
1857 * gst_element_get_query_types:
1858 * @element: a #GstElement to query
1859 *
1860 * Get an array of query types from the element.
1861 * If the element doesn't
1862 * implement a query types function, the query will be forwarded
1863 * to a random sink pad.
1864 *
1865 * Returns: An array of #GstQueryType elements.
1866 */
1867 const GstQueryType*
1868 gst_element_get_query_types (GstElement *element)
1869 {
1870 GstElementClass *oclass;
1872 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1874 oclass = GST_ELEMENT_GET_CLASS (element);
1876 if (oclass->get_query_types)
1877 return oclass->get_query_types (element);
1878 else {
1879 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1880 if (pad)
1881 return gst_pad_get_query_types (GST_PAD_PEER (pad));
1882 }
1884 return FALSE;
1885 }
1887 /**
1888 * gst_element_query:
1889 * @element: a #GstElement to perform the query on.
1890 * @type: the #GstQueryType.
1891 * @format: the #GstFormat pointer to hold the format of the result.
1892 * @value: the pointer to the value of the result.
1893 *
1894 * Performs a query on the given element. If the format is set
1895 * to GST_FORMAT_DEFAULT and this function returns TRUE, the
1896 * format pointer will hold the default format.
1897 * For element that don't implement a query handler, this function
1898 * forwards the query to a random usable sinkpad of this element.
1899 *
1900 * Returns: TRUE if the query could be performed.
1901 */
1902 gboolean
1903 gst_element_query (GstElement *element, GstQueryType type,
1904 GstFormat *format, gint64 *value)
1905 {
1906 GstElementClass *oclass;
1908 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1909 g_return_val_if_fail (format != NULL, FALSE);
1910 g_return_val_if_fail (value != NULL, FALSE);
1912 oclass = GST_ELEMENT_GET_CLASS (element);
1914 if (oclass->query)
1915 return oclass->query (element, type, format, value);
1916 else {
1917 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1918 if (pad)
1919 return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
1920 }
1922 return FALSE;
1923 }
1925 /**
1926 * gst_element_get_formats:
1927 * @element: a #GstElement to query
1928 *
1929 * Get an array of formst from the element.
1930 * If the element doesn't
1931 * implement a formats function, the query will be forwarded
1932 * to a random sink pad.
1933 *
1934 * Returns: An array of #GstFormat elements.
1935 */
1936 const GstFormat*
1937 gst_element_get_formats (GstElement *element)
1938 {
1939 GstElementClass *oclass;
1941 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1943 oclass = GST_ELEMENT_GET_CLASS (element);
1945 if (oclass->get_formats)
1946 return oclass->get_formats (element);
1947 else {
1948 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1949 if (pad)
1950 return gst_pad_get_formats (GST_PAD_PEER (pad));
1951 }
1953 return FALSE;
1954 }
1956 /**
1957 * gst_element_convert:
1958 * @element: a #GstElement to invoke the converter on.
1959 * @src_format: the source #GstFormat.
1960 * @src_value: the source value.
1961 * @dest_format: a pointer to the destination #GstFormat.
1962 * @dest_value: a pointer to the destination value.
1963 *
1964 * Invokes a conversion on the element.
1965 * If the element doesn't
1966 * implement a convert function, the query will be forwarded
1967 * to a random sink pad.
1968 *
1969 * Returns: TRUE if the conversion could be performed.
1970 */
1971 gboolean
1972 gst_element_convert (GstElement *element,
1973 GstFormat src_format, gint64 src_value,
1974 GstFormat *dest_format, gint64 *dest_value)
1975 {
1976 GstElementClass *oclass;
1978 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1979 g_return_val_if_fail (dest_format != NULL, FALSE);
1980 g_return_val_if_fail (dest_value != NULL, FALSE);
1982 if (src_format == *dest_format) {
1983 *dest_value = src_value;
1984 return TRUE;
1985 }
1987 oclass = GST_ELEMENT_GET_CLASS (element);
1989 if (oclass->convert)
1990 return oclass->convert (element,
1991 src_format, src_value,
1992 dest_format, dest_value);
1993 else {
1994 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1995 if (pad)
1996 return gst_pad_convert (GST_PAD_PEER (pad),
1997 src_format, src_value,
1998 dest_format, dest_value);
1999 }
2001 return FALSE;
2002 }
2004 /**
2005 * gst_element_error:
2006 * @element: a #GstElement with the error.
2007 * @error: the printf-style string describing the error.
2008 * @...: the optional arguments for the string.
2009 *
2010 * signals an error condition on an element.
2011 * This function is used internally by elements.
2012 * It results in the "error" signal.
2013 */
2014 void
2015 gst_element_error (GstElement *element, const gchar *error, ...)
2016 {
2017 va_list var_args;
2018 gchar *string;
2020 /* checks */
2021 g_return_if_fail (GST_IS_ELEMENT (element));
2022 g_return_if_fail (error != NULL);
2024 /* create error message */
2025 va_start (var_args, error);
2026 string = g_strdup_vprintf (error, var_args);
2027 va_end (var_args);
2028 GST_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
2030 /* emit the signal, make sure the element stays available */
2031 gst_object_ref (GST_OBJECT (element));
2032 g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, string);
2034 /* tell the scheduler */
2035 if (element->sched) {
2036 gst_scheduler_error (element->sched, element);
2037 }
2039 gst_element_set_state (element, GST_STATE_PAUSED);
2041 /* cleanup */
2042 gst_object_unref (GST_OBJECT (element));
2043 g_free (string);
2044 }
2046 /**
2047 * gst_element_get_state:
2048 * @element: a #GstElement to get the state of.
2049 *
2050 * Gets the state of the element.
2051 *
2052 * Returns: the #GstElementState of the element.
2053 */
2054 GstElementState
2055 gst_element_get_state (GstElement *element)
2056 {
2057 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2059 return GST_STATE (element);
2060 }
2062 /**
2063 * gst_element_wait_state_change:
2064 * @element: a #GstElement to wait for a state change on.
2065 *
2066 * Waits and blocks until the element changed its state.
2067 */
2068 void
2069 gst_element_wait_state_change (GstElement *element)
2070 {
2071 g_mutex_lock (element->state_mutex);
2072 g_cond_wait (element->state_cond, element->state_mutex);
2073 g_mutex_unlock (element->state_mutex);
2074 }
2076 /**
2077 * gst_element_set_state:
2078 * @element: a #GstElement to change state of.
2079 * @state: the element's new #GstElementState.
2080 *
2081 * Sets the state of the element. This function will try to set the
2082 * requested state by going through all the intermediary states and calling
2083 * the class's state change function for each.
2084 *
2085 * Returns: TRUE if the state was successfully set.
2086 * (using #GstElementStateReturn).
2087 */
2088 GstElementStateReturn
2089 gst_element_set_state (GstElement *element, GstElementState state)
2090 {
2091 GstElementClass *oclass;
2092 GstElementState curpending;
2093 GstElementStateReturn return_val = GST_STATE_SUCCESS;
2095 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2097 /* start with the current state */
2098 curpending = GST_STATE(element);
2100 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s",
2101 gst_element_state_get_name (curpending),
2102 gst_element_state_get_name (state));
2104 /* loop until the final requested state is set */
2105 while (GST_STATE (element) != state
2106 && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2107 /* move the curpending state in the correct direction */
2108 if (curpending < state)
2109 curpending <<= 1;
2110 else
2111 curpending >>= 1;
2113 /* set the pending state variable */
2114 /* FIXME: should probably check to see that we don't already have one */
2115 GST_STATE_PENDING (element) = curpending;
2117 if (curpending != state) {
2118 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2119 "intermediate: setting state from %s to %s",
2120 gst_element_state_get_name (GST_STATE (element)),
2121 gst_element_state_get_name (curpending));
2122 }
2124 /* call the state change function so it can set the state */
2125 oclass = GST_ELEMENT_GET_CLASS (element);
2126 if (oclass->change_state)
2127 return_val = (oclass->change_state) (element);
2129 switch (return_val) {
2130 case GST_STATE_FAILURE:
2131 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2132 "have failed change_state return");
2133 goto exit;
2134 case GST_STATE_ASYNC:
2135 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2136 "element will change state async");
2137 goto exit;
2138 case GST_STATE_SUCCESS:
2139 /* Last thing we do is verify that a successful state change really
2140 * did change the state... */
2141 if (GST_STATE (element) != curpending) {
2142 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2143 "element claimed state-change success,"
2144 "but state didn't change %s, %s <-> %s",
2145 gst_element_state_get_name (GST_STATE (element)),
2146 gst_element_state_get_name (GST_STATE_PENDING (element)),
2147 gst_element_state_get_name (curpending));
2148 return GST_STATE_FAILURE;
2149 }
2150 break;
2151 default:
2152 /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2153 g_assert_not_reached ();
2154 }
2155 }
2156 exit:
2158 return return_val;
2159 }
2161 static gboolean
2162 gst_element_negotiate_pads (GstElement *element)
2163 {
2164 GList *pads = GST_ELEMENT_PADS (element);
2166 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads");
2168 while (pads) {
2169 GstPad *pad = GST_PAD (pads->data);
2170 GstRealPad *srcpad;
2172 pads = g_list_next (pads);
2174 if (!GST_IS_REAL_PAD (pad))
2175 continue;
2177 srcpad = GST_PAD_REALIZE (pad);
2179 /* if we have a connection on this pad and it doesn't have caps
2180 * allready, try to negotiate */
2181 if (GST_PAD_IS_CONNECTED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2182 GstRealPad *sinkpad;
2183 GstElementState otherstate;
2184 GstElement *parent;
2186 sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2188 /* check the parent of the peer pad, if there is no parent do nothing */
2189 parent = GST_PAD_PARENT (sinkpad);
2190 if (!parent)
2191 continue;
2193 /* skips pads that were already negotiating */
2194 if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
2195 GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
2196 continue;
2198 otherstate = GST_STATE (parent);
2200 /* swap pads if needed */
2201 if (!GST_PAD_IS_SRC (srcpad)) {
2202 GstRealPad *temp;
2204 temp = srcpad;
2205 srcpad = sinkpad;
2206 sinkpad = temp;
2207 }
2209 /* only try to negotiate if the peer element is in PAUSED or higher too */
2210 if (otherstate >= GST_STATE_READY) {
2211 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element,
2212 "perform negotiate for %s:%s and %s:%s",
2213 GST_DEBUG_PAD_NAME (srcpad),
2214 GST_DEBUG_PAD_NAME (sinkpad));
2215 if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
2216 return FALSE;
2217 }
2218 else {
2219 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element,
2220 "not negotiating %s:%s and %s:%s, not in READY yet",
2221 GST_DEBUG_PAD_NAME (srcpad),
2222 GST_DEBUG_PAD_NAME (sinkpad));
2223 }
2224 }
2225 }
2227 return TRUE;
2228 }
2230 static void
2231 gst_element_clear_pad_caps (GstElement *element)
2232 {
2233 GList *pads = GST_ELEMENT_PADS (element);
2235 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps");
2237 while (pads) {
2238 GstRealPad *pad = GST_PAD_REALIZE (pads->data);
2240 if (GST_PAD_CAPS (pad)) {
2241 GST_PAD_CAPS (pad) = NULL;
2242 }
2243 pads = g_list_next (pads);
2244 }
2245 }
2247 static void
2248 gst_element_pads_activate (GstElement *element, gboolean active)
2249 {
2250 GList *pads = element->pads;
2252 while (pads) {
2253 GstPad *pad = GST_PAD_CAST (pads->data);
2254 pads = g_list_next (pads);
2256 if (!GST_IS_REAL_PAD (pad))
2257 continue;
2259 gst_pad_set_active (pad, active);
2260 }
2261 }
2263 static GstElementStateReturn
2264 gst_element_change_state (GstElement *element)
2265 {
2266 GstElementState old_state;
2267 GstObject *parent;
2268 gint old_pending, old_transition;
2270 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2272 old_state = GST_STATE (element);
2273 old_pending = GST_STATE_PENDING (element);
2274 old_transition = GST_STATE_TRANSITION (element);
2276 if (old_pending == GST_STATE_VOID_PENDING ||
2277 old_state == GST_STATE_PENDING (element)) {
2278 GST_INFO (GST_CAT_STATES,
2279 "no state change needed for element %s (VOID_PENDING)",
2280 GST_ELEMENT_NAME (element));
2281 return GST_STATE_SUCCESS;
2282 }
2284 GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x",
2285 GST_ELEMENT_NAME (element),
2286 gst_element_state_get_name (old_state),
2287 gst_element_state_get_name (old_pending),
2288 old_transition);
2290 /* we set the state change early for the negotiation functions */
2291 GST_STATE (element) = old_pending;
2292 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2294 switch (old_transition) {
2295 case GST_STATE_PLAYING_TO_PAUSED:
2296 gst_element_pads_activate (element, FALSE);
2297 break;
2298 case GST_STATE_PAUSED_TO_PLAYING:
2299 gst_element_pads_activate (element, TRUE);
2300 break;
2301 /* if we are going to paused, we try to negotiate the pads */
2302 case GST_STATE_READY_TO_PAUSED:
2303 if (!gst_element_negotiate_pads (element))
2304 goto failure;
2305 break;
2306 /* going to the READY state clears all pad caps */
2307 case GST_STATE_PAUSED_TO_READY:
2308 gst_element_clear_pad_caps (element);
2309 break;
2310 default:
2311 break;
2312 }
2314 parent = GST_ELEMENT_PARENT (element);
2316 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2317 "signaling state change from %s to %s",
2318 gst_element_state_get_name (old_state),
2319 gst_element_state_get_name (GST_STATE (element)));
2321 /* tell the scheduler if we have one */
2322 if (element->sched) {
2323 if (gst_scheduler_state_transition (element->sched, element,
2324 old_transition) != GST_STATE_SUCCESS) {
2325 goto failure;
2326 }
2327 }
2329 g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2330 0, old_state, GST_STATE (element));
2332 /* tell our parent about the state change */
2333 if (parent && GST_IS_BIN (parent)) {
2334 gst_bin_child_state_change (GST_BIN (parent), old_state,
2335 GST_STATE (element), element);
2336 }
2338 /* signal the state change in case somebody is waiting for us */
2339 g_mutex_lock (element->state_mutex);
2340 g_cond_signal (element->state_cond);
2341 g_mutex_unlock (element->state_mutex);
2343 return GST_STATE_SUCCESS;
2345 failure:
2346 /* undo the state change */
2347 GST_STATE (element) = old_state;
2348 GST_STATE_PENDING (element) = old_pending;
2350 return GST_STATE_FAILURE;
2351 }
2353 /**
2354 * gst_element_get_factory:
2355 * @element: a #GstElement to request the element factory of.
2356 *
2357 * Retrieves the factory that was used to create this element.
2358 *
2359 * Returns: the #GstElementFactory used for creating this element.
2360 */
2361 GstElementFactory*
2362 gst_element_get_factory (GstElement *element)
2363 {
2364 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2366 return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2367 }
2369 static void
2370 gst_element_dispose (GObject *object)
2371 {
2372 GstElement *element = GST_ELEMENT (object);
2373 GList *pads;
2374 GstPad *pad;
2376 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose");
2378 gst_element_set_state (element, GST_STATE_NULL);
2380 /* first we break all our connections with the ouside */
2381 if (element->pads) {
2382 GList *orig;
2383 orig = pads = g_list_copy (element->pads);
2384 while (pads) {
2385 pad = GST_PAD (pads->data);
2387 if (GST_PAD_PEER (pad)) {
2388 GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'",
2389 GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2390 gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
2391 }
2392 gst_element_remove_pad (element, pad);
2394 pads = g_list_next (pads);
2395 }
2396 g_list_free (orig);
2397 g_list_free (element->pads);
2398 element->pads = NULL;
2399 }
2401 element->numsrcpads = 0;
2402 element->numsinkpads = 0;
2403 element->numpads = 0;
2404 g_mutex_free (element->state_mutex);
2405 g_cond_free (element->state_cond);
2407 if (element->prop_value_queue)
2408 g_async_queue_unref (element->prop_value_queue);
2409 element->prop_value_queue = NULL;
2410 if (element->property_mutex)
2411 g_mutex_free (element->property_mutex);
2413 G_OBJECT_CLASS (parent_class)->dispose (object);
2414 }
2416 #ifndef GST_DISABLE_LOADSAVE
2417 /**
2418 * gst_element_save_thyself:
2419 * @element: a #GstElement to save.
2420 * @parent: the xml parent node.
2421 *
2422 * Saves the element as part of the given XML structure.
2423 *
2424 * Returns: the new #xmlNodePtr.
2425 */
2426 static xmlNodePtr
2427 gst_element_save_thyself (GstObject *object,
2428 xmlNodePtr parent)
2429 {
2430 GList *pads;
2431 GstElementClass *oclass;
2432 GParamSpec **specs, *spec;
2433 gint nspecs, i;
2434 GValue value = { 0, };
2435 GstElement *element;
2437 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2439 element = GST_ELEMENT (object);
2441 oclass = GST_ELEMENT_GET_CLASS (element);
2443 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2445 if (oclass->elementfactory != NULL) {
2446 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2448 xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
2449 xmlNewChild (parent, NULL, "version", factory->details->version);
2450 }
2452 /* FIXME: what is this? */
2453 /* if (element->manager) */
2454 /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2456 /* params */
2457 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2459 for (i=0; i<nspecs; i++) {
2460 spec = specs[i];
2461 if (spec->flags & G_PARAM_READABLE) {
2462 xmlNodePtr param;
2463 char *contents;
2465 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
2467 g_object_get_property (G_OBJECT (element), spec->name, &value);
2468 param = xmlNewChild (parent, NULL, "param", NULL);
2469 xmlNewChild (param, NULL, "name", spec->name);
2471 if (G_IS_PARAM_SPEC_STRING (spec))
2472 contents = g_value_dup_string (&value);
2473 else if (G_IS_PARAM_SPEC_ENUM (spec))
2474 contents = g_strdup_printf ("%d", g_value_get_enum (&value));
2475 else if (G_IS_PARAM_SPEC_INT64 (spec))
2476 contents = g_strdup_printf ("%" G_GINT64_FORMAT,
2477 g_value_get_int64 (&value));
2478 else
2479 contents = g_strdup_value_contents (&value);
2481 xmlNewChild (param, NULL, "value", contents);
2482 g_free (contents);
2484 g_value_unset(&value);
2485 }
2486 }
2488 pads = GST_ELEMENT_PADS (element);
2490 while (pads) {
2491 GstPad *pad = GST_PAD (pads->data);
2492 /* figure out if it's a direct pad or a ghostpad */
2493 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
2494 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
2495 gst_object_save_thyself (GST_OBJECT (pad), padtag);
2496 }
2497 pads = g_list_next (pads);
2498 }
2500 return parent;
2501 }
2503 static void
2504 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
2505 {
2506 xmlNodePtr children;
2507 GstElement *element;
2508 gchar *name = NULL;
2509 gchar *value = NULL;
2511 element = GST_ELEMENT (object);
2512 g_return_if_fail (element != NULL);
2514 /* parameters */
2515 children = self->xmlChildrenNode;
2516 while (children) {
2517 if (!strcmp (children->name, "param")) {
2518 xmlNodePtr child = children->xmlChildrenNode;
2520 while (child) {
2521 if (!strcmp (child->name, "name")) {
2522 name = xmlNodeGetContent (child);
2523 }
2524 else if (!strcmp (child->name, "value")) {
2525 value = xmlNodeGetContent (child);
2526 }
2527 child = child->next;
2528 }
2529 /* FIXME: can this just be g_object_set ? */
2530 gst_util_set_object_arg (G_OBJECT (element), name, value);
2531 }
2532 children = children->next;
2533 }
2535 /* pads */
2536 children = self->xmlChildrenNode;
2537 while (children) {
2538 if (!strcmp (children->name, "pad")) {
2539 gst_pad_load_and_connect (children, GST_OBJECT (element));
2540 }
2541 children = children->next;
2542 }
2544 if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
2545 (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
2546 }
2547 #endif /* GST_DISABLE_LOADSAVE */
2549 /**
2550 * gst_element_yield:
2551 * @element: a #GstElement to yield.
2552 *
2553 * Requests a yield operation for the element. The scheduler will typically
2554 * give control to another element.
2555 */
2556 void
2557 gst_element_yield (GstElement *element)
2558 {
2559 if (GST_ELEMENT_SCHED (element)) {
2560 gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
2561 }
2562 }
2564 /**
2565 * gst_element_interrupt:
2566 * @element: a #GstElement to interrupt.
2567 *
2568 * Requests the scheduler of this element to interrupt the execution of
2569 * this element and scheduler another one.
2570 *
2571 * Returns: TRUE if the element should exit its chain/loop/get
2572 * function ASAP, depending on the scheduler implementation.
2573 */
2574 gboolean
2575 gst_element_interrupt (GstElement *element)
2576 {
2577 if (GST_ELEMENT_SCHED (element)) {
2578 return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
2579 }
2580 else
2581 return FALSE;
2582 }
2584 /**
2585 * gst_element_set_scheduler:
2586 * @element: a #GstElement to set the scheduler of.
2587 * @sched: the #GstScheduler to set.
2588 *
2589 * Sets the scheduler of the element. For internal use only, unless you're
2590 * writing a new bin subclass.
2591 */
2592 void
2593 gst_element_set_scheduler (GstElement *element,
2594 GstScheduler *sched)
2595 {
2596 g_return_if_fail (GST_IS_ELEMENT (element));
2598 GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
2600 GST_ELEMENT_SCHED (element) = sched;
2601 }
2603 /**
2604 * gst_element_get_scheduler:
2605 * @element: a #GstElement to get the scheduler of.
2606 *
2607 * Returns the scheduler of the element.
2608 *
2609 * Returns: the element's #GstScheduler.
2610 */
2611 GstScheduler*
2612 gst_element_get_scheduler (GstElement *element)
2613 {
2614 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2616 return GST_ELEMENT_SCHED (element);
2617 }
2619 /**
2620 * gst_element_set_loop_function:
2621 * @element: a #GstElement to set the loop function of.
2622 * @loop: Pointer to #GstElementLoopFunction.
2623 *
2624 * This sets the loop function for the element. The function pointed to
2625 * can deviate from the GstElementLoopFunction definition in type of
2626 * pointer only.
2627 *
2628 * NOTE: in order for this to take effect, the current loop function *must*
2629 * exit. Assuming the loop function itself is the only one who will cause
2630 * a new loopfunc to be assigned, this should be no problem.
2631 */
2632 void
2633 gst_element_set_loop_function (GstElement *element,
2634 GstElementLoopFunction loop)
2635 {
2636 g_return_if_fail (GST_IS_ELEMENT (element));
2638 /* set the loop function */
2639 element->loopfunc = loop;
2641 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
2642 GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
2644 if (GST_ELEMENT_SCHED (element)) {
2645 gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
2646 }
2647 }
2649 /**
2650 * gst_element_set_eos:
2651 * @element: a #GstElement to set to the EOS state.
2652 *
2653 * Perform the actions needed to bring the element in the EOS state.
2654 */
2655 void
2656 gst_element_set_eos (GstElement *element)
2657 {
2658 g_return_if_fail (GST_IS_ELEMENT (element));
2660 GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s",
2661 GST_OBJECT_NAME (element));
2663 gst_element_set_state (element, GST_STATE_PAUSED);
2665 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2666 }
2669 /**
2670 * gst_element_state_get_name:
2671 * @state: a #GstElementState to get the name of.
2672 *
2673 * Gets a string representing the given state.
2674 *
2675 * Returns: a string with the name of the state.
2676 */
2677 const gchar*
2678 gst_element_state_get_name (GstElementState state)
2679 {
2680 switch (state) {
2681 #ifdef GST_DEBUG_COLOR
2682 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2683 case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
2684 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
2685 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
2686 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
2687 default:
2688 /* This is a memory leak */
2689 return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
2690 #else
2691 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2692 case GST_STATE_NULL: return "NULL";break;
2693 case GST_STATE_READY: return "READY";break;
2694 case GST_STATE_PLAYING: return "PLAYING";break;
2695 case GST_STATE_PAUSED: return "PAUSED";break;
2696 default: return "UNKNOWN!";
2697 #endif
2698 }
2699 return "";
2700 }
2702 static void
2703 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name,
2704 guint arg_id, GParamFlags flags)
2705 {
2706 GQuark prop_id = g_quark_from_string (prop_name);
2707 GParamSpec *pspec;
2709 static GQuark fd_id = 0;
2710 static GQuark blocksize_id;
2711 static GQuark bytesperread_id;
2712 static GQuark dump_id;
2713 static GQuark filesize_id;
2714 static GQuark mmapsize_id;
2715 static GQuark location_id;
2716 static GQuark offset_id;
2717 static GQuark silent_id;
2718 static GQuark touch_id;
2720 if (!fd_id) {
2721 fd_id = g_quark_from_static_string ("fd");
2722 blocksize_id = g_quark_from_static_string ("blocksize");
2723 bytesperread_id = g_quark_from_static_string ("bytesperread");
2724 dump_id = g_quark_from_static_string ("dump");
2725 filesize_id = g_quark_from_static_string ("filesize");
2726 mmapsize_id = g_quark_from_static_string ("mmapsize");
2727 location_id = g_quark_from_static_string ("location");
2728 offset_id = g_quark_from_static_string ("offset");
2729 silent_id = g_quark_from_static_string ("silent");
2730 touch_id = g_quark_from_static_string ("touch");
2731 }
2733 if (prop_id == fd_id) {
2734 pspec = g_param_spec_int ("fd", "File-descriptor",
2735 "File-descriptor for the file being read",
2736 0, G_MAXINT, 0, flags);
2737 }
2738 else if (prop_id == blocksize_id) {
2739 pspec = g_param_spec_ulong ("blocksize", "Block Size",
2740 "Block size to read per buffer",
2741 0, G_MAXULONG, 4096, flags);
2743 }
2744 else if (prop_id == bytesperread_id) {
2745 pspec = g_param_spec_int ("bytesperread", "Bytes per read",
2746 "Number of bytes to read per buffer",
2747 G_MININT, G_MAXINT, 0, flags);
2749 }
2750 else if (prop_id == dump_id) {
2751 pspec = g_param_spec_boolean ("dump", "Dump",
2752 "Dump bytes to stdout",
2753 FALSE, flags);
2755 }
2756 else if (prop_id == filesize_id) {
2757 pspec = g_param_spec_int64 ("filesize", "File Size",
2758 "Size of the file being read",
2759 0, G_MAXINT64, 0, flags);
2761 }
2762 else if (prop_id == mmapsize_id) {
2763 pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
2764 "Size in bytes of mmap()d regions",
2765 0, G_MAXULONG, 4 * 1048576, flags);
2767 }
2768 else if (prop_id == location_id) {
2769 pspec = g_param_spec_string ("location", "File Location",
2770 "Location of the file to read",
2771 NULL, flags);
2773 }
2774 else if (prop_id == offset_id) {
2775 pspec = g_param_spec_int64 ("offset", "File Offset",
2776 "Byte offset of current read pointer",
2777 0, G_MAXINT64, 0, flags);
2779 }
2780 else if (prop_id == silent_id) {
2781 pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
2782 FALSE, flags);
2784 }
2785 else if (prop_id == touch_id) {
2786 pspec = g_param_spec_boolean ("touch", "Touch read data",
2787 "Touch data to force disk read before "
2788 "push ()", TRUE, flags);
2789 }
2790 else {
2791 g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
2792 prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
2793 pspec = NULL;
2794 }
2796 if (pspec) {
2797 g_object_class_install_property (klass, arg_id, pspec);
2798 }
2799 }
2801 /**
2802 * gst_element_class_install_std_props:
2803 * @klass: the #GstElementClass to add the properties to.
2804 * @first_name: the name of the first property.
2805 * in a NULL terminated
2806 * @...: the id and flags of the first property, followed by
2807 * further 'name', 'id', 'flags' triplets and terminated by NULL.
2808 *
2809 * Adds a list of standardized properties with types to the @klass.
2810 * the id is for the property switch in your get_prop method, and
2811 * the flags determine readability / writeability.
2812 **/
2813 void
2814 gst_element_class_install_std_props (GstElementClass * klass,
2815 const gchar *first_name, ...)
2816 {
2817 const char *name;
2819 va_list args;
2821 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
2823 va_start (args, first_name);
2825 name = first_name;
2827 while (name) {
2828 int arg_id = va_arg (args, int);
2829 int flags = va_arg (args, int);
2831 gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
2833 name = va_arg (args, char *);
2834 }
2836 va_end (args);
2837 }
2839 /**
2840 * gst_element_get_managing_bin:
2841 * @element: a #GstElement to get the managing bin of.
2842 *
2843 * Gets the managing bin (a pipeline or a thread, for example) of an element.
2844 *
2845 * Returns: the #GstBin, or NULL on failure.
2846 **/
2847 GstBin*
2848 gst_element_get_managing_bin (GstElement *element)
2849 {
2850 GstBin *bin;
2852 g_return_val_if_fail (element != NULL, NULL);
2854 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
2856 while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
2857 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
2859 return bin;
2860 }