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"
31 /* Element signals and args */
47 static void gst_element_class_init (GstElementClass *klass);
48 static void gst_element_init (GstElement *element);
50 static void gst_element_real_destroy (GtkObject *object);
52 static GstElementStateReturn gst_element_change_state (GstElement *element);
54 static xmlNodePtr gst_element_save_thyself (GstObject *object, xmlNodePtr parent);
56 static GstObjectClass *parent_class = NULL;
57 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
59 GtkType gst_element_get_type(void) {
60 static GtkType element_type = 0;
63 static const GtkTypeInfo element_info = {
66 sizeof(GstElementClass),
67 (GtkClassInitFunc)gst_element_class_init,
68 (GtkObjectInitFunc)gst_element_init,
71 (GtkClassInitFunc)NULL,
73 element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
79 gst_element_class_init (GstElementClass *klass)
81 GtkObjectClass *gtkobject_class;
82 GstObjectClass *gstobject_class;
84 gtkobject_class = (GtkObjectClass*) klass;
85 gstobject_class = (GstObjectClass*) klass;
87 parent_class = gtk_type_class(GST_TYPE_OBJECT);
89 gst_element_signals[STATE_CHANGE] =
90 gtk_signal_new ("state_change", GTK_RUN_LAST, gtkobject_class->type,
91 GTK_SIGNAL_OFFSET (GstElementClass, state_change),
92 gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1,
94 gst_element_signals[NEW_PAD] =
95 gtk_signal_new ("new_pad", GTK_RUN_LAST, gtkobject_class->type,
96 GTK_SIGNAL_OFFSET (GstElementClass, new_pad),
97 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
99 gst_element_signals[NEW_GHOST_PAD] =
100 gtk_signal_new ("new_ghost_pad", GTK_RUN_LAST, gtkobject_class->type,
101 GTK_SIGNAL_OFFSET (GstElementClass, new_ghost_pad),
102 gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
104 gst_element_signals[ERROR] =
105 gtk_signal_new ("error", GTK_RUN_LAST, gtkobject_class->type,
106 GTK_SIGNAL_OFFSET (GstElementClass, error),
107 gtk_marshal_NONE__STRING, GTK_TYPE_NONE,1,
109 gst_element_signals[EOS] =
110 gtk_signal_new ("eos", GTK_RUN_LAST, gtkobject_class->type,
111 GTK_SIGNAL_OFFSET (GstElementClass,eos),
112 gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
115 gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
117 gtkobject_class->destroy = gst_element_real_destroy;
119 gstobject_class->save_thyself = gst_element_save_thyself;
121 klass->change_state = gst_element_change_state;
122 klass->elementfactory = NULL;
126 gst_element_init (GstElement *element)
128 element->current_state = GST_STATE_NULL;
129 element->pending_state = -1;
130 element->numpads = 0;
131 element->numsrcpads = 0;
132 element->numsinkpads = 0;
133 element->pads = NULL;
134 element->loopfunc = NULL;
135 element->threadstate = NULL;
141 * Create a new element. Should never be used, as it does no good.
143 * Returns: new element
146 gst_element_new(void)
148 return GST_ELEMENT (gtk_type_new (GST_TYPE_ELEMENT));
152 * gst_element_set_name:
153 * @element: GstElement to set name of
154 * @name: new name of element
156 * Set the name of the element, getting rid of the old name if there was
160 gst_element_set_name (GstElement *element, const gchar *name)
162 g_return_if_fail (element != NULL);
163 g_return_if_fail (GST_IS_ELEMENT (element));
164 g_return_if_fail (name != NULL);
166 gst_object_set_name (GST_OBJECT (element), name);
170 * gst_element_get_name:
171 * @element: GstElement to get name of
173 * Get the name of the element.
175 * Returns: name of the element
178 gst_element_get_name (GstElement *element)
180 g_return_val_if_fail (element != NULL, NULL);
181 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
183 return GST_OBJECT_NAME (element);
187 * gst_element_set_parent:
188 * @element: GstElement to set parent of
189 * @parent: new parent of the object
191 * Set the parent of the element.
194 gst_element_set_parent (GstElement *element, GstObject *parent)
196 g_return_if_fail (element != NULL);
197 g_return_if_fail (GST_IS_ELEMENT (element));
198 g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
199 g_return_if_fail (parent != NULL);
200 g_return_if_fail (GTK_IS_OBJECT (parent));
201 g_return_if_fail ((gpointer)element != (gpointer)parent);
203 gst_object_set_parent (GST_OBJECT (element), parent);
207 * gst_element_get_parent:
208 * @element: GstElement to get the parent of
210 * Get the parent of the element.
212 * Returns: parent of the element
215 gst_element_get_parent (GstElement *element)
217 g_return_val_if_fail (element != NULL, NULL);
218 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
220 return GST_OBJECT_PARENT (element);
224 * gst_element_add_pad:
225 * @element: element to add pad to
228 * Add a pad (connection point) to the element, setting the parent of the
229 * pad to the element (and thus adding a reference).
232 gst_element_add_pad (GstElement *element, GstPad *pad)
234 g_return_if_fail (element != NULL);
235 g_return_if_fail (GST_IS_ELEMENT (element));
236 g_return_if_fail (pad != NULL);
237 g_return_if_fail (GST_IS_PAD (pad));
239 /* set the pad's parent */
240 GST_DEBUG (0,"setting parent of pad '%s'(%p) to '%s'(%p)\n",
241 GST_PAD_NAME (pad), pad, GST_ELEMENT_NAME (element), element);
242 gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
244 /* add it to the list */
245 element->pads = g_list_append (element->pads, pad);
247 if (gst_pad_get_direction (pad) == GST_PAD_SRC)
248 element->numsrcpads++;
250 element->numsinkpads++;
252 /* emit the NEW_PAD signal */
253 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad);
257 * gst_element_add_ghost_pad:
258 * @element: element to add ghost pad to
259 * @pad: pad from which the new ghost pad will be created
260 * @name: name of the new ghost pad
262 * Create a ghost pad from the given pad, and add it to the list of pads
266 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
270 g_return_if_fail (element != NULL);
271 g_return_if_fail (GST_IS_ELEMENT (element));
272 g_return_if_fail (pad != NULL);
273 g_return_if_fail (GST_IS_PAD (pad));
275 GST_DEBUG(0,"creating new ghost pad called %s, from pad %s:%s\n",name,GST_DEBUG_PAD_NAME(pad));
276 ghostpad = gst_ghost_pad_new (name, pad);
278 /* add it to the list */
279 GST_DEBUG(0,"adding ghost pad %s to element %s\n", name, GST_ELEMENT_NAME (element));
280 element->pads = g_list_append (element->pads, ghostpad);
282 // set the parent of the ghostpad
283 gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
285 GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
287 /* emit the NEW_GHOST_PAD signal */
288 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
292 * gst_element_remove_ghost_pad:
293 * @element: element to remove the ghost pad from
294 * @pad: ghost pad to remove
296 * removes a ghost pad from an element
300 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
302 g_return_if_fail (element != NULL);
303 g_return_if_fail (GST_IS_ELEMENT (element));
304 g_return_if_fail (pad != NULL);
305 g_return_if_fail (GST_IS_PAD (pad));
307 // FIXME this is redundant?
312 * gst_element_get_pad:
313 * @element: element to find pad of
314 * @name: name of pad to retrieve
316 * Retrieve a pad from the element by name.
318 * Returns: requested pad if found, otherwise NULL.
321 gst_element_get_pad (GstElement *element, const gchar *name)
325 g_return_val_if_fail (element != NULL, NULL);
326 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
327 g_return_val_if_fail (name != NULL, NULL);
329 // if there aren't any pads, well, we're not likely to find one
330 if (!element->numpads)
333 GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
334 name, GST_ELEMENT_NAME (element));
336 // look through the list, matching by name
337 walk = element->pads;
339 GstPad *pad = GST_PAD(walk->data);
340 if (!strcmp (gst_object_get_name (GST_OBJECT(pad)), name)) {
341 GST_DEBUG(GST_CAT_ELEMENT_PADS,"found pad '%s'\n",name);
344 walk = g_list_next (walk);
347 GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name);
352 * gst_element_get_pad_list:
353 * @element: element to get pads of
355 * Retrieve a list of the pads associated with the element.
357 * Returns: GList of pads
360 gst_element_get_pad_list (GstElement *element)
362 g_return_val_if_fail (element != NULL, NULL);
363 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
365 /* return the list of pads */
366 return element->pads;
370 * gst_element_get_padtemplate_list:
371 * @element: element to get padtemplates of
373 * Retrieve a list of the padtemplates associated with the element.
375 * Returns: GList of padtemplates
378 gst_element_get_padtemplate_list (GstElement *element)
380 GstElementClass *oclass;
382 g_return_val_if_fail (element != NULL, NULL);
383 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
385 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
387 if (oclass->elementfactory == NULL) return NULL;
389 /* return the list of pads */
390 return oclass->elementfactory->padtemplates;
394 * gst_element_get_padtemplate_by_name:
395 * @element: element to get padtemplate of
396 * @name: the name of the padtemplate to get.
398 * Retrieve a padtemplate from this element with the
401 * Returns: the padtemplate with the given name
404 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
408 g_return_val_if_fail (element != NULL, NULL);
409 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
410 g_return_val_if_fail (name != NULL, NULL);
412 padlist = gst_element_get_padtemplate_list (element);
415 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
417 if (!strcmp (padtempl->name_template, name))
420 padlist = g_list_next (padlist);
427 * gst_element_get_padtemplate_by_compatible:
428 * @element: element to get padtemplate of
429 * @templ: a template to find a compatible template for
431 * Generate a padtemplate for this element compatible with the given
432 * template, ie able to link to it.
434 * Returns: the padtemplate
436 static GstPadTemplate*
437 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
439 GstPadTemplate *newtempl = NULL;
442 GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n");
444 g_return_val_if_fail (element != NULL, NULL);
445 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
446 g_return_val_if_fail (compattempl != NULL, NULL);
448 padlist = gst_element_get_padtemplate_list (element);
451 GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
452 gboolean compat = FALSE;
456 // Check direction (must be opposite)
459 GST_DEBUG(0,"checking direction and caps\n");
460 if (padtempl->direction == GST_PAD_SRC &&
461 compattempl->direction == GST_PAD_SINK) {
462 GST_DEBUG(0,"compatible direction: found src pad template\n");
463 compat = gst_caps_list_check_compatibility(padtempl->caps,
465 GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
466 } else if (padtempl->direction == GST_PAD_SINK &&
467 compattempl->direction == GST_PAD_SRC) {
468 GST_DEBUG(0,"compatible direction: found sink pad template\n");
469 compat = gst_caps_list_check_compatibility(compattempl->caps,
471 GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
479 padlist = g_list_next (padlist);
486 gst_element_request_pad (GstElement *element, GstPadTemplate *templ)
488 GstPad *newpad = NULL;
489 GstElementClass *oclass;
491 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
492 if (oclass->request_new_pad)
493 newpad = (oclass->request_new_pad)(element, templ);
499 * gst_element_request_compatible_pad:
500 * @element: element to request a new pad from
501 * @templ: a pad template to which the new pad should be able to connect
503 * Request a new pad from the element. The template will
504 * be used to decide what type of pad to create. This function
505 * is typically used for elements with a padtemplate with presence
508 * Returns: the new pad that was created.
511 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
513 GstPadTemplate *templ_new;
516 g_return_val_if_fail (element != NULL, NULL);
517 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
518 g_return_val_if_fail (templ != NULL, NULL);
520 templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
521 if (templ_new != NULL)
522 pad = gst_element_request_pad (element, templ_new);
528 * gst_element_request_pad_by_name:
529 * @element: element to request a new pad from
530 * @name: the name of the padtemplate to use.
532 * Request a new pad from the element. The name argument will
533 * be used to decide what padtemplate to use. This function
534 * is typically used for elements with a padtemplate with presence
537 * Returns: the new pad that was created.
540 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
542 GstPadTemplate *templ;
545 g_return_val_if_fail (element != NULL, NULL);
546 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
547 g_return_val_if_fail (name != NULL, NULL);
549 templ = gst_element_get_padtemplate_by_name (element, name);
550 g_return_val_if_fail (templ != NULL, NULL);
552 pad = gst_element_request_pad (element, templ);
558 * gst_element_connect:
559 * @src: element containing source pad
560 * @srcpadname: name of pad in source element
561 * @dest: element containing destination pad
562 * @destpadname: name of pad in destination element
564 * Connect the two named pads of the source and destination elements.
565 * Side effect is that if one of the pads has no parent, it becomes a
566 * child of the parent of the other element. If they have different
567 * parents, the connection fails.
570 gst_element_connect (GstElement *src, const gchar *srcpadname,
571 GstElement *dest, const gchar *destpadname)
573 GstPad *srcpad,*destpad;
574 GstObject *srcparent,*destparent;
576 g_return_if_fail (src != NULL);
577 g_return_if_fail (GST_IS_ELEMENT(src));
578 g_return_if_fail (srcpadname != NULL);
579 g_return_if_fail (dest != NULL);
580 g_return_if_fail (GST_IS_ELEMENT(dest));
581 g_return_if_fail (destpadname != NULL);
583 /* obtain the pads requested */
584 srcpad = gst_element_get_pad (src, srcpadname);
585 if (srcpad == NULL) {
586 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
589 destpad = gst_element_get_pad (dest, destpadname);
590 if (srcpad == NULL) {
591 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
595 /* find the parent elements of each element */
596 srcparent = gst_object_get_parent (GST_OBJECT (src));
597 destparent = gst_object_get_parent (GST_OBJECT (dest));
599 /* have to make sure that they have the same parents... */
601 if (srcparent != destparent) {
602 GST_ERROR_OBJECT(srcparent,destparent,"%s and %s have different parents",
603 GST_ELEMENT_NAME (src),GST_ELEMENT_NAME (dest));
608 /* we're satisified they can be connected, let's do it */
609 gst_pad_connect(srcpad,destpad);
613 * gst_element_disconnect:
614 * @src: element containing source pad
615 * @srcpadname: name of pad in source element
616 * @dest: element containing destination pad
617 * @destpadname: name of pad in destination element
619 * Disconnect the two named pads of the source and destination elements.
622 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
623 GstElement *dest, const gchar *destpadname)
625 GstPad *srcpad,*destpad;
627 g_return_if_fail (src != NULL);
628 g_return_if_fail (GST_IS_ELEMENT(src));
629 g_return_if_fail (srcpadname != NULL);
630 g_return_if_fail (dest != NULL);
631 g_return_if_fail (GST_IS_ELEMENT(dest));
632 g_return_if_fail (destpadname != NULL);
634 /* obtain the pads requested */
635 srcpad = gst_element_get_pad (src, srcpadname);
636 if (srcpad == NULL) {
637 GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
640 destpad = gst_element_get_pad (dest, destpadname);
641 if (srcpad == NULL) {
642 GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
646 /* we're satisified they can be disconnected, let's do it */
647 gst_pad_disconnect(srcpad,destpad);
652 * @element: Element with the error
653 * @error: String describing the error
655 * This function is used internally by elements to signal an error
656 * condition. It results in the "error" signal.
659 gst_element_error (GstElement *element, const gchar *error)
661 g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
663 /* FIXME: this is not finished!!! */
665 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[ERROR], error);
670 * gst_element_set_state:
671 * @element: element to change state of
672 * @state: new element state
674 * Sets the state of the element. This function will only set
675 * the elements pending state.
677 * Returns: whether or not the state was successfully set.
680 gst_element_set_state (GstElement *element, GstElementState state)
682 GstElementClass *oclass;
683 GstElementState curpending;
684 GstElementStateReturn return_val = GST_STATE_SUCCESS;
686 // g_print("gst_element_set_state(\"%s\",%08lx)\n",
687 // element->name,state);
689 g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
690 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
692 /* start with the current state */
693 curpending = GST_STATE(element);
695 /* loop until the final requested state is set */
696 while (GST_STATE(element) != state) {
697 /* move the curpending state in the correct direction */
698 if (curpending < state) curpending<<=1;
701 /* set the pending state variable */
702 // FIXME: should probably check to see that we don't already have one
703 GST_STATE_PENDING (element) = curpending;
705 /* call the state change function so it can set the state */
706 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
707 if (oclass->change_state)
708 return_val = (oclass->change_state)(element);
710 /* if that outright didn't work, we need to bail right away */
711 /* NOTE: this will bail on ASYNC as well! */
712 if (return_val == GST_STATE_FAILURE) {
713 // GST_DEBUG (0,"have async return from '%s'\n",GST_ELEMENT_NAME (element));
718 /* this is redundant, really, it will always return SUCCESS */
723 * gst_element_get_factory:
724 * @element: element to request the factory
726 * Retrieves the factory that was used to create this element
728 * Returns: the factory used for creating this element
731 gst_element_get_factory (GstElement *element)
733 GstElementClass *oclass;
735 g_return_val_if_fail (element != NULL, NULL);
736 g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
738 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
740 return oclass->elementfactory;
744 * gst_element_change_state:
745 * @element: element to change state of
747 * Changes the state of the element, but more importantly fires off a signal
748 * indicating the new state.
749 * The element will have no pending states anymore.
751 * Returns: whether or not the state change was successfully set.
753 GstElementStateReturn
754 gst_element_change_state (GstElement *element)
756 g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
757 g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
759 // g_print("gst_element_change_state(\"%s\",%d)\n",
760 // element->name,state);
762 GST_STATE (element) = GST_STATE_PENDING (element);
763 GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
765 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
766 GST_STATE (element));
771 gst_element_real_destroy (GtkObject *object)
773 GstElement *element = GST_ELEMENT (object);
777 // g_print("in gst_element_real_destroy()\n");
779 pads = element->pads;
781 pad = GST_PAD (pads->data);
782 gst_pad_destroy (pad);
783 pads = g_list_next (pads);
786 g_list_free (element->pads);
790 static gchar *_gst_element_type_names[] = {
807 * gst_element_save_thyself:
808 * @element: GstElement to save
809 * @parent: the xml parent node
811 * Saves the element as part of the given XML structure
813 * Returns: the new xml node
816 gst_element_save_thyself (GstObject *object,
820 GstElementClass *oclass;
824 g_return_val_if_fail (object != NULL, parent);
825 g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
826 g_return_val_if_fail (parent != NULL, parent);
828 element = GST_ELEMENT (object);
830 oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
832 xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
834 if (oclass->elementfactory != NULL) {
835 GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
837 xmlNewChild (parent, NULL, "type", factory->name);
838 xmlNewChild (parent, NULL, "version", factory->details->version);
841 // output all args to the element
842 type = GTK_OBJECT_TYPE (element);
843 while (type != GTK_TYPE_INVALID) {
848 args = gtk_object_query_args (type, &flags, &num_args);
850 for (i=0; i<num_args; i++) {
851 if ((args[i].type > GTK_TYPE_NONE) &&
852 (flags[i] & GTK_ARG_READABLE)) {
854 gtk_object_getv (GTK_OBJECT (element), 1, &args[i]);
855 arg = xmlNewChild (parent, NULL, "arg", NULL);
856 xmlNewChild (arg, NULL, "name", args[i].name);
857 switch (args[i].type) {
859 xmlNewChild (arg, NULL, "value",
860 g_strdup_printf ("%c", GTK_VALUE_CHAR (args[i])));
863 xmlNewChild (arg, NULL, "value",
864 g_strdup_printf ("%d", GTK_VALUE_UCHAR (args[i])));
867 xmlNewChild (arg, NULL, "value",
868 GTK_VALUE_BOOL (args[i]) ? "true" : "false");
871 xmlNewChild (arg, NULL, "value",
872 g_strdup_printf ("%d", GTK_VALUE_INT (args[i])));
875 xmlNewChild (arg, NULL, "value",
876 g_strdup_printf ("%ld", GTK_VALUE_LONG (args[i])));
879 xmlNewChild (arg, NULL, "value",
880 g_strdup_printf ("%lu", GTK_VALUE_ULONG (args[i])));
883 xmlNewChild (arg, NULL, "value",
884 g_strdup_printf ("%f", GTK_VALUE_FLOAT (args[i])));
886 case GTK_TYPE_DOUBLE:
887 xmlNewChild (arg, NULL, "value",
888 g_strdup_printf ("%g", GTK_VALUE_DOUBLE (args[i])));
890 case GTK_TYPE_STRING:
891 xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
894 if (args[i].type == GST_TYPE_FILENAME) {
895 xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
901 type = gtk_type_parent (type);
904 pads = element->pads;
906 GstPad *pad = GST_PAD (pads->data);
907 xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
908 // figure out if it's a direct pad or a ghostpad
909 if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element)
910 gst_object_save_thyself (GST_OBJECT (pad), padtag);
911 pads = g_list_next (pads);
918 * gst_element_load_thyself:
919 * @self: the xml node
920 * @parent: the parent of this object when it's loaded
922 * Load the element from the XML description
924 * Returns: the new element
927 gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
929 xmlNodePtr children = self->xmlChildrenNode;
931 GstObjectClass *oclass;
933 guchar *value = NULL;
936 // first get the needed tags to construct the element
938 if (!strcmp (children->name, "name")) {
939 name = g_strdup (xmlNodeGetContent (children));
940 } else if (!strcmp (children->name, "type")) {
941 type = g_strdup (xmlNodeGetContent (children));
943 children = children->next;
945 g_return_val_if_fail (name != NULL, NULL);
946 g_return_val_if_fail (type != NULL, NULL);
948 GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type);
950 element = gst_elementfactory_make (type, name);
952 g_return_val_if_fail (element != NULL, NULL);
954 // ne need to set the parent on this object bacause the pads
955 // will go through the hierarchy to connect to thier peers
957 gst_object_set_parent (GST_OBJECT (element), parent);
959 // we have the element now, set the arguments
960 children = self->xmlChildrenNode;
963 if (!strcmp (children->name, "arg")) {
964 xmlNodePtr child = children->xmlChildrenNode;
967 if (!strcmp (child->name, "name")) {
968 name = g_strdup (xmlNodeGetContent (child));
970 else if (!strcmp (child->name, "value")) {
971 value = g_strdup (xmlNodeGetContent (child));
976 GtkType type = GTK_OBJECT_TYPE (element);
980 result = gtk_object_arg_get_info (type, name, &info);
983 g_print("gstelement: %s\n", result);
985 else if (info->arg_flags & GTK_ARG_WRITABLE) {
986 switch (info->type) {
987 case GTK_TYPE_STRING:
988 gtk_object_set (GTK_OBJECT (element), name, value, NULL);
992 sscanf (value, "%d", &i);
993 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
996 case GTK_TYPE_LONG: {
998 sscanf (value, "%ld", &i);
999 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1002 case GTK_TYPE_ULONG: {
1004 sscanf (value, "%lu", &i);
1005 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1008 case GTK_TYPE_BOOL: {
1010 if (!strcmp ("true", value)) i = TRUE;
1011 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1014 case GTK_TYPE_CHAR: {
1016 sscanf (value, "%c", &i);
1017 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1020 case GTK_TYPE_UCHAR: {
1022 sscanf (value, "%c", &i);
1023 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1026 case GTK_TYPE_FLOAT: {
1028 sscanf (value, "%f", &i);
1029 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1032 case GTK_TYPE_DOUBLE: {
1034 sscanf (value, "%g", (float *)&i);
1035 gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1039 if (info->type == GST_TYPE_FILENAME) {
1040 gtk_object_set (GTK_OBJECT (element), name, value, NULL);
1048 children = children->next;
1050 // we have the element now, set the pads
1051 children = self->xmlChildrenNode;
1054 if (!strcmp (children->name, "pad")) {
1055 gst_pad_load_and_connect (children, GST_OBJECT (element));
1057 children = children->next;
1060 oclass = GST_OBJECT_CLASS (GTK_OBJECT (element)->klass);
1061 if (oclass->restore_thyself)
1062 (oclass->restore_thyself) (GST_OBJECT (element), self);
1065 gst_object_unparent (GST_OBJECT (element));
1067 gst_class_signal_emit_by_name (GST_OBJECT (element), "object_loaded", self);
1073 * gst_element_set_manager:
1074 * @element: Element to set manager of.
1075 * @manager: Element to be the manager.
1077 * Sets the manager of the element. For internal use only, unless you're
1078 * writing a new bin subclass.
1081 gst_element_set_manager (GstElement *element,
1082 GstElement *manager)
1084 element->manager = manager;
1088 * gst_element_get_manager:
1089 * @element: Element to get manager of.
1091 * Returns the manager of the element.
1093 * Returns: Element's manager
1096 gst_element_get_manager (GstElement *element)
1098 return element->manager;
1102 * gst_element_set_loop_function:
1103 * @element: Element to set loop function of.
1104 * @loop: Pointer to loop function.
1106 * This sets the loop function for the element. The function pointed to
1107 * can deviate from the GstElementLoopFunction definition in type of
1110 * NOTE: in order for this to take effect, the current loop function *must*
1111 * exit. Assuming the loop function itself is the only one who will cause
1112 * a new loopfunc to be assigned, this should be no problem.
1115 gst_element_set_loop_function(GstElement *element,
1116 GstElementLoopFunction loop)
1118 /* set the loop function */
1119 element->loopfunc = loop;
1121 /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1122 GST_FLAG_SET(element,GST_ELEMENT_NEW_LOOPFUNC);
1126 * gst_element_signal_eos:
1127 * @element: element to trigger the eos signal of
1129 * Throws the eos signal to indicate that the end of the stream is reached.
1132 gst_element_signal_eos (GstElement *element)
1134 g_return_if_fail (element != NULL);
1135 g_return_if_fail (GST_IS_ELEMENT (element));
1137 gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[EOS]);
1138 GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);