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
24 #include "gst_private.h"
26 #include "gstelement.h"
27 #include "gstextratypes.h"
29 #include "gstscheduler.h"
32 /* Element signals and args */
50 static void gst_element_class_init (GstElementClass *klass);
51 static void gst_element_init (GstElement *element);
53 static void gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id);
54 static void gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id);
56 static void gst_element_shutdown (GtkObject *object);
57 static void gst_element_real_destroy (GtkObject *object);
59 static GstElementStateReturn gst_element_change_state (GstElement *element);
61 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
63 static GstObjectClass *parent_class = NULL;
64 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
66 GtkType gst_element_get_type(void) {
67 static GtkType element_type = 0;
70 static const GtkTypeInfo element_info = {
73 sizeof(GstElementClass),
74 (GtkClassInitFunc)gst_element_class_init,
75 (GtkObjectInitFunc)gst_element_init,
76 (GtkArgSetFunc)gst_element_set_arg,
77 (GtkArgGetFunc)gst_element_get_arg,
78 (GtkClassInitFunc)NULL,
80 element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
86 gst_element_class_init (GstElementClass *klass)
88 GtkObjectClass *gtkobject_class;
89 GstObjectClass *gstobject_class;
91 gtkobject_class = (GtkObjectClass*) klass;
92 gstobject_class = (GstObjectClass*) klass;
94 parent_class = gtk_type_class(GST_TYPE_OBJECT);
96 gst_element_signals[STATE_CHANGE] =
97 gtk_signal_new ("state_change", GTK_RUN_LAST, gtkobject_class->type,
98 GTK_SIGNAL_OFFSET (GstElementClass, state_change),
99 gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1,
101 gst_element_signals[NEW_PAD] =
102 gtk_signal_new ("new_pad", GTK_RUN_LAST, gtkobject_class->type,
103 GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
104 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
106 gst_element_signals[PAD_REMOVED] =
107 gtk_signal_new ("pad_removed", GTK_RUN_LAST, gtkobject_class->type,
108 GTK_SIGNAL_OFFSET (GstElementClass, pad_removed),
109 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
111 gst_element_signals[NEW_GHOST_PAD] =
112 gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
113 GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
114 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
116 gst_element_signals[GHOST_PAD_REMOVED] =
117 gtk_signal_new ("ghost_pad_removed", GTK_RUN_LAST, gtkobject_class->type,
118 GTK_SIGNAL_OFFSET (GstElementClass, ghost_pad_removed),
119 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
121 gst_element_signals[ERROR] =
122 gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
123 GTK_SIGNAL_OFFSET (GstElementClass, error),
124 gtk_marshal_NONE__STRING, GTK_TYPE_NONE,1,
126 gst_element_signals[EOS] =
127 gtk_signal_new ("eos", GTK_RUN_LAST, gtkobject_class->type,
128 GTK_SIGNAL_OFFSET (GstElementClass,eos),
129 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
132 gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
134 gtkobject_class->set_arg = GST_DEBUG_FUNCPTR(gst_element_set_arg);
135 gtkobject_class->get_arg = GST_DEBUG_FUNCPTR(gst_element_get_arg);
136 gtkobject_class->shutdown = GST_DEBUG_FUNCPTR(gst_element_shutdown);
137 gtkobject_class->destroy = GST_DEBUG_FUNCPTR(gst_element_real_destroy);
139 gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_element_save_thyself);
140 gstobject_class->restore_thyself = GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
142 klass->change_state = GST_DEBUG_FUNCPTR(gst_element_change_state);
143 klass->elementfactory = NULL;
147 gst_element_init (GstElement *element)
149 element->current_state = GST_STATE_NULL;
150 element->pending_state = -1;
151 element->numpads = 0;
152 element->numsrcpads = 0;
153 element->numsinkpads = 0;
154 element->pads = NULL;
155 element->loopfunc = NULL;
156 element->threadstate = NULL;
157 element->sched = NULL;
162 gst_element_set_arg (GtkObject *object, GtkArg *arg, guint id)
164 GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
166 GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
169 (oclass->set_arg)(object,arg,id);
171 GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
176 gst_element_get_arg (GtkObject *object, GtkArg *arg, guint id)
178 GstElementClass *oclass = GST_ELEMENT_CLASS (object->klass);
180 GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
183 (oclass->get_arg)(object,arg,id);
185 GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
192 * Create a new element. Should never be used, as it does no good.
194 * Returns: new element
197 gst_element_new(void)
199 return GST_ELEMENT (gtk_type_new (GST_TYPE_ELEMENT));
203 * gst_element_set_name:
204 * @element: GstElement to set name of
205 * @name: new name of element
207 * Set the name of the element, getting rid of the old name if there was
211 gst_element_set_name (GstElement *element, const gchar *name)
213 g_return_if_fail (element != NULL);
214 g_return_if_fail (GST_IS_ELEMENT (element));
215 g_return_if_fail (name != NULL);
217 gst_object_set_name (GST_OBJECT (element), name);
221 * gst_element_get_name:
222 * @element: GstElement to get name of
224 * Get the name of the element.
226 * Returns: name of the element
229 gst_element_get_name (GstElement *element)
231 g_return_val_if_fail (element != NULL, NULL);
232 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
234 return GST_OBJECT_NAME (element);
238 * gst_element_set_parent:
239 * @element: GstElement to set parent of
240 * @parent: new parent of the object
242 * Set the parent of the element.
245 gst_element_set_parent (GstElement *element, GstObject *parent)
247 g_return_if_fail (element != NULL);
248 g_return_if_fail (GST_IS_ELEMENT (element));
249 g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
250 g_return_if_fail (parent != NULL);
251 g_return_if_fail (GTK_IS_OBJECT (parent));
252 g_return_if_fail ((gpointer)element != (gpointer)parent);
254 gst_object_set_parent (GST_OBJECT (element), parent);
258 * gst_element_get_parent:
259 * @element: GstElement to get the parent of
261 * Get the parent of the element.
263 * Returns: parent of the element
266 gst_element_get_parent (GstElement *element)
268 g_return_val_if_fail (element != NULL, NULL);
269 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
271 return GST_OBJECT_PARENT (element);
275 * gst_element_add_pad:
276 * @element: element to add pad to
279 * Add a pad (connection point) to the element, setting the parent of the
280 * pad to the element (and thus adding a reference).
283 gst_element_add_pad (GstElement *element, GstPad *pad)
285 g_return_if_fail (element != NULL);
286 g_return_if_fail (GST_IS_ELEMENT (element));
287 g_return_if_fail (pad != NULL);
288 g_return_if_fail (GST_IS_PAD (pad));
290 // first check to make sure the pad's parent is already set
291 g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
293 // then check to see if there's already a pad by that name here
294 g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
296 /* set the pad's parent */
297 GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
298 GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
299 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
301 /* add it to the list */
302 element->pads = g_list_append (element->pads, pad);
304 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
305 element->numsrcpads++;
307 element->numsinkpads++;
309 /* emit the NEW_PAD signal */
310 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad);
314 * gst_element_remove_pad:
315 * @element: element to remove pad from
316 * @pad: pad to remove
318 * Remove a pad (connection point) from the element,
321 gst_element_remove_pad (GstElement *element, GstPad *pad)
323 g_return_if_fail (element != NULL);
324 g_return_if_fail (GST_IS_ELEMENT (element));
325 g_return_if_fail (pad != NULL);
326 g_return_if_fail (GST_IS_PAD (pad));
328 g_return_if_fail (GST_PAD_PARENT (pad) == element);
330 /* add it to the list */
331 element->pads = g_list_remove (element->pads, pad);
333 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
334 element->numsrcpads--;
336 element->numsinkpads--;
338 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[PAD_REMOVED], pad);
340 gst_object_unparent (GST_OBJECT (pad));
344 * gst_element_add_ghost_pad:
345 * @element: element to add ghost pad to
346 * @pad: pad from which the new ghost pad will be created
347 * @name: name of the new ghost pad
349 * Create a ghost pad from the given pad, and add it to the list of pads
353 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
357 g_return_if_fail (element != NULL);
358 g_return_if_fail (GST_IS_ELEMENT (element));
359 g_return_if_fail (pad != NULL);
360 g_return_if_fail (GST_IS_PAD (pad));
362 // then check to see if there's already a pad by that name here
363 g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
365 GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
366 name,GST_DEBUG_PAD_NAME(pad));
367 ghostpad = gst_ghost_pad_new (name, pad);
369 /* add it to the list */
370 GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
371 name, GST_ELEMENT_NAME (element));
372 element->pads = g_list_append (element->pads, ghostpad);
374 // set the parent of the ghostpad
375 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
377 GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
379 /* emit the NEW_GHOST_PAD signal */
380 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
384 * gst_element_remove_ghost_pad:
385 * @element: element to remove the ghost pad from
386 * @pad: ghost pad to remove
388 * removes a ghost pad from an element
392 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
394 g_return_if_fail (element != NULL);
395 g_return_if_fail (GST_IS_ELEMENT (element));
396 g_return_if_fail (pad != NULL);
397 g_return_if_fail (GST_IS_PAD (pad));
399 // FIXME this is redundant?
404 * gst_element_get_pad:
405 * @element: element to find pad of
406 * @name: name of pad to retrieve
408 * Retrieve a pad from the element by name.
410 * Returns: requested pad if found, otherwise NULL.
413 gst_element_get_pad (GstElement *element, const gchar *name)
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 (name != NULL, NULL);
421 // if there aren't any pads, well, we're not likely to find one
422 if (!element->numpads)
425 // look through the list, matching by name
426 walk = element->pads;
428 GstPad *pad = GST_PAD(walk->data);
429 if (!strcmp (GST_PAD_NAME(pad), name)) {
430 GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
433 walk = g_list_next (walk);
436 GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
441 * gst_element_get_pad_list:
442 * @element: element to get pads of
444 * Retrieve a list of the pads associated with the element.
446 * Returns: GList of pads
449 gst_element_get_pad_list (GstElement *element)
451 g_return_val_if_fail (element != NULL, NULL);
452 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
454 /* return the list of pads */
455 return element->pads;
459 * gst_element_get_padtemplate_list:
460 * @element: element to get padtemplates of
462 * Retrieve a list of the padtemplates associated with the element.
464 * Returns: GList of padtemplates
467 gst_element_get_padtemplate_list (GstElement *element)
469 GstElementClass *oclass;
471 g_return_val_if_fail (element != NULL, NULL);
472 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
474 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
476 if (oclass->elementfactory == NULL) return NULL;
478 /* return the list of pads */
479 return oclass->elementfactory->padtemplates;
483 * gst_element_get_padtemplate_by_name:
484 * @element: element to get padtemplate of
485 * @name: the name of the padtemplate to get.
487 * Retrieve a padtemplate from this element with the
490 * Returns: the padtemplate with the given name
493 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
497 g_return_val_if_fail (element != NULL, NULL);
498 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
499 g_return_val_if_fail (name != NULL, NULL);
501 padlist = gst_element_get_padtemplate_list (element);
504 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
506 if (!strcmp (padtempl->name_template, name))
509 padlist = g_list_next (padlist);
516 * gst_element_get_padtemplate_by_compatible:
517 * @element: element to get padtemplate of
518 * @templ: a template to find a compatible template for
520 * Generate a padtemplate for this element compatible with the given
521 * template, ie able to link to it.
523 * Returns: the padtemplate
525 static GstPadTemplate*
526 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
528 GstPadTemplate *newtempl = NULL;
531 GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
533 g_return_val_if_fail (element != NULL, NULL);
534 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
535 g_return_val_if_fail (compattempl != NULL, NULL);
537 padlist = gst_element_get_padtemplate_list (element);
540 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
541 gboolean compat = FALSE;
545 // Check direction (must be opposite)
548 GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
549 if (padtempl->direction == GST_PAD_SRC &&
550 compattempl->direction == GST_PAD_SINK) {
551 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
552 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
553 GST_PADTEMPLATE_CAPS (compattempl));
554 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
555 } else if (padtempl->direction == GST_PAD_SINK &&
556 compattempl->direction == GST_PAD_SRC) {
557 GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
558 compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
559 GST_PADTEMPLATE_CAPS (padtempl));
560 GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
568 padlist = g_list_next (padlist);
575 gst_element_request_pad (GstElement *element, GstPadTemplate *templ)
577 GstPad *newpad = NULL;
578 GstElementClass *oclass;
580 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
581 if (oclass->request_new_pad)
582 newpad = (oclass->request_new_pad)(element, templ);
588 * gst_element_request_compatible_pad:
589 * @element: element to request a new pad from
590 * @templ: a pad template to which the new pad should be able to connect
592 * Request a new pad from the element. The template will
593 * be used to decide what type of pad to create. This function
594 * is typically used for elements with a padtemplate with presence
597 * Returns: the new pad that was created.
600 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
602 GstPadTemplate *templ_new;
605 g_return_val_if_fail (element != NULL, NULL);
606 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
607 g_return_val_if_fail (templ != NULL, NULL);
609 templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
610 if (templ_new != NULL)
611 pad = gst_element_request_pad (element, templ_new);
617 * gst_element_request_pad_by_name:
618 * @element: element to request a new pad from
619 * @name: the name of the padtemplate to use.
621 * Request a new pad from the element. The name argument will
622 * be used to decide what padtemplate to use. This function
623 * is typically used for elements with a padtemplate with presence
626 * Returns: the new pad that was created.
629 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
631 GstPadTemplate *templ;
634 g_return_val_if_fail (element != NULL, NULL);
635 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
636 g_return_val_if_fail (name != NULL, NULL);
638 templ = gst_element_get_padtemplate_by_name (element, name);
639 g_return_val_if_fail (templ != NULL, NULL);
641 pad = gst_element_request_pad (element, templ);
647 * gst_element_connect:
648 * @src: element containing source pad
649 * @srcpadname: name of pad in source element
650 * @dest: element containing destination pad
651 * @destpadname: name of pad in destination element
653 * Connect the two named pads of the source and destination elements.
654 * Side effect is that if one of the pads has no parent, it becomes a
655 * child of the parent of the other element. If they have different
656 * parents, the connection fails.
659 gst_element_connect (GstElement *src, const gchar *srcpadname,
660 GstElement *dest, const gchar *destpadname)
662 GstPad *srcpad,*destpad;
663 GstObject *srcparent,*destparent;
665 g_return_if_fail (src != NULL);
666 g_return_if_fail (GST_IS_ELEMENT(src));
667 g_return_if_fail (srcpadname != NULL);
668 g_return_if_fail (dest != NULL);
669 g_return_if_fail (GST_IS_ELEMENT(dest));
670 g_return_if_fail (destpadname != NULL);
672 /* obtain the pads requested */
673 srcpad = gst_element_get_pad (src, srcpadname);
674 if (srcpad == NULL) {
675 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
678 destpad = gst_element_get_pad (dest, destpadname);
679 if (srcpad == NULL) {
680 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
684 /* find the parent elements of each element */
685 srcparent = gst_object_get_parent (GST_OBJECT (src));
686 destparent = gst_object_get_parent (GST_OBJECT (dest));
688 /* have to make sure that they have the same parents... */
690 if (srcparent != destparent) {
691 GST_ERROR_OBJECT(srcparent,destparent,"%s and %s have different parents",
692 GST_ELEMENT_NAME (src),GST_ELEMENT_NAME (dest));
697 /* we're satisified they can be connected, let's do it */
698 gst_pad_connect(srcpad,destpad);
702 * gst_element_disconnect:
703 * @src: element containing source pad
704 * @srcpadname: name of pad in source element
705 * @dest: element containing destination pad
706 * @destpadname: name of pad in destination element
708 * Disconnect the two named pads of the source and destination elements.
711 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
712 GstElement *dest, const gchar *destpadname)
714 GstPad *srcpad,*destpad;
716 g_return_if_fail (src != NULL);
717 g_return_if_fail (GST_IS_ELEMENT(src));
718 g_return_if_fail (srcpadname != NULL);
719 g_return_if_fail (dest != NULL);
720 g_return_if_fail (GST_IS_ELEMENT(dest));
721 g_return_if_fail (destpadname != NULL);
723 /* obtain the pads requested */
724 srcpad = gst_element_get_pad (src, srcpadname);
725 if (srcpad == NULL) {
726 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
729 destpad = gst_element_get_pad (dest, destpadname);
730 if (srcpad == NULL) {
731 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
735 /* we're satisified they can be disconnected, let's do it */
736 gst_pad_disconnect(srcpad,destpad);
741 * @element: Element with the error
742 * @error: String describing the error
744 * This function is used internally by elements to signal an error
745 * condition. It results in the "error" signal.
748 gst_element_error (GstElement *element, const gchar *error)
750 g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
752 /* FIXME: this is not finished!!! */
754 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[ERROR], error);
759 * gst_element_set_state:
760 * @element: element to change state of
761 * @state: new element state
763 * Sets the state of the element. This function will only set
764 * the elements pending state.
766 * Returns: whether or not the state was successfully set.
769 gst_element_set_state (GstElement *element, GstElementState state)
771 GstElementClass *oclass;
772 GstElementState curpending;
773 GstElementStateReturn return_val = GST_STATE_SUCCESS;
775 // g_print("gst_element_set_state(\"%s\",%08lx)\n",
776 // element->name,state);
778 g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
779 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
780 g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
782 GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
783 gst_element_statename(GST_STATE(element)),
784 gst_element_statename(state));
786 /* start with the current state */
787 curpending = GST_STATE(element);
789 /* loop until the final requested state is set */
790 while (GST_STATE(element) != state) {
791 /* move the curpending state in the correct direction */
792 if (curpending < state) curpending<<=1;
795 /* set the pending state variable */
796 // FIXME: should probably check to see that we don't already have one
797 GST_STATE_PENDING (element) = curpending;
798 if (curpending != state)
799 GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
800 gst_element_statename(curpending));
802 /* call the state change function so it can set the state */
803 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
804 if (oclass->change_state)
805 return_val = (oclass->change_state)(element);
807 /* if that outright didn't work, we need to bail right away */
808 /* NOTE: this will bail on ASYNC as well! */
809 if (return_val == GST_STATE_FAILURE) {
810 GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
815 /* this is redundant, really, it will always return SUCCESS */
820 * gst_element_get_factory:
821 * @element: element to request the factory
823 * Retrieves the factory that was used to create this element
825 * Returns: the factory used for creating this element
828 gst_element_get_factory (GstElement *element)
830 GstElementClass *oclass;
832 g_return_val_if_fail (element != NULL, NULL);
833 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
835 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
837 return oclass->elementfactory;
842 * gst_element_change_state:
843 * @element: element to change state of
845 * Changes the state of the element, but more importantly fires off a signal
846 * indicating the new state.
847 * The element will have no pending states anymore.
849 * Returns: whether or not the state change was successfully set.
851 GstElementStateReturn
852 gst_element_change_state (GstElement *element)
854 g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
855 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
857 // GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
858 // gst_element_statename(GST_STATE_PENDING(element)));
860 if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
861 g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
862 if (GST_ELEMENT_PARENT(element))
863 fprintf(stderr,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
864 GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
865 GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
867 else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
868 if (GST_ELEMENT_PARENT(element))
869 fprintf(stderr,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
870 GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
871 GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
874 GST_STATE (element) = GST_STATE_PENDING (element);
875 GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
877 // note: queues' state_change is a special case because it needs to lock
878 // for synchronization (from another thread). since this signal may block
879 // or (worse) make another state change, the queue needs to unlock before
880 // calling. thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
881 // unlocks, then emits this.
882 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
883 GST_STATE (element));
884 return GST_STATE_SUCCESS;
888 gst_element_shutdown (GtkObject *object)
890 GstElement *element = GST_ELEMENT (object);
892 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
894 if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
895 gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
897 if (GTK_OBJECT_CLASS (parent_class)->shutdown)
898 GTK_OBJECT_CLASS (parent_class)->shutdown (object);
902 gst_element_real_destroy (GtkObject *object)
904 GstElement *element = GST_ELEMENT (object);
908 GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
912 orig = pads = g_list_copy (element->pads);
914 pad = GST_PAD (pads->data);
915 //gst_object_destroy (GST_OBJECT (pad));
916 gst_object_ref (GST_OBJECT (pad));
917 gst_element_remove_pad (element, pad);
918 gst_object_unref (GST_OBJECT (pad));
919 pads = g_list_next (pads);
922 g_list_free (element->pads);
923 element->pads = NULL;
926 element->numsrcpads = 0;
927 element->numsinkpads = 0;
929 if (GTK_OBJECT_CLASS (parent_class)->destroy)
930 GTK_OBJECT_CLASS (parent_class)->destroy (object);
934 static gchar *_gst_element_type_names[] = {
951 * gst_element_save_thyself:
952 * @element: GstElement to save
953 * @parent: the xml parent node
955 * Saves the element as part of the given XML structure
957 * Returns: the new xml node
960 gst_element_save_thyself (GstObject *object,
964 GstElementClass *oclass;
968 g_return_val_if_fail (object != NULL, parent);
969 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
970 g_return_val_if_fail (parent != NULL, parent);
972 element = GST_ELEMENT (object);
974 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
976 xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
978 if (oclass->elementfactory != NULL) {
979 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
981 xmlNewChild (parent, NULL, "type", factory->name);
982 xmlNewChild (parent, NULL, "version", factory->details->version);
985 // if (element->manager)
986 // xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
988 // output all args to the element
989 type = GTK_OBJECT_TYPE (element);
990 while (type != GTK_TYPE_INVALID) {
995 args = gtk_object_query_args (type, &flags, &num_args);
997 for (i=0; i<num_args; i++) {
998 if ((args[i].type > GTK_TYPE_NONE) &&
999 (flags[i] & GTK_ARG_READABLE)) {
1001 gtk_object_getv (GTK_OBJECT (element), 1, &args[i]);
1002 arg = xmlNewChild (parent, NULL, "arg", NULL);
1003 xmlNewChild (arg, NULL, "name", args[i].name);
1004 switch (args[i].type) {
1006 xmlNewChild (arg, NULL, "value",
1007 g_strdup_printf ("%c", GTK_VALUE_CHAR (args[i])));
1009 case GTK_TYPE_UCHAR:
1010 xmlNewChild (arg, NULL, "value",
1011 g_strdup_printf ("%d", GTK_VALUE_UCHAR (args[i])));
1014 xmlNewChild (arg, NULL, "value",
1015 GTK_VALUE_BOOL (args[i]) ? "true" : "false");
1018 xmlNewChild (arg, NULL, "value",
1019 g_strdup_printf ("%d", GTK_VALUE_INT (args[i])));
1022 xmlNewChild (arg, NULL, "value",
1023 g_strdup_printf ("%ld", GTK_VALUE_LONG (args[i])));
1025 case GTK_TYPE_ULONG:
1026 xmlNewChild (arg, NULL, "value",
1027 g_strdup_printf ("%lu", GTK_VALUE_ULONG (args[i])));
1029 case GTK_TYPE_FLOAT:
1030 xmlNewChild (arg, NULL, "value",
1031 g_strdup_printf ("%f", GTK_VALUE_FLOAT (args[i])));
1033 case GTK_TYPE_DOUBLE:
1034 xmlNewChild (arg, NULL, "value",
1035 g_strdup_printf ("%g", GTK_VALUE_DOUBLE (args[i])));
1037 case GTK_TYPE_STRING:
1038 xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
1041 if (args[i].type == GST_TYPE_FILENAME) {
1042 xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
1048 type = gtk_type_parent (type);
1051 pads = GST_ELEMENT_PADS (element);
1054 GstPad *pad = GST_PAD (pads->data);
1055 // figure out if it's a direct pad or a ghostpad
1056 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
1057 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
1058 gst_object_save_thyself (GST_OBJECT (pad), padtag);
1060 pads = g_list_next (pads);
1067 * gst_element_restore_thyself:
1068 * @self: the xml node
1069 * @parent: the parent of this object when it's loaded
1071 * Load the element from the XML description
1073 * Returns: the new element
1076 gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
1078 xmlNodePtr children = self->xmlChildrenNode;
1079 GstElement *element;
1080 GstObjectClass *oclass;
1081 guchar *name = NULL;
1082 guchar *value = NULL;
1083 guchar *type = NULL;
1085 // first get the needed tags to construct the element
1087 if (!strcmp (children->name, "name")) {
1088 name = g_strdup (xmlNodeGetContent (children));
1089 } else if (!strcmp (children->name, "type")) {
1090 type = g_strdup (xmlNodeGetContent (children));
1092 children = children->next;
1094 g_return_val_if_fail (name != NULL, NULL);
1095 g_return_val_if_fail (type != NULL, NULL);
1097 GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
1099 element = gst_elementfactory_make (type, name);
1101 g_return_val_if_fail (element != NULL, NULL);
1103 // ne need to set the parent on this object bacause the pads
1104 // will go through the hierarchy to connect to thier peers
1106 gst_object_set_parent (GST_OBJECT (element), parent);
1108 // we have the element now, set the arguments
1109 children = self->xmlChildrenNode;
1112 if (!strcmp (children->name, "arg")) {
1113 xmlNodePtr child = children->xmlChildrenNode;
1116 if (!strcmp (child->name, "name")) {
1117 name = g_strdup (xmlNodeGetContent (child));
1119 else if (!strcmp (child->name, "value")) {
1120 value = g_strdup (xmlNodeGetContent (child));
1122 child = child->next;
1124 gst_util_set_object_arg (GTK_OBJECT (element), name, value);
1126 children = children->next;
1128 // we have the element now, set the pads
1129 children = self->xmlChildrenNode;
1132 if (!strcmp (children->name, "pad")) {
1133 gst_pad_load_and_connect (children, GST_OBJECT (element));
1135 children = children->next;
1138 oclass = GST_OBJECT_CLASS (GTK_OBJECT (element)->klass);
1139 if (oclass->restore_thyself)
1140 (oclass->restore_thyself) (GST_OBJECT (element), self);
1143 gst_object_unparent (GST_OBJECT (element));
1145 gst_class_signal_emit_by_name (GST_OBJECT (element), "object_loaded", self);
1151 * gst_element_set_sched:
1152 * @element: Element to set manager of.
1153 * @sched: @GstSchedule to set.
1155 * Sets the scheduler of the element. For internal use only, unless you're
1156 * writing a new bin subclass.
1159 gst_element_set_sched (GstElement *element,
1162 GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
1163 element->sched = sched;
1167 * gst_element_get_sched:
1168 * @element: Element to get manager of.
1170 * Returns the scheduler of the element.
1172 * Returns: Element's scheduler
1175 gst_element_get_sched (GstElement *element)
1177 return element->sched;
1181 * gst_element_set_loop_function:
1182 * @element: Element to set loop function of.
1183 * @loop: Pointer to loop function.
1185 * This sets the loop function for the element. The function pointed to
1186 * can deviate from the GstElementLoopFunction definition in type of
1189 * NOTE: in order for this to take effect, the current loop function *must*
1190 * exit. Assuming the loop function itself is the only one who will cause
1191 * a new loopfunc to be assigned, this should be no problem.
1194 gst_element_set_loop_function(GstElement *element,
1195 GstElementLoopFunction loop)
1197 /* set the loop function */
1198 element->loopfunc = loop;
1200 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1201 GST_FLAG_SET(element,GST_ELEMENT_NEW_LOOPFUNC);
1205 * gst_element_signal_eos:
1206 * @element: element to trigger the eos signal of
1208 * Throws the eos signal to indicate that the end of the stream is reached.
1211 gst_element_signal_eos (GstElement *element)
1213 g_return_if_fail (element != NULL);
1214 g_return_if_fail (GST_IS_ELEMENT (element));
1216 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[EOS]);
1217 GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
1221 const gchar *gst_element_statename(int state) {
1223 #ifdef GST_DEBUG_COLOR
1224 case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
1225 case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
1226 case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
1227 case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
1228 case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
1229 default: return "\033[01;37;41mUNKNOWN!\033[00m";
1231 case GST_STATE_NONE_PENDING: return "NONE_PENDING";break;
1232 case GST_STATE_NULL: return "NULL";break;
1233 case GST_STATE_READY: return "READY";break;
1234 case GST_STATE_PLAYING: return "PLAYING";break;
1235 case GST_STATE_PAUSED: return "PAUSED";break;
1236 default: return "UNKNOWN!";