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 "gst_private.h"
28 #include "gstelement.h"
29 #include "gstextratypes.h"
30 #include "gstbin.h"
31 #include "gstscheduler.h"
32 #include "gstevent.h"
33 #include "gstutils.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 #define CLASS(element) GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))
52 static void gst_element_class_init (GstElementClass *klass);
53 static void gst_element_init (GstElement *element);
54 static void gst_element_base_class_init (GstElementClass *klass);
56 static void gst_element_set_property (GObject *object, guint prop_id,
57 const GValue *value, GParamSpec *pspec);
58 static void gst_element_get_property (GObject *object, guint prop_id, GValue *value,
59 GParamSpec *pspec);
61 static void gst_element_dispose (GObject *object);
63 static GstElementStateReturn gst_element_change_state (GstElement *element);
64 static void gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg);
66 #ifndef GST_DISABLE_LOADSAVE
67 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
68 static void gst_element_restore_thyself (GstObject *parent, xmlNodePtr self);
69 #endif
71 GType _gst_element_type = 0;
73 static GstObjectClass *parent_class = NULL;
74 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
76 GType gst_element_get_type (void)
77 {
78 if (!_gst_element_type) {
79 static const GTypeInfo element_info = {
80 sizeof(GstElementClass),
81 (GBaseInitFunc)gst_element_base_class_init,
82 NULL,
83 (GClassInitFunc)gst_element_class_init,
84 NULL,
85 NULL,
86 sizeof(GstElement),
87 0,
88 (GInstanceInitFunc)gst_element_init,
89 NULL
90 };
91 _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT);
92 }
93 return _gst_element_type;
94 }
96 static void
97 gst_element_class_init (GstElementClass *klass)
98 {
99 GObjectClass *gobject_class;
100 GstObjectClass *gstobject_class;
102 gobject_class = (GObjectClass*) klass;
103 gstobject_class = (GstObjectClass*) klass;
105 parent_class = g_type_class_ref(GST_TYPE_OBJECT);
107 gst_element_signals[STATE_CHANGE] =
108 g_signal_new ("state_change", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
109 G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
110 gst_marshal_VOID__INT_INT, G_TYPE_NONE, 2,
111 G_TYPE_INT, G_TYPE_INT);
112 gst_element_signals[NEW_PAD] =
113 g_signal_new ("new_pad", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
114 G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
115 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
116 G_TYPE_OBJECT);
117 gst_element_signals[PAD_REMOVED] =
118 g_signal_new ("pad_removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
119 G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
120 gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
121 G_TYPE_OBJECT);
122 gst_element_signals[ERROR] =
123 g_signal_new ("error", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
124 G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
125 gst_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
126 G_TYPE_OBJECT, G_TYPE_STRING);
127 gst_element_signals[EOS] =
128 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
129 G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
130 gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
134 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_set_property);
135 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_get_property);
136 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
138 #ifndef GST_DISABLE_LOADSAVE
139 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
140 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
141 #endif
143 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
144 klass->error = GST_DEBUG_FUNCPTR (gst_element_error_func);
145 klass->elementfactory = NULL;
146 klass->padtemplates = NULL;
147 klass->numpadtemplates = 0;
148 }
150 static void
151 gst_element_base_class_init (GstElementClass *klass)
152 {
153 GObjectClass *gobject_class;
155 gobject_class = (GObjectClass*) klass;
157 gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_set_property);
158 gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_get_property);
159 }
161 static void
162 gst_element_init (GstElement *element)
163 {
164 element->current_state = GST_STATE_NULL;
165 element->pending_state = GST_STATE_VOID_PENDING;
166 element->numpads = 0;
167 element->numsrcpads = 0;
168 element->numsinkpads = 0;
169 element->pads = NULL;
170 element->loopfunc = NULL;
171 element->sched = NULL;
172 element->sched_private = NULL;
173 element->state_mutex = g_mutex_new ();
174 element->state_cond = g_cond_new ();
175 }
178 static void
179 gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
180 {
181 GstElementClass *oclass = CLASS (object);
183 if (oclass->set_property)
184 (oclass->set_property) (object, prop_id, value, pspec);
185 }
188 static void
189 gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
190 {
191 GstElementClass *oclass = CLASS (object);
193 if (oclass->get_property)
194 (oclass->get_property) (object, prop_id, value, pspec);
195 }
198 /**
199 * gst_element_set_name:
200 * @element: GstElement to set name of
201 * @name: new name of element
202 *
203 * Set the name of the element, getting rid of the old name if there was
204 * one.
205 */
206 void
207 gst_element_set_name (GstElement *element, const gchar *name)
208 {
209 g_return_if_fail (element != NULL);
210 g_return_if_fail (GST_IS_ELEMENT (element));
212 gst_object_set_name (GST_OBJECT (element), name);
213 }
215 /**
216 * gst_element_get_name:
217 * @element: GstElement to get name of
218 *
219 * Get the name of the element.
220 *
221 * Returns: name of the element
222 */
223 const gchar*
224 gst_element_get_name (GstElement *element)
225 {
226 g_return_val_if_fail (element != NULL, NULL);
227 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
229 return GST_OBJECT_NAME (element);
230 }
232 /**
233 * gst_element_set_parent:
234 * @element: GstElement to set parent of
235 * @parent: new parent of the object
236 *
237 * Set the parent of the element.
238 */
239 void
240 gst_element_set_parent (GstElement *element, GstObject *parent)
241 {
242 g_return_if_fail (element != NULL);
243 g_return_if_fail (GST_IS_ELEMENT (element));
244 g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
245 g_return_if_fail (parent != NULL);
246 g_return_if_fail (GST_IS_OBJECT (parent));
247 g_return_if_fail ((gpointer)element != (gpointer)parent);
249 gst_object_set_parent (GST_OBJECT (element), parent);
250 }
252 /**
253 * gst_element_get_parent:
254 * @element: GstElement to get the parent of
255 *
256 * Get the parent of the element.
257 *
258 * Returns: parent of the element
259 */
260 GstObject*
261 gst_element_get_parent (GstElement *element)
262 {
263 g_return_val_if_fail (element != NULL, NULL);
264 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
266 return GST_OBJECT_PARENT (element);
267 }
269 /**
270 * gst_element_set_clock:
271 * @element: GstElement to set the clock to
272 * @clock: the clock to set for the element
273 *
274 * Set the clock for the element
275 */
276 void
277 gst_element_set_clock (GstElement *element, GstClock *clock)
278 {
279 g_return_if_fail (element != NULL);
280 g_return_if_fail (GST_IS_ELEMENT (element));
282 if (element->setclockfunc)
283 element->setclockfunc (element, clock);
284 }
286 /**
287 * gst_element_get_clock:
288 * @element: GstElement to get the clock of
289 *
290 * Get the clock of the element
291 */
292 GstClock*
293 gst_element_get_clock (GstElement *element)
294 {
295 g_return_val_if_fail (element != NULL, NULL);
296 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
298 if (element->getclockfunc)
299 return element->getclockfunc (element);
301 return NULL;
302 }
304 /**
305 * gst_element_clock_wait:
306 * @element: GstElement to wait for the clock
307 * @clock: the clock to wait for
308 * @time: the time to wait for
309 *
310 * Wait for a specific time on the clock
311 */
312 GstClockReturn
313 gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time)
314 {
315 g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR);
316 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
318 if (GST_ELEMENT_SCHED (element)) {
319 return gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time);
320 }
321 else
322 return GST_CLOCK_TIMEOUT;
323 }
325 /**
326 * gst_element_add_pad:
327 * @element: element to add pad to
328 * @pad: pad to add
329 *
330 * Add a pad (connection point) to the element, setting the parent of the
331 * pad to the element (and thus adding a reference).
332 */
333 void
334 gst_element_add_pad (GstElement *element, GstPad *pad)
335 {
336 g_return_if_fail (element != NULL);
337 g_return_if_fail (GST_IS_ELEMENT (element));
338 g_return_if_fail (pad != NULL);
339 g_return_if_fail (GST_IS_PAD (pad));
341 /* first check to make sure the pad's parent is already set */
342 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
344 /* then check to see if there's already a pad by that name here */
345 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
347 /* set the pad's parent */
348 GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
349 GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
350 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
352 /* add it to the list */
353 element->pads = g_list_append (element->pads, pad);
354 element->numpads++;
355 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
356 element->numsrcpads++;
357 else
358 element->numsinkpads++;
360 /* emit the NEW_PAD signal */
361 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
362 }
364 /**
365 * gst_element_remove_pad:
366 * @element: element to remove pad from
367 * @pad: pad to remove
368 *
369 * Remove a pad (connection point) from the element,
370 */
371 void
372 gst_element_remove_pad (GstElement *element, GstPad *pad)
373 {
374 g_return_if_fail (element != NULL);
375 g_return_if_fail (GST_IS_ELEMENT (element));
376 g_return_if_fail (pad != NULL);
377 g_return_if_fail (GST_IS_PAD (pad));
379 g_return_if_fail (GST_PAD_PARENT (pad) == element);
381 /* check to see if the pad is still connected */
382 /* FIXME: what if someone calls _remove_pad instead of
383 _remove_ghost_pad? */
384 if (GST_IS_REAL_PAD (pad)) {
385 g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
386 }
388 /* remove it from the list */
389 element->pads = g_list_remove (element->pads, pad);
390 element->numpads--;
391 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
392 element->numsrcpads--;
393 else
394 element->numsinkpads--;
396 g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
398 gst_object_unparent (GST_OBJECT (pad));
399 }
401 /**
402 * gst_element_add_ghost_pad:
403 * @element: element to add ghost pad to
404 * @pad: pad from which the new ghost pad will be created
405 * @name: name of the new ghost pad
406 *
407 * Create a ghost pad from the given pad, and add it to the list of pads
408 * for this element.
409 *
410 * Returns: the added ghost pad or NULL, if no ghost pad was created.
411 */
412 GstPad *
413 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
414 {
415 GstPad *ghostpad;
417 g_return_val_if_fail (element != NULL, NULL);
418 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
419 g_return_val_if_fail (pad != NULL, NULL);
420 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
422 /* then check to see if there's already a pad by that name here */
423 g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
425 GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s",
426 name,GST_DEBUG_PAD_NAME(pad));
427 ghostpad = gst_ghost_pad_new (name, pad);
429 /* add it to the list */
430 GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
431 name, GST_ELEMENT_NAME (element));
432 element->pads = g_list_append (element->pads, ghostpad);
433 element->numpads++;
434 /* set the parent of the ghostpad */
435 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
437 GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
439 /* emit the NEW_GHOST_PAD signal */
440 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
442 return ghostpad;
443 }
445 /**
446 * gst_element_remove_ghost_pad:
447 * @element: element to remove the ghost pad from
448 * @pad: ghost pad to remove
449 *
450 * removes a ghost pad from an element
451 */
452 void
453 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
454 {
455 g_return_if_fail (element != NULL);
456 g_return_if_fail (GST_IS_ELEMENT (element));
457 g_return_if_fail (pad != NULL);
458 g_return_if_fail (GST_IS_GHOST_PAD (pad));
460 /* FIXME this is redundant?
461 * wingo 10-july-2001: I don't think so, you have to actually remove the pad
462 * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
463 * the real pad's ghost pad list
464 */
465 gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
466 gst_element_remove_pad (element, pad);
467 }
470 /**
471 * gst_element_get_pad:
472 * @element: element to find pad of
473 * @name: name of pad to retrieve
474 *
475 * Retrieve a pad from the element by name.
476 *
477 * Returns: requested pad if found, otherwise NULL.
478 */
479 GstPad*
480 gst_element_get_pad (GstElement *element, const gchar *name)
481 {
482 GList *walk;
484 g_return_val_if_fail (element != NULL, NULL);
485 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
486 g_return_val_if_fail (name != NULL, NULL);
488 /* if there aren't any pads, well, we're not likely to find one */
489 if (!element->numpads)
490 return NULL;
492 /* look through the list, matching by name */
493 walk = element->pads;
494 while (walk) {
495 GstPad *pad;
497 pad = GST_PAD(walk->data);
498 if (!strcmp (GST_PAD_NAME(pad), name)) {
499 GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
500 return pad;
501 }
502 walk = g_list_next (walk);
503 }
505 GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
506 return NULL;
507 }
509 /**
510 * gst_element_get_pad_list:
511 * @element: element to get pads of
512 *
513 * Retrieve a list of the pads associated with the element.
514 *
515 * Returns: GList of pads
516 */
517 GList*
518 gst_element_get_pad_list (GstElement *element)
519 {
520 g_return_val_if_fail (element != NULL, NULL);
521 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
523 /* return the list of pads */
524 return element->pads;
525 }
527 /**
528 * gst_element_class_add_padtemplate:
529 * @klass: element class to add padtemplate to
530 * @templ: padtemplate to add
531 *
532 * Add a padtemplate to an element class. This is useful if you have derived a custom
533 * bin and wish to provide an on-request pad at runtime. Plugin writers should use
534 * gst_elementfactory_add_padtemplate instead.
535 */
536 void
537 gst_element_class_add_padtemplate (GstElementClass *klass, GstPadTemplate *templ)
538 {
539 g_return_if_fail (klass != NULL);
540 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
541 g_return_if_fail (templ != NULL);
542 g_return_if_fail (GST_IS_PADTEMPLATE (templ));
544 klass->padtemplates = g_list_append (klass->padtemplates, templ);
545 klass->numpadtemplates++;
546 }
548 /**
549 * gst_element_get_padtemplate_list:
550 * @element: element to get padtemplates of
551 *
552 * Retrieve a list of the padtemplates associated with the element.
553 *
554 * Returns: GList of padtemplates
555 */
556 GList*
557 gst_element_get_padtemplate_list (GstElement *element)
558 {
559 g_return_val_if_fail (element != NULL, NULL);
560 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
562 return CLASS (element)->padtemplates;
563 }
565 /**
566 * gst_element_get_padtemplate_by_name:
567 * @element: element to get padtemplate of
568 * @name: the name of the padtemplate to get.
569 *
570 * Retrieve a padtemplate from this element with the
571 * given name.
572 *
573 * Returns: the padtemplate with the given name
574 */
575 GstPadTemplate*
576 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
577 {
578 GList *padlist;
580 g_return_val_if_fail (element != NULL, NULL);
581 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
582 g_return_val_if_fail (name != NULL, NULL);
584 padlist = gst_element_get_padtemplate_list (element);
586 while (padlist) {
587 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
589 if (!strcmp (padtempl->name_template, name))
590 return padtempl;
592 padlist = g_list_next (padlist);
593 }
595 return NULL;
596 }
598 /**
599 * gst_element_get_padtemplate_by_compatible:
600 * @element: element to get padtemplate of
601 * @templ: a template to find a compatible template for
602 *
603 * Generate a padtemplate for this element compatible with the given
604 * template, ie able to link to it.
605 *
606 * Returns: the padtemplate
607 */
608 static GstPadTemplate*
609 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
610 {
611 GstPadTemplate *newtempl = NULL;
612 GList *padlist;
614 GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()");
616 g_return_val_if_fail (element != NULL, NULL);
617 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
618 g_return_val_if_fail (compattempl != NULL, NULL);
620 padlist = gst_element_get_padtemplate_list (element);
622 while (padlist) {
623 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
624 gboolean compat = FALSE;
626 /* Ignore name
627 * Ignore presence
628 * Check direction (must be opposite)
629 * Check caps
630 */
631 GST_DEBUG(GST_CAT_CAPS,"checking direction and caps");
632 if (padtempl->direction == GST_PAD_SRC &&
633 compattempl->direction == GST_PAD_SINK) {
634 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template");
635 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
636 GST_PADTEMPLATE_CAPS (compattempl));
637 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible", (compat?"":"not "));
638 } else if (padtempl->direction == GST_PAD_SINK &&
639 compattempl->direction == GST_PAD_SRC) {
640 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template");
641 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
642 GST_PADTEMPLATE_CAPS (padtempl));
643 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible", (compat?"":"not "));
644 }
646 if (compat) {
647 newtempl = padtempl;
648 break;
649 }
651 padlist = g_list_next (padlist);
652 }
654 return newtempl;
655 }
657 static GstPad*
658 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
659 {
660 GstPad *newpad = NULL;
661 GstElementClass *oclass;
663 oclass = CLASS (element);
664 if (oclass->request_new_pad)
665 newpad = (oclass->request_new_pad)(element, templ, name);
667 return newpad;
668 }
670 /**
671 * gst_element_request_compatible_pad:
672 * @element: element to request a new pad from
673 * @templ: a pad template to which the new pad should be able to connect
674 *
675 * Request a new pad from the element. The template will
676 * be used to decide what type of pad to create. This function
677 * is typically used for elements with a padtemplate with presence
678 * GST_PAD_REQUEST.
679 *
680 * Returns: the new pad that was created.
681 */
682 GstPad*
683 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
684 {
685 GstPadTemplate *templ_new;
686 GstPad *pad = NULL;
688 g_return_val_if_fail (element != NULL, NULL);
689 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
690 g_return_val_if_fail (templ != NULL, NULL);
692 templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
693 if (templ_new != NULL)
694 pad = gst_element_request_pad (element, templ_new, NULL);
696 return pad;
697 }
699 /**
700 * gst_element_request_pad_by_name:
701 * @element: element to request a new pad from
702 * @name: the name of the padtemplate to use.
703 *
704 * Request a new pad from the element. The name argument will
705 * be used to decide what padtemplate to use. This function
706 * is typically used for elements with a padtemplate with presence
707 * GST_PAD_REQUEST.
708 *
709 * Returns: the new pad that was created.
710 */
711 GstPad*
712 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
713 {
714 GstPadTemplate *templ = NULL;
715 GstPad *pad;
716 const gchar *req_name = NULL;
717 gboolean templ_found = FALSE;
718 GList *list;
719 gint n;
720 gchar *str;
722 g_return_val_if_fail (element != NULL, NULL);
723 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
724 g_return_val_if_fail (name != NULL, NULL);
727 if (strstr (name, "%")) {
728 templ = gst_element_get_padtemplate_by_name (element, name);
729 req_name = NULL;
730 if (templ)
731 templ_found = TRUE;
732 } else {
733 list = gst_element_get_padtemplate_list(element);
734 while (!templ_found && list) {
735 templ = (GstPadTemplate*) list->data;
736 if (templ->presence == GST_PAD_REQUEST) {
737 /* we know that %s and %d are the ony possibilities because of sanity
738 checks in gst_padtemplate_new */
739 if (strstr (templ->name_template, "%d")) {
740 if (sscanf(name, templ->name_template, &n)) {
741 templ_found = TRUE;
742 req_name = name;
743 break;
744 }
745 } else if (strstr (templ->name_template, "%s")) {
746 if (sscanf(name, templ->name_template, &str)) {
747 templ_found = TRUE;
748 req_name = name;
749 break;
750 }
751 }
752 }
753 list = list->next;
754 }
755 }
757 if (!templ_found)
758 return NULL;
760 pad = gst_element_request_pad (element, templ, req_name);
762 return pad;
763 }
765 /**
766 * gst_element_get_compatible_pad_filtered:
767 * @element: the element in which the pad should be found
768 * @pad: the pad to find a compatible one for
769 * @filtercaps: the caps to use as a filter
770 *
771 * Looks for an unconnected pad to which the given pad can connect to.
772 * It is not guaranteed that connecting the pads will work, though
773 * it should work in most cases.
774 *
775 * Returns: the pad to which a connection can be made
776 */
778 GstPad*
779 gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad, GstCaps *filtercaps)
780 {
781 GList *pads;
782 GstPadTemplate *templ;
783 GstCaps *templcaps;
784 GstPad *foundpad = NULL;
786 /* checks */
787 g_return_val_if_fail (element != NULL, NULL);
788 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
789 g_return_val_if_fail (pad != NULL, NULL);
790 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
792 /* let's use the real pad */
793 pad = (GstPad *) GST_PAD_REALIZE (pad);
794 g_return_val_if_fail (pad != NULL, NULL);
795 g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
797 /* try to get an existing unconnected pad */
798 pads = gst_element_get_pad_list (element);
799 while (pads) {
800 GstPad *current = GST_PAD (pads->data);
801 if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
802 gst_pad_can_connect_filtered (pad, current, filtercaps)) {
803 return current;
804 }
805 pads = g_list_next (pads);
806 }
808 /* try to create a new one */
809 /* requesting is a little crazy, we need a template. Let's create one */
810 if (filtercaps != NULL) {
811 templcaps = gst_caps_intersect (filtercaps, (GstCaps *) GST_RPAD_CAPS (pad));
812 if (templcaps == NULL)
813 return NULL;
814 } else {
815 templcaps = gst_caps_copy (gst_pad_get_caps (pad));
816 }
818 templ = gst_padtemplate_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
819 GST_PAD_ALWAYS, templcaps, NULL);
820 foundpad = gst_element_request_compatible_pad (element, templ);
821 gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
823 /* FIXME: this is broken, but it's in here so autoplugging elements that don't
824 have caps on their source padtemplates (spider) can connect... */
825 if (!foundpad && !filtercaps) {
826 templ = gst_padtemplate_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
827 GST_PAD_ALWAYS, NULL, NULL);
828 foundpad = gst_element_request_compatible_pad (element, templ);
829 gst_object_unref (GST_OBJECT (templ));
830 }
832 return foundpad;
833 }
835 /**
836 * gst_element_get_compatible_pad:
837 * @element: the element in which the pad should be found
838 * @pad: the pad to find a compatible one for
839 *
840 * Looks for an unconnected pad to which the given pad can connect to.
841 * It is not guaranteed that connecting the pads will work, though
842 * it should work in most cases.
843 *
844 * Returns: the pad to which a connection can be made
845 */
846 GstPad*
847 gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
848 {
849 return gst_element_get_compatible_pad_filtered (element, pad, NULL);
850 }
852 /**
853 * gst_element_connect_elements_filtered:
854 * @src: the element containing source pad
855 * @dest: the element containing destination pad
856 * @filtercaps: the caps to use as filter
857 *
858 * Connect the source to the destination element using the filtercaps.
859 * The connection must be from source to destination, the other
860 * direction will not be tried.
861 * The functions looks for existing pads that aren't connected yet.
862 + It will use request pads if possible. But both pads will not be requested.
863 * If multiple connections are possible, only one is established.
864 *
865 * Return: TRUE if the elements could be connected.
866 */
867 gboolean
868 gst_element_connect_elements_filtered (GstElement *src, GstElement *dest,
869 GstCaps *filtercaps)
870 {
871 GList *srcpads, *destpads, *srctempls, *desttempls, *l;
872 GstPad *srcpad, *destpad;
873 GstPadTemplate *srctempl, *desttempl;
875 /* checks */
876 g_return_val_if_fail (src != NULL, FALSE);
877 g_return_val_if_fail (GST_IS_ELEMENT(src), FALSE);
878 g_return_val_if_fail (dest != NULL, FALSE);
879 g_return_val_if_fail (GST_IS_ELEMENT(dest), FALSE);
881 GST_DEBUG (GST_CAT_ELEMENT_PADS, "attempting to connect element %s to element %s", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
883 /* loop through the existing pads in the source */
884 srcpads = gst_element_get_pad_list (src);
885 destpads = gst_element_get_pad_list (dest);
887 if (srcpads || destpads) {
888 while (srcpads) {
889 srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
890 if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
891 (GST_PAD_PEER (srcpad) == NULL)) {
892 destpad = gst_element_get_compatible_pad_filtered (dest, srcpad, filtercaps);
893 if (destpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
894 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
895 return TRUE;
896 }
897 }
898 srcpads = g_list_next (srcpads);
899 }
901 /* loop through the existing pads in the destination */
902 while (destpads) {
903 destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
904 if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
905 (GST_PAD_PEER (destpad) == NULL)) {
906 srcpad = gst_element_get_compatible_pad_filtered (src, destpad, filtercaps);
907 if (srcpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
908 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
909 return TRUE;
910 }
911 }
912 destpads = g_list_next (destpads);
913 }
914 }
916 GST_DEBUG (GST_CAT_ELEMENT_PADS, "we might have request pads on both sides, checking...");
917 srctempls = gst_element_get_padtemplate_list (src);
918 desttempls = gst_element_get_padtemplate_list (dest);
920 if (srctempls && desttempls) {
921 while (srctempls) {
922 srctempl = (GstPadTemplate*) srctempls->data;
923 if (srctempl->presence == GST_PAD_REQUEST) {
924 for (l=desttempls; l; l=l->next) {
925 desttempl = (GstPadTemplate*) desttempls->data;
926 if (desttempl->presence == GST_PAD_REQUEST && desttempl->direction != srctempl->direction) {
927 if (gst_caps_check_compatibility (gst_padtemplate_get_caps (srctempl),
928 gst_padtemplate_get_caps (desttempl))) {
929 srcpad = gst_element_request_pad_by_name (src, srctempl->name_template);
930 destpad = gst_element_request_pad_by_name (dest, desttempl->name_template);
931 if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
932 GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s",
933 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
934 return TRUE;
935 }
936 /* FIXME: we have extraneous request pads lying around */
937 }
938 }
939 }
940 }
941 srctempls = srctempls->next;
942 }
943 }
945 GST_DEBUG (GST_CAT_ELEMENT_PADS, "no connection possible from %s to %s", GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
946 return FALSE;
947 }
949 /**
950 * gst_element_connect_elements_many:
951 * @element_1: the first element in the connection chain
952 * @element_2: the second element in the connection chain
953 * @...: NULL-terminated list of elements to connect in order
954 *
955 * Chain together a series of elements. Uses #gst_element_connect_elements.
956 *
957 * Returns: TRUE on success, FALSE otherwise.
958 **/
959 /* API FIXME: this should be called gst_element_connect_many, and connect_elements
960 * should just be connect */
961 gboolean
962 gst_element_connect_elements_many (GstElement *element_1, GstElement *element_2, ...)
963 {
964 va_list args;
966 g_return_val_if_fail (element_1 != NULL && element_2 != NULL, FALSE);
967 g_return_val_if_fail (GST_IS_ELEMENT (element_1) && GST_IS_ELEMENT (element_2), FALSE);
969 va_start (args, element_2);
971 while (element_2) {
972 if (!gst_element_connect_elements (element_1, element_2))
973 return FALSE;
975 element_1 = element_2;
976 element_2 = va_arg (args, GstElement*);
977 }
979 va_end (args);
981 return TRUE;
982 }
984 /**
985 * gst_element_connect_elements:
986 * @src: element containing source pad
987 * @dest: element containing destination pad
988 *
989 * Connect the source to the destination element.
990 * The connection must be from source to destination, the other
991 * direction will not be tried.
992 * The functions looks for existing pads and request pads that aren't
993 * connected yet. If multiple connections are possible, only one is
994 * established.
995 *
996 * Return: TRUE if the elements could be connected.
997 */
998 gboolean
999 gst_element_connect_elements (GstElement *src, GstElement *dest)
1000 {
1001 return gst_element_connect_elements_filtered (src, dest, NULL);
1002 }
1004 /**
1005 * gst_element_connect_filtered:
1006 * @src: element containing source pad
1007 * @srcpadname: name of pad in source element
1008 * @dest: element containing destination pad
1009 * @destpadname: name of pad in destination element
1010 * @filtercaps: the caps to use as a filter
1011 *
1012 * Connect the two named pads of the source and destination elements.
1013 * Side effect is that if one of the pads has no parent, it becomes a
1014 * child of the parent of the other element. If they have different
1015 * parents, the connection fails.
1016 *
1017 * Return: TRUE if the pads could be connected.
1018 */
1019 gboolean
1020 gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
1021 GstElement *dest, const gchar *destpadname,
1022 GstCaps *filtercaps)
1023 {
1024 GstPad *srcpad,*destpad;
1026 g_return_val_if_fail (src != NULL, FALSE);
1027 g_return_val_if_fail (GST_IS_ELEMENT(src), FALSE);
1028 g_return_val_if_fail (srcpadname != NULL, FALSE);
1029 g_return_val_if_fail (dest != NULL, FALSE);
1030 g_return_val_if_fail (GST_IS_ELEMENT(dest), FALSE);
1031 g_return_val_if_fail (destpadname != NULL, FALSE);
1033 /* obtain the pads requested */
1034 srcpad = gst_element_get_pad (src, srcpadname);
1035 if (srcpad == NULL) {
1036 GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
1037 return FALSE;
1038 }
1039 destpad = gst_element_get_pad (dest, destpadname);
1040 if (srcpad == NULL) {
1041 GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
1042 return FALSE;
1043 }
1045 /* we're satisified they can be connected, let's do it */
1046 return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
1047 }
1049 /**
1050 * gst_element_connect:
1051 * @src: element containing source pad
1052 * @srcpadname: name of pad in source element
1053 * @dest: element containing destination pad
1054 * @destpadname: name of pad in destination element
1055 *
1056 * Connect the two named pads of the source and destination elements.
1057 * Side effect is that if one of the pads has no parent, it becomes a
1058 * child of the parent of the other element. If they have different
1059 * parents, the connection fails.
1060 *
1061 * Return: TRUE if the pads could be connected.
1062 */
1063 gboolean
1064 gst_element_connect (GstElement *src, const gchar *srcpadname,
1065 GstElement *dest, const gchar *destpadname)
1066 {
1067 return gst_element_connect_filtered (src, srcpadname, dest, destpadname, NULL);
1068 }
1070 /**
1071 * gst_element_disconnect:
1072 * @src: element containing source pad
1073 * @srcpadname: name of pad in source element
1074 * @dest: element containing destination pad
1075 * @destpadname: name of pad in destination element
1076 *
1077 * Disconnect the two named pads of the source and destination elements.
1078 */
1079 void
1080 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
1081 GstElement *dest, const gchar *destpadname)
1082 {
1083 GstPad *srcpad,*destpad;
1085 g_return_if_fail (src != NULL);
1086 g_return_if_fail (GST_IS_ELEMENT(src));
1087 g_return_if_fail (srcpadname != NULL);
1088 g_return_if_fail (dest != NULL);
1089 g_return_if_fail (GST_IS_ELEMENT(dest));
1090 g_return_if_fail (destpadname != NULL);
1092 /* obtain the pads requested */
1093 srcpad = gst_element_get_pad (src, srcpadname);
1094 if (srcpad == NULL) {
1095 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
1096 return;
1097 }
1098 destpad = gst_element_get_pad (dest, destpadname);
1099 if (srcpad == NULL) {
1100 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
1101 return;
1102 }
1104 /* we're satisified they can be disconnected, let's do it */
1105 gst_pad_disconnect(srcpad,destpad);
1106 }
1108 /**
1109 * gst_element_disconnect_elements:
1110 * @src: source element
1111 * @dest: sink element
1112 *
1113 * Disconnect all pads connecting the two elements in the direction src -> dest.
1114 */
1115 void
1116 gst_element_disconnect_elements (GstElement *src, GstElement *dest)
1117 {
1118 GList *srcpads;
1119 GstPad *pad;
1121 g_return_if_fail (GST_IS_ELEMENT(src));
1122 g_return_if_fail (GST_IS_ELEMENT(dest));
1124 srcpads = gst_element_get_pad_list (src);
1126 while (srcpads) {
1127 pad = GST_PAD (srcpads->data);
1129 if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
1130 if (GST_OBJECT_PARENT (GST_PAD_PEER (pad)) == (GstObject*) dest)
1131 gst_pad_disconnect (pad, GST_PAD_PEER (pad));
1133 srcpads = g_list_next (srcpads);
1134 }
1135 }
1137 static void
1138 gst_element_error_func (GstElement* element, GstElement *source, gchar *errormsg)
1139 {
1140 /* tell the parent */
1141 if (GST_OBJECT_PARENT (element)) {
1142 GST_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s", errormsg,
1143 GST_ELEMENT_NAME (element), GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
1145 gst_object_ref (GST_OBJECT (element));
1146 g_signal_emit (G_OBJECT (GST_OBJECT_PARENT (element)), gst_element_signals[ERROR], 0, source, errormsg);
1147 gst_object_unref (GST_OBJECT (element));
1148 }
1149 }
1150 /**
1151 * gst_element_error:
1152 * @element: Element with the error
1153 * @error: A printf-like string describing the error
1154 * @...: optional arguments for the string
1155 *
1156 * This function is used internally by elements to signal an error
1157 * condition. It results in the "error" signal.
1158 */
1159 void
1160 gst_element_error (GstElement *element, const gchar *error, ...)
1161 {
1162 va_list var_args;
1163 gchar *string;
1165 /* checks */
1166 g_return_if_fail (GST_IS_ELEMENT (element));
1167 g_return_if_fail (element != NULL);
1168 g_return_if_fail (error != NULL);
1170 /* create error message */
1171 va_start (var_args, error);
1172 string = g_strdup_vprintf (error, var_args);
1173 va_end (var_args);
1174 GST_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
1176 /* emit the signal, make sure the element stays available */
1177 gst_object_ref (GST_OBJECT (element));
1178 g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, element, string);
1180 /* tell the scheduler */
1181 if (element->sched) {
1182 gst_scheduler_error (element->sched, element);
1183 }
1185 /* cleanup */
1186 gst_object_unref (GST_OBJECT (element));
1187 g_free (string);
1188 }
1190 /**
1191 * gst_element_get_state:
1192 * @element: element to get state of
1193 *
1194 * Gets the state of the element.
1195 *
1196 * Returns: The element state
1197 */
1198 GstElementState
1199 gst_element_get_state (GstElement *element)
1200 {
1201 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
1203 return GST_STATE (element);
1204 }
1206 /**
1207 * gst_element_wait_state_change:
1208 * @element: element wait for
1209 *
1210 * Wait and block until the element changed its state.
1211 */
1212 void
1213 gst_element_wait_state_change (GstElement *element)
1214 {
1215 g_mutex_lock (element->state_mutex);
1216 g_cond_wait (element->state_cond, element->state_mutex);
1217 g_mutex_unlock (element->state_mutex);
1218 }
1219 /**
1220 * gst_element_set_state:
1221 * @element: element to change state of
1222 * @state: new element state
1223 *
1224 * Sets the state of the element. This function will only set
1225 * the elements pending state.
1226 *
1227 * Returns: whether or not the state was successfully set.
1228 */
1229 gint
1230 gst_element_set_state (GstElement *element, GstElementState state)
1231 {
1232 GstElementClass *oclass;
1233 GstElementState curpending;
1234 GstElementStateReturn return_val = GST_STATE_SUCCESS;
1236 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
1238 /* start with the current state */
1239 curpending = GST_STATE(element);
1241 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s\n",
1242 gst_element_statename (curpending),
1243 gst_element_statename (state));
1245 /* loop until the final requested state is set */
1246 while (GST_STATE (element) != state && GST_STATE (element) != GST_STATE_VOID_PENDING) {
1247 /* move the curpending state in the correct direction */
1248 if (curpending < state)
1249 curpending<<=1;
1250 else
1251 curpending>>=1;
1253 /* set the pending state variable */
1254 /* FIXME: should probably check to see that we don't already have one */
1255 GST_STATE_PENDING (element) = curpending;
1257 if (curpending != state) {
1258 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "intermediate: setting state to %s\n",
1259 gst_element_statename (curpending));
1260 }
1262 /* call the state change function so it can set the state */
1263 oclass = CLASS (element);
1264 if (oclass->change_state)
1265 return_val = (oclass->change_state) (element);
1267 switch (return_val) {
1268 case GST_STATE_FAILURE:
1269 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "have failed change_state return\n");
1270 return return_val;
1271 case GST_STATE_ASYNC:
1272 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element will change state async\n");
1273 return return_val;
1274 default:
1275 /* Last thing we do is verify that a successful state change really
1276 * did change the state... */
1277 if (GST_STATE (element) != curpending) {
1278 GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
1279 "element claimed state-change success, but state didn't change %s, %s <-> %s\n",
1280 gst_element_statename (GST_STATE (element)),
1281 gst_element_statename (GST_STATE_PENDING (element)),
1282 gst_element_statename (curpending));
1283 return GST_STATE_FAILURE;
1284 }
1285 break;
1286 }
1287 }
1289 return return_val;
1290 }
1292 static gboolean
1293 gst_element_negotiate_pads (GstElement *element)
1294 {
1295 GList *pads = GST_ELEMENT_PADS (element);
1297 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads\n");
1299 while (pads) {
1300 GstPad *pad = GST_PAD (pads->data);
1301 GstRealPad *srcpad;
1303 pads = g_list_next (pads);
1305 if (!GST_IS_REAL_PAD (pad))
1306 continue;
1308 srcpad = GST_PAD_REALIZE (pad);
1310 /* if we have a connection on this pad and it doesn't have caps
1311 * allready, try to negotiate */
1312 if (GST_PAD_IS_CONNECTED (srcpad) && !GST_PAD_CAPS (srcpad)) {
1313 GstRealPad *sinkpad;
1314 GstElementState otherstate;
1315 GstElement *parent;
1317 sinkpad = GST_RPAD_PEER (GST_PAD_REALIZE (srcpad));
1319 /* check the parent of the peer pad, if there is no parent do nothing */
1320 parent = GST_PAD_PARENT (sinkpad);
1321 if (!parent)
1322 continue;
1324 otherstate = GST_STATE (parent);
1326 /* swap pads if needed */
1327 if (!GST_PAD_IS_SRC (srcpad)) {
1328 GstRealPad *temp;
1330 temp = srcpad;
1331 srcpad = sinkpad;
1332 sinkpad = temp;
1333 }
1335 /* only try to negotiate if the peer element is in PAUSED or higher too */
1336 if (otherstate >= GST_STATE_READY) {
1337 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "perform negotiate for %s:%s and %s:%s\n",
1338 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1339 if (!gst_pad_perform_negotiate (GST_PAD (srcpad), GST_PAD (sinkpad)))
1340 return FALSE;
1341 }
1342 else {
1343 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "not negotiatiating %s:%s and %s:%s, not in READY yet\n",
1344 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
1345 }
1346 }
1347 }
1349 return TRUE;
1350 }
1352 static void
1353 gst_element_clear_pad_caps (GstElement *element)
1354 {
1355 GList *pads = GST_ELEMENT_PADS (element);
1357 GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps\n");
1359 while (pads) {
1360 GstRealPad *pad = GST_PAD_REALIZE (pads->data);
1362 if (GST_PAD_CAPS (pad)) {
1363 GST_PAD_CAPS (pad) = NULL;
1364 }
1365 pads = g_list_next (pads);
1366 }
1367 }
1369 static GstElementStateReturn
1370 gst_element_change_state (GstElement *element)
1371 {
1372 GstElementState old_state;
1373 GstObject *parent;
1374 gint old_pending, old_transition;
1376 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
1378 old_state = GST_STATE (element);
1379 old_pending = GST_STATE_PENDING (element);
1380 old_transition = GST_STATE_TRANSITION (element);
1382 if (old_pending == GST_STATE_VOID_PENDING || old_state == GST_STATE_PENDING (element)) {
1383 GST_INFO (GST_CAT_STATES, "no state change needed for element %s (VOID_PENDING)", GST_ELEMENT_NAME (element));
1384 return GST_STATE_SUCCESS;
1385 }
1387 GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %d", GST_ELEMENT_NAME (element),
1388 gst_element_statename (old_state),
1389 gst_element_statename (old_pending),
1390 GST_STATE_TRANSITION (element));
1392 /* we set the state change early for the negotiation functions */
1393 GST_STATE (element) = old_pending;
1394 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
1396 /* if we are going to paused, we try to negotiate the pads */
1397 if (old_transition == GST_STATE_NULL_TO_READY) {
1398 if (!gst_element_negotiate_pads (element))
1399 goto failure;
1400 }
1401 /* going to the READY state clears all pad caps */
1402 else if (old_transition == GST_STATE_READY_TO_NULL) {
1403 gst_element_clear_pad_caps (element);
1404 }
1406 /* tell the scheduler if we have one */
1407 if (element->sched) {
1408 if (gst_scheduler_state_transition (element->sched, element, old_transition)
1409 != GST_STATE_SUCCESS) {
1410 goto failure;
1411 }
1412 }
1414 parent = GST_ELEMENT_PARENT (element);
1416 /* tell our parent about the state change */
1417 if (parent && GST_IS_BIN (parent)) {
1418 gst_bin_child_state_change (GST_BIN (parent), old_state, GST_STATE (element), element);
1419 }
1421 g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
1422 0, old_state, GST_STATE (element));
1424 /* signal the state change in case somebody is waiting for us */
1425 g_mutex_lock (element->state_mutex);
1426 g_cond_signal (element->state_cond);
1427 g_mutex_unlock (element->state_mutex);
1429 return GST_STATE_SUCCESS;
1431 failure:
1432 /* undo the state change */
1433 GST_STATE (element) = old_state;
1434 GST_STATE_PENDING (element) = old_pending;
1436 return GST_STATE_FAILURE;
1437 }
1439 /**
1440 * gst_element_get_factory:
1441 * @element: element to request the factory
1442 *
1443 * Retrieves the factory that was used to create this element
1444 *
1445 * Returns: the factory used for creating this element
1446 */
1447 GstElementFactory*
1448 gst_element_get_factory (GstElement *element)
1449 {
1450 GstElementClass *oclass;
1452 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1454 oclass = CLASS (element);
1456 return oclass->elementfactory;
1457 }
1459 static void
1460 gst_element_dispose (GObject *object)
1461 {
1462 GstElement *element = GST_ELEMENT (object);
1463 GList *pads;
1464 GstPad *pad;
1466 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose\n");
1468 gst_element_set_state (element, GST_STATE_NULL);
1470 /* first we break all our connections with the ouside */
1471 if (element->pads) {
1472 GList *orig;
1473 orig = pads = g_list_copy (element->pads);
1474 while (pads) {
1475 pad = GST_PAD (pads->data);
1477 if (GST_PAD_PEER (pad)) {
1478 GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'",
1479 GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
1480 gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
1481 }
1482 gst_element_remove_pad (element, pad);
1484 pads = g_list_next (pads);
1485 }
1486 g_list_free (orig);
1487 g_list_free (element->pads);
1488 element->pads = NULL;
1489 }
1491 element->numsrcpads = 0;
1492 element->numsinkpads = 0;
1493 element->numpads = 0;
1494 g_mutex_free (element->state_mutex);
1495 g_cond_free (element->state_cond);
1497 G_OBJECT_CLASS (parent_class)->dispose (object);
1498 }
1500 #ifndef GST_DISABLE_LOADSAVE
1501 /**
1502 * gst_element_save_thyself:
1503 * @element: GstElement to save
1504 * @parent: the xml parent node
1505 *
1506 * Saves the element as part of the given XML structure
1507 *
1508 * Returns: the new xml node
1509 */
1510 static xmlNodePtr
1511 gst_element_save_thyself (GstObject *object,
1512 xmlNodePtr parent)
1513 {
1514 GList *pads;
1515 GstElementClass *oclass;
1516 GParamSpec **specs, *spec;
1517 gint nspecs, i;
1518 GValue value = { 0, };
1519 GstElement *element;
1521 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
1523 element = GST_ELEMENT (object);
1525 oclass = CLASS (element);
1527 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
1529 if (oclass->elementfactory != NULL) {
1530 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
1532 xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
1533 xmlNewChild (parent, NULL, "version", factory->details->version);
1534 }
1536 /* FIXME: what is this? */
1537 /* if (element->manager) */
1538 /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
1540 /* params */
1541 specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &nspecs);
1543 for (i=0; i<nspecs; i++) {
1544 spec = specs[i];
1545 if (spec->flags & G_PARAM_READABLE) {
1546 xmlNodePtr param;
1548 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (spec));
1550 g_object_get_property (G_OBJECT (element), spec->name, &value);
1551 param = xmlNewChild (parent, NULL, "param", NULL);
1552 xmlNewChild (param, NULL, "name", spec->name);
1554 if (G_IS_PARAM_SPEC_STRING (spec))
1555 xmlNewChild (param, NULL, "value", g_value_dup_string (&value));
1556 else if (G_IS_PARAM_SPEC_ENUM (spec))
1557 xmlNewChild (param, NULL, "value", g_strdup_printf ("%d", g_value_get_enum (&value)));
1558 else if (G_IS_PARAM_SPEC_INT64 (spec))
1559 xmlNewChild (param, NULL, "value", g_strdup_printf ("%lld", g_value_get_int64 (&value)));
1560 else
1561 xmlNewChild (param, NULL, "value", g_strdup_value_contents (&value));
1563 g_value_unset(&value);
1564 }
1565 }
1567 pads = GST_ELEMENT_PADS (element);
1569 while (pads) {
1570 GstPad *pad = GST_PAD (pads->data);
1571 /* figure out if it's a direct pad or a ghostpad */
1572 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
1573 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
1574 gst_object_save_thyself (GST_OBJECT (pad), padtag);
1575 }
1576 pads = g_list_next (pads);
1577 }
1579 return parent;
1580 }
1582 static void
1583 gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
1584 {
1585 xmlNodePtr children;
1586 GstElement *element;
1587 guchar *name = NULL;
1588 guchar *value = NULL;
1590 element = GST_ELEMENT (object);
1591 g_return_if_fail (element != NULL);
1593 /* parameters */
1594 children = self->xmlChildrenNode;
1595 while (children) {
1596 if (!strcmp (children->name, "param")) {
1597 xmlNodePtr child = children->xmlChildrenNode;
1599 while (child) {
1600 if (!strcmp (child->name, "name")) {
1601 name = xmlNodeGetContent (child);
1602 }
1603 else if (!strcmp (child->name, "value")) {
1604 value = xmlNodeGetContent (child);
1605 }
1606 child = child->next;
1607 }
1608 /* FIXME: can this just be g_object_set ? */
1609 gst_util_set_object_arg ((GObject *)G_OBJECT (element), name, value);
1610 }
1611 children = children->next;
1612 }
1614 /* pads */
1615 children = self->xmlChildrenNode;
1616 while (children) {
1617 if (!strcmp (children->name, "pad")) {
1618 gst_pad_load_and_connect (children, GST_OBJECT (element));
1619 }
1620 children = children->next;
1621 }
1623 if (GST_OBJECT_CLASS(parent_class)->restore_thyself)
1624 (GST_OBJECT_CLASS(parent_class)->restore_thyself) (object, self);
1625 }
1626 #endif /* GST_DISABLE_LOADSAVE */
1628 /**
1629 * gst_element_yield:
1630 * @element: Element to yield
1631 *
1632 * Request a yield operation for the child. The scheduler will typically
1633 * give control to another element.
1634 */
1635 void
1636 gst_element_yield (GstElement *element)
1637 {
1638 if (GST_ELEMENT_SCHED (element)) {
1639 gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
1640 }
1641 }
1643 /**
1644 * gst_element_interrupt:
1645 * @element: Element to interrupt
1646 *
1647 * Request the scheduler of this element to interrupt the execution of
1648 * this element and scheduler another one.
1649 *
1650 * Returns: a boolean indicating that the child should exit its chain/loop/get
1651 * function ASAP, depending on the scheduler implementation.
1652 */
1653 gboolean
1654 gst_element_interrupt (GstElement *element)
1655 {
1656 if (GST_ELEMENT_SCHED (element)) {
1657 return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
1658 }
1659 else
1660 return FALSE;
1661 }
1663 /**
1664 * gst_element_set_sched:
1665 * @element: Element to set manager of.
1666 * @sched: @GstScheduler to set.
1667 *
1668 * Sets the scheduler of the element. For internal use only, unless you're
1669 * writing a new bin subclass.
1670 */
1671 void
1672 gst_element_set_sched (GstElement *element,
1673 GstScheduler *sched)
1674 {
1675 g_return_if_fail (GST_IS_ELEMENT (element));
1677 GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
1679 element->sched = sched;
1680 }
1682 /**
1683 * gst_element_get_sched:
1684 * @element: Element to get manager of.
1685 *
1686 * Returns the scheduler of the element.
1687 *
1688 * Returns: Element's scheduler
1689 */
1690 GstScheduler*
1691 gst_element_get_sched (GstElement *element)
1692 {
1693 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1695 return element->sched;
1696 }
1698 /**
1699 * gst_element_set_loop_function:
1700 * @element: Element to set loop function of.
1701 * @loop: Pointer to loop function.
1702 *
1703 * This sets the loop function for the element. The function pointed to
1704 * can deviate from the GstElementLoopFunction definition in type of
1705 * pointer only.
1706 *
1707 * NOTE: in order for this to take effect, the current loop function *must*
1708 * exit. Assuming the loop function itself is the only one who will cause
1709 * a new loopfunc to be assigned, this should be no problem.
1710 */
1711 void
1712 gst_element_set_loop_function (GstElement *element,
1713 GstElementLoopFunction loop)
1714 {
1715 g_return_if_fail (GST_IS_ELEMENT (element));
1717 /* set the loop function */
1718 element->loopfunc = loop;
1720 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1721 GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
1722 }
1724 /**
1725 * gst_element_set_eos:
1726 * @element: element to set to the EOS state
1727 *
1728 * Perform the actions needed to bring the element in the EOS state.
1729 */
1730 void
1731 gst_element_set_eos (GstElement *element)
1732 {
1733 g_return_if_fail (GST_IS_ELEMENT (element));
1735 GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", GST_OBJECT_NAME (element));
1737 gst_element_set_state (element, GST_STATE_PAUSED);
1739 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
1740 }
1743 /**
1744 * gst_element_statename:
1745 * @state: The state to get the name of
1746 *
1747 * Gets a string representing the given state.
1748 *
1749 * Returns: a string with the statename.
1750 */
1751 const gchar*
1752 gst_element_statename (GstElementState state)
1753 {
1754 switch (state) {
1755 #ifdef GST_DEBUG_COLOR
1756 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1757 case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
1758 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
1759 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
1760 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
1761 default: return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
1762 #else
1763 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1764 case GST_STATE_NULL: return "NULL";break;
1765 case GST_STATE_READY: return "READY";break;
1766 case GST_STATE_PLAYING: return "PLAYING";break;
1767 case GST_STATE_PAUSED: return "PAUSED";break;
1768 default: return "UNKNOWN!";
1769 #endif
1770 }
1771 return "";
1772 }
1774 static void
1775 gst_element_populate_std_props (GObjectClass * klass,
1776 const char *prop_name, guint arg_id, GParamFlags flags)
1777 {
1778 GQuark prop_id = g_quark_from_string (prop_name);
1779 GParamSpec *pspec;
1781 static GQuark fd_id = 0;
1782 static GQuark blocksize_id;
1783 static GQuark bytesperread_id;
1784 static GQuark dump_id;
1785 static GQuark filesize_id;
1786 static GQuark mmapsize_id;
1787 static GQuark location_id;
1788 static GQuark offset_id;
1789 static GQuark silent_id;
1790 static GQuark touch_id;
1792 if (!fd_id) {
1793 fd_id = g_quark_from_static_string ("fd");
1794 blocksize_id = g_quark_from_static_string ("blocksize");
1795 bytesperread_id = g_quark_from_static_string ("bytesperread");
1796 dump_id = g_quark_from_static_string ("dump");
1797 filesize_id = g_quark_from_static_string ("filesize");
1798 mmapsize_id = g_quark_from_static_string ("mmapsize");
1799 location_id = g_quark_from_static_string ("location");
1800 offset_id = g_quark_from_static_string ("offset");
1801 silent_id = g_quark_from_static_string ("silent");
1802 touch_id = g_quark_from_static_string ("touch");
1803 }
1805 if (prop_id == fd_id) {
1806 pspec = g_param_spec_int ("fd", "File-descriptor",
1807 "File-descriptor for the file being read",
1808 0, G_MAXINT, 0, flags);
1809 }
1810 else if (prop_id == blocksize_id) {
1811 pspec = g_param_spec_ulong ("blocksize", "Block Size",
1812 "Block size to read per buffer",
1813 0, G_MAXULONG, 4096, flags);
1815 }
1816 else if (prop_id == bytesperread_id) {
1817 pspec = g_param_spec_int ("bytesperread", "bytesperread",
1818 "bytesperread",
1819 G_MININT, G_MAXINT, 0, flags);
1821 }
1822 else if (prop_id == dump_id) {
1823 pspec = g_param_spec_boolean ("dump", "dump", "dump", FALSE, flags);
1825 }
1826 else if (prop_id == filesize_id) {
1827 pspec = g_param_spec_int64 ("filesize", "File Size",
1828 "Size of the file being read",
1829 0, G_MAXINT64, 0, flags);
1831 }
1832 else if (prop_id == mmapsize_id) {
1833 pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
1834 "Size in bytes of mmap()d regions",
1835 0, G_MAXULONG, 4 * 1048576, flags);
1837 }
1838 else if (prop_id == location_id) {
1839 pspec = g_param_spec_string ("location", "File Location",
1840 "Location of the file to read",
1841 NULL, flags);
1843 }
1844 else if (prop_id == offset_id) {
1845 pspec = g_param_spec_int64 ("offset", "File Offset",
1846 "Byte offset of current read pointer",
1847 0, G_MAXINT64, 0, flags);
1849 }
1850 else if (prop_id == silent_id) {
1851 pspec = g_param_spec_boolean ("silent", "silent", "silent",
1852 FALSE, flags);
1854 }
1855 else if (prop_id == touch_id) {
1856 pspec = g_param_spec_boolean ("touch", "Touch read data",
1857 "Touch data to force disk read before "
1858 "push ()", TRUE, flags);
1859 }
1860 else {
1861 g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
1862 prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
1863 pspec = NULL;
1864 }
1866 if (pspec) {
1867 g_object_class_install_property (klass, arg_id, pspec);
1868 }
1869 }
1871 /**
1872 * gst_element_class_install_std_props:
1873 * @klass: the class to add the properties to
1874 * @first_name: the first in a NULL terminated
1875 * 'name', 'id', 'flags' triplet list.
1876 * @...: the triplet list
1877 *
1878 * Add a list of standardized properties with types to the @klass.
1879 * the id is for the property switch in your get_prop method, and
1880 * the flags determine readability / writeability.
1881 **/
1882 void
1883 gst_element_class_install_std_props (GstElementClass * klass, const char *first_name, ...)
1884 {
1885 const char *name;
1887 va_list args;
1889 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1891 va_start (args, first_name);
1893 name = first_name;
1895 while (name) {
1896 int arg_id = va_arg (args, int);
1897 int flags = va_arg (args, int);
1899 gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
1901 name = va_arg (args, char *);
1902 }
1904 va_end (args);
1905 }
1907 /**
1908 * gst_element_get_managing_bin:
1909 * @element: the element in question
1910 *
1911 * Get the managing bin (a pipeline or a thread, for example) of an element.
1912 *
1913 * Returns: the bin, or NULL on failure
1914 **/
1915 GstBin*
1916 gst_element_get_managing_bin (GstElement *element)
1917 {
1918 GstBin *bin;
1920 g_return_val_if_fail (element != NULL, NULL);
1922 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (element)));
1924 while (bin && !GST_FLAG_IS_SET (GST_OBJECT_CAST (bin), GST_BIN_FLAG_MANAGER))
1925 bin = GST_BIN (gst_object_get_parent (GST_OBJECT_CAST (bin)));
1927 return bin;
1928 }