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 #include <glib.h>
24 #include <stdarg.h>
25 #include <gobject/gvaluecollector.h>
26 #include "gst_private.h"
28 #include "gstelement.h"
29 #include "gstbin.h"
30 #include "gstscheduler.h"
31 #include "gstevent.h"
32 #include "gstutils.h"
33 #include "gstinfo.h"
35 /* Element signals and args */
36 enum {
37 STATE_CHANGE,
38 NEW_PAD,
39 PAD_REMOVED,
40 ERROR,
41 EOS,
42 LAST_SIGNAL
43 };
45 enum {
46 ARG_0,
47 /* FILL ME */
48 };
50 static void gst_element_class_init (GstElementClass *klass);
51 static void gst_element_init (GstElement *element);
52 static void gst_element_base_class_init (GstElementClass *klass);
54 static void gst_element_real_set_property (GObject *object, guint prop_id,
55 const GValue *value, GParamSpec *pspec);
56 static void gst_element_real_get_property (GObject *object, guint prop_id, GValue *value,
57 GParamSpec *pspec);
59 static void gst_element_dispose (GObject *object);
61 static GstElementStateReturn gst_element_change_state (GstElement *element);
62 static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg);
64 #ifndef GST_DISABLE_LOADSAVE
65 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
66 static void gst_element_restore_thyself (GstObject *parent, xmlNodePtr self);
67 #endif
69 GType _gst_element_type = 0;
71 static GstObjectClass *parent_class = NULL;
72 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
74 GType gst_element_get_type (void)
75 {
76 if (!_gst_element_type) {
77 static const GTypeInfo element_info = {
78 sizeof(GstElementClass),
79 (GBaseInitFunc)gst_element_base_class_init,
80 NULL,
81 (GClassInitFunc)gst_element_class_init,
82 NULL,
83 NULL,
84 sizeof(GstElement),
85 0,
86 (GInstanceInitFunc)gst_element_init,
87 NULL
88 };
89 _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement",
90 &element_info, G_TYPE_FLAG_ABSTRACT);
91 }
92 return _gst_element_type;
93 }
95 static void
96 gst_element_class_init (GstElementClass *klass)
97 {
98 GObjectClass *gobject_class;
99 GstObjectClass *gstobject_class;
101 gobject_class = (GObjectClass*) klass;
102 gstobject_class = (GstObjectClass*) klass;
104 parent_class = g_type_class_ref(GST_TYPE_OBJECT);
106 gst_element_signals[STATE_CHANGE] =
107 g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
108 G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
109 gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
110 G_TYPE_INT, G_TYPE_INT);
111 gst_element_signals[NEW_PAD] =
112 g_signal_new ("new_pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
113 G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
114 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
115 G_TYPE_OBJECT);
116 gst_element_signals[PAD_REMOVED] =
117 g_signal_new ("pad_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
118 G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
119 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
120 G_TYPE_OBJECT);
121 gst_element_signals[ERROR] =
122 g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
123 G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
124 gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
125 G_TYPE_OBJECT, G_TYPE_STRING);
126 gst_element_signals[EOS] =
127 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
128 G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
129 gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
131 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
132 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
134 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
136 #ifndef GST_DISABLE_LOADSAVE
137 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
138 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
139 #endif
141 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
142 klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
143 klass->elementfactory = NULL;
144 klass->padtemplates = NULL;
145 klass->numpadtemplates = 0;
146 }
148 static void
149 gst_element_base_class_init (GstElementClass *klass)
150 {
151 GObjectClass *gobject_class;
153 gobject_class = (GObjectClass*) klass;
155 gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_real_set_property);
156 gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_real_get_property);
157 }
159 static void
160 gst_element_init (GstElement *element)
161 {
162 element->current_state = GST_STATE_NULL;
163 element->pending_state = GST_STATE_VOID_PENDING;
164 element->numpads = 0;
165 element->numsrcpads = 0;
166 element->numsinkpads = 0;
167 element->pads = NULL;
168 element->loopfunc = NULL;
169 element->sched = NULL;
170 element->clock = NULL;
171 element->sched_private = NULL;
172 element->state_mutex = g_mutex_new ();
173 element->state_cond = g_cond_new ();
174 }
176 static void
177 gst_element_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
178 {
179 GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
181 if (oclass->set_property)
182 (oclass->set_property) (object, prop_id, value, pspec);
183 }
185 static void
186 gst_element_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
187 {
188 GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
190 if (oclass->get_property)
191 (oclass->get_property) (object, prop_id, value, pspec);
192 }
194 /**
195 * gst_element_default_error:
196 * @object: a #GObject that signalled the error.
197 * @orig: the #GstObject that initiated the error.
198 * @error: the error message.
199 *
200 * Adds a default error signal callback to an
201 * element. The user data passed to the g_signal_connect is
202 * ignored.
203 * The default handler will simply print the error string
204 * using g_print.
205 */
206 void
207 gst_element_default_error (GObject *object, GstObject *orig, gchar *error)
208 {
209 gchar *name = gst_object_get_path_string (orig);
210 g_print ("ERROR: %s: %s\n", name, error);
211 g_free (name);
212 }
214 typedef struct {
215 const GParamSpec *pspec;
216 GValue value;
217 } prop_value_t;
219 static void
220 element_set_property (GstElement *element, const GParamSpec *pspec, const GValue *value)
221 {
222 prop_value_t *prop_value = g_new0 (prop_value_t, 1);
224 prop_value->pspec = pspec;
225 prop_value->value = *value;
227 g_async_queue_push (element->prop_value_queue, prop_value);
228 }
230 static void
231 element_get_property (GstElement *element, const GParamSpec *pspec, GValue *value)
232 {
233 g_mutex_lock (element->property_mutex);
234 g_object_get_property ((GObject*)element, pspec->name, value);
235 g_mutex_unlock (element->property_mutex);
236 }
238 static void
239 gst_element_threadsafe_properties_pre_run (GstElement *element)
240 {
241 GST_CAT_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
242 g_mutex_lock (element->property_mutex);
243 gst_element_set_pending_properties (element);
244 }
246 static void
247 gst_element_threadsafe_properties_post_run (GstElement *element)
248 {
249 GST_CAT_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
250 g_mutex_unlock (element->property_mutex);
251 }
253 /**
254 * gst_element_enable_threadsafe_properties:
255 * @element: a #GstElement to enable threadsafe properties on.
256 *
257 * Installs an asynchronous queue, a mutex and pre- and post-run functions on
258 * this element so that properties on the element can be set in a
259 * threadsafe way.
260 */
261 void
262 gst_element_enable_threadsafe_properties (GstElement *element)
263 {
264 g_return_if_fail (GST_IS_ELEMENT (element));
266 GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
267 element->pre_run_func = gst_element_threadsafe_properties_pre_run;
268 element->post_run_func = gst_element_threadsafe_properties_post_run;
269 if (!element->prop_value_queue)
270 element->prop_value_queue = g_async_queue_new ();
271 if (!element->property_mutex)
272 element->property_mutex = g_mutex_new ();
273 }
275 /**
276 * gst_element_disable_threadsafe_properties:
277 * @element: a #GstElement to disable threadsafe properties on.
278 *
279 * Removes the threadsafe properties, post- and pre-run locks from
280 * this element.
281 */
282 void
283 gst_element_disable_threadsafe_properties (GstElement *element)
284 {
285 g_return_if_fail (GST_IS_ELEMENT (element));
287 GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
288 element->pre_run_func = NULL;
289 element->post_run_func = NULL;
290 /* let's keep around that async queue */
291 }
293 /**
294 * gst_element_set_pending_properties:
295 * @element: a #GstElement to set the pending properties on.
296 *
297 * Sets all pending properties on the threadsafe properties enabled
298 * element.
299 */
300 void
301 gst_element_set_pending_properties (GstElement *element)
302 {
303 prop_value_t *prop_value;
305 while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) {
306 g_object_set_property ((GObject*)element, prop_value->pspec->name, &prop_value->value);
307 g_value_unset (&prop_value->value);
308 g_free (prop_value);
309 }
310 }
312 /* following 6 functions taken mostly from gobject.c */
314 /**
315 * gst_element_set:
316 * @element: a #GstElement to set properties on.
317 * @first_property_name: the first property to set.
318 * @...: value of the first property, and more properties to set, ending
319 * with NULL.
320 *
321 * Sets properties on an element. If the element uses threadsafe properties,
322 * they will be queued and set on the object when it is scheduled again.
323 */
324 void
325 gst_element_set (GstElement *element, const gchar *first_property_name, ...)
326 {
327 va_list var_args;
329 g_return_if_fail (GST_IS_ELEMENT (element));
331 va_start (var_args, first_property_name);
332 gst_element_set_valist (element, first_property_name, var_args);
333 va_end (var_args);
334 }
336 /**
337 * gst_element_get:
338 * @element: a #GstElement to get properties of.
339 * @first_property_name: the first property to get.
340 * @...: pointer to a variable to store the first property in, as well as
341 * more properties to get, ending with NULL.
342 *
343 * Gets properties from an element. If the element uses threadsafe properties,
344 * the element will be locked before getting the given properties.
345 */
346 void
347 gst_element_get (GstElement *element, const gchar *first_property_name, ...)
348 {
349 va_list var_args;
351 g_return_if_fail (GST_IS_ELEMENT (element));
353 va_start (var_args, first_property_name);
354 gst_element_get_valist (element, first_property_name, var_args);
355 va_end (var_args);
356 }
358 /**
359 * gst_element_set_valist:
360 * @element: a #GstElement to set properties on.
361 * @first_property_name: the first property to set.
362 * @var_args: the var_args list of other properties to get.
363 *
364 * Sets properties on an element. If the element uses threadsafe properties,
365 * the property change will be put on the async queue.
366 */
367 void
368 gst_element_set_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
369 {
370 const gchar *name;
371 GObject *object;
373 g_return_if_fail (GST_IS_ELEMENT (element));
375 object = (GObject *) element;
377 GST_CAT_DEBUG (GST_CAT_PROPERTIES,
378 "setting valist of properties starting with %s on element %s",
379 first_property_name, gst_element_get_name (element));
381 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
382 g_object_set_valist (object, first_property_name, var_args);
383 return;
384 }
386 g_object_ref (object);
388 name = first_property_name;
390 while (name)
391 {
392 GValue value = { 0, };
393 GParamSpec *pspec;
394 gchar *error = NULL;
396 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
398 if (!pspec)
399 {
400 g_warning ("%s: object class `%s' has no property named `%s'",
401 G_STRLOC,
402 G_OBJECT_TYPE_NAME (object),
403 name);
404 break;
405 }
406 if (!(pspec->flags & G_PARAM_WRITABLE))
407 {
408 g_warning ("%s: property `%s' of object class `%s' is not writable",
409 G_STRLOC,
410 pspec->name,
411 G_OBJECT_TYPE_NAME (object));
412 break;
413 }
415 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
417 G_VALUE_COLLECT (&value, var_args, 0, &error);
418 if (error)
419 {
420 g_warning ("%s: %s", G_STRLOC, error);
421 g_free (error);
423 /* we purposely leak the value here, it might not be
424 * in a sane state if an error condition occoured
425 */
426 break;
427 }
429 element_set_property (element, pspec, &value);
430 g_value_unset (&value);
432 name = va_arg (var_args, gchar*);
433 }
435 g_object_unref (object);
436 }
438 /**
439 * gst_element_get_valist:
440 * @element: a #GstElement to get properties of.
441 * @first_property_name: the first property to get.
442 * @var_args: the var_args list of other properties to get.
443 *
444 * Gets properties from an element. If the element uses threadsafe properties,
445 * the element will be locked before getting the given properties.
446 */
447 void
448 gst_element_get_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
449 {
450 const gchar *name;
451 GObject *object;
453 g_return_if_fail (GST_IS_ELEMENT (element));
455 object = (GObject*)element;
457 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
458 g_object_get_valist (object, first_property_name, var_args);
459 return;
460 }
462 g_object_ref (object);
464 name = first_property_name;
466 while (name)
467 {
468 GValue value = { 0, };
469 GParamSpec *pspec;
470 gchar *error;
472 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
474 if (!pspec)
475 {
476 g_warning ("%s: object class `%s' has no property named `%s'",
477 G_STRLOC,
478 G_OBJECT_TYPE_NAME (object),
479 name);
480 break;
481 }
482 if (!(pspec->flags & G_PARAM_READABLE))
483 {
484 g_warning ("%s: property `%s' of object class `%s' is not readable",
485 G_STRLOC,
486 pspec->name,
487 G_OBJECT_TYPE_NAME (object));
488 break;
489 }
491 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
493 element_get_property (element, pspec, &value);
495 G_VALUE_LCOPY (&value, var_args, 0, &error);
496 if (error)
497 {
498 g_warning ("%s: %s", G_STRLOC, error);
499 g_free (error);
500 g_value_unset (&value);
501 break;
502 }
504 g_value_unset (&value);
506 name = va_arg (var_args, gchar*);
507 }
509 g_object_unref (object);
510 }
512 /**
513 * gst_element_set_property:
514 * @element: a #GstElement to set properties on.
515 * @property_name: the first property to get.
516 * @value: the #GValue that holds the value to set.
517 *
518 * Sets a property on an element. If the element uses threadsafe properties,
519 * the property will be put on the async queue.
520 */
521 void
522 gst_element_set_property (GstElement *element, const gchar *property_name,
523 const GValue *value)
524 {
525 GParamSpec *pspec;
526 GObject *object;
528 g_return_if_fail (GST_IS_ELEMENT (element));
529 g_return_if_fail (property_name != NULL);
530 g_return_if_fail (G_IS_VALUE (value));
532 object = (GObject*) element;
534 GST_CAT_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
535 property_name, gst_element_get_name (element));
536 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
537 g_object_set_property (object, property_name, value);
538 return;
539 }
541 g_object_ref (object);
543 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
544 property_name);
546 if (!pspec)
547 g_warning ("%s: object class `%s' has no property named `%s'",
548 G_STRLOC,
549 G_OBJECT_TYPE_NAME (object),
550 property_name);
551 else
552 element_set_property (element, pspec, value);
554 g_object_unref (object);
555 }
557 /**
558 * gst_element_get_property:
559 * @element: a #GstElement to get properties of.
560 * @property_name: the first property to get.
561 * @value: the #GValue to store the property value in.
562 *
563 * Gets a property from an element. If the element uses threadsafe properties,
564 * the element will be locked before getting the given property.
565 */
566 void
567 gst_element_get_property (GstElement *element, const gchar *property_name, GValue *value)
568 {
569 GParamSpec *pspec;
570 GObject *object;
572 g_return_if_fail (GST_IS_ELEMENT (element));
573 g_return_if_fail (property_name != NULL);
574 g_return_if_fail (G_IS_VALUE (value));
576 object = (GObject*)element;
578 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
579 g_object_get_property (object, property_name, value);
580 return;
581 }
583 g_object_ref (object);
585 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
587 if (!pspec)
588 g_warning ("%s: object class `%s' has no property named `%s'",
589 G_STRLOC,
590 G_OBJECT_TYPE_NAME (object),
591 property_name);
592 else
593 {
594 GValue *prop_value, tmp_value = { 0, };
596 /* auto-conversion of the callers value type
597 */
598 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
599 {
600 g_value_reset (value);
601 prop_value = value;
602 }
603 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
604 {
605 g_warning ("can't retrieve property `%s' of type `%s' as value of type `%s'",
606 pspec->name,
607 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
608 G_VALUE_TYPE_NAME (value));
609 g_object_unref (object);
610 return;
611 }
612 else
613 {
614 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
615 prop_value = &tmp_value;
616 }
617 element_get_property (element, pspec, prop_value);
618 if (prop_value != value)
619 {
620 g_value_transform (prop_value, value);
621 g_value_unset (&tmp_value);
622 }
623 }
625 g_object_unref (object);
626 }
628 static GstPad*
629 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
630 {
631 GstPad *newpad = NULL;
632 GstElementClass *oclass;
634 oclass = GST_ELEMENT_GET_CLASS (element);
636 if (oclass->request_new_pad)
637 newpad = (oclass->request_new_pad)(element, templ, name);
639 return newpad;
640 }
642 /**
643 * gst_element_release_request_pad:
644 * @element: a #GstElement to release the request pad of.
645 * @pad: the #GstPad to release.
646 *
647 * Makes the element free the previously requested pad as obtained
648 * with gst_element_get_request_pad().
649 */
650 void
651 gst_element_release_request_pad (GstElement *element, GstPad *pad)
652 {
653 GstElementClass *oclass;
655 g_return_if_fail (GST_IS_ELEMENT (element));
656 g_return_if_fail (GST_IS_PAD (pad));
658 oclass = GST_ELEMENT_GET_CLASS (element);
660 if (oclass->release_pad)
661 (oclass->release_pad) (element, pad);
662 }
664 /**
665 * gst_element_requires_clock:
666 * @element: a #GstElement to query
667 *
668 * Query if the element requiresd a clock
669 *
670 * Returns: TRUE if the element requires a clock
671 */
672 gboolean
673 gst_element_requires_clock (GstElement *element)
674 {
675 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
677 return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL);
678 }
680 /**
681 * gst_element_provides_clock:
682 * @element: a #GstElement to query
683 *
684 * Query if the element provides a clock
685 *
686 * Returns: TRUE if the element provides a clock
687 */
688 gboolean
689 gst_element_provides_clock (GstElement *element)
690 {
691 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
693 return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL);
694 }
696 /**
697 * gst_element_set_clock:
698 * @element: a #GstElement to set the clock for.
699 * @clock: the #GstClock to set for the element.
700 *
701 * Sets the clock for the element.
702 */
703 void
704 gst_element_set_clock (GstElement *element, GstClock *clock)
705 {
706 GstElementClass *oclass;
708 g_return_if_fail (GST_IS_ELEMENT (element));
710 oclass = GST_ELEMENT_GET_CLASS (element);
712 if (oclass->set_clock)
713 oclass->set_clock (element, clock);
715 gst_object_replace ((GstObject **)&element->clock, (GstObject *)clock);
716 }
718 /**
719 * gst_element_get_clock:
720 * @element: a #GstElement to get the clock of.
721 *
722 * Gets the clock of the element.
723 *
724 * Returns: the #GstClock of the element.
725 */
726 GstClock*
727 gst_element_get_clock (GstElement *element)
728 {
729 GstElementClass *oclass;
731 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
733 oclass = GST_ELEMENT_GET_CLASS (element);
735 if (oclass->get_clock)
736 return oclass->get_clock (element);
738 return NULL;
739 }
741 /**
742 * gst_element_clock_wait:
743 * @element: a #GstElement.
744 * @id: the #GstClock to use.
745 * @jitter: the difference between requested time and actual time.
746 *
747 * Waits for a specific time on the clock.
748 *
749 * Returns: the #GstClockReturn result of the wait operation.
750 */
751 GstClockReturn
752 gst_element_clock_wait (GstElement *element, GstClockID id, GstClockTimeDiff *jitter)
753 {
754 GstClockReturn res;
756 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
758 if (GST_ELEMENT_SCHED (element)) {
759 GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on scheduler clock");
760 res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id, jitter);
761 }
762 else {
763 GST_CAT_DEBUG (GST_CAT_CLOCK, "no scheduler, returning GST_CLOCK_TIMEOUT");
764 res = GST_CLOCK_TIMEOUT;
765 }
767 return res;
768 }
770 #ifndef GST_DISABLE_INDEX
771 /**
772 * gst_element_is_indexable:
773 * @element: a #GstElement.
774 *
775 * Queries if the element can be indexed/
776 *
777 * Returns: TRUE if the element can be indexed.
778 */
779 gboolean
780 gst_element_is_indexable (GstElement *element)
781 {
782 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
784 return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
785 }
787 /**
788 * gst_element_set_index:
789 * @element: a #GstElement.
790 * @index: a #GstIndex.
791 *
792 * Set the specified GstIndex on the element.
793 */
794 void
795 gst_element_set_index (GstElement *element, GstIndex *index)
796 {
797 GstElementClass *oclass;
799 g_return_if_fail (GST_IS_ELEMENT (element));
800 g_return_if_fail (GST_IS_INDEX (index));
802 oclass = GST_ELEMENT_GET_CLASS (element);
804 if (oclass->set_index)
805 oclass->set_index (element, index);
806 }
808 /**
809 * gst_element_get_index:
810 * @element: a #GstElement.
811 *
812 * Gets the index from the element.
813 *
814 * Returns: a #GstIndex or NULL when no index was set on the
815 * element.
816 */
817 GstIndex*
818 gst_element_get_index (GstElement *element)
819 {
820 GstElementClass *oclass;
822 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
824 oclass = GST_ELEMENT_GET_CLASS (element);
826 if (oclass->get_index)
827 return oclass->get_index (element);
829 return NULL;
830 }
831 #endif
833 /**
834 * gst_element_release_locks:
835 * @element: a #GstElement to release all locks on.
836 *
837 * Instruct the element to release all the locks it is holding, such as
838 * blocking reads, waiting for the clock, ...
839 *
840 * Returns: TRUE if the locks could be released.
841 */
842 gboolean
843 gst_element_release_locks (GstElement *element)
844 {
845 GstElementClass *oclass;
847 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
849 oclass = GST_ELEMENT_GET_CLASS (element);
851 if (oclass->release_locks)
852 return oclass->release_locks (element);
854 return TRUE;
855 }
857 /**
858 * gst_element_add_pad:
859 * @element: a #GstElement to add the pad to.
860 * @pad: the #GstPad to add to the element.
861 *
862 * Add a pad (link point) to the element, setting the parent of the
863 * pad to the element (and thus adding a reference).
864 * Pads are automatically activated when the element is in state PLAYING.
865 */
866 void
867 gst_element_add_pad (GstElement *element, GstPad *pad)
868 {
869 g_return_if_fail (GST_IS_ELEMENT (element));
870 g_return_if_fail (GST_IS_PAD (pad));
872 /* first check to make sure the pad's parent is already set */
873 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
875 /* then check to see if there's already a pad by that name here */
876 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
878 /* set the pad's parent */
879 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
880 GST_PAD_NAME (pad), GST_STR_NULL (GST_ELEMENT_NAME (element)));
881 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
883 /* add it to the list */
884 element->pads = g_list_append (element->pads, pad);
885 element->numpads++;
886 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
887 element->numsrcpads++;
888 else
889 element->numsinkpads++;
891 /* activate element when we are playing */
892 if (GST_STATE (element) == GST_STATE_PLAYING)
893 gst_pad_set_active (pad, TRUE);
895 /* emit the NEW_PAD signal */
896 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
897 }
899 /**
900 * gst_element_remove_pad:
901 * @element: a #GstElement to remove pad from.
902 * @pad: the #GstPad to remove from the element.
903 *
904 * Remove a pad (link point) from the element.
905 */
906 void
907 gst_element_remove_pad (GstElement *element, GstPad *pad)
908 {
909 g_return_if_fail (element != NULL);
910 g_return_if_fail (GST_IS_ELEMENT (element));
911 g_return_if_fail (pad != NULL);
912 g_return_if_fail (GST_IS_PAD (pad));
914 g_return_if_fail (GST_PAD_PARENT (pad) == element);
916 /* check to see if the pad is still linked */
917 /* FIXME: what if someone calls _remove_pad instead of
918 _remove_ghost_pad? */
919 if (GST_IS_REAL_PAD (pad)) {
920 g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
921 }
923 /* remove it from the list */
924 element->pads = g_list_remove (element->pads, pad);
925 element->numpads--;
926 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
927 element->numsrcpads--;
928 else
929 element->numsinkpads--;
931 g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
933 gst_object_unparent (GST_OBJECT (pad));
934 }
936 /**
937 * gst_element_add_ghost_pad:
938 * @element: a #GstElement to add the ghost pad to.
939 * @pad: the #GstPad from which the new ghost pad will be created.
940 * @name: the name of the new ghost pad.
941 *
942 * Creates a ghost pad from the given pad, and adds it to the list of pads
943 * for this element.
944 *
945 * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
946 */
947 GstPad *
948 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
949 {
950 GstPad *ghostpad;
952 g_return_val_if_fail (element != NULL, NULL);
953 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
954 g_return_val_if_fail (pad != NULL, NULL);
955 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
957 /* then check to see if there's already a pad by that name here */
958 g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
960 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
961 "creating new ghost pad called %s, from pad %s:%s",
962 name, GST_DEBUG_PAD_NAME(pad));
963 ghostpad = gst_ghost_pad_new (name, pad);
965 /* add it to the list */
966 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
967 name, GST_ELEMENT_NAME (element));
968 element->pads = g_list_append (element->pads, ghostpad);
969 element->numpads++;
970 /* set the parent of the ghostpad */
971 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
973 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
975 /* emit the NEW_GHOST_PAD signal */
976 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
978 return ghostpad;
979 }
981 /**
982 * gst_element_remove_ghost_pad:
983 * @element: a #GstElement to remove the ghost pad from.
984 * @pad: ghost #GstPad to remove.
985 *
986 * Removes a ghost pad from an element.
987 */
988 void
989 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
990 {
991 g_return_if_fail (GST_IS_ELEMENT (element));
992 g_return_if_fail (GST_IS_GHOST_PAD (pad));
994 /* FIXME this is redundant?
995 * wingo 10-july-2001: I don't think so, you have to actually remove the pad
996 * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
997 * the real pad's ghost pad list
998 */
999 gst_object_ref (GST_OBJECT (pad));
1000 gst_element_remove_pad (element, pad);
1001 gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
1002 gst_object_unref (GST_OBJECT (pad));
1003 }
1006 /**
1007 * gst_element_get_pad:
1008 * @element: a #GstElement to find pad of.
1009 * @name: the name of the pad to retrieve.
1010 *
1011 * Retrieves a pad from the element by name.
1012 *
1013 * Returns: requested #GstPad if found, otherwise NULL.
1014 */
1015 GstPad*
1016 gst_element_get_pad (GstElement *element, const gchar *name)
1017 {
1018 GstPad *pad;
1020 g_return_val_if_fail (element != NULL, NULL);
1021 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1022 g_return_val_if_fail (name != NULL, NULL);
1024 pad = gst_element_get_static_pad (element, name);
1025 if (!pad)
1026 pad = gst_element_get_request_pad (element, name);
1028 return pad;
1029 }
1031 /**
1032 * gst_element_get_static_pad:
1033 * @element: a #GstElement to find a static pad of.
1034 * @name: the name of the static #GstPad to retrieve.
1035 *
1036 * Retrieves a pad from the element by name. This version only retrieves
1037 * already-existing (i.e. 'static') pads.
1038 *
1039 * Returns: the requested #GstPad if found, otherwise NULL.
1040 */
1041 GstPad *
1042 gst_element_get_static_pad (GstElement *element, const gchar *name)
1043 {
1044 GList *walk;
1046 g_return_val_if_fail (element != NULL, NULL);
1047 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1048 g_return_val_if_fail (name != NULL, NULL);
1050 walk = element->pads;
1051 while (walk) {
1052 GstPad *pad;
1054 pad = GST_PAD(walk->data);
1055 if (strcmp (GST_PAD_NAME(pad), name) == 0) {
1056 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1057 return pad;
1058 }
1059 walk = g_list_next (walk);
1060 }
1062 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
1063 return NULL;
1064 }
1066 /**
1067 * gst_element_get_request_pad:
1068 * @element: a #GstElement to find a request pad of.
1069 * @name: the name of the request #GstPad to retrieve.
1070 *
1071 * Retrieves a pad from the element by name. This version only retrieves
1072 * request pads.
1073 *
1074 * Returns: requested #GstPad if found, otherwise NULL.
1075 */
1076 GstPad*
1077 gst_element_get_request_pad (GstElement *element, const gchar *name)
1078 {
1079 GstPadTemplate *templ = NULL;
1080 GstPad *pad;
1081 const gchar *req_name = NULL;
1082 gboolean templ_found = FALSE;
1083 GList *list;
1084 gint n;
1085 const gchar *data;
1086 gchar *str, *endptr = NULL;
1088 g_return_val_if_fail (element != NULL, NULL);
1089 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1090 g_return_val_if_fail (name != NULL, NULL);
1092 if (strstr (name, "%")) {
1093 templ = gst_element_get_pad_template (element, name);
1094 req_name = NULL;
1095 if (templ)
1096 templ_found = TRUE;
1097 } else {
1098 list = gst_element_get_pad_template_list(element);
1099 while (!templ_found && list) {
1100 templ = (GstPadTemplate*) list->data;
1101 if (templ->presence == GST_PAD_REQUEST) {
1102 /* we know that %s and %d are the only possibilities because of sanity
1103 checks in gst_pad_template_new */
1104 GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
1105 if ((str = strchr (templ->name_template, '%')) &&
1106 strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
1107 strlen (name) > str - templ->name_template) {
1108 data = name + (str - templ->name_template);
1109 if (*(str+1) == 'd') {
1110 /* it's an int */
1111 n = (gint) strtol (data, &endptr, 10);
1112 if (endptr && *endptr == '\0') {
1113 templ_found = TRUE;
1114 req_name = name;
1115 break;
1116 }
1117 } else {
1118 /* it's a string */
1119 templ_found = TRUE;
1120 req_name = name;
1121 break;
1122 }
1123 }
1124 }
1125 list = list->next;
1126 }
1127 }
1129 if (!templ_found)
1130 return NULL;
1132 pad = gst_element_request_pad (element, templ, req_name);
1134 return pad;
1135 }
1137 /**
1138 * gst_element_get_pad_list:
1139 * @element: a #GstElement to get pads of.
1140 *
1141 * Retrieves a list of the pads associated with the element.
1142 *
1143 * Returns: the #GList of pads.
1144 */
1145 const GList*
1146 gst_element_get_pad_list (GstElement *element)
1147 {
1148 g_return_val_if_fail (element != NULL, NULL);
1149 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1151 /* return the list of pads */
1152 return element->pads;
1153 }
1155 /**
1156 * gst_element_class_add_pad_template:
1157 * @klass: the #GstElementClass to add the pad template to.
1158 * @templ: a #GstPadTemplate to add to the element class.
1159 *
1160 * Adds a padtemplate to an element class.
1161 * This is useful if you have derived a custom bin and wish to provide
1162 * an on-request pad at runtime. Plug-in writers should use
1163 * gst_element_factory_add_pad_template instead.
1164 */
1165 void
1166 gst_element_class_add_pad_template (GstElementClass *klass,
1167 GstPadTemplate *templ)
1168 {
1169 g_return_if_fail (klass != NULL);
1170 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1171 g_return_if_fail (templ != NULL);
1172 g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1174 klass->padtemplates = g_list_append (klass->padtemplates, templ);
1175 klass->numpadtemplates++;
1176 }
1178 /**
1179 * gst_element_get_pad_template_list:
1180 * @element: a #GstElement to get pad templates of.
1181 *
1182 * Retrieves a list of the pad templates associated with the element.
1183 *
1184 * Returns: the #GList of padtemplates.
1185 */
1186 GList*
1187 gst_element_get_pad_template_list (GstElement *element)
1188 {
1189 g_return_val_if_fail (element != NULL, NULL);
1190 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1192 return GST_ELEMENT_GET_CLASS (element)->padtemplates;
1193 }
1195 /**
1196 * gst_element_get_pad_template:
1197 * @element: a #GstElement to get the pad template of.
1198 * @name: the name of the #GstPadTemplate to get.
1199 *
1200 * Retrieves a padtemplate from this element with the
1201 * given name.
1202 *
1203 * Returns: the #GstPadTemplate with the given name, or NULL if none was found.
1204 * No unreferencing is necessary.
1205 */
1206 GstPadTemplate*
1207 gst_element_get_pad_template (GstElement *element, const gchar *name)
1208 {
1209 GList *padlist;
1211 g_return_val_if_fail (element != NULL, NULL);
1212 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1213 g_return_val_if_fail (name != NULL, NULL);
1215 padlist = gst_element_get_pad_template_list (element);
1217 while (padlist) {
1218 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1220 if (!strcmp (padtempl->name_template, name))
1221 return padtempl;
1223 padlist = g_list_next (padlist);
1224 }
1226 return NULL;
1227 }
1229 /**
1230 * gst_element_get_compatible_pad_template:
1231 * @element: a #GstElement to get a compatible pad template for.
1232 * @compattempl: the #GstPadTemplate to find a compatible template for.
1233 *
1234 * Generates a pad template for this element compatible with the given
1235 * template (meaning it is able to link with it).
1236 *
1237 * Returns: the #GstPadTemplate of the element that is compatible with
1238 * the given GstPadTemplate, or NULL if none was found. No unreferencing
1239 * is necessary.
1240 */
1241 GstPadTemplate*
1242 gst_element_get_compatible_pad_template (GstElement *element,
1243 GstPadTemplate *compattempl)
1244 {
1245 GstPadTemplate *newtempl = NULL;
1246 GList *padlist;
1248 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
1250 g_return_val_if_fail (element != NULL, NULL);
1251 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1252 g_return_val_if_fail (compattempl != NULL, NULL);
1254 padlist = gst_element_get_pad_template_list (element);
1256 while (padlist) {
1257 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1258 gboolean comp = FALSE;
1260 /* Ignore name
1261 * Ignore presence
1262 * Check direction (must be opposite)
1263 * Check caps
1264 */
1265 GST_CAT_DEBUG (GST_CAT_CAPS, "checking direction and caps");
1266 if (padtempl->direction == GST_PAD_SRC &&
1267 compattempl->direction == GST_PAD_SINK) {
1268 GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
1269 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (padtempl),
1270 GST_PAD_TEMPLATE_CAPS (compattempl));
1271 GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1272 } else if (padtempl->direction == GST_PAD_SINK &&
1273 compattempl->direction == GST_PAD_SRC) {
1274 GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
1275 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1276 GST_PAD_TEMPLATE_CAPS (padtempl));
1277 GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1278 }
1280 if (comp) {
1281 newtempl = padtempl;
1282 break;
1283 }
1285 padlist = g_list_next (padlist);
1286 }
1288 return newtempl;
1289 }
1291 /**
1292 * gst_element_request_compatible_pad:
1293 * @element: a #GstElement to request a new pad from.
1294 * @templ: the #GstPadTemplate to which the new pad should be able to link.
1295 *
1296 * Requests a new pad from the element. The template will
1297 * be used to decide what type of pad to create. This function
1298 * is typically used for elements with a padtemplate with presence
1299 * GST_PAD_REQUEST.
1300 *
1301 * Returns: the new #GstPad that was created, or NULL if none could be created.
1302 */
1303 GstPad*
1304 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
1305 {
1306 GstPadTemplate *templ_new;
1307 GstPad *pad = NULL;
1309 g_return_val_if_fail (element != NULL, NULL);
1310 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1311 g_return_val_if_fail (templ != NULL, NULL);
1313 templ_new = gst_element_get_compatible_pad_template (element, templ);
1314 if (templ_new != NULL)
1315 pad = gst_element_request_pad (element, templ_new, NULL);
1317 return pad;
1318 }
1321 /**
1322 * gst_element_get_compatible_pad_filtered:
1323 * @element: a #GstElement in which the pad should be found.
1324 * @pad: the #GstPad to find a compatible one for.
1325 * @filtercaps: the #GstCaps to use as a filter.
1326 *
1327 * Looks for an unlinked pad to which the given pad can link to.
1328 * It is not guaranteed that linking the pads will work, though
1329 * it should work in most cases.
1330 *
1331 * Returns: the #GstPad to which a link can be made.
1332 */
1333 GstPad*
1334 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
1335 GstCaps *filtercaps)
1336 {
1337 const GList *pads;
1338 GstPadTemplate *templ;
1339 GstCaps *templcaps;
1340 GstPad *foundpad = NULL;
1342 /* checks */
1343 g_return_val_if_fail (element != NULL, NULL);
1344 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1345 g_return_val_if_fail (pad != NULL, NULL);
1346 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1348 /* let's use the real pad */
1349 pad = (GstPad *) GST_PAD_REALIZE (pad);
1350 g_return_val_if_fail (pad != NULL, NULL);
1351 g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1353 /* try to get an existing unlinked pad */
1354 pads = gst_element_get_pad_list (element);
1355 while (pads) {
1356 GstPad *current = GST_PAD (pads->data);
1357 if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
1358 gst_pad_can_link_filtered (pad, current, filtercaps)) {
1359 return current;
1360 }
1361 pads = g_list_next (pads);
1362 }
1364 /* try to create a new one */
1365 /* requesting is a little crazy, we need a template. Let's create one */
1366 if (filtercaps != NULL) {
1367 templcaps = gst_caps_intersect (filtercaps, (GstCaps *) GST_RPAD_CAPS (pad));
1368 if (templcaps == NULL)
1369 return NULL;
1370 } else {
1371 templcaps = gst_pad_get_caps (pad);
1372 }
1374 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1375 GST_PAD_ALWAYS, templcaps, NULL);
1376 foundpad = gst_element_request_compatible_pad (element, templ);
1377 gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
1379 /* FIXME: this is broken, but it's in here so autoplugging elements that don't
1380 have caps on their source padtemplates (spider) can link... */
1381 if (!foundpad && !filtercaps) {
1382 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1383 GST_PAD_ALWAYS, NULL, NULL);
1384 foundpad = gst_element_request_compatible_pad (element, templ);
1385 gst_object_unref (GST_OBJECT (templ));
1386 }
1388 return foundpad;
1389 }
1391 /**
1392 * gst_element_get_compatible_pad:
1393 * @element: a #GstElement in which the pad should be found.
1394 * @pad: the #GstPad to find a compatible one for.
1395 *
1396 * Looks for an unlinked pad to which the given pad can link to.
1397 * It is not guaranteed that linking the pads will work, though
1398 * it should work in most cases.
1399 *
1400 * Returns: the #GstPad to which a link can be made, or NULL if none
1401 * could be found.
1402 */
1403 GstPad*
1404 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
1405 {
1406 return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1407 }
1409 /**
1410 * gst_element_link_pads_filtered:
1411 * @src: a #GstElement containing the source pad.
1412 * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
1413 * @dest: the #GstElement containing the destination pad.
1414 * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
1415 * @filtercaps: the #GstCaps to use as a filter.
1416 *
1417 * Links the two named pads of the source and destination elements.
1418 * Side effect is that if one of the pads has no parent, it becomes a
1419 * child of the parent of the other element. If they have different
1420 * parents, the link fails.
1421 *
1422 * Returns: TRUE if the pads could be linked.
1423 */
1424 gboolean
1425 gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
1426 GstElement *dest, const gchar *destpadname,
1427 GstCaps *filtercaps)
1428 {
1429 const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1430 GstPad *srcpad, *destpad;
1431 GstPadTemplate *srctempl, *desttempl;
1433 /* checks */
1434 g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1435 g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1437 GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "trying to link element %s:%s to element %s:%s",
1438 GST_ELEMENT_NAME (src), srcpadname ? srcpadname : "(any)",
1439 GST_ELEMENT_NAME (dest), destpadname ? destpadname : "(any)");
1441 /* now get the pads we're trying to link and a list of all remaining pads */
1442 if (srcpadname) {
1443 srcpad = gst_element_get_pad (src, srcpadname);
1444 if (!srcpad) {
1445 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (src), srcpadname);
1446 return FALSE;
1447 } else {
1448 if (!(GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
1449 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad", GST_DEBUG_PAD_NAME (srcpad));
1450 return FALSE;
1451 }
1452 if (GST_PAD_PEER (srcpad) != NULL) {
1453 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (srcpad));
1454 return FALSE;
1455 }
1456 }
1457 srcpads = NULL;
1458 } else {
1459 srcpads = gst_element_get_pad_list (src);
1460 srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
1461 }
1462 if (destpadname) {
1463 destpad = gst_element_get_pad (dest, destpadname);
1464 if (!destpad) {
1465 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (dest), destpadname);
1466 return FALSE;
1467 } else {
1468 if (!(GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK)) {
1469 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad", GST_DEBUG_PAD_NAME (destpad));
1470 return FALSE;
1471 }
1472 if (GST_PAD_PEER (destpad) != NULL) {
1473 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (destpad));
1474 return FALSE;
1475 }
1476 }
1477 destpads = NULL;
1478 } else {
1479 destpads = gst_element_get_pad_list (dest);
1480 destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
1481 }
1483 if (srcpadname && destpadname) {
1484 /* two explicitly specified pads */
1485 return gst_pad_link_filtered (srcpad, destpad, filtercaps);
1486 }
1487 if (srcpad) {
1488 /* loop through the allowed pads in the source, trying to find a
1489 * compatible destination pad */
1490 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "looping through allowed src and dest pads");
1491 do {
1492 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
1493 GST_DEBUG_PAD_NAME (srcpad));
1494 if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1495 (GST_PAD_PEER (srcpad) == NULL)) {
1496 GstPad *temp = gst_element_get_compatible_pad_filtered (dest, srcpad,
1497 filtercaps);
1498 if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) {
1499 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
1500 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
1501 return TRUE;
1502 }
1503 }
1504 /* find a better way for this mess */
1505 if (srcpads) {
1506 srcpads = g_list_next (srcpads);
1507 if (srcpads)
1508 srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1509 }
1510 } while (srcpads);
1511 }
1512 if (srcpadname) {
1513 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",
1514 GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
1515 return FALSE;
1516 }
1517 if (destpad) {
1518 /* loop through the existing pads in the destination */
1519 do {
1520 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
1521 GST_DEBUG_PAD_NAME (destpad));
1522 if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1523 (GST_PAD_PEER (destpad) == NULL)) {
1524 GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad,
1525 filtercaps);
1526 if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) {
1527 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",
1528 GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
1529 return TRUE;
1530 }
1531 }
1532 if (destpads) {
1533 destpads = g_list_next (destpads);
1534 if (destpads)
1535 destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1536 }
1537 } while (destpads);
1538 }
1539 if (destpadname) {
1540 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s",
1541 GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
1542 return FALSE;
1543 }
1545 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1546 "we might have request pads on both sides, checking...");
1547 srctempls = gst_element_get_pad_template_list (src);
1548 desttempls = gst_element_get_pad_template_list (dest);
1550 if (srctempls && desttempls) {
1551 while (srctempls) {
1552 srctempl = (GstPadTemplate*) srctempls->data;
1553 if (srctempl->presence == GST_PAD_REQUEST) {
1554 for (l=desttempls; l; l=l->next) {
1555 desttempl = (GstPadTemplate*) desttempls->data;
1556 if (desttempl->presence == GST_PAD_REQUEST &&
1557 desttempl->direction != srctempl->direction) {
1558 if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
1559 gst_pad_template_get_caps (desttempl))) {
1560 srcpad = gst_element_get_request_pad (src,
1561 srctempl->name_template);
1562 destpad = gst_element_get_request_pad (dest,
1563 desttempl->name_template);
1564 if (gst_pad_link_filtered (srcpad, destpad, filtercaps)) {
1565 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
1566 "linked pad %s:%s to pad %s:%s",
1567 GST_DEBUG_PAD_NAME (srcpad),
1568 GST_DEBUG_PAD_NAME (destpad));
1569 return TRUE;
1570 }
1571 /* FIXME: we have extraneous request pads lying around */
1572 }
1573 }
1574 }
1575 }
1576 srctempls = srctempls->next;
1577 }
1578 }
1580 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s",
1581 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1582 return FALSE;
1583 }
1584 /**
1585 * gst_element_link_filtered:
1586 * @src: a #GstElement containing the source pad.
1587 * @dest: the #GstElement containing the destination pad.
1588 * @filtercaps: the #GstCaps to use as a filter.
1589 *
1590 * Links the source to the destination element using the filtercaps.
1591 * The link must be from source to destination, the other
1592 * direction will not be tried.
1593 * The functions looks for existing pads that aren't linked yet.
1594 * It will use request pads if possible. But both pads will not be requested.
1595 * If multiple links are possible, only one is established.
1596 *
1597 * Returns: TRUE if the elements could be linked.
1598 */
1599 gboolean
1600 gst_element_link_filtered (GstElement *src, GstElement *dest,
1601 GstCaps *filtercaps)
1602 {
1603 return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
1604 }
1606 /**
1607 * gst_element_link_many:
1608 * @element_1: the first #GstElement in the link chain.
1609 * @element_2: the second #GstElement in the link chain.
1610 * @...: the NULL-terminated list of elements to link in order.
1611 *
1612 * Chain together a series of elements. Uses #gst_element_link.
1613 *
1614 * Returns: TRUE on success, FALSE otherwise.
1615 */
1616 gboolean
1617 gst_element_link_many (GstElement *element_1, GstElement *element_2, ...)
1618 {
1619 va_list args;
1621 g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1622 g_return_val_if_fail (GST_IS_ELEMENT (element_1) &&
1623 GST_IS_ELEMENT (element_2), FALSE);
1625 va_start (args, element_2);
1627 while (element_2) {
1628 if (!gst_element_link (element_1, element_2))
1629 return FALSE;
1631 element_1 = element_2;
1632 element_2 = va_arg (args, GstElement*);
1633 }
1635 va_end (args);
1637 return TRUE;
1638 }
1640 /**
1641 * gst_element_link:
1642 * @src: a #GstElement containing the source pad.
1643 * @dest: the #GstElement containing the destination pad.
1644 *
1645 * Links the source to the destination element.
1646 * The link must be from source to destination, the other
1647 * direction will not be tried.
1648 * The functions looks for existing pads and request pads that aren't
1649 * linked yet. If multiple links are possible, only one is
1650 * established.
1651 *
1652 * Returns: TRUE if the elements could be linked.
1653 */
1654 gboolean
1655 gst_element_link (GstElement *src, GstElement *dest)
1656 {
1657 return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
1658 }
1660 /**
1661 * gst_element_link_pads:
1662 * @src: a #GstElement containing the source pad.
1663 * @srcpadname: the name of the #GstPad in the source element.
1664 * @dest: the #GstElement containing the destination pad.
1665 * @destpadname: the name of the #GstPad in destination element.
1666 *
1667 * Links the two named pads of the source and destination elements.
1668 * Side effect is that if one of the pads has no parent, it becomes a
1669 * child of the parent of the other element. If they have different
1670 * parents, the link fails.
1671 *
1672 * Returns: TRUE if the pads could be linked.
1673 */
1674 gboolean
1675 gst_element_link_pads (GstElement *src, const gchar *srcpadname,
1676 GstElement *dest, const gchar *destpadname)
1677 {
1678 return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1679 }
1681 /**
1682 * gst_element_unlink_pads:
1683 * @src: a #GstElement containing the source pad.
1684 * @srcpadname: the name of the #GstPad in source element.
1685 * @dest: a #GstElement containing the destination pad.
1686 * @destpadname: the name of the #GstPad in destination element.
1687 *
1688 * Unlinks the two named pads of the source and destination elements.
1689 */
1690 void
1691 gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
1692 GstElement *dest, const gchar *destpadname)
1693 {
1694 GstPad *srcpad,*destpad;
1696 g_return_if_fail (src != NULL);
1697 g_return_if_fail (GST_IS_ELEMENT(src));
1698 g_return_if_fail (srcpadname != NULL);
1699 g_return_if_fail (dest != NULL);
1700 g_return_if_fail (GST_IS_ELEMENT(dest));
1701 g_return_if_fail (destpadname != NULL);
1703 /* obtain the pads requested */
1704 srcpad = gst_element_get_pad (src, srcpadname);
1705 if (srcpad == NULL) {
1706 GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
1707 return;
1708 }
1709 destpad = gst_element_get_pad (dest, destpadname);
1710 if (srcpad == NULL) {
1711 GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"", destpadname);
1712 return;
1713 }
1715 /* we're satisified they can be unlinked, let's do it */
1716 gst_pad_unlink (srcpad,destpad);
1717 }
1719 /**
1720 * gst_element_unlink_many:
1721 * @element_1: the first #GstElement in the link chain.
1722 * @element_2: the second #GstElement in the link chain.
1723 * @...: the NULL-terminated list of elements to unlink in order.
1724 *
1725 * Unlinks a series of elements. Uses #gst_element_unlink.
1726 */
1727 void
1728 gst_element_unlink_many (GstElement *element_1, GstElement *element_2, ...)
1729 {
1730 va_list args;
1732 g_return_if_fail (element_1 != NULL && element_2 != NULL);
1733 g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1735 va_start (args, element_2);
1737 while (element_2) {
1738 gst_element_unlink (element_1, element_2);
1740 element_1 = element_2;
1741 element_2 = va_arg (args, GstElement*);
1742 }
1744 va_end (args);
1745 }
1747 /**
1748 * gst_element_unlink:
1749 * @src: the source #GstElement to unlink.
1750 * @dest: the sink #GstElement to unlink.
1751 *
1752 * Unlinks all source pads of the source element with all sink pads
1753 * of the sink element to which they are linked.
1754 */
1755 void
1756 gst_element_unlink (GstElement *src, GstElement *dest)
1757 {
1758 const GList *srcpads;
1759 GstPad *pad;
1761 g_return_if_fail (GST_IS_ELEMENT (src));
1762 g_return_if_fail (GST_IS_ELEMENT (dest));
1764 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
1765 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1767 srcpads = gst_element_get_pad_list (src);
1769 while (srcpads) {
1770 pad = GST_PAD_CAST (srcpads->data);
1772 /* we only care about real src pads */
1773 if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
1774 GstPad *peerpad = GST_PAD_PEER (pad);
1776 /* see if the pad is connected and is really a pad
1777 * of dest */
1778 if (peerpad &&
1779 (GST_OBJECT_PARENT (peerpad) == (GstObject*) dest))
1780 {
1781 gst_pad_unlink (pad, peerpad);
1782 }
1783 }
1785 srcpads = g_list_next (srcpads);
1786 }
1787 }
1789 static void
1790 gst_element_error_func (GstElement* element, GstElement *source,
1791 gchar *errormsg)
1792 {
1793 /* tell the parent */
1794 if (GST_OBJECT_PARENT (element)) {
1795 GST_CAT_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s",
1796 errormsg, GST_ELEMENT_NAME (element),
1797 GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
1799 gst_object_ref (GST_OBJECT (element));
1800 g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)),
1801 gst_element_signals[ERROR], 0, source, errormsg);
1802 gst_object_unref (GST_OBJECT (element));
1803 }
1804 }
1806 static GstPad*
1807 gst_element_get_random_pad (GstElement *element, GstPadDirection dir)
1808 {
1809 GList *pads = element->pads;
1810 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
1811 while (pads) {
1812 GstPad *pad = GST_PAD_CAST (pads->data);
1814 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
1815 GST_DEBUG_PAD_NAME (pad));
1817 if (GST_PAD_DIRECTION (pad) == dir) {
1818 if (GST_PAD_IS_LINKED (pad)) {
1819 return pad;
1820 }
1821 else {
1822 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
1823 GST_DEBUG_PAD_NAME (pad));
1824 }
1825 }
1826 else {
1827 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
1828 GST_DEBUG_PAD_NAME (pad));
1829 }
1831 pads = g_list_next (pads);
1832 }
1833 return NULL;
1834 }
1836 /**
1837 * gst_element_get_event_masks:
1838 * @element: a #GstElement to query
1839 *
1840 * Get an array of event masks from the element.
1841 * If the element doesn't
1842 * implement an event masks function, the query will be forwarded
1843 * to a random linked sink pad.
1844 *
1845 * Returns: An array of #GstEventMask elements.
1846 */
1847 const GstEventMask*
1848 gst_element_get_event_masks (GstElement *element)
1849 {
1850 GstElementClass *oclass;
1852 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1854 oclass = GST_ELEMENT_GET_CLASS (element);
1856 if (oclass->get_event_masks)
1857 return oclass->get_event_masks (element);
1858 else {
1859 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1860 if (pad)
1861 return gst_pad_get_event_masks (GST_PAD_PEER (pad));
1862 }
1864 return FALSE;
1865 }
1867 /**
1868 * gst_element_send_event:
1869 * @element: a #GstElement to send the event to.
1870 * @event: the #GstEvent to send to the element.
1871 *
1872 * Sends an event to an element. If the element doesn't
1873 * implement an event handler, the event will be forwarded
1874 * to a random sink pad.
1875 *
1876 * Returns: TRUE if the event was handled.
1877 */
1878 gboolean
1879 gst_element_send_event (GstElement *element, GstEvent *event)
1880 {
1881 GstElementClass *oclass;
1883 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1884 g_return_val_if_fail (event != NULL, FALSE);
1886 oclass = GST_ELEMENT_GET_CLASS (element);
1888 if (oclass->send_event)
1889 return oclass->send_event (element, event);
1890 else {
1891 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1892 if (pad) {
1893 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
1894 GST_DEBUG_PAD_NAME (pad));
1895 return gst_pad_send_event (GST_PAD_PEER (pad), event);
1896 }
1897 }
1898 GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
1899 GST_ELEMENT_NAME (element));
1900 return FALSE;
1901 }
1903 /**
1904 * gst_element_seek:
1905 * @element: a #GstElement to send the event to.
1906 * @seek_type: the method to use for seeking.
1907 * @offset: the offset to seek to.
1908 *
1909 * Sends a seek event to an element.
1910 *
1911 * Returns: TRUE if the event was handled.
1912 */
1913 gboolean
1914 gst_element_seek (GstElement *element,
1915 GstSeekType seek_type,
1916 guint64 offset)
1917 {
1918 GstEvent *event = gst_event_new_seek (seek_type, offset);
1920 return gst_element_send_event (element, event);
1921 }
1923 /**
1924 * gst_element_get_query_types:
1925 * @element: a #GstElement to query
1926 *
1927 * Get an array of query types from the element.
1928 * If the element doesn't
1929 * implement a query types function, the query will be forwarded
1930 * to a random sink pad.
1931 *
1932 * Returns: An array of #GstQueryType elements.
1933 */
1934 const GstQueryType*
1935 gst_element_get_query_types (GstElement *element)
1936 {
1937 GstElementClass *oclass;
1939 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1941 oclass = GST_ELEMENT_GET_CLASS (element);
1943 if (oclass->get_query_types)
1944 return oclass->get_query_types (element);
1945 else {
1946 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1947 if (pad)
1948 return gst_pad_get_query_types (GST_PAD_PEER (pad));
1949 }
1951 return FALSE;
1952 }
1954 /**
1955 * gst_element_query:
1956 * @element: a #GstElement to perform the query on.
1957 * @type: the #GstQueryType.
1958 * @format: the #GstFormat pointer to hold the format of the result.
1959 * @value: the pointer to the value of the result.
1960 *
1961 * Performs a query on the given element. If the format is set
1962 * to GST_FORMAT_DEFAULT and this function returns TRUE, the
1963 * format pointer will hold the default format.
1964 * For element that don't implement a query handler, this function
1965 * forwards the query to a random usable sinkpad of this element.
1966 *
1967 * Returns: TRUE if the query could be performed.
1968 */
1969 gboolean
1970 gst_element_query (GstElement *element, GstQueryType type,
1971 GstFormat *format, gint64 *value)
1972 {
1973 GstElementClass *oclass;
1975 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1976 g_return_val_if_fail (format != NULL, FALSE);
1977 g_return_val_if_fail (value != NULL, FALSE);
1979 oclass = GST_ELEMENT_GET_CLASS (element);
1981 if (oclass->query)
1982 return oclass->query (element, type, format, value);
1983 else {
1984 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
1985 if (pad)
1986 return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
1987 }
1989 return FALSE;
1990 }
1992 /**
1993 * gst_element_get_formats:
1994 * @element: a #GstElement to query
1995 *
1996 * Get an array of formst from the element.
1997 * If the element doesn't
1998 * implement a formats function, the query will be forwarded
1999 * to a random sink pad.
2000 *
2001 * Returns: An array of #GstFormat elements.
2002 */
2003 const GstFormat*
2004 gst_element_get_formats (GstElement *element)
2005 {
2006 GstElementClass *oclass;
2008 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2010 oclass = GST_ELEMENT_GET_CLASS (element);
2012 if (oclass->get_formats)
2013 return oclass->get_formats (element);
2014 else {
2015 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2016 if (pad)
2017 return gst_pad_get_formats (GST_PAD_PEER (pad));
2018 }
2020 return FALSE;
2021 }
2023 /**
2024 * gst_element_convert:
2025 * @element: a #GstElement to invoke the converter on.
2026 * @src_format: the source #GstFormat.
2027 * @src_value: the source value.
2028 * @dest_format: a pointer to the destination #GstFormat.
2029 * @dest_value: a pointer to the destination value.
2030 *
2031 * Invokes a conversion on the element.
2032 * If the element doesn't
2033 * implement a convert function, the query will be forwarded
2034 * to a random sink pad.
2035 *
2036 * Returns: TRUE if the conversion could be performed.
2037 */
2038 gboolean
2039 gst_element_convert (GstElement *element,
2040 GstFormat src_format, gint64 src_value,
2041 GstFormat *dest_format, gint64 *dest_value)
2042 {
2043 GstElementClass *oclass;
2045 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2046 g_return_val_if_fail (dest_format != NULL, FALSE);
2047 g_return_val_if_fail (dest_value != NULL, FALSE);
2049 if (src_format == *dest_format) {
2050 *dest_value = src_value;
2051 return TRUE;
2052 }
2054 oclass = GST_ELEMENT_GET_CLASS (element);
2056 if (oclass->convert)
2057 return oclass->convert (element,
2058 src_format, src_value,
2059 dest_format, dest_value);
2060 else {
2061 GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
2062 if (pad)
2063 return gst_pad_convert (GST_PAD_PEER (pad),
2064 src_format, src_value,
2065 dest_format, dest_value);
2066 }
2068 return FALSE;
2069 }
2071 /**
2072 * gst_element_error:
2073 * @element: a #GstElement with the error.
2074 * @error: the printf-style string describing the error.
2075 * @...: the optional arguments for the string.
2076 *
2077 * signals an error condition on an element.
2078 * This function is used internally by elements.
2079 * It results in the "error" signal.
2080 */
2081 void
2082 gst_element_error (GstElement *element, const gchar *error, ...)
2083 {
2084 va_list var_args;
2085 gchar *string;
2087 /* checks */
2088 g_return_if_fail (GST_IS_ELEMENT (element));
2089 g_return_if_fail (error != NULL);
2091 /* create error message */
2092 va_start (var_args, error);
2093 string = g_strdup_vprintf (error, var_args);
2094 va_end (var_args);
2095 GST_CAT_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
2097 /* if the element was already in error, stop now */
2098 if (GST_FLAG_IS_SET (element, GST_ELEMENT_ERROR)) {
2099 GST_CAT_INFO (GST_CAT_EVENT, "recursive ERROR detected in %s", GST_ELEMENT_NAME (element));
2100 g_free (string);
2101 return;
2102 }
2104 GST_FLAG_SET (element, GST_ELEMENT_ERROR);
2106 /* emit the signal, make sure the element stays available */
2107 gst_object_ref (GST_OBJECT (element));
2108 g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, string);
2110 /* tell the scheduler */
2111 if (element->sched) {
2112 gst_scheduler_error (element->sched, element);
2113 }
2115 if (GST_STATE (element) == GST_STATE_PLAYING) {
2116 GstElementStateReturn ret;
2118 ret = gst_element_set_state (element, GST_STATE_PAUSED);
2119 if (ret != GST_STATE_SUCCESS) {
2120 g_warning ("could not PAUSE element \"%s\" after error, help!", GST_ELEMENT_NAME (element));
2121 }
2122 }
2124 GST_FLAG_UNSET (element, GST_ELEMENT_ERROR);
2126 /* cleanup */
2127 gst_object_unref (GST_OBJECT (element));
2128 g_free (string);
2129 }
2131 /**
2132 * gst_element_is_locked_state:
2133 * @element: a #GstElement.
2134 *
2135 * Checks if the state of an element is locked.
2136 * If the state of an element is locked, state changes of the parent don't
2137 * affect the element.
2138 * This way you can leave currently unused elements inside bins. Just lock their
2139 * state before changing the state from #GST_STATE_NULL.
2140 *
2141 * Returns: TRUE, if the element's state is locked.
2142 */
2143 gboolean
2144 gst_element_is_locked_state (GstElement *element)
2145 {
2146 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2148 return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE;
2149 }
2150 /**
2151 * gst_element_set_locked_state:
2152 * @element: a #GstElement
2153 * @locked_state: TRUE to lock the element's state
2154 *
2155 * Locks the state of an element, so state changes of the parent don't affect
2156 * this element anymore.
2157 */
2158 void
2159 gst_element_set_locked_state (GstElement *element, gboolean locked_state)
2160 {
2161 gboolean old;
2163 g_return_if_fail (GST_IS_ELEMENT (element));
2165 old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
2167 if (old == locked_state)
2168 return;
2170 if (locked_state) {
2171 GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s",
2172 GST_ELEMENT_NAME (element));
2173 GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE);
2174 } else {
2175 GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s",
2176 GST_ELEMENT_NAME (element));
2177 GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
2178 }
2179 }
2180 /**
2181 * gst_element_sync_state_with_parent:
2182 * @element: a #GstElement.
2183 *
2184 * Tries to change the state of the element to the same as its parent.
2185 * If this function returns FALSE, the state of element is undefined.
2186 *
2187 * Returns: TRUE, if the element's state could be synced to the parent's state.
2188 */
2189 gboolean
2190 gst_element_sync_state_with_parent (GstElement *element)
2191 {
2192 GstElement *parent;
2194 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
2195 parent = GST_ELEMENT (GST_ELEMENT_PARENT(element));
2196 g_return_val_if_fail (GST_IS_BIN (parent), FALSE);
2198 GST_CAT_DEBUG (GST_CAT_STATES, "syncing state of element %s (%s) to %s (%s)",
2199 GST_ELEMENT_NAME (element), gst_element_state_get_name (GST_STATE (element)),
2200 GST_ELEMENT_NAME (parent), gst_element_state_get_name (GST_STATE (parent)));
2201 if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
2202 return FALSE;
2203 }
2204 return TRUE;
2205 }
2206 /**
2207 * gst_element_get_state:
2208 * @element: a #GstElement to get the state of.
2209 *
2210 * Gets the state of the element.
2211 *
2212 * Returns: the #GstElementState of the element.
2213 */
2214 GstElementState
2215 gst_element_get_state (GstElement *element)
2216 {
2217 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
2219 return GST_STATE (element);
2220 }
2222 /**
2223 * gst_element_wait_state_change:
2224 * @element: a #GstElement to wait for a state change on.
2225 *
2226 * Waits and blocks until the element changed its state.
2227 */
2228 void
2229 gst_element_wait_state_change (GstElement *element)
2230 {
2231 g_mutex_lock (element->state_mutex);
2232 g_cond_wait (element->state_cond, element->state_mutex);
2233 g_mutex_unlock (element->state_mutex);
2234 }
2236 /**
2237 * gst_element_set_state:
2238 * @element: a #GstElement to change state of.
2239 * @state: the element's new #GstElementState.
2240 *
2241 * Sets the state of the element. This function will try to set the
2242 * requested state by going through all the intermediary states and calling
2243 * the class's state change function for each.
2244 *
2245 * Returns: TRUE if the state was successfully set.
2246 * (using #GstElementStateReturn).
2247 */
2248 GstElementStateReturn
2249 gst_element_set_state (GstElement *element, GstElementState state)
2250 {
2251 GstElementClass *oclass;
2252 GstElementState curpending;
2253 GstElementStateReturn return_val = GST_STATE_SUCCESS;
2255 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2257 /* start with the current state */
2258 curpending = GST_STATE(element);
2260 if (state == curpending)
2261 {
2262 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2263 "element is already in requested state %s",
2264 gst_element_state_get_name (state));
2265 return (GST_STATE_SUCCESS);
2266 }
2268 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s",
2269 gst_element_state_get_name (curpending),
2270 gst_element_state_get_name (state));
2272 /* loop until the final requested state is set */
2273 while (GST_STATE (element) != state
2274 && GST_STATE (element) != GST_STATE_VOID_PENDING) {
2275 /* move the curpending state in the correct direction */
2276 if (curpending < state)
2277 curpending <<= 1;
2278 else
2279 curpending >>= 1;
2281 /* set the pending state variable */
2282 /* FIXME: should probably check to see that we don't already have one */
2283 GST_STATE_PENDING (element) = curpending;
2285 if (curpending != state) {
2286 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2287 "intermediate: setting state from %s to %s",
2288 gst_element_state_get_name (GST_STATE (element)),
2289 gst_element_state_get_name (curpending));
2290 }
2292 /* call the state change function so it can set the state */
2293 oclass = GST_ELEMENT_GET_CLASS (element);
2294 if (oclass->change_state)
2295 return_val = (oclass->change_state) (element);
2297 switch (return_val) {
2298 case GST_STATE_FAILURE:
2299 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2300 "have failed change_state return");
2301 goto exit;
2302 case GST_STATE_ASYNC:
2303 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2304 "element will change state async");
2305 goto exit;
2306 case GST_STATE_SUCCESS:
2307 /* Last thing we do is verify that a successful state change really
2308 * did change the state... */
2309 /* if it did not, this is an error - fix the element that does this */
2310 if (GST_STATE (element) != curpending) {
2311 g_warning ("element %s claimed state-change success,"
2312 "but state didn't change to %s. State is %s (%s pending), fix the element",
2313 GST_ELEMENT_NAME (element),
2314 gst_element_state_get_name (curpending),
2315 gst_element_state_get_name (GST_STATE (element)),
2316 gst_element_state_get_name (GST_STATE_PENDING (element)));
2317 return_val = GST_STATE_FAILURE;
2318 goto exit;
2319 }
2320 break;
2321 default:
2322 /* somebody added a GST_STATE_ and forgot to do stuff here ! */
2323 g_assert_not_reached ();
2324 }
2325 }
2326 exit:
2328 return return_val;
2329 }
2331 static gboolean
2332 gst_element_negotiate_pads (GstElement *element)
2333 {
2334 GList *pads = GST_ELEMENT_PADS (element);
2336 GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "negotiating pads");
2338 while (pads) {
2339 GstPad *pad = GST_PAD (pads->data);
2340 GstRealPad *srcpad;
2342 pads = g_list_next (pads);
2344 if (!GST_IS_REAL_PAD (pad))
2345 continue;
2347 srcpad = GST_PAD_REALIZE (pad);
2349 /* if we have a link on this pad and it doesn't have caps
2350 * allready, try to negotiate */
2351 if (GST_PAD_IS_LINKED (srcpad) && !GST_PAD_CAPS (srcpad)) {
2352 GstRealPad *sinkpad;
2353 GstElementState otherstate;
2354 GstElement *parent;
2356 sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
2358 /* check the parent of the peer pad, if there is no parent do nothing */
2359 parent = GST_PAD_PARENT (sinkpad);
2360 if (!parent)
2361 continue;
2363 /* skips pads that were already negotiating */
2364 if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
2365 GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
2366 continue;
2368 otherstate = GST_STATE (parent);
2370 /* swap pads if needed */
2371 if (!GST_PAD_IS_SRC (srcpad)) {
2372 GstRealPad *temp;
2374 temp = srcpad;
2375 srcpad = sinkpad;
2376 sinkpad = temp;
2377 }
2379 /* only try to negotiate if the peer element is in PAUSED or higher too */
2380 if (otherstate >= GST_STATE_READY) {
2381 GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element,
2382 "perform negotiate for %s:%s and %s:%s",
2383 GST_DEBUG_PAD_NAME (srcpad),
2384 GST_DEBUG_PAD_NAME (sinkpad));
2385 if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
2386 return FALSE;
2387 }
2388 else {
2389 GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element,
2390 "not negotiating %s:%s and %s:%s, not in READY yet",
2391 GST_DEBUG_PAD_NAME (srcpad),
2392 GST_DEBUG_PAD_NAME (sinkpad));
2393 }
2394 }
2395 }
2397 return TRUE;
2398 }
2400 static void
2401 gst_element_clear_pad_caps (GstElement *element)
2402 {
2403 GList *pads = GST_ELEMENT_PADS (element);
2405 GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "clearing pad caps");
2407 while (pads) {
2408 GstRealPad *pad = GST_PAD_REALIZE (pads->data);
2410 gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
2412 pads = g_list_next (pads);
2413 }
2414 }
2416 static void
2417 gst_element_pads_activate (GstElement *element, gboolean active)
2418 {
2419 GList *pads = element->pads;
2421 while (pads) {
2422 GstPad *pad = GST_PAD_CAST (pads->data);
2423 pads = g_list_next (pads);
2425 if (!GST_IS_REAL_PAD (pad))
2426 continue;
2428 gst_pad_set_active (pad, active);
2429 }
2430 }
2432 static GstElementStateReturn
2433 gst_element_change_state (GstElement *element)
2434 {
2435 GstElementState old_state;
2436 GstObject *parent;
2437 gint old_pending, old_transition;
2439 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2441 old_state = GST_STATE (element);
2442 old_pending = GST_STATE_PENDING (element);
2443 old_transition = GST_STATE_TRANSITION (element);
2445 if (old_pending == GST_STATE_VOID_PENDING ||
2446 old_state == GST_STATE_PENDING (element)) {
2447 GST_CAT_INFO (GST_CAT_STATES,
2448 "no state change needed for element %s (VOID_PENDING)",
2449 GST_ELEMENT_NAME (element));
2450 return GST_STATE_SUCCESS;
2451 }
2453 GST_CAT_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x",
2454 GST_ELEMENT_NAME (element),
2455 gst_element_state_get_name (old_state),
2456 gst_element_state_get_name (old_pending),
2457 old_transition);
2459 /* we set the state change early for the negotiation functions */
2460 GST_STATE (element) = old_pending;
2461 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2463 switch (old_transition) {
2464 case GST_STATE_PLAYING_TO_PAUSED:
2465 gst_element_pads_activate (element, FALSE);
2466 break;
2467 case GST_STATE_PAUSED_TO_PLAYING:
2468 gst_element_pads_activate (element, TRUE);
2469 break;
2470 /* if we are going to paused, we try to negotiate the pads */
2471 case GST_STATE_READY_TO_PAUSED:
2472 if (!gst_element_negotiate_pads (element))
2473 goto failure;
2474 break;
2475 /* going to the READY state clears all pad caps */
2476 case GST_STATE_PAUSED_TO_READY:
2477 gst_element_clear_pad_caps (element);
2478 break;
2479 default:
2480 break;
2481 }
2483 parent = GST_ELEMENT_PARENT (element);
2485 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2486 "signaling state change from %s to %s",
2487 gst_element_state_get_name (old_state),
2488 gst_element_state_get_name (GST_STATE (element)));
2490 /* tell the scheduler if we have one */
2491 if (element->sched) {
2492 if (gst_scheduler_state_transition (element->sched, element,
2493 old_transition) != GST_STATE_SUCCESS) {
2494 GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
2495 "scheduler could not change state");
2496 goto failure;
2497 }
2498 }
2500 /* tell our parent about the state change */
2501 if (parent && GST_IS_BIN (parent)) {
2502 gst_bin_child_state_change (GST_BIN (parent), old_state,
2503 GST_STATE (element), element);
2504 }
2505 /* at this point the state of the element could have changed again */
2507 g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2508 0, old_state, GST_STATE (element));
2510 /* signal the state change in case somebody is waiting for us */
2511 g_mutex_lock (element->state_mutex);
2512 g_cond_signal (element->state_cond);
2513 g_mutex_unlock (element->state_mutex);
2515 return GST_STATE_SUCCESS;
2517 failure:
2518 /* undo the state change */
2519 GST_STATE (element) = old_state;
2520 GST_STATE_PENDING (element) = old_pending;
2522 return GST_STATE_FAILURE;
2523 }
2525 /**
2526 * gst_element_get_factory:
2527 * @element: a #GstElement to request the element factory of.
2528 *
2529 * Retrieves the factory that was used to create this element.
2530 *
2531 * Returns: the #GstElementFactory used for creating this element.
2532 */
2533 GstElementFactory*
2534 gst_element_get_factory (GstElement *element)
2535 {
2536 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2538 return GST_ELEMENT_GET_CLASS (element)->elementfactory;
2539 }
2541 static void
2542 gst_element_dispose (GObject *object)
2543 {
2544 GstElement *element = GST_ELEMENT (object);
2545 GList *pads;
2546 GstPad *pad;
2548 GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
2550 gst_element_set_state (element, GST_STATE_NULL);
2552 /* first we break all our links with the ouside */
2553 if (element->pads) {
2554 GList *orig;
2555 orig = pads = g_list_copy (element->pads);
2556 while (pads) {
2557 pad = GST_PAD (pads->data);
2559 if (GST_PAD_PEER (pad)) {
2560 GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "unlinking pad '%s'",
2561 GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2562 gst_pad_unlink (pad, GST_PAD (GST_PAD_PEER (pad)));
2563 }
2564 gst_element_remove_pad (element, pad);
2566 pads = g_list_next (pads);
2567 }
2568 g_list_free (orig);
2569 g_list_free (element->pads);
2570 element->pads = NULL;
2571 }
2573 element->numsrcpads = 0;
2574 element->numsinkpads = 0;
2575 element->numpads = 0;
2576 g_mutex_free (element->state_mutex);
2577 g_cond_free (element->state_cond);
2579 if (element->prop_value_queue)
2580 g_async_queue_unref (element->prop_value_queue);
2581 element->prop_value_queue = NULL;
2582 if (element->property_mutex)
2583 g_mutex_free (element->property_mutex);
2585 gst_object_replace ((GstObject **)&element->sched, NULL);
2586 gst_object_replace ((GstObject **)&element->clock, NULL);
2588 G_OBJECT_CLASS (parent_class)->dispose (object);
2589 }
2591 #ifndef GST_DISABLE_LOADSAVE
2592 /**
2593 * gst_element_save_thyself:
2594 * @element: a #GstElement to save.
2595 * @parent: the xml parent node.
2596 *
2597 * Saves the element as part of the given XML structure.
2598 *
2599 * Returns: the new #xmlNodePtr.
2600 */
2601 static xmlNodePtr
2602 gst_element_save_thyself (GstObject *object,
2603 xmlNodePtr parent)
2604 {
2605 GList *pads;
2606 GstElementClass *oclass;
2607 GParamSpec **specs, *spec;
2608 gint nspecs, i;
2609 GValue value = { 0, };
2610 GstElement *element;
2612 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2614 element = GST_ELEMENT (object);
2616 oclass = GST_ELEMENT_GET_CLASS (element);
2618 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2620 if (oclass->elementfactory != NULL) {
2621 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2623 xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
2624 xmlNewChild (parent, NULL, "version", factory->details->version);
2625 }
2627 /* FIXME: what is this? */
2628 /* if (element->manager) */
2629 /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2631 /* params */
2632 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2634 for (i=0; i<nspecs; i++) {
2635 spec = specs[i];
2636 if (spec->flags & G_PARAM_READABLE) {
2637 xmlNodePtr param;
2638 char *contents;
2640 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
2642 g_object_get_property (G_OBJECT (element), spec->name, &value);
2643 param = xmlNewChild (parent, NULL, "param", NULL);
2644 xmlNewChild (param, NULL, "name", spec->name);
2646 if (G_IS_PARAM_SPEC_STRING (spec))
2647 contents = g_value_dup_string (&value);
2648 else if (G_IS_PARAM_SPEC_ENUM (spec))
2649 contents = g_strdup_printf ("%d", g_value_get_enum (&value));
2650 else if (G_IS_PARAM_SPEC_INT64 (spec))
2651 contents = g_strdup_printf ("%" G_GINT64_FORMAT,
2652 g_value_get_int64 (&value));
2653 else
2654 contents = g_strdup_value_contents (&value);
2656 xmlNewChild (param, NULL, "value", contents);
2657 g_free (contents);
2659 g_value_unset(&value);
2660 }
2661 }
2663 pads = GST_ELEMENT_PADS (element);
2665 while (pads) {
2666 GstPad *pad = GST_PAD (pads->data);
2667 /* figure out if it's a direct pad or a ghostpad */
2668 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
2669 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
2670 gst_object_save_thyself (GST_OBJECT (pad), padtag);
2671 }
2672 pads = g_list_next (pads);
2673 }
2675 return parent;
2676 }
2678 static void
2679 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
2680 {
2681 xmlNodePtr children;
2682 GstElement *element;
2683 gchar *name = NULL;
2684 gchar *value = NULL;
2686 element = GST_ELEMENT (object);
2687 g_return_if_fail (element != NULL);
2689 /* parameters */
2690 children = self->xmlChildrenNode;
2691 while (children) {
2692 if (!strcmp (children->name, "param")) {
2693 xmlNodePtr child = children->xmlChildrenNode;
2695 while (child) {
2696 if (!strcmp (child->name, "name")) {
2697 name = xmlNodeGetContent (child);
2698 }
2699 else if (!strcmp (child->name, "value")) {
2700 value = xmlNodeGetContent (child);
2701 }
2702 child = child->next;
2703 }
2704 /* FIXME: can this just be g_object_set ? */
2705 gst_util_set_object_arg (G_OBJECT (element), name, value);
2706 }
2707 children = children->next;
2708 }
2710 /* pads */
2711 children = self->xmlChildrenNode;
2712 while (children) {
2713 if (!strcmp (children->name, "pad")) {
2714 gst_pad_load_and_link (children, GST_OBJECT (element));
2715 }
2716 children = children->next;
2717 }
2719 if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
2720 (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
2721 }
2722 #endif /* GST_DISABLE_LOADSAVE */
2724 /**
2725 * gst_element_yield:
2726 * @element: a #GstElement to yield.
2727 *
2728 * Requests a yield operation for the element. The scheduler will typically
2729 * give control to another element.
2730 */
2731 void
2732 gst_element_yield (GstElement *element)
2733 {
2734 if (GST_ELEMENT_SCHED (element)) {
2735 gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
2736 }
2737 }
2739 /**
2740 * gst_element_interrupt:
2741 * @element: a #GstElement to interrupt.
2742 *
2743 * Requests the scheduler of this element to interrupt the execution of
2744 * this element and scheduler another one.
2745 *
2746 * Returns: TRUE if the element should exit its chain/loop/get
2747 * function ASAP, depending on the scheduler implementation.
2748 */
2749 gboolean
2750 gst_element_interrupt (GstElement *element)
2751 {
2752 if (GST_ELEMENT_SCHED (element)) {
2753 return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
2754 }
2755 else
2756 return TRUE;
2757 }
2759 /**
2760 * gst_element_set_scheduler:
2761 * @element: a #GstElement to set the scheduler of.
2762 * @sched: the #GstScheduler to set.
2763 *
2764 * Sets the scheduler of the element. For internal use only, unless you're
2765 * writing a new bin subclass.
2766 */
2767 void
2768 gst_element_set_scheduler (GstElement *element,
2769 GstScheduler *sched)
2770 {
2771 g_return_if_fail (GST_IS_ELEMENT (element));
2773 GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
2775 gst_object_replace ((GstObject **)&GST_ELEMENT_SCHED (element), GST_OBJECT (sched));
2776 }
2778 /**
2779 * gst_element_get_scheduler:
2780 * @element: a #GstElement to get the scheduler of.
2781 *
2782 * Returns the scheduler of the element.
2783 *
2784 * Returns: the element's #GstScheduler.
2785 */
2786 GstScheduler*
2787 gst_element_get_scheduler (GstElement *element)
2788 {
2789 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2791 return GST_ELEMENT_SCHED (element);
2792 }
2794 /**
2795 * gst_element_set_loop_function:
2796 * @element: a #GstElement to set the loop function of.
2797 * @loop: Pointer to #GstElementLoopFunction.
2798 *
2799 * This sets the loop function for the element. The function pointed to
2800 * can deviate from the GstElementLoopFunction definition in type of
2801 * pointer only.
2802 *
2803 * NOTE: in order for this to take effect, the current loop function *must*
2804 * exit. Assuming the loop function itself is the only one who will cause
2805 * a new loopfunc to be assigned, this should be no problem.
2806 */
2807 void
2808 gst_element_set_loop_function (GstElement *element,
2809 GstElementLoopFunction loop)
2810 {
2811 gboolean need_notify = FALSE;
2813 g_return_if_fail (GST_IS_ELEMENT (element));
2815 /* if the element changed from loop based to chain/get based
2816 * or vice versa, we need to inform the scheduler about that */
2817 if ((element->loopfunc == NULL && loop != NULL) ||
2818 (element->loopfunc != NULL && loop == NULL))
2819 {
2820 need_notify = TRUE;
2821 }
2823 /* set the loop function */
2824 element->loopfunc = loop;
2826 if (need_notify) {
2827 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
2828 GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
2830 if (GST_ELEMENT_SCHED (element)) {
2831 gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
2832 }
2833 }
2834 }
2836 static inline void
2837 gst_element_set_eos_recursive (GstElement *element)
2838 {
2839 /* this function is only called, when we were in PLAYING before. So every
2840 parent that's PAUSED was PLAYING before. That means it has reached EOS. */
2841 GstElement *parent;
2843 GST_CAT_DEBUG (GST_CAT_EVENT, "setting recursive EOS on %s",
2844 GST_OBJECT_NAME (element));
2845 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2847 if (!GST_OBJECT_PARENT (element))
2848 return;
2850 parent = GST_ELEMENT (GST_OBJECT_PARENT (element));
2851 if (GST_STATE (parent) == GST_STATE_PAUSED)
2852 gst_element_set_eos_recursive (parent);
2853 }
2854 /**
2855 * gst_element_set_eos:
2856 * @element: a #GstElement to set to the EOS state.
2857 *
2858 * Perform the actions needed to bring the element in the EOS state.
2859 */
2860 void
2861 gst_element_set_eos (GstElement *element)
2862 {
2863 g_return_if_fail (GST_IS_ELEMENT (element));
2865 GST_CAT_DEBUG (GST_CAT_EVENT, "setting EOS on element %s",
2866 GST_OBJECT_NAME (element));
2868 if (GST_STATE (element) == GST_STATE_PLAYING) {
2869 gst_element_set_state (element, GST_STATE_PAUSED);
2870 gst_element_set_eos_recursive (element);
2871 } else {
2872 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2873 }
2874 }
2877 /**
2878 * gst_element_state_get_name:
2879 * @state: a #GstElementState to get the name of.
2880 *
2881 * Gets a string representing the given state.
2882 *
2883 * Returns: a string with the name of the state.
2884 */
2885 const gchar*
2886 gst_element_state_get_name (GstElementState state)
2887 {
2888 switch (state) {
2889 #ifdef GST_DEBUG_COLOR
2890 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2891 case GST_STATE_NULL: return "\033[01;34mNULL\033[00m";break;
2892 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
2893 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
2894 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
2895 default:
2896 /* This is a memory leak */
2897 return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
2898 #else
2899 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2900 case GST_STATE_NULL: return "NULL";break;
2901 case GST_STATE_READY: return "READY";break;
2902 case GST_STATE_PLAYING: return "PLAYING";break;
2903 case GST_STATE_PAUSED: return "PAUSED";break;
2904 default: return "UNKNOWN!";
2905 #endif
2906 }
2907 return "";
2908 }
2910 static void
2911 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name,
2912 guint arg_id, GParamFlags flags)
2913 {
2914 GQuark prop_id = g_quark_from_string (prop_name);
2915 GParamSpec *pspec;
2917 static GQuark fd_id = 0;
2918 static GQuark blocksize_id;
2919 static GQuark bytesperread_id;
2920 static GQuark dump_id;
2921 static GQuark filesize_id;
2922 static GQuark mmapsize_id;
2923 static GQuark location_id;
2924 static GQuark offset_id;
2925 static GQuark silent_id;
2926 static GQuark touch_id;
2928 if (!fd_id) {
2929 fd_id = g_quark_from_static_string ("fd");
2930 blocksize_id = g_quark_from_static_string ("blocksize");
2931 bytesperread_id = g_quark_from_static_string ("bytesperread");
2932 dump_id = g_quark_from_static_string ("dump");
2933 filesize_id = g_quark_from_static_string ("filesize");
2934 mmapsize_id = g_quark_from_static_string ("mmapsize");
2935 location_id = g_quark_from_static_string ("location");
2936 offset_id = g_quark_from_static_string ("offset");
2937 silent_id = g_quark_from_static_string ("silent");
2938 touch_id = g_quark_from_static_string ("touch");
2939 }
2941 if (prop_id == fd_id) {
2942 pspec = g_param_spec_int ("fd", "File-descriptor",
2943 "File-descriptor for the file being read",
2944 0, G_MAXINT, 0, flags);
2945 }
2946 else if (prop_id == blocksize_id) {
2947 pspec = g_param_spec_ulong ("blocksize", "Block Size",
2948 "Block size to read per buffer",
2949 0, G_MAXULONG, 4096, flags);
2951 }
2952 else if (prop_id == bytesperread_id) {
2953 pspec = g_param_spec_int ("bytesperread", "Bytes per read",
2954 "Number of bytes to read per buffer",
2955 G_MININT, G_MAXINT, 0, flags);
2957 }
2958 else if (prop_id == dump_id) {
2959 pspec = g_param_spec_boolean ("dump", "Dump",
2960 "Dump bytes to stdout",
2961 FALSE, flags);
2963 }
2964 else if (prop_id == filesize_id) {
2965 pspec = g_param_spec_int64 ("filesize", "File Size",
2966 "Size of the file being read",
2967 0, G_MAXINT64, 0, flags);
2969 }
2970 else if (prop_id == mmapsize_id) {
2971 pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
2972 "Size in bytes of mmap()d regions",
2973 0, G_MAXULONG, 4 * 1048576, flags);
2975 }
2976 else if (prop_id == location_id) {
2977 pspec = g_param_spec_string ("location", "File Location",
2978 "Location of the file to read",
2979 NULL, flags);
2981 }
2982 else if (prop_id == offset_id) {
2983 pspec = g_param_spec_int64 ("offset", "File Offset",
2984 "Byte offset of current read pointer",
2985 0, G_MAXINT64, 0, flags);
2987 }
2988 else if (prop_id == silent_id) {
2989 pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
2990 FALSE, flags);
2992 }
2993 else if (prop_id == touch_id) {
2994 pspec = g_param_spec_boolean ("touch", "Touch read data",
2995 "Touch data to force disk read before "
2996 "push ()", TRUE, flags);
2997 }
2998 else {
2999 g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
3000 prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
3001 pspec = NULL;
3002 }
3004 if (pspec) {
3005 g_object_class_install_property (klass, arg_id, pspec);
3006 }
3007 }
3009 /**
3010 * gst_element_class_install_std_props:
3011 * @klass: the #GstElementClass to add the properties to.
3012 * @first_name: the name of the first property.
3013 * in a NULL terminated
3014 * @...: the id and flags of the first property, followed by
3015 * further 'name', 'id', 'flags' triplets and terminated by NULL.
3016 *
3017 * Adds a list of standardized properties with types to the @klass.
3018 * the id is for the property switch in your get_prop method, and
3019 * the flags determine readability / writeability.
3020 **/
3021 void
3022 gst_element_class_install_std_props (GstElementClass * klass,
3023 const gchar *first_name, ...)
3024 {
3025 const char *name;
3027 va_list args;
3029 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
3031 va_start (args, first_name);
3033 name = first_name;
3035 while (name) {
3036 int arg_id = va_arg (args, int);
3037 int flags = va_arg (args, int);
3039 gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
3041 name = va_arg (args, char *);
3042 }
3044 va_end (args);
3045 }
3047 /**
3048 * gst_element_get_managing_bin:
3049 * @element: a #GstElement to get the managing bin of.
3050 *
3051 * Gets the managing bin (a pipeline or a thread, for example) of an element.
3052 *
3053 * Returns: the #GstBin, or NULL on failure.
3054 **/
3055 GstBin*
3056 gst_element_get_managing_bin (GstElement *element)
3057 {
3058 GstBin *bin;
3060 g_return_val_if_fail (element != NULL, NULL);
3062 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
3064 while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
3065 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
3067 return bin;
3068 }