2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstelement.c: The base element, all elements derive from this
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.
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.
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.
23 /* #define GST_DEBUG_ENABLED */
26 #include "gst_private.h"
28 #include "gstelement.h"
29 #include "gstextratypes.h"
31 #include "gstscheduler.h"
35 /* Element signals and args */
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,
61 static void gst_element_dispose (GObject *object);
63 static GstElementStateReturn gst_element_change_state (GstElement *element);
64 static void gst_element_send_event_func (GstElement *element, GstEvent *event);
66 #ifndef GST_DISABLE_LOADSAVE
67 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
68 GstElement* gst_element_restore_thyself (xmlNodePtr self, GstObject *parent);
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)
78 if (!_gst_element_type) {
79 static const GTypeInfo element_info = {
80 sizeof(GstElementClass),
81 (GBaseInitFunc)gst_element_base_class_init,
83 (GClassInitFunc)gst_element_class_init,
88 (GInstanceInitFunc)gst_element_init,
91 _gst_element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT);
93 return _gst_element_type;
97 gst_element_class_init (GstElementClass *klass)
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__POINTER, G_TYPE_NONE, 1,
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__POINTER, G_TYPE_NONE, 1,
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__STRING, G_TYPE_NONE,1,
127 gst_element_signals[EVENT] =
128 g_signal_new ("event", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
129 G_STRUCT_OFFSET (GstElementClass, event), NULL, NULL,
130 gst_marshal_VOID__POINTER, G_TYPE_NONE,1,
132 gst_element_signals[EOS] =
133 g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
134 G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
135 gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
139 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_element_set_property);
140 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_element_get_property);
141 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
143 #ifndef GST_DISABLE_LOADSAVE
144 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
145 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
148 klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state);
149 klass->send_event = GST_DEBUG_FUNCPTR (gst_element_send_event_func);
150 klass->elementfactory = NULL;
151 klass->padtemplates = NULL;
152 klass->numpadtemplates = 0;
156 gst_element_base_class_init (GstElementClass *klass)
158 GObjectClass *gobject_class;
160 gobject_class = (GObjectClass*) klass;
162 gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_element_set_property);
163 gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_element_get_property);
167 gst_element_init (GstElement *element)
169 element->current_state = GST_STATE_NULL;
170 element->pending_state = GST_STATE_VOID_PENDING;
171 element->numpads = 0;
172 element->numsrcpads = 0;
173 element->numsinkpads = 0;
174 element->pads = NULL;
175 element->loopfunc = NULL;
176 element->sched = NULL;
177 element->sched_private = NULL;
178 element->state_mutex = g_mutex_new ();
179 element->state_cond = g_cond_new ();
184 gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
186 GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object);
188 if (oclass->set_property)
189 (oclass->set_property)(object,prop_id,value,pspec);
194 gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
196 GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object);
198 if (oclass->get_property)
199 (oclass->get_property)(object,prop_id,value,pspec);
204 * gst_element_set_name:
205 * @element: GstElement to set name of
206 * @name: new name of element
208 * Set the name of the element, getting rid of the old name if there was
212 gst_element_set_name (GstElement *element, const gchar *name)
214 g_return_if_fail (element != NULL);
215 g_return_if_fail (GST_IS_ELEMENT (element));
216 g_return_if_fail (name != NULL);
218 gst_object_set_name (GST_OBJECT (element), name);
222 * gst_element_get_name:
223 * @element: GstElement to get name of
225 * Get the name of the element.
227 * Returns: name of the element
230 gst_element_get_name (GstElement *element)
232 g_return_val_if_fail (element != NULL, NULL);
233 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
235 return GST_OBJECT_NAME (element);
239 * gst_element_set_parent:
240 * @element: GstElement to set parent of
241 * @parent: new parent of the object
243 * Set the parent of the element.
246 gst_element_set_parent (GstElement *element, GstObject *parent)
248 g_return_if_fail (element != NULL);
249 g_return_if_fail (GST_IS_ELEMENT (element));
250 g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
251 g_return_if_fail (parent != NULL);
252 g_return_if_fail (GST_IS_OBJECT (parent));
253 g_return_if_fail ((gpointer)element != (gpointer)parent);
255 gst_object_set_parent (GST_OBJECT (element), parent);
259 * gst_element_get_parent:
260 * @element: GstElement to get the parent of
262 * Get the parent of the element.
264 * Returns: parent of the element
267 gst_element_get_parent (GstElement *element)
269 g_return_val_if_fail (element != NULL, NULL);
270 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
272 return GST_OBJECT_PARENT (element);
276 * gst_element_add_pad:
277 * @element: element to add pad to
280 * Add a pad (connection point) to the element, setting the parent of the
281 * pad to the element (and thus adding a reference).
284 gst_element_add_pad (GstElement *element, GstPad *pad)
286 g_return_if_fail (element != NULL);
287 g_return_if_fail (GST_IS_ELEMENT (element));
288 g_return_if_fail (pad != NULL);
289 g_return_if_fail (GST_IS_PAD (pad));
291 /* first check to make sure the pad's parent is already set */
292 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
294 /* then check to see if there's already a pad by that name here */
295 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
297 /* set the pad's parent */
298 GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
299 GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
300 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
302 /* add it to the list */
303 element->pads = g_list_append (element->pads, pad);
305 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
306 element->numsrcpads++;
308 element->numsinkpads++;
310 /* emit the NEW_PAD signal */
311 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
315 * gst_element_remove_pad:
316 * @element: element to remove pad from
317 * @pad: pad to remove
319 * Remove a pad (connection point) from the element,
322 gst_element_remove_pad (GstElement *element, GstPad *pad)
324 g_return_if_fail (element != NULL);
325 g_return_if_fail (GST_IS_ELEMENT (element));
326 g_return_if_fail (pad != NULL);
327 g_return_if_fail (GST_IS_PAD (pad));
329 g_return_if_fail (GST_PAD_PARENT (pad) == element);
331 /* add it to the list */
332 element->pads = g_list_remove (element->pads, pad);
334 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
335 element->numsrcpads--;
337 element->numsinkpads--;
339 g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
341 gst_object_unparent (GST_OBJECT (pad));
345 * gst_element_add_ghost_pad:
346 * @element: element to add ghost pad to
347 * @pad: pad from which the new ghost pad will be created
348 * @name: name of the new ghost pad
350 * Create a ghost pad from the given pad, and add it to the list of pads
354 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
358 g_return_if_fail (element != NULL);
359 g_return_if_fail (GST_IS_ELEMENT (element));
360 g_return_if_fail (pad != NULL);
361 g_return_if_fail (GST_IS_PAD (pad));
363 /* then check to see if there's already a pad by that name here */
364 g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
366 GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
367 name,GST_DEBUG_PAD_NAME(pad));
368 ghostpad = gst_ghost_pad_new (name, pad);
370 /* add it to the list */
371 GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
372 name, GST_ELEMENT_NAME (element));
373 element->pads = g_list_append (element->pads, ghostpad);
375 /* set the parent of the ghostpad */
376 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
378 GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
380 /* emit the NEW_GHOST_PAD signal */
381 g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
385 * gst_element_remove_ghost_pad:
386 * @element: element to remove the ghost pad from
387 * @pad: ghost pad to remove
389 * removes a ghost pad from an element
393 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
395 g_return_if_fail (element != NULL);
396 g_return_if_fail (GST_IS_ELEMENT (element));
397 g_return_if_fail (pad != NULL);
398 g_return_if_fail (GST_IS_GHOST_PAD (pad));
400 /* FIXME this is redundant?
401 * wingo 10-july-2001: I don't think so, you have to actually remove the pad
402 * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
403 * the real pad's ghost pad list
405 gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
406 gst_element_remove_pad (element, pad);
411 * gst_element_get_pad:
412 * @element: element to find pad of
413 * @name: name of pad to retrieve
415 * Retrieve a pad from the element by name.
417 * Returns: requested pad if found, otherwise NULL.
420 gst_element_get_pad (GstElement *element, const gchar *name)
424 g_return_val_if_fail (element != NULL, NULL);
425 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
426 g_return_val_if_fail (name != NULL, NULL);
428 /* if there aren't any pads, well, we're not likely to find one */
429 if (!element->numpads)
432 /* look through the list, matching by name */
433 walk = element->pads;
435 GstPad *pad = GST_PAD(walk->data);
436 if (!strcmp (GST_PAD_NAME(pad), name)) {
437 GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
440 walk = g_list_next (walk);
443 GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
448 * gst_element_get_pad_list:
449 * @element: element to get pads of
451 * Retrieve a list of the pads associated with the element.
453 * Returns: GList of pads
456 gst_element_get_pad_list (GstElement *element)
458 g_return_val_if_fail (element != NULL, NULL);
459 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
461 /* return the list of pads */
462 return element->pads;
466 * gst_element_class_add_padtemplate:
467 * @klass: element class to add padtemplate to
468 * @templ: padtemplate to add
470 * Add a padtemplate to an element class. This is useful if you have derived a custom
471 * bin and wish to provide an on-request pad at runtime. Plugin writers should use
472 * gst_elementfactory_add_padtemplate instead.
475 gst_element_class_add_padtemplate (GstElementClass *klass, GstPadTemplate *templ)
477 g_return_if_fail (klass != NULL);
478 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
479 g_return_if_fail (templ != NULL);
480 g_return_if_fail (GST_IS_PADTEMPLATE (templ));
482 klass->padtemplates = g_list_append (klass->padtemplates, templ);
483 klass->numpadtemplates++;
487 * gst_element_get_padtemplate_list:
488 * @element: element to get padtemplates of
490 * Retrieve a list of the padtemplates associated with the element.
492 * Returns: GList of padtemplates
495 gst_element_get_padtemplate_list (GstElement *element)
497 GstElementClass *oclass;
499 g_return_val_if_fail (element != NULL, NULL);
500 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
502 oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
504 return oclass->padtemplates;
508 * gst_element_get_padtemplate_by_name:
509 * @element: element to get padtemplate of
510 * @name: the name of the padtemplate to get.
512 * Retrieve a padtemplate from this element with the
515 * Returns: the padtemplate with the given name
518 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
522 g_return_val_if_fail (element != NULL, NULL);
523 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
524 g_return_val_if_fail (name != NULL, NULL);
526 padlist = gst_element_get_padtemplate_list (element);
529 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
531 if (!strcmp (padtempl->name_template, name))
534 padlist = g_list_next (padlist);
541 * gst_element_get_padtemplate_by_compatible:
542 * @element: element to get padtemplate of
543 * @templ: a template to find a compatible template for
545 * Generate a padtemplate for this element compatible with the given
546 * template, ie able to link to it.
548 * Returns: the padtemplate
550 static GstPadTemplate*
551 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
553 GstPadTemplate *newtempl = NULL;
556 GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
558 g_return_val_if_fail (element != NULL, NULL);
559 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
560 g_return_val_if_fail (compattempl != NULL, NULL);
562 padlist = gst_element_get_padtemplate_list (element);
565 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
566 gboolean compat = FALSE;
570 * Check direction (must be opposite)
573 GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
574 if (padtempl->direction == GST_PAD_SRC &&
575 compattempl->direction == GST_PAD_SINK) {
576 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
577 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
578 GST_PADTEMPLATE_CAPS (compattempl));
579 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
580 } else if (padtempl->direction == GST_PAD_SINK &&
581 compattempl->direction == GST_PAD_SRC) {
582 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
583 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
584 GST_PADTEMPLATE_CAPS (padtempl));
585 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
593 padlist = g_list_next (padlist);
600 gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar* name)
602 GstPad *newpad = NULL;
603 GstElementClass *oclass;
605 oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
606 if (oclass->request_new_pad)
607 newpad = (oclass->request_new_pad)(element, templ, name);
613 * gst_element_request_compatible_pad:
614 * @element: element to request a new pad from
615 * @templ: a pad template to which the new pad should be able to connect
617 * Request a new pad from the element. The template will
618 * be used to decide what type of pad to create. This function
619 * is typically used for elements with a padtemplate with presence
622 * Returns: the new pad that was created.
625 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
627 GstPadTemplate *templ_new;
630 g_return_val_if_fail (element != NULL, NULL);
631 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
632 g_return_val_if_fail (templ != NULL, NULL);
634 templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
635 if (templ_new != NULL)
636 pad = gst_element_request_pad (element, templ_new, NULL);
642 * gst_element_request_pad_by_name:
643 * @element: element to request a new pad from
644 * @name: the name of the padtemplate to use.
646 * Request a new pad from the element. The name argument will
647 * be used to decide what padtemplate to use. This function
648 * is typically used for elements with a padtemplate with presence
651 * Returns: the new pad that was created.
654 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
656 GstPadTemplate *templ = NULL;
658 const gchar *req_name = NULL;
659 gboolean templ_found = FALSE;
663 g_return_val_if_fail (element != NULL, NULL);
664 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
665 g_return_val_if_fail (name != NULL, NULL);
667 if (strstr (name, "%d")) {
668 templ = gst_element_get_padtemplate_by_name (element, name);
671 list = gst_element_get_padtemplate_list(element);
672 while (!templ_found && list) {
673 templ = (GstPadTemplate*) list->data;
674 if (strstr (templ->name_template, "%d")) {
675 if (sscanf(name, templ->name_template, &n)) {
688 pad = gst_element_request_pad (element, templ, req_name);
694 * gst_element_connect:
695 * @src: element containing source pad
696 * @srcpadname: name of pad in source element
697 * @dest: element containing destination pad
698 * @destpadname: name of pad in destination element
700 * Connect the two named pads of the source and destination elements.
701 * Side effect is that if one of the pads has no parent, it becomes a
702 * child of the parent of the other element. If they have different
703 * parents, the connection fails.
706 gst_element_connect (GstElement *src, const gchar *srcpadname,
707 GstElement *dest, const gchar *destpadname)
709 GstPad *srcpad,*destpad;
711 g_return_if_fail (src != NULL);
712 g_return_if_fail (GST_IS_ELEMENT(src));
713 g_return_if_fail (srcpadname != NULL);
714 g_return_if_fail (dest != NULL);
715 g_return_if_fail (GST_IS_ELEMENT(dest));
716 g_return_if_fail (destpadname != NULL);
718 /* obtain the pads requested */
719 srcpad = gst_element_get_pad (src, srcpadname);
720 if (srcpad == NULL) {
721 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
724 destpad = gst_element_get_pad (dest, destpadname);
725 if (srcpad == NULL) {
726 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
730 /* we're satisified they can be connected, let's do it */
731 gst_pad_connect(srcpad,destpad);
735 * gst_element_disconnect:
736 * @src: element containing source pad
737 * @srcpadname: name of pad in source element
738 * @dest: element containing destination pad
739 * @destpadname: name of pad in destination element
741 * Disconnect the two named pads of the source and destination elements.
744 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
745 GstElement *dest, const gchar *destpadname)
747 GstPad *srcpad,*destpad;
749 g_return_if_fail (src != NULL);
750 g_return_if_fail (GST_IS_ELEMENT(src));
751 g_return_if_fail (srcpadname != NULL);
752 g_return_if_fail (dest != NULL);
753 g_return_if_fail (GST_IS_ELEMENT(dest));
754 g_return_if_fail (destpadname != NULL);
756 /* obtain the pads requested */
757 srcpad = gst_element_get_pad (src, srcpadname);
758 if (srcpad == NULL) {
759 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
762 destpad = gst_element_get_pad (dest, destpadname);
763 if (srcpad == NULL) {
764 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
768 /* we're satisified they can be disconnected, let's do it */
769 gst_pad_disconnect(srcpad,destpad);
773 gst_element_message (GstElement *element, const gchar *type, const gchar *info, va_list var_args)
779 string = g_strdup_vprintf (info, var_args);
781 GST_INFO (GST_CAT_EVENT, "%s sends message %s", GST_ELEMENT_NAME (element),
784 event = gst_event_new_info (type, GST_PROPS_STRING (string), NULL);
785 gst_element_send_event (element, event);
792 * @element: Element with the error
793 * @error: A printf-like string describing the error
794 * @...: optional arguments for the string
796 * This function is used internally by elements to signal an error
797 * condition. It results in the "error" signal.
800 gst_element_error (GstElement *element, const gchar *error, ...)
805 g_return_if_fail (GST_IS_ELEMENT (element));
806 g_return_if_fail (error != NULL);
808 va_start (var_args, error);
809 gst_element_message (element, "error", error, var_args);
812 parent = GST_ELEMENT_PARENT (element);
814 if (parent && GST_IS_BIN (parent)) {
815 gst_bin_child_error (GST_BIN (parent), element);
818 if (element->sched) {
819 gst_scheduler_error (element->sched, element);
826 * @element: Element with the info
827 * @info: String describing the info
828 * @...: arguments for the string.
830 * This function is used internally by elements to signal an info
831 * condition. It results in the "info" signal.
834 gst_element_info (GstElement *element, const gchar *info, ...)
838 g_return_if_fail (GST_IS_ELEMENT (element));
839 g_return_if_fail (info != NULL);
841 va_start (var_args, info);
842 gst_element_message (element, "info", info, var_args);
848 gst_element_send_event_func (GstElement *element, GstEvent *event)
850 if (GST_OBJECT_PARENT (element)) {
851 gst_element_send_event (GST_ELEMENT (GST_OBJECT_PARENT (element)), event);
854 switch (GST_EVENT_TYPE (event)) {
856 g_signal_emit (G_OBJECT (element), gst_element_signals[EVENT], 0, event);
858 gst_event_free (event);
863 * gst_element_send_event:
864 * @element: Element generating the event
865 * @event: the event to send
867 * This function is used intenally by elements to send an event to
868 * the app. It will result in an "event" signal.
871 gst_element_send_event (GstElement *element, GstEvent *event)
873 GstElementClass *oclass = (GstElementClass *) G_OBJECT_GET_CLASS (element);
875 g_return_if_fail (GST_IS_ELEMENT (element));
876 g_return_if_fail (event);
878 if (GST_EVENT_SRC (event) == NULL)
879 GST_EVENT_SRC (event) = gst_object_ref (GST_OBJECT (element));
881 if (oclass->send_event)
882 (oclass->send_event) (element, event);
887 * gst_element_get_state:
888 * @element: element to get state of
890 * Gets the state of the element.
892 * Returns: The element state
895 gst_element_get_state (GstElement *element)
897 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_VOID_PENDING);
899 return GST_STATE (element);
903 * gst_element_wait_state_change:
904 * @element: element wait for
906 * Wait and block until the element changed its state.
909 gst_element_wait_state_change (GstElement *element)
911 g_mutex_lock (element->state_mutex);
912 g_cond_wait (element->state_cond, element->state_mutex);
913 g_mutex_unlock (element->state_mutex);
916 * gst_element_set_state:
917 * @element: element to change state of
918 * @state: new element state
920 * Sets the state of the element. This function will only set
921 * the elements pending state.
923 * Returns: whether or not the state was successfully set.
926 gst_element_set_state (GstElement *element, GstElementState state)
928 GstElementClass *oclass;
929 GstElementState curpending;
930 GstElementStateReturn return_val = GST_STATE_SUCCESS;
932 /* g_print("gst_element_set_state(\"%s\",%08lx)\n", */
933 /* element->name,state); */
935 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
937 GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
938 gst_element_statename(GST_STATE(element)),
939 gst_element_statename(state));
941 /* start with the current state */
942 curpending = GST_STATE(element);
944 /* loop until the final requested state is set */
945 while (GST_STATE(element) != state && GST_STATE (element) != GST_STATE_VOID_PENDING) {
946 /* move the curpending state in the correct direction */
947 if (curpending < state) curpending<<=1;
950 /* set the pending state variable */
951 /* FIXME: should probably check to see that we don't already have one */
952 GST_STATE_PENDING (element) = curpending;
953 if (curpending != state)
954 GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
955 gst_element_statename(curpending));
957 /* call the state change function so it can set the state */
958 oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
959 if (oclass->change_state)
960 return_val = (oclass->change_state)(element);
962 switch (return_val) {
963 case GST_STATE_FAILURE:
964 GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
966 case GST_STATE_ASYNC:
967 GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"element will change state async\n");
970 /* Last thing we do is verify that a successful state change really
971 * did change the state... */
972 if (GST_STATE(element) != curpending) {
973 GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n");
974 return GST_STATE_FAILURE;
983 static GstElementStateReturn
984 gst_element_change_state (GstElement *element)
986 GstElementState old_state;
989 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
991 old_state = GST_STATE (element);
993 if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING || old_state == GST_STATE_PENDING (element)) {
994 GST_INFO (GST_CAT_STATES, "no state change needed for element %s (VOID_PENDING)", GST_ELEMENT_NAME (element));
995 return GST_STATE_SUCCESS;
998 GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %d", GST_ELEMENT_NAME (element),
999 gst_element_statename (old_state),
1000 gst_element_statename (GST_STATE_PENDING (element)),
1001 GST_STATE_TRANSITION (element));
1003 /* tell the scheduler if we have one */
1004 if (element->sched) {
1005 if (gst_scheduler_state_transition (element->sched, element, GST_STATE_TRANSITION (element))
1006 != GST_STATE_SUCCESS) {
1007 return GST_STATE_FAILURE;
1011 GST_STATE (element) = GST_STATE_PENDING (element);
1012 GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
1014 parent = GST_ELEMENT_PARENT (element);
1016 if (parent && GST_IS_BIN (parent)) {
1017 gst_bin_child_state_change (GST_BIN (parent), old_state, GST_STATE (element), element);
1020 g_mutex_lock (element->state_mutex);
1021 g_cond_signal (element->state_cond);
1022 g_mutex_unlock (element->state_mutex);
1025 return GST_STATE_SUCCESS;
1029 * gst_element_get_factory:
1030 * @element: element to request the factory
1032 * Retrieves the factory that was used to create this element
1034 * Returns: the factory used for creating this element
1037 gst_element_get_factory (GstElement *element)
1039 GstElementClass *oclass;
1041 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1043 oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
1045 return oclass->elementfactory;
1049 gst_element_dispose (GObject *object)
1051 GstElement *element = GST_ELEMENT (object);
1056 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose\n");
1058 /* first we break all our connections with the ouside */
1059 if (element->pads) {
1061 orig = pads = g_list_copy (element->pads);
1063 pad = GST_PAD (pads->data);
1064 gst_object_destroy (GST_OBJECT (pad));
1065 pads = g_list_next (pads);
1068 g_list_free (element->pads);
1069 element->pads = NULL;
1072 element->numsrcpads = 0;
1073 element->numsinkpads = 0;
1074 element->numpads = 0;
1075 g_mutex_free (element->state_mutex);
1076 g_cond_free (element->state_cond);
1078 G_OBJECT_CLASS (parent_class)->dispose (object);
1081 #ifndef GST_DISABLE_LOADSAVE
1083 * gst_element_save_thyself:
1084 * @element: GstElement to save
1085 * @parent: the xml parent node
1087 * Saves the element as part of the given XML structure
1089 * Returns: the new xml node
1092 gst_element_save_thyself (GstObject *object,
1096 GstElementClass *oclass;
1097 /* FIXME : this is needed for glib2 */
1099 GstElement *element;
1101 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
1103 element = GST_ELEMENT (object);
1105 oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
1107 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
1109 if (oclass->elementfactory != NULL) {
1110 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
1112 xmlNewChild (parent, NULL, "type", GST_OBJECT_NAME (factory));
1113 xmlNewChild (parent, NULL, "version", factory->details->version);
1116 /* if (element->manager) */
1117 /* xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager)); */
1119 /* FIXME FIXME FIXME! */
1120 /* output all args to the element */
1122 type = G_OBJECT_TYPE (element);
1123 while (type != G_TYPE_INVALID) {
1128 args = gtk_object_query_args (type, &flags, &num_args);
1130 for (i=0; i<num_args; i++) {
1131 if ((args[i].type > G_TYPE_NONE) &&
1132 (flags[i] & GTK_ARG_READABLE)) {
1134 gtk_object_getv (G_OBJECT (element), 1, &args[i]);
1135 arg = xmlNewChild (parent, NULL, "arg", NULL);
1136 xmlNewChild (arg, NULL, "name", args[i].name);
1137 switch (args[i].type) {
1139 xmlNewChild (arg, NULL, "value",
1140 g_strdup_printf ("%c", G_VALUE_CHAR (args[i])));
1143 xmlNewChild (arg, NULL, "value",
1144 g_strdup_printf ("%d", G_VALUE_UCHAR (args[i])));
1146 case G_TYPE_BOOLEAN:
1147 xmlNewChild (arg, NULL, "value",
1148 G_VALUE_BOOL (args[i]) ? "true" : "false");
1151 xmlNewChild (arg, NULL, "value",
1152 g_strdup_printf ("%d", G_VALUE_INT (args[i])));
1155 xmlNewChild (arg, NULL, "value",
1156 g_strdup_printf ("%ld", G_VALUE_LONG (args[i])));
1159 xmlNewChild (arg, NULL, "value",
1160 g_strdup_printf ("%lu", G_VALUE_ULONG (args[i])));
1163 xmlNewChild (arg, NULL, "value",
1164 g_strdup_printf ("%f", G_VALUE_FLOAT (args[i])));
1167 xmlNewChild (arg, NULL, "value",
1168 g_strdup_printf ("%g", G_VALUE_DOUBLE (args[i])));
1171 xmlNewChild (arg, NULL, "value", G_VALUE_STRING (args[i]));
1174 if (args[i].type == GST_TYPE_FILENAME) {
1175 xmlNewChild (arg, NULL, "value", G_VALUE_STRING (args[i]));
1181 type = gtk_type_parent (type);
1185 pads = GST_ELEMENT_PADS (element);
1188 GstPad *pad = GST_PAD (pads->data);
1189 /* figure out if it's a direct pad or a ghostpad */
1190 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
1191 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
1192 gst_object_save_thyself (GST_OBJECT (pad), padtag);
1194 pads = g_list_next (pads);
1201 * gst_element_restore_thyself:
1202 * @self: the xml node
1203 * @parent: the parent of this object when it's loaded
1205 * Load the element from the XML description
1207 * Returns: the new element
1210 gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
1212 xmlNodePtr children = self->xmlChildrenNode;
1213 GstElement *element;
1214 GstObjectClass *oclass;
1215 guchar *name = NULL;
1216 guchar *value = NULL;
1217 guchar *type = NULL;
1219 /* first get the needed tags to construct the element */
1221 if (!strcmp (children->name, "name")) {
1222 name = xmlNodeGetContent (children);
1223 } else if (!strcmp (children->name, "type")) {
1224 type = xmlNodeGetContent (children);
1226 children = children->next;
1228 g_return_val_if_fail (name != NULL, NULL);
1229 g_return_val_if_fail (type != NULL, NULL);
1231 GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
1233 element = gst_elementfactory_make (type, name);
1235 g_return_val_if_fail (element != NULL, NULL);
1237 /* ne need to set the parent on this object bacause the pads */
1238 /* will go through the hierarchy to connect to thier peers */
1240 gst_object_set_parent (GST_OBJECT (element), parent);
1242 /* we have the element now, set the arguments */
1243 children = self->xmlChildrenNode;
1246 if (!strcmp (children->name, "arg")) {
1247 xmlNodePtr child = children->xmlChildrenNode;
1250 if (!strcmp (child->name, "name")) {
1251 name = xmlNodeGetContent (child);
1253 else if (!strcmp (child->name, "value")) {
1254 value = xmlNodeGetContent (child);
1256 child = child->next;
1258 gst_util_set_object_arg ((GObject *)G_OBJECT (element), name, value);
1260 children = children->next;
1262 /* we have the element now, set the pads */
1263 children = self->xmlChildrenNode;
1266 if (!strcmp (children->name, "pad")) {
1267 gst_pad_load_and_connect (children, GST_OBJECT (element));
1269 children = children->next;
1272 oclass = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS(element));
1273 if (oclass->restore_thyself)
1274 (oclass->restore_thyself) (GST_OBJECT (element), self);
1277 gst_object_unparent (GST_OBJECT (element));
1279 gst_class_signal_emit_by_name (GST_OBJECT (element), "object_loaded", self);
1283 #endif /* GST_DISABLE_LOADSAVE */
1286 * gst_element_yield:
1287 * @element: Element to yield
1289 * Request a yield operation for the child. The scheduler will typically
1290 * give control to another element.
1293 gst_element_yield (GstElement *element)
1295 if (GST_ELEMENT_SCHED (element)) {
1296 gst_scheduler_yield (GST_ELEMENT_SCHED (element), element);
1301 * gst_element_interrupt:
1302 * @element: Element to interrupt
1304 * Request the scheduler of this element to interrupt the execution of
1305 * this element and scheduler another one.
1307 * Returns: a boolean indicating that the child should exit its chain/loop/get
1308 * function ASAP, depending on the scheduler implementation.
1311 gst_element_interrupt (GstElement *element)
1313 if (GST_ELEMENT_SCHED (element)) {
1314 return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
1321 * gst_element_set_sched:
1322 * @element: Element to set manager of.
1323 * @sched: @GstScheduler to set.
1325 * Sets the scheduler of the element. For internal use only, unless you're
1326 * writing a new bin subclass.
1329 gst_element_set_sched (GstElement *element,
1330 GstScheduler *sched)
1332 g_return_if_fail (GST_IS_ELEMENT (element));
1334 GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
1336 element->sched = sched;
1340 * gst_element_get_sched:
1341 * @element: Element to get manager of.
1343 * Returns the scheduler of the element.
1345 * Returns: Element's scheduler
1348 gst_element_get_sched (GstElement *element)
1350 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
1352 return element->sched;
1356 * gst_element_set_loop_function:
1357 * @element: Element to set loop function of.
1358 * @loop: Pointer to loop function.
1360 * This sets the loop function for the element. The function pointed to
1361 * can deviate from the GstElementLoopFunction definition in type of
1364 * NOTE: in order for this to take effect, the current loop function *must*
1365 * exit. Assuming the loop function itself is the only one who will cause
1366 * a new loopfunc to be assigned, this should be no problem.
1369 gst_element_set_loop_function(GstElement *element,
1370 GstElementLoopFunction loop)
1372 g_return_if_fail (GST_IS_ELEMENT (element));
1374 /* set the loop function */
1375 element->loopfunc = loop;
1377 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1378 GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
1382 * gst_element_set_eos:
1383 * @element: element to set to the EOS state
1385 * Perform the actions needed to bring the element in the EOS state.
1388 gst_element_set_eos (GstElement *element)
1390 g_return_if_fail (GST_IS_ELEMENT (element));
1392 GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s\n", GST_OBJECT_NAME (element));
1394 gst_element_set_state (element, GST_STATE_PAUSED);
1396 g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
1401 * gst_element_statename:
1402 * @state: The state to get the name of
1404 * Gets a string representing the given state.
1406 * Returns: a string with the statename.
1409 gst_element_statename (GstElementState state)
1412 #ifdef GST_DEBUG_COLOR
1413 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1414 case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
1415 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
1416 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
1417 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
1418 default: return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
1420 case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1421 case GST_STATE_NULL: return "NULL";break;
1422 case GST_STATE_READY: return "READY";break;
1423 case GST_STATE_PLAYING: return "PLAYING";break;
1424 case GST_STATE_PAUSED: return "PAUSED";break;
1425 default: return "UNKNOWN!";
1432 gst_element_populate_std_props (GObjectClass * klass,
1433 const char *prop_name, guint arg_id, GParamFlags flags)
1435 GQuark prop_id = g_quark_from_string (prop_name);
1438 static GQuark fd_id = 0;
1439 static GQuark blocksize_id;
1440 static GQuark bytesperread_id;
1441 static GQuark dump_id;
1442 static GQuark filesize_id;
1443 static GQuark mmapsize_id;
1444 static GQuark location_id;
1445 static GQuark offset_id;
1446 static GQuark silent_id;
1447 static GQuark touch_id;
1450 fd_id = g_quark_from_static_string ("fd");
1451 blocksize_id = g_quark_from_static_string ("blocksize");
1452 bytesperread_id = g_quark_from_static_string ("bytesperread");
1453 dump_id = g_quark_from_static_string ("dump");
1454 filesize_id = g_quark_from_static_string ("filesize");
1455 mmapsize_id = g_quark_from_static_string ("mmapsize");
1456 location_id = g_quark_from_static_string ("location");
1457 offset_id = g_quark_from_static_string ("offset");
1458 silent_id = g_quark_from_static_string ("silent");
1459 touch_id = g_quark_from_static_string ("touch");
1462 if (prop_id == fd_id) {
1463 pspec = g_param_spec_int ("fd", "File-descriptor",
1464 "File-descriptor for the file being read",
1465 0, G_MAXINT, 0, flags);
1467 else if (prop_id == blocksize_id) {
1468 pspec = g_param_spec_ulong ("blocksize", "Block Size",
1469 "Block size to read per buffer",
1470 0, G_MAXULONG, 4096, flags);
1473 else if (prop_id == bytesperread_id) {
1474 pspec = g_param_spec_int ("bytesperread", "bytesperread",
1476 G_MININT, G_MAXINT, 0, flags);
1479 else if (prop_id == dump_id) {
1480 pspec = g_param_spec_boolean ("dump", "dump", "dump", FALSE, flags);
1483 else if (prop_id == filesize_id) {
1484 pspec = g_param_spec_int64 ("filesize", "File Size",
1485 "Size of the file being read",
1486 0, G_MAXINT64, 0, flags);
1489 else if (prop_id == mmapsize_id) {
1490 pspec = g_param_spec_ulong ("mmapsize", "mmap() Block Size",
1491 "Size in bytes of mmap()d regions",
1492 0, G_MAXULONG, 4 * 1048576, flags);
1495 else if (prop_id == location_id) {
1496 pspec = g_param_spec_string ("location", "File Location",
1497 "Location of the file to read",
1501 else if (prop_id == offset_id) {
1502 pspec = g_param_spec_int64 ("offset", "File Offset",
1503 "Byte offset of current read pointer",
1504 0, G_MAXINT64, 0, flags);
1507 else if (prop_id == silent_id) {
1508 pspec = g_param_spec_boolean ("silent", "silent", "silent",
1512 else if (prop_id == touch_id) {
1513 pspec = g_param_spec_boolean ("touch", "Touch read data",
1514 "Touch data to force disk read before "
1515 "push ()", TRUE, flags);
1518 g_warning ("Unknown - 'standard' property '%s' id %d from klass %s",
1519 prop_name, arg_id, g_type_name (G_OBJECT_CLASS_TYPE (klass)));
1524 g_object_class_install_property (klass, arg_id, pspec);
1529 * gst_element_install_std_props:
1530 * @klass: the class to add the properties to
1531 * @first_name: the first in a NULL terminated
1532 * 'name', 'id', 'flags' triplet list.
1533 * @...: the triplet list
1535 * Add a list of standardized properties with types to the @klass.
1536 * the id is for the property switch in your get_prop method, and
1537 * the flags determine readability / writeability.
1540 gst_element_install_std_props (GstElementClass * klass, const char *first_name, ...)
1546 g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
1548 va_start (args, first_name);
1553 int arg_id = va_arg (args, int);
1554 int flags = va_arg (args, int);
1556 gst_element_populate_std_props ((GObjectClass *) klass, name, arg_id, flags);
1558 name = va_arg (args, char *);