1 /* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 *
5 * gstelement.c: The base element, all elements derive from this
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
23 /* #define GST_DEBUG_ENABLED */
24 #include <glib.h>
25 #include <stdarg.h>
26 #include <gobject/gvaluecollector.h>
27 #include "gst_private.h"
29 #include "gstelement.h"
30 #include "gstextratypes.h"
31 #include "gstbin.h"
32 #include "gstscheduler.h"
33 #include "gstevent.h"
34 #include "gstutils.h"
35 #include "gstlog.h"
37 /* Element signals and args */
38 enum {
39 STATE_CHANGE,
40 NEW_PAD,
41 PAD_REMOVED,
42 ERROR,
43 EOS,
44 LAST_SIGNAL
45 };
47 enum {
48 ARG_0,
49 /* FILL ME */
50 };
52 #define CLASS(element) GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))
54 static void gst_element_class_init (GstElementClass *klass);
55 static void gst_element_init (GstElement *element);
56 static void gst_element_base_class_init (GstElementClass *klass);
58 static void gst_element_real_set_property (GObject *object, guint prop_id,
59 const GValue *value, GParamSpec *pspec);
60 static void gst_element_real_get_property (GObject *object, guint prop_id, GValue *value,
61 GParamSpec *pspec);
63 static void gst_element_dispose (GObject *object);
65 static gboolean gst_element_send_event_default (GstElement *element, GstEvent *event);
66 static gboolean gst_element_query_default (GstElement *element, GstPadQueryType type,
67 GstFormat *format, gint64 *value);
69 static GstElementStateReturn gst_element_change_state (GstElement *element);
70 static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg);
72 #ifndef GST_DISABLE_LOADSAVE
73 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
74 static void gst_element_restore_thyself (GstObject *parent, xmlNodePtr self);
75 #endif
77 GType _gst_element_type = 0;
79 static GstObjectClass *parent_class = NULL;
80 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
82 GType gst_element_get_type (void)
83 {
84 if (!_gst_element_type) {
85 static const GTypeInfo element_info = {
86 sizeof(GstElementClass),
87 (GBaseInitFunc)gst_element_base_class_init,
88 NULL,
89 (GClassInitFunc)gst_element_class_init,
90 NULL,
91 NULL,
92 sizeof(GstElement),
93 0,
94 (GInstanceInitFunc)gst_element_init,
95 NULL
96 };
97 _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement",
98 &element_info, G_TYPE_FLAG_ABSTRACT);
99 }
100 return _gst_element_type;
101 }
103 static void
104 gst_element_class_init (GstElementClass *klass)
105 {
106 GObjectClass *gobject_class;
107 GstObjectClass *gstobject_class;
109 gobject_class = (GObjectClass*) klass;
110 gstobject_class = (GstObjectClass*) klass;
112 parent_class = g_type_class_ref(GST_TYPE_OBJECT);
114 gst_element_signals[STATE_CHANGE] =
115 g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
116 G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
117 gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
118 G_TYPE_INT, G_TYPE_INT);
119 gst_element_signals[NEW_PAD] =
120 g_signal_new ("new_pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
121 G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
122 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
123 G_TYPE_OBJECT);
124 gst_element_signals[PAD_REMOVED] =
125 g_signal_new ("pad_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
126 G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
127 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
128 G_TYPE_OBJECT);
129 gst_element_signals[ERROR] =
130 g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
131 G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
132 gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
133 G_TYPE_OBJECT, G_TYPE_STRING);
134 gst_element_signals[EOS] =
135 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
136 G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
137 gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
139 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
140 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
142 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
144 #ifndef GST_DISABLE_LOADSAVE
145 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
146 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
147 #endif
149 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
150 klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
151 klass->elementfactory = NULL;
152 klass->padtemplates = NULL;
153 klass->numpadtemplates = 0;
154 klass->send_event = GST_DEBUG_FUNCPTR (gst_element_send_event_default);
155 klass->query = GST_DEBUG_FUNCPTR (gst_element_query_default);
156 }
158 static void
159 gst_element_base_class_init (GstElementClass *klass)
160 {
161 GObjectClass *gobject_class;
163 gobject_class = (GObjectClass*) klass;
165 gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_real_set_property);
166 gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_real_get_property);
167 }
169 static void
170 gst_element_init (GstElement *element)
171 {
172 element->current_state = GST_STATE_NULL;
173 element->pending_state = GST_STATE_VOID_PENDING;
174 element->numpads = 0;
175 element->numsrcpads = 0;
176 element->numsinkpads = 0;
177 element->pads = NULL;
178 element->loopfunc = NULL;
179 element->sched = NULL;
180 element->clock = NULL;
181 element->sched_private = NULL;
182 element->state_mutex = g_mutex_new ();
183 element->state_cond = g_cond_new ();
184 }
186 static void
187 gst_element_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
188 {
189 GstElementClass *oclass = CLASS (object);
191 if (oclass->set_property)
192 (oclass->set_property) (object, prop_id, value, pspec);
193 }
195 static void
196 gst_element_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
197 {
198 GstElementClass *oclass = CLASS (object);
200 if (oclass->get_property)
201 (oclass->get_property) (object, prop_id, value, pspec);
202 }
204 /**
205 * gst_element_default_error:
206 * @object: a #GObject that signalled the error.
207 * @orig: the #GstObject that initiated the error.
208 * @error: the error message.
209 *
210 * Adds a default error signal callback to an
211 * element. The user data passed to the g_signal_connect is
212 * ignored.
213 * The default handler will simply print the error string
214 * using g_print.
215 */
216 void
217 gst_element_default_error (GObject *object, GstObject *orig, gchar *error)
218 {
219 gchar *name = gst_object_get_path_string (orig);
220 g_print ("ERROR: %s: %s\n", name, error);
221 g_free (name);
222 }
224 typedef struct {
225 const GParamSpec *pspec;
226 GValue value;
227 } prop_value_t;
229 static void
230 element_set_property (GstElement *element, const GParamSpec *pspec, const GValue *value)
231 {
232 prop_value_t *prop_value = g_new0 (prop_value_t, 1);
234 prop_value->pspec = pspec;
235 prop_value->value = *value;
237 g_async_queue_push (element->prop_value_queue, prop_value);
238 }
240 static void
241 element_get_property (GstElement *element, const GParamSpec *pspec, GValue *value)
242 {
243 g_mutex_lock (element->property_mutex);
244 g_object_get_property ((GObject*)element, pspec->name, value);
245 g_mutex_unlock (element->property_mutex);
246 }
248 static void
249 gst_element_threadsafe_properties_pre_run (GstElement *element)
250 {
251 GST_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
252 g_mutex_lock (element->property_mutex);
253 gst_element_set_pending_properties (element);
254 }
256 static void
257 gst_element_threadsafe_properties_post_run (GstElement *element)
258 {
259 GST_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
260 g_mutex_unlock (element->property_mutex);
261 }
263 /**
264 * gst_element_enable_threadsafe_properties:
265 * @element: a #GstElement to enable threadsafe properties on.
266 *
267 * Installs an asynchronous queue, a mutex and pre- and post-run functions on
268 * this element so that properties on the element can be set in a
269 * threadsafe way.
270 */
271 void
272 gst_element_enable_threadsafe_properties (GstElement *element)
273 {
274 g_return_if_fail (GST_IS_ELEMENT (element));
276 GST_FLAG_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
277 element->pre_run_func = gst_element_threadsafe_properties_pre_run;
278 element->post_run_func = gst_element_threadsafe_properties_post_run;
279 if (!element->prop_value_queue)
280 element->prop_value_queue = g_async_queue_new ();
281 if (!element->property_mutex)
282 element->property_mutex = g_mutex_new ();
283 }
285 /**
286 * gst_element_disable_threadsafe_properties:
287 * @element: a #GstElement to disable threadsafe properties on.
288 *
289 * Removes the threadsafe properties, post- and pre-run locks from
290 * this element.
291 */
292 void
293 gst_element_disable_threadsafe_properties (GstElement *element)
294 {
295 g_return_if_fail (GST_IS_ELEMENT (element));
297 GST_FLAG_UNSET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES);
298 element->pre_run_func = NULL;
299 element->post_run_func = NULL;
300 /* let's keep around that async queue */
301 }
303 /**
304 * gst_element_set_pending_properties:
305 * @element: a #GstElement to set the pending properties on.
306 *
307 * Sets all pending properties on the threadsafe properties enabled
308 * element.
309 */
310 void
311 gst_element_set_pending_properties (GstElement *element)
312 {
313 prop_value_t *prop_value;
315 while ((prop_value = g_async_queue_try_pop (element->prop_value_queue))) {
316 g_object_set_property ((GObject*)element, prop_value->pspec->name, &prop_value->value);
317 g_value_unset (&prop_value->value);
318 g_free (prop_value);
319 }
320 }
322 /* following 6 functions taken mostly from gobject.c */
324 /**
325 * gst_element_set:
326 * @element: a #GstElement to set properties on.
327 * @first_property_name: the first property to set.
328 * @...: value of the first property, and more properties to set, ending
329 * with NULL.
330 *
331 * Sets properties on an element. If the element uses threadsafe properties,
332 * they will be queued and set on the object when it is scheduled again.
333 */
334 void
335 gst_element_set (GstElement *element, const gchar *first_property_name, ...)
336 {
337 va_list var_args;
339 g_return_if_fail (GST_IS_ELEMENT (element));
341 va_start (var_args, first_property_name);
342 gst_element_set_valist (element, first_property_name, var_args);
343 va_end (var_args);
344 }
346 /**
347 * gst_element_get:
348 * @element: a #GstElement to get properties of.
349 * @first_property_name: the first property to get.
350 * @...: pointer to a variable to store the first property in, as well as
351 * more properties to get, ending with NULL.
352 *
353 * Gets properties from an element. If the element uses threadsafe properties,
354 * the element will be locked before getting the given properties.
355 */
356 void
357 gst_element_get (GstElement *element, const gchar *first_property_name, ...)
358 {
359 va_list var_args;
361 g_return_if_fail (GST_IS_ELEMENT (element));
363 va_start (var_args, first_property_name);
364 gst_element_get_valist (element, first_property_name, var_args);
365 va_end (var_args);
366 }
368 /**
369 * gst_element_set_valist:
370 * @element: a #GstElement to set properties on.
371 * @first_property_name: the first property to set.
372 * @var_args: the var_args list of other properties to get.
373 *
374 * Sets properties on an element. If the element uses threadsafe properties,
375 * the property change will be put on the async queue.
376 */
377 void
378 gst_element_set_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
379 {
380 const gchar *name;
381 GObject *object;
383 g_return_if_fail (GST_IS_ELEMENT (element));
385 object = (GObject *) element;
387 GST_DEBUG (GST_CAT_PROPERTIES,
388 "setting valist of properties starting with %s on element %s",
389 first_property_name, gst_element_get_name (element));
391 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
392 g_object_set_valist (object, first_property_name, var_args);
393 return;
394 }
396 g_object_ref (object);
398 name = first_property_name;
400 while (name)
401 {
402 GValue value = { 0, };
403 GParamSpec *pspec;
404 gchar *error = NULL;
406 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
408 if (!pspec)
409 {
410 g_warning ("%s: object class `%s' has no property named `%s'",
411 G_STRLOC,
412 G_OBJECT_TYPE_NAME (object),
413 name);
414 break;
415 }
416 if (!(pspec->flags & G_PARAM_WRITABLE))
417 {
418 g_warning ("%s: property `%s' of object class `%s' is not writable",
419 G_STRLOC,
420 pspec->name,
421 G_OBJECT_TYPE_NAME (object));
422 break;
423 }
425 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
427 G_VALUE_COLLECT (&value, var_args, 0, &error);
428 if (error)
429 {
430 g_warning ("%s: %s", G_STRLOC, error);
431 g_free (error);
433 /* we purposely leak the value here, it might not be
434 * in a sane state if an error condition occoured
435 */
436 break;
437 }
439 element_set_property (element, pspec, &value);
440 g_value_unset (&value);
442 name = va_arg (var_args, gchar*);
443 }
445 g_object_unref (object);
446 }
448 /**
449 * gst_element_get_valist:
450 * @element: a #GstElement to get properties of.
451 * @first_property_name: the first property to get.
452 * @var_args: the var_args list of other properties to get.
453 *
454 * Gets properties from an element. If the element uses threadsafe properties,
455 * the element will be locked before getting the given properties.
456 */
457 void
458 gst_element_get_valist (GstElement *element, const gchar *first_property_name, va_list var_args)
459 {
460 const gchar *name;
461 GObject *object;
463 g_return_if_fail (GST_IS_ELEMENT (element));
465 object = (GObject*)element;
467 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
468 g_object_get_valist (object, first_property_name, var_args);
469 return;
470 }
472 g_object_ref (object);
474 name = first_property_name;
476 while (name)
477 {
478 GValue value = { 0, };
479 GParamSpec *pspec;
480 gchar *error;
482 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), name);
484 if (!pspec)
485 {
486 g_warning ("%s: object class `%s' has no property named `%s'",
487 G_STRLOC,
488 G_OBJECT_TYPE_NAME (object),
489 name);
490 break;
491 }
492 if (!(pspec->flags & G_PARAM_READABLE))
493 {
494 g_warning ("%s: property `%s' of object class `%s' is not readable",
495 G_STRLOC,
496 pspec->name,
497 G_OBJECT_TYPE_NAME (object));
498 break;
499 }
501 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
503 element_get_property (element, pspec, &value);
505 G_VALUE_LCOPY (&value, var_args, 0, &error);
506 if (error)
507 {
508 g_warning ("%s: %s", G_STRLOC, error);
509 g_free (error);
510 g_value_unset (&value);
511 break;
512 }
514 g_value_unset (&value);
516 name = va_arg (var_args, gchar*);
517 }
519 g_object_unref (object);
520 }
522 /**
523 * gst_element_set_property:
524 * @element: a #GstElement to set properties on.
525 * @property_name: the first property to get.
526 * @value: the #GValue that holds the value to set.
527 *
528 * Sets a property on an element. If the element uses threadsafe properties,
529 * the property will be put on the async queue.
530 */
531 void
532 gst_element_set_property (GstElement *element, const gchar *property_name,
533 const GValue *value)
534 {
535 GParamSpec *pspec;
536 GObject *object;
538 g_return_if_fail (GST_IS_ELEMENT (element));
539 g_return_if_fail (property_name != NULL);
540 g_return_if_fail (G_IS_VALUE (value));
542 object = (GObject*) element;
544 GST_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
545 property_name, gst_element_get_name (element));
546 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
547 g_object_set_property (object, property_name, value);
548 return;
549 }
551 g_object_ref (object);
553 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
554 property_name);
556 if (!pspec)
557 g_warning ("%s: object class `%s' has no property named `%s'",
558 G_STRLOC,
559 G_OBJECT_TYPE_NAME (object),
560 property_name);
561 else
562 element_set_property (element, pspec, value);
564 g_object_unref (object);
565 }
567 /**
568 * gst_element_get_property:
569 * @element: a #GstElement to get properties of.
570 * @property_name: the first property to get.
571 * @value: the #GValue to store the property value in.
572 *
573 * Gets a property from an element. If the element uses threadsafe properties,
574 * the element will be locked before getting the given property.
575 */
576 void
577 gst_element_get_property (GstElement *element, const gchar *property_name, GValue *value)
578 {
579 GParamSpec *pspec;
580 GObject *object;
582 g_return_if_fail (GST_IS_ELEMENT (element));
583 g_return_if_fail (property_name != NULL);
584 g_return_if_fail (G_IS_VALUE (value));
586 object = (GObject*)element;
588 if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
589 g_object_get_property (object, property_name, value);
590 return;
591 }
593 g_object_ref (object);
595 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
597 if (!pspec)
598 g_warning ("%s: object class `%s' has no property named `%s'",
599 G_STRLOC,
600 G_OBJECT_TYPE_NAME (object),
601 property_name);
602 else
603 {
604 GValue *prop_value, tmp_value = { 0, };
606 /* auto-conversion of the callers value type
607 */
608 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
609 {
610 g_value_reset (value);
611 prop_value = value;
612 }
613 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
614 {
615 g_warning ("can't retrieve property `%s' of type `%s' as value of type `%s'",
616 pspec->name,
617 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
618 G_VALUE_TYPE_NAME (value));
619 g_object_unref (object);
620 return;
621 }
622 else
623 {
624 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
625 prop_value = &tmp_value;
626 }
627 element_get_property (element, pspec, prop_value);
628 if (prop_value != value)
629 {
630 g_value_transform (prop_value, value);
631 g_value_unset (&tmp_value);
632 }
633 }
635 g_object_unref (object);
636 }
638 static GstPad*
639 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
640 {
641 GstPad *newpad = NULL;
642 GstElementClass *oclass;
644 oclass = CLASS (element);
645 if (oclass->request_new_pad)
646 newpad = (oclass->request_new_pad)(element, templ, name);
648 return newpad;
649 }
651 /**
652 * gst_element_release_request_pad:
653 * @element: a #GstElement to release the request pad of.
654 * @pad: the #GstPad to release.
655 *
656 * Makes the element free the previously requested pad as obtained
657 * with gst_element_get_request_pad().
658 */
659 void
660 gst_element_release_request_pad (GstElement *element, GstPad *pad)
661 {
662 GstElementClass *oclass;
664 g_return_if_fail (GST_IS_ELEMENT (element));
665 g_return_if_fail (GST_IS_PAD (pad));
667 oclass = CLASS (element);
668 if (oclass->release_pad)
669 (oclass->release_pad) (element, pad);
670 }
672 /**
673 * gst_element_requires_clock:
674 * @element: a #GstElement to query
675 *
676 * Query if the element requiresd a clock
677 *
678 * Returns: TRUE if the element requires a clock
679 */
680 gboolean
681 gst_element_requires_clock (GstElement *element)
682 {
683 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
685 return (CLASS (element)->set_clock != NULL);
686 }
688 /**
689 * gst_element_provides_clock:
690 * @element: a #GstElement to query
691 *
692 * Query if the element provides a clock
693 *
694 * Returns: TRUE if the element provides a clock
695 */
696 gboolean
697 gst_element_provides_clock (GstElement *element)
698 {
699 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
701 return (CLASS (element)->get_clock != NULL);
702 }
704 /**
705 * gst_element_set_clock:
706 * @element: a #GstElement to set the clock for.
707 * @clock: the #GstClock to set for the element.
708 *
709 * Sets the clock for the element.
710 */
711 void
712 gst_element_set_clock (GstElement *element, GstClock *clock)
713 {
714 g_return_if_fail (GST_IS_ELEMENT (element));
716 if (CLASS (element)->set_clock)
717 CLASS (element)->set_clock (element, clock);
719 element->clock = clock;
720 }
722 /**
723 * gst_element_get_clock:
724 * @element: a #GstElement to get the clock of.
725 *
726 * Gets the clock of the element.
727 *
728 * Returns: the #GstClock of the element.
729 */
730 GstClock*
731 gst_element_get_clock (GstElement *element)
732 {
733 g_return_val_if_fail (element != NULL, NULL);
734 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
736 if (CLASS (element)->get_clock)
737 return CLASS (element)->get_clock (element);
739 return NULL;
740 }
742 /**
743 * gst_element_clock_wait:
744 * @element: a #GstElement.
745 * @clock: the #GstClock to use.
746 * @time: the #GstClockTime to wait for on the clock.
747 * @jitter: the difference between requested time and actual time.
748 *
749 * Waits for a specific time on the clock.
750 *
751 * Returns: the #GstClockReturn result of the wait operation.
752 */
753 GstClockReturn
754 gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter)
755 {
756 GstClockReturn res;
758 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
760 if (GST_ELEMENT_SCHED (element)) {
761 res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time, jitter);
762 }
763 else
764 res = GST_CLOCK_TIMEOUT;
766 return res;
767 }
769 gboolean
770 gst_element_is_cachable (GstElement *element)
771 {
772 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
774 return (CLASS (element)->set_cache != NULL);
775 }
777 void
778 gst_element_set_cache (GstElement *element, GstCache *cache)
779 {
780 g_return_if_fail (GST_IS_ELEMENT (element));
781 g_return_if_fail (GST_IS_CACHE (cache));
783 if (CLASS (element)->set_cache)
784 CLASS (element)->set_cache (element, cache);
785 }
787 GstCache*
788 gst_element_get_cache (GstElement *element)
789 {
790 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
792 if (CLASS (element)->get_cache)
793 return CLASS (element)->get_cache (element);
795 return NULL;
796 }
799 /**
800 * gst_element_release_locks:
801 * @element: a #GstElement to release all locks on.
802 *
803 * Instruct the element to release all the locks it is holding, such as
804 * blocking reads, waiting for the clock, ...
805 *
806 * Returns: TRUE if the locks could be released.
807 */
808 gboolean
809 gst_element_release_locks (GstElement *element)
810 {
811 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
813 if (CLASS (element)->release_locks)
814 return CLASS (element)->release_locks (element);
816 return TRUE;
817 }
819 /**
820 * gst_element_add_pad:
821 * @element: a #GstElement to add the pad to.
822 * @pad: the #GstPad to add to the element.
823 *
824 * Add a pad (connection point) to the element, setting the parent of the
825 * pad to the element (and thus adding a reference).
826 */
827 void
828 gst_element_add_pad (GstElement *element, GstPad *pad)
829 {
830 g_return_if_fail (element != NULL);
831 g_return_if_fail (GST_IS_ELEMENT (element));
832 g_return_if_fail (pad != NULL);
833 g_return_if_fail (GST_IS_PAD (pad));
835 /* first check to make sure the pad's parent is already set */
836 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
838 /* then check to see if there's already a pad by that name here */
839 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
841 /* set the pad's parent */
842 GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
843 GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
844 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
846 /* add it to the list */
847 element->pads = g_list_append (element->pads, pad);
848 element->numpads++;
849 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
850 element->numsrcpads++;
851 else
852 element->numsinkpads++;
854 /* emit the NEW_PAD signal */
855 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
856 }
858 /**
859 * gst_element_remove_pad:
860 * @element: a #GstElement to remove pad from.
861 * @pad: the #GstPad to remove from the element.
862 *
863 * Remove a pad (connection point) from the element.
864 */
865 void
866 gst_element_remove_pad (GstElement *element, GstPad *pad)
867 {
868 g_return_if_fail (element != NULL);
869 g_return_if_fail (GST_IS_ELEMENT (element));
870 g_return_if_fail (pad != NULL);
871 g_return_if_fail (GST_IS_PAD (pad));
873 g_return_if_fail (GST_PAD_PARENT (pad) == element);
875 /* check to see if the pad is still connected */
876 /* FIXME: what if someone calls _remove_pad instead of
877 _remove_ghost_pad? */
878 if (GST_IS_REAL_PAD (pad)) {
879 g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
880 }
882 /* remove it from the list */
883 element->pads = g_list_remove (element->pads, pad);
884 element->numpads--;
885 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
886 element->numsrcpads--;
887 else
888 element->numsinkpads--;
890 g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
892 gst_object_unparent (GST_OBJECT (pad));
893 }
895 /**
896 * gst_element_add_ghost_pad:
897 * @element: a #GstElement to add the ghost pad to.
898 * @pad: the #GstPad from which the new ghost pad will be created.
899 * @name: the name of the new ghost pad.
900 *
901 * Creates a ghost pad from the given pad, and adds it to the list of pads
902 * for this element.
903 *
904 * Returns: the added ghost #GstPad, or NULL, if no ghost pad was created.
905 */
906 GstPad *
907 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
908 {
909 GstPad *ghostpad;
911 g_return_val_if_fail (element != NULL, NULL);
912 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
913 g_return_val_if_fail (pad != NULL, NULL);
914 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
916 /* then check to see if there's already a pad by that name here */
917 g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
919 GST_DEBUG (GST_CAT_ELEMENT_PADS,
920 "creating new ghost pad called %s, from pad %s:%s",
921 name, GST_DEBUG_PAD_NAME(pad));
922 ghostpad = gst_ghost_pad_new (name, pad);
924 /* add it to the list */
925 GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
926 name, GST_ELEMENT_NAME (element));
927 element->pads = g_list_append (element->pads, ghostpad);
928 element->numpads++;
929 /* set the parent of the ghostpad */
930 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
932 GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
934 /* emit the NEW_GHOST_PAD signal */
935 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
937 return ghostpad;
938 }
940 /**
941 * gst_element_remove_ghost_pad:
942 * @element: a #GstElement to remove the ghost pad from.
943 * @pad: ghost #GstPad to remove.
944 *
945 * Removes a ghost pad from an element.
946 */
947 void
948 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
949 {
950 g_return_if_fail (element != NULL);
951 g_return_if_fail (GST_IS_ELEMENT (element));
952 g_return_if_fail (pad != NULL);
953 g_return_if_fail (GST_IS_GHOST_PAD (pad));
955 /* FIXME this is redundant?
956 * wingo 10-july-2001: I don't think so, you have to actually remove the pad
957 * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
958 * the real pad's ghost pad list
959 */
960 gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
961 gst_element_remove_pad (element, pad);
962 }
965 /**
966 * gst_element_get_pad:
967 * @element: a #GstElement to find pad of.
968 * @name: the name of the pad to retrieve.
969 *
970 * Retrieves a pad from the element by name.
971 *
972 * Returns: requested #GstPad if found, otherwise NULL.
973 */
974 GstPad*
975 gst_element_get_pad (GstElement *element, const gchar *name)
976 {
977 GstPad *pad;
979 g_return_val_if_fail (element != NULL, NULL);
980 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
981 g_return_val_if_fail (name != NULL, NULL);
983 pad = gst_element_get_static_pad (element, name);
984 if (!pad)
985 pad = gst_element_get_request_pad (element, name);
987 return pad;
988 }
990 /**
991 * gst_element_get_static_pad:
992 * @element: a #GstElement to find a static pad of.
993 * @name: the name of the static #GstPad to retrieve.
994 *
995 * Retrieves a pad from the element by name. This version only retrieves
996 * already-existing (i.e. 'static') pads.
997 *
998 * Returns: the requested #GstPad if found, otherwise NULL.
999 */
1000 GstPad *
1001 gst_element_get_static_pad (GstElement *element, const gchar *name)
1002 {
1003 GList *walk;
1005 g_return_val_if_fail (element != NULL, NULL);
1006 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1007 g_return_val_if_fail (name != NULL, NULL);
1009 walk = element->pads;
1010 while (walk) {
1011 GstPad *pad;
1013 pad = GST_PAD(walk->data);
1014 if (strcmp (GST_PAD_NAME(pad), name) == 0) {
1015 GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1016 return pad;
1017 }
1018 walk = g_list_next (walk);
1019 }
1021 GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
1022 return NULL;
1023 }
1025 /**
1026 * gst_element_get_request_pad:
1027 * @element: a #GstElement to find a request pad of.
1028 * @name: the name of the request #GstPad to retrieve.
1029 *
1030 * Retrieves a pad from the element by name. This version only retrieves
1031 * request pads.
1032 *
1033 * Returns: requested #GstPad if found, otherwise NULL.
1034 */
1035 GstPad*
1036 gst_element_get_request_pad (GstElement *element, const gchar *name)
1037 {
1038 GstPadTemplate *templ = NULL;
1039 GstPad *pad;
1040 const gchar *req_name = NULL;
1041 gboolean templ_found = FALSE;
1042 GList *list;
1043 gint n;
1044 const gchar *data;
1045 gchar *str, *endptr = NULL;
1047 g_return_val_if_fail (element != NULL, NULL);
1048 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1049 g_return_val_if_fail (name != NULL, NULL);
1051 if (strstr (name, "%")) {
1052 templ = gst_element_get_pad_template (element, name);
1053 req_name = NULL;
1054 if (templ)
1055 templ_found = TRUE;
1056 } else {
1057 list = gst_element_get_pad_template_list(element);
1058 while (!templ_found && list) {
1059 templ = (GstPadTemplate*) list->data;
1060 if (templ->presence == GST_PAD_REQUEST) {
1061 /* we know that %s and %d are the only possibilities because of sanity
1062 checks in gst_pad_template_new */
1063 GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
1064 if ((str = strchr (templ->name_template, '%')) &&
1065 strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
1066 strlen (name) > str - templ->name_template) {
1067 data = name + (str - templ->name_template);
1068 if (*(str+1) == 'd') {
1069 /* it's an int */
1070 n = (gint) strtol (data, &endptr, 10);
1071 if (endptr && *endptr == '\0') {
1072 templ_found = TRUE;
1073 req_name = name;
1074 break;
1075 }
1076 } else {
1077 /* it's a string */
1078 templ_found = TRUE;
1079 req_name = name;
1080 break;
1081 }
1082 }
1083 }
1084 list = list->next;
1085 }
1086 }
1088 if (!templ_found)
1089 return NULL;
1091 pad = gst_element_request_pad (element, templ, req_name);
1093 return pad;
1094 }
1096 /**
1097 * gst_element_get_pad_list:
1098 * @element: a #GstElement to get pads of.
1099 *
1100 * Retrieves a list of the pads associated with the element.
1101 *
1102 * Returns: the #GList of pads.
1103 */
1104 const GList*
1105 gst_element_get_pad_list (GstElement *element)
1106 {
1107 g_return_val_if_fail (element != NULL, NULL);
1108 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1110 /* return the list of pads */
1111 return element->pads;
1112 }
1114 /**
1115 * gst_element_class_add_pad_template:
1116 * @klass: the #GstElementClass to add the pad template to.
1117 * @templ: a #GstPadTemplate to add to the element class.
1118 *
1119 * Adds a padtemplate to an element class.
1120 * This is useful if you have derived a custom bin and wish to provide
1121 * an on-request pad at runtime. Plug-in writers should use
1122 * gst_element_factory_add_pad_template instead.
1123 */
1124 void
1125 gst_element_class_add_pad_template (GstElementClass *klass,
1126 GstPadTemplate *templ)
1127 {
1128 g_return_if_fail (klass != NULL);
1129 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1130 g_return_if_fail (templ != NULL);
1131 g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
1133 klass->padtemplates = g_list_append (klass->padtemplates, templ);
1134 klass->numpadtemplates++;
1135 }
1137 /**
1138 * gst_element_get_pad_template_list:
1139 * @element: a #GstElement to get pad templates of.
1140 *
1141 * Retrieves a list of the pad templates associated with the element.
1142 *
1143 * Returns: the #GList of padtemplates.
1144 */
1145 GList*
1146 gst_element_get_pad_template_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 CLASS (element)->padtemplates;
1152 }
1154 /**
1155 * gst_element_get_pad_template:
1156 * @element: a #GstElement to get the pad template of.
1157 * @name: the name of the #GstPadTemplate to get.
1158 *
1159 * Retrieves a padtemplate from this element with the
1160 * given name.
1161 *
1162 * Returns: the #GstPadTemplate with the given name, or NULL if none was found.
1163 * No unreferencing is necessary.
1164 */
1165 GstPadTemplate*
1166 gst_element_get_pad_template (GstElement *element, const gchar *name)
1167 {
1168 GList *padlist;
1170 g_return_val_if_fail (element != NULL, NULL);
1171 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1172 g_return_val_if_fail (name != NULL, NULL);
1174 padlist = gst_element_get_pad_template_list (element);
1176 while (padlist) {
1177 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1179 if (!strcmp (padtempl->name_template, name))
1180 return padtempl;
1182 padlist = g_list_next (padlist);
1183 }
1185 return NULL;
1186 }
1188 /**
1189 * gst_element_get_compatible_pad_template:
1190 * @element: a #GstElement to get a compatible pad template for.
1191 * @compattempl: the #GstPadTemplate to find a compatible template for.
1192 *
1193 * Generates a pad template for this element compatible with the given
1194 * template (meaning it is able to connect with it).
1195 *
1196 * Returns: the #GstPadTemplate of the element that is compatible with
1197 * the given GstPadTemplate, or NULL if none was found. No unreferencing
1198 * is necessary.
1199 */
1200 GstPadTemplate*
1201 gst_element_get_compatible_pad_template (GstElement *element,
1202 GstPadTemplate *compattempl)
1203 {
1204 GstPadTemplate *newtempl = NULL;
1205 GList *padlist;
1207 GST_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
1209 g_return_val_if_fail (element != NULL, NULL);
1210 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1211 g_return_val_if_fail (compattempl != NULL, NULL);
1213 padlist = gst_element_get_pad_template_list (element);
1215 while (padlist) {
1216 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
1217 gboolean comp = FALSE;
1219 /* Ignore name
1220 * Ignore presence
1221 * Check direction (must be opposite)
1222 * Check caps
1223 */
1224 GST_DEBUG (GST_CAT_CAPS, "checking direction and caps");
1225 if (padtempl->direction == GST_PAD_SRC &&
1226 compattempl->direction == GST_PAD_SINK) {
1227 GST_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
1228 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (padtempl),
1229 GST_PAD_TEMPLATE_CAPS (compattempl));
1230 GST_DEBUG(GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1231 } else if (padtempl->direction == GST_PAD_SINK &&
1232 compattempl->direction == GST_PAD_SRC) {
1233 GST_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
1234 comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
1235 GST_PAD_TEMPLATE_CAPS (padtempl));
1236 GST_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
1237 }
1239 if (comp) {
1240 newtempl = padtempl;
1241 break;
1242 }
1244 padlist = g_list_next (padlist);
1245 }
1247 return newtempl;
1248 }
1250 /**
1251 * gst_element_request_compatible_pad:
1252 * @element: a #GstElement to request a new pad from.
1253 * @templ: the #GstPadTemplate to which the new pad should be able to connect.
1254 *
1255 * Requests a new pad from the element. The template will
1256 * be used to decide what type of pad to create. This function
1257 * is typically used for elements with a padtemplate with presence
1258 * GST_PAD_REQUEST.
1259 *
1260 * Returns: the new #GstPad that was created, or NULL if none could be created.
1261 */
1262 GstPad*
1263 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
1264 {
1265 GstPadTemplate *templ_new;
1266 GstPad *pad = NULL;
1268 g_return_val_if_fail (element != NULL, NULL);
1269 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1270 g_return_val_if_fail (templ != NULL, NULL);
1272 templ_new = gst_element_get_compatible_pad_template (element, templ);
1273 if (templ_new != NULL)
1274 pad = gst_element_request_pad (element, templ_new, NULL);
1276 return pad;
1277 }
1280 /**
1281 * gst_element_get_compatible_pad_filtered:
1282 * @element: a #GstElement in which the pad should be found.
1283 * @pad: the #GstPad to find a compatible one for.
1284 * @filtercaps: the #GstCaps to use as a filter.
1285 *
1286 * Looks for an unconnected pad to which the given pad can connect to.
1287 * It is not guaranteed that connecting the pads will work, though
1288 * it should work in most cases.
1289 *
1290 * Returns: the #GstPad to which a connection can be made.
1291 */
1292 GstPad*
1293 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
1294 GstCaps *filtercaps)
1295 {
1296 const GList *pads;
1297 GstPadTemplate *templ;
1298 GstCaps *templcaps;
1299 GstPad *foundpad = NULL;
1301 /* checks */
1302 g_return_val_if_fail (element != NULL, NULL);
1303 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1304 g_return_val_if_fail (pad != NULL, NULL);
1305 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1307 /* let's use the real pad */
1308 pad = (GstPad *) GST_PAD_REALIZE (pad);
1309 g_return_val_if_fail (pad != NULL, NULL);
1310 g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
1312 /* try to get an existing unconnected pad */
1313 pads = gst_element_get_pad_list (element);
1314 while (pads) {
1315 GstPad *current = GST_PAD (pads->data);
1316 if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
1317 gst_pad_can_connect_filtered (pad, current, filtercaps)) {
1318 return current;
1319 }
1320 pads = g_list_next (pads);
1321 }
1323 /* try to create a new one */
1324 /* requesting is a little crazy, we need a template. Let's create one */
1325 if (filtercaps != NULL) {
1326 templcaps = gst_caps_intersect (filtercaps, (GstCaps *) GST_RPAD_CAPS (pad));
1327 if (templcaps == NULL)
1328 return NULL;
1329 } else {
1330 templcaps = gst_caps_copy (gst_pad_get_caps (pad));
1331 }
1333 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1334 GST_PAD_ALWAYS, templcaps, NULL);
1335 foundpad = gst_element_request_compatible_pad (element, templ);
1336 gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
1338 /* FIXME: this is broken, but it's in here so autoplugging elements that don't
1339 have caps on their source padtemplates (spider) can connect... */
1340 if (!foundpad && !filtercaps) {
1341 templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
1342 GST_PAD_ALWAYS, NULL, NULL);
1343 foundpad = gst_element_request_compatible_pad (element, templ);
1344 gst_object_unref (GST_OBJECT (templ));
1345 }
1347 return foundpad;
1348 }
1350 /**
1351 * gst_element_get_compatible_pad:
1352 * @element: a #GstElement in which the pad should be found.
1353 * @pad: the #GstPad to find a compatible one for.
1354 *
1355 * Looks for an unconnected pad to which the given pad can connect to.
1356 * It is not guaranteed that connecting the pads will work, though
1357 * it should work in most cases.
1358 *
1359 * Returns: the #GstPad to which a connection can be made, or NULL if none
1360 * could be found.
1361 */
1362 GstPad*
1363 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
1364 {
1365 return gst_element_get_compatible_pad_filtered (element, pad, NULL);
1366 }
1368 /**
1369 * gst_element_connect_filtered:
1370 * @src: a #GstElement containing the source pad.
1371 * @dest: the #GstElement containing the destination pad.
1372 * @filtercaps: the #GstCaps to use as a filter.
1373 *
1374 * Connects the source to the destination element using the filtercaps.
1375 * The connection must be from source to destination, the other
1376 * direction will not be tried.
1377 * The functions looks for existing pads that aren't connected yet.
1378 * It will use request pads if possible. But both pads will not be requested.
1379 * If multiple connections are possible, only one is established.
1380 *
1381 * Returns: TRUE if the elements could be connected.
1382 */
1383 gboolean
1384 gst_element_connect_filtered (GstElement *src, GstElement *dest,
1385 GstCaps *filtercaps)
1386 {
1387 const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
1388 GstPad *srcpad, *destpad;
1389 GstPadTemplate *srctempl, *desttempl;
1391 /* checks */
1392 g_return_val_if_fail (src != NULL, FALSE);
1393 g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1394 g_return_val_if_fail (dest != NULL, FALSE);
1395 g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1397 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying to connect element %s to element %s",
1398 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1400 srcpads = gst_element_get_pad_list (src);
1401 destpads = gst_element_get_pad_list (dest);
1403 if (srcpads || destpads) {
1404 GST_DEBUG (GST_CAT_ELEMENT_PADS, "looping through src and dest pads");
1405 /* loop through the existing pads in the source, trying to find a
1406 * compatible destination pad */
1407 while (srcpads) {
1408 srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
1409 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s",
1410 GST_DEBUG_PAD_NAME (srcpad));
1411 if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
1412 (GST_PAD_PEER (srcpad) == NULL)) {
1413 destpad = gst_element_get_compatible_pad_filtered (dest, srcpad,
1414 filtercaps);
1415 if (destpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1416 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
1417 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1418 return TRUE;
1419 }
1420 }
1421 srcpads = g_list_next (srcpads);
1422 }
1424 /* loop through the existing pads in the destination */
1425 while (destpads) {
1426 destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
1427 GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s",
1428 GST_DEBUG_PAD_NAME (destpad));
1429 if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
1430 (GST_PAD_PEER (destpad) == NULL)) {
1431 srcpad = gst_element_get_compatible_pad_filtered (src, destpad,
1432 filtercaps);
1433 if (srcpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1434 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
1435 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1436 return TRUE;
1437 }
1438 }
1439 destpads = g_list_next (destpads);
1440 }
1441 }
1443 GST_DEBUG (GST_CAT_ELEMENT_PADS,
1444 "we might have request pads on both sides, checking...");
1445 srctempls = gst_element_get_pad_template_list (src);
1446 desttempls = gst_element_get_pad_template_list (dest);
1448 if (srctempls && desttempls) {
1449 while (srctempls) {
1450 srctempl = (GstPadTemplate*) srctempls->data;
1451 if (srctempl->presence == GST_PAD_REQUEST) {
1452 for (l=desttempls; l; l=l->next) {
1453 desttempl = (GstPadTemplate*) desttempls->data;
1454 if (desttempl->presence == GST_PAD_REQUEST &&
1455 desttempl->direction != srctempl->direction) {
1456 if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
1457 gst_pad_template_get_caps (desttempl))) {
1458 srcpad = gst_element_get_request_pad (src,
1459 srctempl->name_template);
1460 destpad = gst_element_get_request_pad (dest,
1461 desttempl->name_template);
1462 if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
1463 GST_DEBUG (GST_CAT_ELEMENT_PADS,
1464 "connected pad %s:%s to pad %s:%s",
1465 GST_DEBUG_PAD_NAME (srcpad),
1466 GST_DEBUG_PAD_NAME (destpad));
1467 return TRUE;
1468 }
1469 /* FIXME: we have extraneous request pads lying around */
1470 }
1471 }
1472 }
1473 }
1474 srctempls = srctempls->next;
1475 }
1476 }
1478 GST_DEBUG (GST_CAT_ELEMENT_PADS, "no connection possible from %s to %s",
1479 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1480 return FALSE;
1481 }
1483 /**
1484 * gst_element_connect_many:
1485 * @element_1: the first #GstElement in the connection chain.
1486 * @element_2: the second #GstElement in the connection chain.
1487 * @...: the NULL-terminated list of elements to connect in order.
1488 *
1489 * Chain together a series of elements. Uses #gst_element_connect.
1490 *
1491 * Returns: TRUE on success, FALSE otherwise.
1492 */
1493 gboolean
1494 gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
1495 {
1496 va_list args;
1498 g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
1499 g_return_val_if_fail (GST_IS_ELEMENT (element_1) &&
1500 GST_IS_ELEMENT (element_2), FALSE);
1502 va_start (args, element_2);
1504 while (element_2) {
1505 if (!gst_element_connect (element_1, element_2))
1506 return FALSE;
1508 element_1 = element_2;
1509 element_2 = va_arg (args, GstElement*);
1510 }
1512 va_end (args);
1514 return TRUE;
1515 }
1517 /**
1518 * gst_element_connect:
1519 * @src: a #GstElement containing the source pad.
1520 * @dest: the #GstElement containing the destination pad.
1521 *
1522 * Connects the source to the destination element.
1523 * The connection must be from source to destination, the other
1524 * direction will not be tried.
1525 * The functions looks for existing pads and request pads that aren't
1526 * connected yet. If multiple connections are possible, only one is
1527 * established.
1528 *
1529 * Returns: TRUE if the elements could be connected.
1530 */
1531 gboolean
1532 gst_element_connect (GstElement *src, GstElement *dest)
1533 {
1534 return gst_element_connect_filtered (src, dest, NULL);
1535 }
1537 /**
1538 * gst_element_connect_pads_filtered:
1539 * @src: a #GstElement containing the source pad.
1540 * @srcpadname: the name of the #GstPad in source element.
1541 * @dest: the #GstElement containing the destination pad.
1542 * @destpadname: the name of the #GstPad in destination element.
1543 * @filtercaps: the #GstCaps to use as a filter.
1544 *
1545 * Connects the two named pads of the source and destination elements.
1546 * Side effect is that if one of the pads has no parent, it becomes a
1547 * child of the parent of the other element. If they have different
1548 * parents, the connection fails.
1549 *
1550 * Returns: TRUE if the pads could be connected.
1551 */
1552 gboolean
1553 gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
1554 GstElement *dest, const gchar *destpadname,
1555 GstCaps *filtercaps)
1556 {
1557 GstPad *srcpad,*destpad;
1559 g_return_val_if_fail (src != NULL, FALSE);
1560 g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
1561 g_return_val_if_fail (srcpadname != NULL, FALSE);
1562 g_return_val_if_fail (dest != NULL, FALSE);
1563 g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
1564 g_return_val_if_fail (destpadname != NULL, FALSE);
1566 /* obtain the pads requested */
1567 srcpad = gst_element_get_pad (src, srcpadname);
1568 if (srcpad == NULL) {
1569 GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
1570 return FALSE;
1571 }
1572 destpad = gst_element_get_pad (dest, destpadname);
1573 if (srcpad == NULL) {
1574 GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
1575 return FALSE;
1576 }
1578 /* we're satisified they can be connected, let's do it */
1579 return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
1580 }
1582 /**
1583 * gst_element_connect_pads:
1584 * @src: a #GstElement containing the source pad.
1585 * @srcpadname: the name of the #GstPad in the source element.
1586 * @dest: the #GstElement containing the destination pad.
1587 * @destpadname: the name of the #GstPad in destination element.
1588 *
1589 * Connects the two named pads of the source and destination elements.
1590 * Side effect is that if one of the pads has no parent, it becomes a
1591 * child of the parent of the other element. If they have different
1592 * parents, the connection fails.
1593 *
1594 * Returns: TRUE if the pads could be connected.
1595 */
1596 gboolean
1597 gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
1598 GstElement *dest, const gchar *destpadname)
1599 {
1600 return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL);
1601 }
1603 /**
1604 * gst_element_disconnect_pads:
1605 * @src: a #GstElement containing the source pad.
1606 * @srcpadname: the name of the #GstPad in source element.
1607 * @dest: a #GstElement containing the destination pad.
1608 * @destpadname: the name of the #GstPad in destination element.
1609 *
1610 * Disconnects the two named pads of the source and destination elements.
1611 */
1612 void
1613 gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
1614 GstElement *dest, const gchar *destpadname)
1615 {
1616 GstPad *srcpad,*destpad;
1618 g_return_if_fail (src != NULL);
1619 g_return_if_fail (GST_IS_ELEMENT(src));
1620 g_return_if_fail (srcpadname != NULL);
1621 g_return_if_fail (dest != NULL);
1622 g_return_if_fail (GST_IS_ELEMENT(dest));
1623 g_return_if_fail (destpadname != NULL);
1625 /* obtain the pads requested */
1626 srcpad = gst_element_get_pad (src, srcpadname);
1627 if (srcpad == NULL) {
1628 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
1629 return;
1630 }
1631 destpad = gst_element_get_pad (dest, destpadname);
1632 if (srcpad == NULL) {
1633 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
1634 return;
1635 }
1637 /* we're satisified they can be disconnected, let's do it */
1638 gst_pad_disconnect(srcpad,destpad);
1639 }
1641 /**
1642 * gst_element_disconnect_many:
1643 * @element_1: the first #GstElement in the connection chain.
1644 * @element_2: the second #GstElement in the connection chain.
1645 * @...: the NULL-terminated list of elements to disconnect in order.
1646 *
1647 * Disconnects a series of elements. Uses #gst_element_disconnect.
1648 */
1649 void
1650 gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
1651 {
1652 va_list args;
1654 g_return_if_fail (element_1 != NULL && element_2 != NULL);
1655 g_return_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2));
1657 va_start (args, element_2);
1659 while (element_2) {
1660 gst_element_disconnect (element_1, element_2);
1662 element_1 = element_2;
1663 element_2 = va_arg (args, GstElement*);
1664 }
1666 va_end (args);
1667 }
1669 /**
1670 * gst_element_disconnect:
1671 * @src: the source #GstElement to disconnect.
1672 * @dest: the sink #GstElement to disconnect.
1673 *
1674 * Disconnects all source pads of the source element with all sink pads
1675 * of the sink element to which they are connected.
1676 */
1677 void
1678 gst_element_disconnect (GstElement *src, GstElement *dest)
1679 {
1680 const GList *srcpads;
1681 GstPad *pad;
1683 g_return_if_fail (GST_IS_ELEMENT (src));
1684 g_return_if_fail (GST_IS_ELEMENT (dest));
1686 GST_DEBUG (GST_CAT_ELEMENT_PADS, "disconnecting \"%s\" and \"%s\"",
1687 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
1689 srcpads = gst_element_get_pad_list (src);
1691 while (srcpads) {
1692 pad = GST_PAD_CAST (srcpads->data);
1694 if (GST_IS_REAL_PAD (pad) && GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1695 GstPad *peerpad = GST_PAD_PEER (pad);
1697 if (peerpad &&
1698 (GST_OBJECT_PARENT (GST_PAD_PEER (peerpad)) == (GstObject*) src)) {
1699 gst_pad_disconnect (pad, peerpad);
1700 }
1701 }
1703 srcpads = g_list_next (srcpads);
1704 }
1705 }
1707 static void
1708 gst_element_error_func (GstElement* element, GstElement *source,
1709 gchar *errormsg)
1710 {
1711 /* tell the parent */
1712 if (GST_OBJECT_PARENT (element)) {
1713 GST_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s",
1714 errormsg, GST_ELEMENT_NAME (element),
1715 GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
1717 gst_object_ref (GST_OBJECT (element));
1718 g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)),
1719 gst_element_signals[ERROR], 0, source, errormsg);
1720 gst_object_unref (GST_OBJECT (element));
1721 }
1722 }
1724 static gboolean
1725 gst_element_send_event_default (GstElement *element, GstEvent *event)
1726 {
1727 GList *pads = element->pads;
1728 gboolean res = FALSE;
1730 while (pads) {
1731 GstPad *pad = GST_PAD_CAST (pads->data);
1733 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1734 if (GST_PAD_IS_USABLE (pad)) {
1735 res = gst_pad_send_event (GST_PAD_PEER (pad), event);
1736 break;
1737 }
1738 }
1739 pads = g_list_next (pads);
1740 }
1741 return res;
1742 }
1744 /**
1745 * gst_element_send_event:
1746 * @element: a #GstElement to send the event to.
1747 * @event: the #GstEvent to send to the element.
1748 *
1749 * Sends an event to an element. If the element doesn't
1750 * implement an event handler, the event will be forwarded
1751 * to a random sink pad.
1752 *
1753 * Returns: TRUE if the event was handled.
1754 */
1755 gboolean
1756 gst_element_send_event (GstElement *element, GstEvent *event)
1757 {
1758 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1759 g_return_val_if_fail (event != NULL, FALSE);
1761 if (CLASS (element)->send_event)
1762 return CLASS (element)->send_event (element, event);
1764 return FALSE;
1765 }
1767 static gboolean
1768 gst_element_query_default (GstElement *element, GstPadQueryType type,
1769 GstFormat *format, gint64 *value)
1770 {
1771 GList *pads = element->pads;
1772 gboolean res = FALSE;
1774 while (pads) {
1775 GstPad *pad = GST_PAD_CAST (pads->data);
1777 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1778 if (GST_PAD_IS_USABLE (pad)) {
1779 res = gst_pad_query (GST_PAD_PEER (pad), type, format, value);
1780 break;
1781 }
1782 }
1783 pads = g_list_next (pads);
1784 }
1785 return res;
1786 }
1788 /**
1789 * gst_element_query:
1790 * @element: a #GstElement to perform the query on.
1791 * @type: the #GstPadQueryType.
1792 * @format: the #GstFormat pointer to hold the format of the result.
1793 * @value: the pointer to the value of the result.
1794 *
1795 * Performs a query on the given element. If the format is set
1796 * to GST_FORMAT_DEFAULT and this function returns TRUE, the
1797 * format pointer will hold the default format.
1798 * For element that don't implement a query handler, this function
1799 * forwards the query to a random connected sinkpad of this element.
1800 *
1801 * Returns: TRUE if the query could be performed.
1802 */
1803 gboolean
1804 gst_element_query (GstElement *element, GstPadQueryType type,
1805 GstFormat *format, gint64 *value)
1806 {
1807 g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
1808 g_return_val_if_fail (format != NULL, FALSE);
1809 g_return_val_if_fail (value != NULL, FALSE);
1811 if (CLASS (element)->query)
1812 return CLASS (element)->query (element, type, format, value);
1814 return FALSE;
1815 }
1817 /**
1818 * gst_element_error:
1819 * @element: a #GstElement with the error.
1820 * @error: the printf-style string describing the error.
1821 * @...: the optional arguments for the string.
1822 *
1823 * signals an error condition on an element.
1824 * This function is used internally by elements.
1825 * It results in the "error" signal.
1826 */
1827 void
1828 gst_element_error (GstElement *element, const gchar *error, ...)
1829 {
1830 va_list var_args;
1831 gchar *string;
1833 /* checks */
1834 g_return_if_fail (GST_IS_ELEMENT (element));
1835 g_return_if_fail (error != NULL);
1837 /* create error message */
1838 va_start (var_args, error);
1839 string = g_strdup_vprintf (error, var_args);
1840 va_end (var_args);
1841 GST_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
1843 /* emit the signal, make sure the element stays available */
1844 gst_object_ref (GST_OBJECT (element));
1845 g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, string);
1847 /* tell the scheduler */
1848 if (element->sched) {
1849 gst_scheduler_error (element->sched, element);
1850 }
1852 /* cleanup */
1853 gst_object_unref (GST_OBJECT (element));
1854 g_free (string);
1855 }
1857 /**
1858 * gst_element_get_state:
1859 * @element: a #GstElement to get the state of.
1860 *
1861 * Gets the state of the element.
1862 *
1863 * Returns: the #GstElementState of the element.
1864 */
1865 GstElementState
1866 gst_element_get_state (GstElement *element)
1867 {
1868 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
1870 return GST_STATE (element);
1871 }
1873 /**
1874 * gst_element_wait_state_change:
1875 * @element: a #GstElement to wait for a state change on.
1876 *
1877 * Waits and blocks until the element changed its state.
1878 */
1879 void
1880 gst_element_wait_state_change (GstElement *element)
1881 {
1882 g_mutex_lock (element->state_mutex);
1883 g_cond_wait (element->state_cond, element->state_mutex);
1884 g_mutex_unlock (element->state_mutex);
1885 }
1887 /**
1888 * gst_element_set_state:
1889 * @element: a #GstElement to change state of.
1890 * @state: the element's new #GstElementState.
1891 *
1892 * Sets the state of the element. This function will try to set the
1893 * requested state by going through all the intermediary states and calling
1894 * the class's state change function for each.
1895 *
1896 * Returns: TRUE if the state was successfully set.
1897 * (using #GstElementStateReturn).
1898 */
1899 GstElementStateReturn
1900 gst_element_set_state (GstElement *element, GstElementState state)
1901 {
1902 GstElementClass *oclass;
1903 GstElementState curpending;
1904 GstElementStateReturn return_val = GST_STATE_SUCCESS;
1906 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
1908 /* start with the current state */
1909 curpending = GST_STATE(element);
1911 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s",
1912 gst_element_state_get_name (curpending),
1913 gst_element_state_get_name (state));
1915 /* loop until the final requested state is set */
1916 while (GST_STATE (element) != state
1917 && GST_STATE (element) != GST_STATE_VOID_PENDING) {
1918 /* move the curpending state in the correct direction */
1919 if (curpending < state)
1920 curpending <<= 1;
1921 else
1922 curpending >>= 1;
1924 /* set the pending state variable */
1925 /* FIXME: should probably check to see that we don't already have one */
1926 GST_STATE_PENDING (element) = curpending;
1928 if (curpending != state) {
1929 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
1930 "intermediate: setting state from %s to %s",
1931 gst_element_state_get_name (GST_STATE (element)),
1932 gst_element_state_get_name (curpending));
1933 }
1935 /* call the state change function so it can set the state */
1936 oclass = CLASS (element);
1937 if (oclass->change_state)
1938 return_val = (oclass->change_state) (element);
1940 switch (return_val) {
1941 case GST_STATE_FAILURE:
1942 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
1943 "have failed change_state return");
1944 goto exit;
1945 case GST_STATE_ASYNC:
1946 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
1947 "element will change state async");
1948 goto exit;
1949 case GST_STATE_SUCCESS:
1950 /* Last thing we do is verify that a successful state change really
1951 * did change the state... */
1952 if (GST_STATE (element) != curpending) {
1953 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
1954 "element claimed state-change success,"
1955 "but state didn't change %s, %s <-> %s",
1956 gst_element_state_get_name (GST_STATE (element)),
1957 gst_element_state_get_name (GST_STATE_PENDING (element)),
1958 gst_element_state_get_name (curpending));
1959 return GST_STATE_FAILURE;
1960 }
1961 break;
1962 default:
1963 /* somebody added a GST_STATE_ and forgot to do stuff here ! */
1964 g_assert_not_reached ();
1965 }
1966 }
1967 exit:
1969 return return_val;
1970 }
1972 static gboolean
1973 gst_element_negotiate_pads (GstElement *element)
1974 {
1975 GList *pads = GST_ELEMENT_PADS (element);
1977 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads");
1979 while (pads) {
1980 GstPad *pad = GST_PAD (pads->data);
1981 GstRealPad *srcpad;
1983 pads = g_list_next (pads);
1985 if (!GST_IS_REAL_PAD (pad))
1986 continue;
1988 srcpad = GST_PAD_REALIZE (pad);
1990 /* if we have a connection on this pad and it doesn't have caps
1991 * allready, try to negotiate */
1992 if (GST_PAD_IS_USABLE (srcpad) && !GST_PAD_CAPS (srcpad)) {
1993 GstRealPad *sinkpad;
1994 GstElementState otherstate;
1995 GstElement *parent;
1997 sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
1999 /* check the parent of the peer pad, if there is no parent do nothing */
2000 parent = GST_PAD_PARENT (sinkpad);
2001 if (!parent)
2002 continue;
2004 otherstate = GST_STATE (parent);
2006 /* swap pads if needed */
2007 if (!GST_PAD_IS_SRC (srcpad)) {
2008 GstRealPad *temp;
2010 temp = srcpad;
2011 srcpad = sinkpad;
2012 sinkpad = temp;
2013 }
2015 /* only try to negotiate if the peer element is in PAUSED or higher too */
2016 if (otherstate >= GST_STATE_READY) {
2017 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element,
2018 "perform negotiate for %s:%s and %s:%s",
2019 GST_DEBUG_PAD_NAME (srcpad),
2020 GST_DEBUG_PAD_NAME (sinkpad));
2021 if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
2022 return FALSE;
2023 }
2024 else {
2025 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element,
2026 "not negotiating %s:%s and %s:%s, not in READY yet",
2027 GST_DEBUG_PAD_NAME (srcpad),
2028 GST_DEBUG_PAD_NAME (sinkpad));
2029 }
2030 }
2031 }
2033 return TRUE;
2034 }
2036 static void
2037 gst_element_clear_pad_caps (GstElement *element)
2038 {
2039 GList *pads = GST_ELEMENT_PADS (element);
2041 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps");
2043 while (pads) {
2044 GstRealPad *pad = GST_PAD_REALIZE (pads->data);
2046 if (GST_PAD_CAPS (pad)) {
2047 GST_PAD_CAPS (pad) = NULL;
2048 }
2049 pads = g_list_next (pads);
2050 }
2051 }
2053 static GstElementStateReturn
2054 gst_element_change_state (GstElement *element)
2055 {
2056 GstElementState old_state;
2057 GstObject *parent;
2058 gint old_pending, old_transition;
2060 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
2062 old_state = GST_STATE (element);
2063 old_pending = GST_STATE_PENDING (element);
2064 old_transition = GST_STATE_TRANSITION (element);
2066 if (old_pending == GST_STATE_VOID_PENDING ||
2067 old_state == GST_STATE_PENDING (element)) {
2068 GST_INFO (GST_CAT_STATES,
2069 "no state change needed for element %s (VOID_PENDING)",
2070 GST_ELEMENT_NAME (element));
2071 return GST_STATE_SUCCESS;
2072 }
2074 GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %d",
2075 GST_ELEMENT_NAME (element),
2076 gst_element_state_get_name (old_state),
2077 gst_element_state_get_name (old_pending),
2078 GST_STATE_TRANSITION (element));
2080 /* we set the state change early for the negotiation functions */
2081 GST_STATE (element) = old_pending;
2082 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
2084 switch (old_transition) {
2085 /* if we are going to paused, we try to negotiate the pads */
2086 case GST_STATE_READY_TO_PAUSED:
2087 if (!gst_element_negotiate_pads (element))
2088 goto failure;
2089 break;
2090 /* going to the READY state clears all pad caps */
2091 case GST_STATE_PAUSED_TO_READY:
2092 gst_element_clear_pad_caps (element);
2093 break;
2094 default:
2095 break;
2096 }
2098 parent = GST_ELEMENT_PARENT (element);
2100 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
2101 "signaling state change from %s to %s",
2102 gst_element_state_get_name (old_state),
2103 gst_element_state_get_name (GST_STATE (element)));
2105 /* tell the scheduler if we have one */
2106 if (element->sched) {
2107 if (gst_scheduler_state_transition (element->sched, element,
2108 old_transition) != GST_STATE_SUCCESS) {
2109 goto failure;
2110 }
2111 }
2113 g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
2114 0, old_state, GST_STATE (element));
2116 /* tell our parent about the state change */
2117 if (parent && GST_IS_BIN (parent)) {
2118 gst_bin_child_state_change (GST_BIN (parent), old_state,
2119 GST_STATE (element), element);
2120 }
2122 /* signal the state change in case somebody is waiting for us */
2123 g_mutex_lock (element->state_mutex);
2124 g_cond_signal (element->state_cond);
2125 g_mutex_unlock (element->state_mutex);
2127 return GST_STATE_SUCCESS;
2129 failure:
2130 /* undo the state change */
2131 GST_STATE (element) = old_state;
2132 GST_STATE_PENDING (element) = old_pending;
2134 return GST_STATE_FAILURE;
2135 }
2137 /**
2138 * gst_element_get_factory:
2139 * @element: a #GstElement to request the element factory of.
2140 *
2141 * Retrieves the factory that was used to create this element.
2142 *
2143 * Returns: the #GstElementFactory used for creating this element.
2144 */
2145 GstElementFactory*
2146 gst_element_get_factory (GstElement *element)
2147 {
2148 GstElementClass *oclass;
2150 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2152 oclass = CLASS (element);
2154 return oclass->elementfactory;
2155 }
2157 static void
2158 gst_element_dispose (GObject *object)
2159 {
2160 GstElement *element = GST_ELEMENT (object);
2161 GList *pads;
2162 GstPad *pad;
2164 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose");
2166 gst_element_set_state (element, GST_STATE_NULL);
2168 /* first we break all our connections with the ouside */
2169 if (element->pads) {
2170 GList *orig;
2171 orig = pads = g_list_copy (element->pads);
2172 while (pads) {
2173 pad = GST_PAD (pads->data);
2175 if (GST_PAD_PEER (pad)) {
2176 GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'",
2177 GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
2178 gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
2179 }
2180 gst_element_remove_pad (element, pad);
2182 pads = g_list_next (pads);
2183 }
2184 g_list_free (orig);
2185 g_list_free (element->pads);
2186 element->pads = NULL;
2187 }
2189 element->numsrcpads = 0;
2190 element->numsinkpads = 0;
2191 element->numpads = 0;
2192 g_mutex_free (element->state_mutex);
2193 g_cond_free (element->state_cond);
2195 if (element->prop_value_queue)
2196 g_async_queue_unref (element->prop_value_queue);
2197 element->prop_value_queue = NULL;
2198 if (element->property_mutex)
2199 g_mutex_free (element->property_mutex);
2201 G_OBJECT_CLASS (parent_class)->dispose (object);
2202 }
2204 #ifndef GST_DISABLE_LOADSAVE
2205 /**
2206 * gst_element_save_thyself:
2207 * @element: a #GstElement to save.
2208 * @parent: the xml parent node.
2209 *
2210 * Saves the element as part of the given XML structure.
2211 *
2212 * Returns: the new #xmlNodePtr.
2213 */
2214 static xmlNodePtr
2215 gst_element_save_thyself (GstObject *object,
2216 xmlNodePtr parent)
2217 {
2218 GList *pads;
2219 GstElementClass *oclass;
2220 GParamSpec **specs, *spec;
2221 gint nspecs, i;
2222 GValue value = { 0, };
2223 GstElement *element;
2225 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
2227 element = GST_ELEMENT (object);
2229 oclass = CLASS (element);
2231 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
2233 if (oclass->elementfactory != NULL) {
2234 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
2236 xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
2237 xmlNewChild (parent, NULL, "version", factory->details->version);
2238 }
2240 /* FIXME: what is this? */
2241 /* if (element->manager) */
2242 /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
2244 /* params */
2245 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
2247 for (i=0; i<nspecs; i++) {
2248 spec = specs[i];
2249 if (spec->flags & G_PARAM_READABLE) {
2250 xmlNodePtr param;
2251 char *contents;
2253 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
2255 g_object_get_property (G_OBJECT (element), spec->name, &value);
2256 param = xmlNewChild (parent, NULL, "param", NULL);
2257 xmlNewChild (param, NULL, "name", spec->name);
2259 if (G_IS_PARAM_SPEC_STRING (spec))
2260 contents = g_value_dup_string (&value);
2261 else if (G_IS_PARAM_SPEC_ENUM (spec))
2262 contents = g_strdup_printf ("%d", g_value_get_enum (&value));
2263 else if (G_IS_PARAM_SPEC_INT64 (spec))
2264 contents = g_strdup_printf ("%" G_GINT64_FORMAT,
2265 g_value_get_int64 (&value));
2266 else
2267 contents = g_strdup_value_contents (&value);
2269 xmlNewChild (param, NULL, "value", contents);
2270 g_free (contents);
2272 g_value_unset(&value);
2273 }
2274 }
2276 pads = GST_ELEMENT_PADS (element);
2278 while (pads) {
2279 GstPad *pad = GST_PAD (pads->data);
2280 /* figure out if it's a direct pad or a ghostpad */
2281 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
2282 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
2283 gst_object_save_thyself (GST_OBJECT (pad), padtag);
2284 }
2285 pads = g_list_next (pads);
2286 }
2288 return parent;
2289 }
2291 static void
2292 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
2293 {
2294 xmlNodePtr children;
2295 GstElement *element;
2296 gchar *name = NULL;
2297 gchar *value = NULL;
2299 element = GST_ELEMENT (object);
2300 g_return_if_fail (element != NULL);
2302 /* parameters */
2303 children = self->xmlChildrenNode;
2304 while (children) {
2305 if (!strcmp (children->name, "param")) {
2306 xmlNodePtr child = children->xmlChildrenNode;
2308 while (child) {
2309 if (!strcmp (child->name, "name")) {
2310 name = xmlNodeGetContent (child);
2311 }
2312 else if (!strcmp (child->name, "value")) {
2313 value = xmlNodeGetContent (child);
2314 }
2315 child = child->next;
2316 }
2317 /* FIXME: can this just be g_object_set ? */
2318 gst_util_set_object_arg (G_OBJECT (element), name, value);
2319 }
2320 children = children->next;
2321 }
2323 /* pads */
2324 children = self->xmlChildrenNode;
2325 while (children) {
2326 if (!strcmp (children->name, "pad")) {
2327 gst_pad_load_and_connect (children, GST_OBJECT (element));
2328 }
2329 children = children->next;
2330 }
2332 if (GST_OBJECT_CLASS(parent_class)->restore_thyself)
2333 (GST_OBJECT_CLASS(parent_class)->restore_thyself) (object, self);
2334 }
2335 #endif /* GST_DISABLE_LOADSAVE */
2337 /**
2338 * gst_element_yield:
2339 * @element: a #GstElement to yield.
2340 *
2341 * Requests a yield operation for the element. The scheduler will typically
2342 * give control to another element.
2343 */
2344 void
2345 gst_element_yield (GstElement *element)
2346 {
2347 if (GST_ELEMENT_SCHED (element)) {
2348 gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
2349 }
2350 }
2352 /**
2353 * gst_element_interrupt:
2354 * @element: a #GstElement to interrupt.
2355 *
2356 * Requests the scheduler of this element to interrupt the execution of
2357 * this element and scheduler another one.
2358 *
2359 * Returns: TRUE if the element should exit its chain/loop/get
2360 * function ASAP, depending on the scheduler implementation.
2361 */
2362 gboolean
2363 gst_element_interrupt (GstElement *element)
2364 {
2365 if (GST_ELEMENT_SCHED (element)) {
2366 return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
2367 }
2368 else
2369 return FALSE;
2370 }
2372 /**
2373 * gst_element_set_scheduler:
2374 * @element: a #GstElement to set the scheduler of.
2375 * @sched: the #GstScheduler to set.
2376 *
2377 * Sets the scheduler of the element. For internal use only, unless you're
2378 * writing a new bin subclass.
2379 */
2380 void
2381 gst_element_set_scheduler (GstElement *element,
2382 GstScheduler *sched)
2383 {
2384 g_return_if_fail (GST_IS_ELEMENT (element));
2386 GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
2388 GST_ELEMENT_SCHED (element) = sched;
2389 }
2391 /**
2392 * gst_element_get_scheduler:
2393 * @element: a #GstElement to get the scheduler of.
2394 *
2395 * Returns the scheduler of the element.
2396 *
2397 * Returns: the element's #GstScheduler.
2398 */
2399 GstScheduler*
2400 gst_element_get_scheduler (GstElement *element)
2401 {
2402 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
2404 return GST_ELEMENT_SCHED (element);
2405 }
2407 /**
2408 * gst_element_set_loop_function:
2409 * @element: a #GstElement to set the loop function of.
2410 * @loop: Pointer to #GstElementLoopFunction.
2411 *
2412 * This sets the loop function for the element. The function pointed to
2413 * can deviate from the GstElementLoopFunction definition in type of
2414 * pointer only.
2415 *
2416 * NOTE: in order for this to take effect, the current loop function *must*
2417 * exit. Assuming the loop function itself is the only one who will cause
2418 * a new loopfunc to be assigned, this should be no problem.
2419 */
2420 void
2421 gst_element_set_loop_function (GstElement *element,
2422 GstElementLoopFunction loop)
2423 {
2424 g_return_if_fail (GST_IS_ELEMENT (element));
2426 /* set the loop function */
2427 element->loopfunc = loop;
2429 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
2430 GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
2431 }
2433 /**
2434 * gst_element_set_eos:
2435 * @element: a #GstElement to set to the EOS state.
2436 *
2437 * Perform the actions needed to bring the element in the EOS state.
2438 */
2439 void
2440 gst_element_set_eos (GstElement *element)
2441 {
2442 g_return_if_fail (GST_IS_ELEMENT (element));
2444 GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s",
2445 GST_OBJECT_NAME (element));
2447 gst_element_set_state (element, GST_STATE_PAUSED);
2449 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
2450 }
2453 /**
2454 * gst_element_state_get_name:
2455 * @state: a #GstElementState to get the name of.
2456 *
2457 * Gets a string representing the given state.
2458 *
2459 * Returns: a string with the name of the state.
2460 */
2461 const gchar*
2462 gst_element_state_get_name (GstElementState state)
2463 {
2464 switch (state) {
2465 #ifdef GST_DEBUG_COLOR
2466 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2467 case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
2468 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
2469 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
2470 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
2471 default:
2472 /* This is a memory leak */
2473 return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
2474 #else
2475 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
2476 case GST_STATE_NULL: return "NULL";break;
2477 case GST_STATE_READY: return "READY";break;
2478 case GST_STATE_PLAYING: return "PLAYING";break;
2479 case GST_STATE_PAUSED: return "PAUSED";break;
2480 default: return "UNKNOWN!";
2481 #endif
2482 }
2483 return "";
2484 }
2486 static void
2487 gst_element_populate_std_props (GObjectClass * klass, const gchar *prop_name,
2488 guint arg_id, GParamFlags flags)
2489 {
2490 GQuark prop_id = g_quark_from_string (prop_name);
2491 GParamSpec *pspec;
2493 static GQuark fd_id = 0;
2494 static GQuark blocksize_id;
2495 static GQuark bytesperread_id;
2496 static GQuark dump_id;
2497 static GQuark filesize_id;
2498 static GQuark mmapsize_id;
2499 static GQuark location_id;
2500 static GQuark offset_id;
2501 static GQuark silent_id;
2502 static GQuark touch_id;
2504 if (!fd_id) {
2505 fd_id = g_quark_from_static_string ("fd");
2506 blocksize_id = g_quark_from_static_string ("blocksize");
2507 bytesperread_id = g_quark_from_static_string ("bytesperread");
2508 dump_id = g_quark_from_static_string ("dump");
2509 filesize_id = g_quark_from_static_string ("filesize");
2510 mmapsize_id = g_quark_from_static_string ("mmapsize");
2511 location_id = g_quark_from_static_string ("location");
2512 offset_id = g_quark_from_static_string ("offset");
2513 silent_id = g_quark_from_static_string ("silent");
2514 touch_id = g_quark_from_static_string ("touch");
2515 }
2517 if (prop_id == fd_id) {
2518 pspec = g_param_spec_int ("fd", "File-descriptor",
2519 "File-descriptor for the file being read",
2520 0, G_MAXINT, 0, flags);
2521 }
2522 else if (prop_id == blocksize_id) {
2523 pspec = g_param_spec_ulong ("blocksize", "Block Size",
2524 "Block size to read per buffer",
2525 0, G_MAXULONG, 4096, flags);
2527 }
2528 else if (prop_id == bytesperread_id) {
2529 pspec = g_param_spec_int ("bytesperread", "Bytes per read",
2530 "Number of bytes to read per buffer",
2531 G_MININT, G_MAXINT, 0, flags);
2533 }
2534 else if (prop_id == dump_id) {
2535 pspec = g_param_spec_boolean ("dump", "Dump",
2536 "Dump bytes to stdout",
2537 FALSE, flags);
2539 }
2540 else if (prop_id == filesize_id) {
2541 pspec = g_param_spec_int64 ("filesize", "File Size",
2542 "Size of the file being read",
2543 0, G_MAXINT64, 0, flags);
2545 }
2546 else if (prop_id == mmapsize_id) {
2547 pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
2548 "Size in bytes of mmap()d regions",
2549 0, G_MAXULONG, 4 * 1048576, flags);
2551 }
2552 else if (prop_id == location_id) {
2553 pspec = g_param_spec_string ("location", "File Location",
2554 "Location of the file to read",
2555 NULL, flags);
2557 }
2558 else if (prop_id == offset_id) {
2559 pspec = g_param_spec_int64 ("offset", "File Offset",
2560 "Byte offset of current read pointer",
2561 0, G_MAXINT64, 0, flags);
2563 }
2564 else if (prop_id == silent_id) {
2565 pspec = g_param_spec_boolean ("silent", "Silent", "Don't produce events",
2566 FALSE, flags);
2568 }
2569 else if (prop_id == touch_id) {
2570 pspec = g_param_spec_boolean ("touch", "Touch read data",
2571 "Touch data to force disk read before "
2572 "push ()", TRUE, flags);
2573 }
2574 else {
2575 g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
2576 prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
2577 pspec = NULL;
2578 }
2580 if (pspec) {
2581 g_object_class_install_property (klass, arg_id, pspec);
2582 }
2583 }
2585 /**
2586 * gst_element_class_install_std_props:
2587 * @klass: the #GstElementClass to add the properties to.
2588 * @first_name: the name of the first property.
2589 * in a NULL terminated
2590 * @...: the id and flags of the first property, followed by
2591 * further 'name', 'id', 'flags' triplets and terminated by NULL.
2592 *
2593 * Adds a list of standardized properties with types to the @klass.
2594 * the id is for the property switch in your get_prop method, and
2595 * the flags determine readability / writeability.
2596 **/
2597 void
2598 gst_element_class_install_std_props (GstElementClass * klass,
2599 const gchar *first_name, ...)
2600 {
2601 const char *name;
2603 va_list args;
2605 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
2607 va_start (args, first_name);
2609 name = first_name;
2611 while (name) {
2612 int arg_id = va_arg (args, int);
2613 int flags = va_arg (args, int);
2615 gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
2617 name = va_arg (args, char *);
2618 }
2620 va_end (args);
2621 }
2623 /**
2624 * gst_element_get_managing_bin:
2625 * @element: a #GstElement to get the managing bin of.
2626 *
2627 * Gets the managing bin (a pipeline or a thread, for example) of an element.
2628 *
2629 * Returns: the #GstBin, or NULL on failure.
2630 **/
2631 GstBin*
2632 gst_element_get_managing_bin (GstElement *element)
2633 {
2634 GstBin *bin;
2636 g_return_val_if_fail (element != NULL, NULL);
2638 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
2640 while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
2641 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
2643 return bin;
2644 }