This is a megapatch with the following changes:
[platform/upstream/gstreamer.git] / gst / gstelement.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstelement.c: The base element, all elements derive from this
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
25
26 #include "gstelement.h"
27 #include "gstextratypes.h"
28 #include "gstbin.h"
29
30
31 /* Element signals and args */
32 enum {
33   STATE_CHANGE,
34   NEW_PAD,
35   NEW_GHOST_PAD,
36   ERROR,
37   EOS,
38   LAST_SIGNAL
39 };
40
41 enum {
42   ARG_0,
43   /* FILL ME */
44 };
45
46
47 static void                     gst_element_class_init          (GstElementClass *klass);
48 static void                     gst_element_init                (GstElement *element);
49
50 static void                     gst_element_real_destroy        (GtkObject *object);
51
52 static GstElementStateReturn    gst_element_change_state        (GstElement *element);
53
54 static xmlNodePtr               gst_element_save_thyself        (GstObject *object, xmlNodePtr parent);
55
56 static GstObjectClass *parent_class = NULL;
57 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
58
59 GtkType gst_element_get_type(void) {
60   static GtkType element_type = 0;
61
62   if (!element_type) {
63     static const GtkTypeInfo element_info = {
64       "GstElement",
65       sizeof(GstElement),
66       sizeof(GstElementClass),
67       (GtkClassInitFunc)gst_element_class_init,
68       (GtkObjectInitFunc)gst_element_init,
69       (GtkArgSetFunc)NULL,
70       (GtkArgGetFunc)NULL,
71       (GtkClassInitFunc)NULL,
72     };
73     element_type = gtk_type_unique(GST_TYPE_OBJECT,&element_info);
74   }
75   return element_type;
76 }
77
78 static void
79 gst_element_class_init (GstElementClass *klass)
80 {
81   GtkObjectClass *gtkobject_class;
82   GstObjectClass *gstobject_class;
83
84   gtkobject_class = (GtkObjectClass*) klass;
85   gstobject_class = (GstObjectClass*) klass;
86
87   parent_class = gtk_type_class(GST_TYPE_OBJECT);
88
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,
93                     GTK_TYPE_INT);
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,
98                     GST_TYPE_PAD);
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,
103                     GST_TYPE_PAD);
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,
108                     GTK_TYPE_STRING);
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);
113
114
115   gtk_object_class_add_signals (gtkobject_class, gst_element_signals, LAST_SIGNAL);
116
117   gtkobject_class->destroy =            gst_element_real_destroy;
118
119   gstobject_class->save_thyself =       gst_element_save_thyself;
120
121   klass->change_state = gst_element_change_state;
122   klass->elementfactory = NULL;
123 }
124
125 static void
126 gst_element_init (GstElement *element)
127 {
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;
136 }
137
138 /**
139  * gst_element_new:
140  *
141  * Create a new element.  Should never be used, as it does no good.
142  *
143  * Returns: new element
144  */
145 GstElement*
146 gst_element_new(void)
147 {
148   return GST_ELEMENT (gtk_type_new (GST_TYPE_ELEMENT));
149 }
150
151 /**
152  * gst_element_set_name:
153  * @element: GstElement to set name of
154  * @name: new name of element
155  *
156  * Set the name of the element, getting rid of the old name if there was
157  * one.
158  */
159 void
160 gst_element_set_name (GstElement *element, const gchar *name)
161 {
162   g_return_if_fail (element != NULL);
163   g_return_if_fail (GST_IS_ELEMENT (element));
164   g_return_if_fail (name != NULL);
165
166   gst_object_set_name (GST_OBJECT (element), name);
167 }
168
169 /**
170  * gst_element_get_name:
171  * @element: GstElement to get name of
172  *
173  * Get the name of the element.
174  *
175  * Returns: name of the element
176  */
177 const gchar*
178 gst_element_get_name (GstElement *element)
179 {
180   g_return_val_if_fail (element != NULL, NULL);
181   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
182
183   return GST_OBJECT_NAME (element);
184 }
185
186 /**
187  * gst_element_set_parent:
188  * @element: GstElement to set parent of
189  * @name: new parent of the object
190  *
191  * Set the parent of the element.
192  */
193 void
194 gst_element_set_parent (GstElement *element, GstObject *parent)
195 {
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);
202
203   gst_object_set_parent (GST_OBJECT (element), parent);
204 }
205
206 /**
207  * gst_element_get_parent:
208  * @element: GstElement to get the parent of
209  *
210  * Get the parent of the element.
211  *
212  * Returns: parent of the element
213  */
214 GstObject*
215 gst_element_get_parent (GstElement *element)
216 {
217   g_return_val_if_fail (element != NULL, NULL);
218   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
219
220   return GST_OBJECT_PARENT (element);
221 }
222
223 /**
224  * gst_element_add_pad:
225  * @element: element to add pad to
226  * @pad: pad to add
227  *
228  * Add a pad (connection point) to the element, setting the parent of the
229  * pad to the element (and thus adding a reference).
230  */
231 void
232 gst_element_add_pad (GstElement *element, GstPad *pad)
233 {
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));
238
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));
243
244   /* add it to the list */
245   element->pads = g_list_append (element->pads, pad);
246   element->numpads++;
247   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
248     element->numsrcpads++;
249   else
250     element->numsinkpads++;
251
252   /* emit the NEW_PAD signal */
253   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_PAD], pad);
254 }
255
256 /**
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
261  *
262  * Create a ghost pad from the given pad, and add it to the list of pads
263  * for this element.
264  */
265 void
266 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
267 {
268   GstPad *ghostpad;
269
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));
274
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);
277
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);
281   element->numpads++;
282   // set the parent of the ghostpad
283   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
284
285   GST_DEBUG(0,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
286
287   /* emit the NEW_GHOST_PAD signal */
288   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], ghostpad);
289 }
290
291 /**
292  * gst_element_remove_ghost_pad:
293  * @element: element to remove the ghost pad from
294  * @pad: ghost pad to remove
295  *
296  * removes a ghost pad from an element
297  *
298  */
299 void
300 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
301 {
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));
306
307   // FIXME this is redundant?
308 }
309
310
311 /**
312  * gst_element_get_pad:
313  * @element: element to find pad of
314  * @name: name of pad to retrieve
315  *
316  * Retrieve a pad from the element by name.
317  *
318  * Returns: requested pad if found, otherwise NULL.
319  */
320 GstPad*
321 gst_element_get_pad (GstElement *element, const gchar *name)
322 {
323   GList *walk;
324
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);
328
329   // if there aren't any pads, well, we're not likely to find one
330   if (!element->numpads)
331     return NULL;
332
333   GST_DEBUG(GST_CAT_ELEMENT_PADS,"searching for pad '%s' in element %s\n",
334             name, GST_ELEMENT_NAME (element));
335
336   // look through the list, matching by name
337   walk = element->pads;
338   while (walk) {
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);
342       return pad;
343     }
344     walk = g_list_next (walk);
345   }
346
347   GST_DEBUG(GST_CAT_ELEMENT_PADS,"no such pad '%s'\n",name);
348   return NULL;
349 }
350
351 /**
352  * gst_element_get_pad_list:
353  * @element: element to get pads of
354  *
355  * Retrieve a list of the pads associated with the element.
356  *
357  * Returns: GList of pads
358  */
359 GList*
360 gst_element_get_pad_list (GstElement *element)
361 {
362   g_return_val_if_fail (element != NULL, NULL);
363   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
364
365   /* return the list of pads */
366   return element->pads;
367 }
368
369 /**
370  * gst_element_get_padtemplate_list:
371  * @element: element to get padtemplates of
372  *
373  * Retrieve a list of the padtemplates associated with the element.
374  *
375  * Returns: GList of padtemplates
376  */
377 GList*
378 gst_element_get_padtemplate_list (GstElement *element)
379 {
380   GstElementClass *oclass;
381
382   g_return_val_if_fail (element != NULL, NULL);
383   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
384
385   oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
386
387   if (oclass->elementfactory == NULL) return NULL;
388
389   /* return the list of pads */
390   return oclass->elementfactory->padtemplates;
391 }
392
393 /**
394  * gst_element_get_padtemplate_by_name:
395  * @element: element to get padtemplate of
396  * @name: the name of the padtemplate to get.
397  *
398  * Retrieve a padtemplate from this element with the
399  * given name.
400  *
401  * Returns: the padtemplate with the given name
402  */
403 GstPadTemplate*
404 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
405 {
406   GList *padlist;
407
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);
411
412   padlist = gst_element_get_padtemplate_list (element);
413
414   while (padlist) {
415     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
416
417     if (!strcmp (padtempl->name_template, name))
418       return padtempl;
419
420     padlist = g_list_next (padlist);
421   }
422
423   return NULL;
424 }
425
426 /**
427  * gst_element_get_padtemplate_by_compatible:
428  * @element: element to get padtemplate of
429  * @templ: a template to find a compatible template for
430  *
431  * Generate a padtemplate for this element compatible with the given
432  * template, ie able to link to it.
433  *
434  * Returns: the padtemplate
435  */
436 static GstPadTemplate*
437 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
438 {
439   GstPadTemplate *newtempl = NULL;
440   GList *padlist;
441
442   GST_DEBUG(0,"gst_element_get_padtemplate_by_compatible()\n");
443
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);
447
448   padlist = gst_element_get_padtemplate_list (element);
449
450   while (padlist) {
451     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
452     gboolean compat = FALSE;
453
454     // Ignore name
455     // Ignore presence
456     // Check direction (must be opposite)
457     // Check caps
458
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,
464                                                  compattempl->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,
470                                                  padtempl->caps);
471       GST_DEBUG(0,"caps are %scompatible\n", (compat?"":"not "));
472     }
473
474     if (compat) {
475       newtempl = padtempl;
476       break;
477     }
478
479     padlist = g_list_next (padlist);
480   }
481
482   return newtempl;
483 }
484
485 static GstPad*
486 gst_element_request_pad (GstElement *element, GstPadTemplate *templ)
487 {
488   GstPad *newpad = NULL;
489   GstElementClass *oclass;
490
491   oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
492   if (oclass->request_new_pad)
493     newpad = (oclass->request_new_pad)(element, templ);
494
495   return newpad;
496 }
497
498 /**
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
502  *
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
506  * GST_PAD_REQUEST.
507  *
508  * Returns: the new pad that was created.
509  */
510 GstPad*
511 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
512 {
513   GstPadTemplate *templ_new;
514   GstPad *pad = NULL;
515
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);
519
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);
523
524   return pad;
525 }
526
527 /**
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.
531  *
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
535  * GST_PAD_REQUEST.
536  *
537  * Returns: the new pad that was created.
538  */
539 GstPad*
540 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
541 {
542   GstPadTemplate *templ;
543   GstPad *pad;
544
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);
548
549   templ = gst_element_get_padtemplate_by_name (element, name);
550   g_return_val_if_fail (templ != NULL, NULL);
551
552   pad = gst_element_request_pad (element, templ);
553
554   return pad;
555 }
556
557 /**
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
563  *
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.
568  */
569 void
570 gst_element_connect (GstElement *src, const gchar *srcpadname,
571                      GstElement *dest, const gchar *destpadname)
572 {
573   GstPad *srcpad,*destpad;
574   GstObject *srcparent,*destparent;
575
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);
582
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);
587     return;
588   }
589   destpad = gst_element_get_pad (dest, destpadname);
590   if (srcpad == NULL) {
591     GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
592     return;
593   }
594
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));
598
599   /* have to make sure that they have the same parents... */
600   /*
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));
604     return;
605   }
606   */
607
608   /* we're satisified they can be connected, let's do it */
609   gst_pad_connect(srcpad,destpad);
610 }
611
612 /**
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
618  *
619  * Disconnect the two named pads of the source and destination elements.
620  */
621 void
622 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
623                         GstElement *dest, const gchar *destpadname)
624 {
625   GstPad *srcpad,*destpad;
626
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);
633
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);
638     return;
639   }
640   destpad = gst_element_get_pad (dest, destpadname);
641   if (srcpad == NULL) {
642     GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
643     return;
644   }
645
646   /* we're satisified they can be disconnected, let's do it */
647   gst_pad_disconnect(srcpad,destpad);
648 }
649
650 /**
651  * gst_element_error:
652  * @element: Element with the error
653  * @error: String describing the error
654  *
655  * This function is used internally by elements to signal an error
656  * condition.  It results in the "error" signal.
657  */
658 void
659 gst_element_error (GstElement *element, const gchar *error)
660 {
661   g_error("GstElement: error in element '%s': %s\n", gst_object_get_name (GST_OBJECT (element)), error);
662
663   /* FIXME: this is not finished!!! */
664
665   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[ERROR], error);
666 }
667
668
669 /**
670  * gst_element_set_state:
671  * @element: element to change state of
672  * @state: new element state
673  *
674  * Sets the state of the element. This function will only set
675  * the elements pending state.
676  *
677  * Returns: whether or not the state was successfully set.
678  */
679 gint
680 gst_element_set_state (GstElement *element, GstElementState state)
681 {
682   GstElementClass *oclass;
683   GstElementState curpending;
684   GstElementStateReturn return_val = GST_STATE_SUCCESS;
685
686 //  g_print("gst_element_set_state(\"%s\",%08lx)\n",
687 //          element->name,state);
688
689   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
690   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
691
692   /* start with the current state */
693   curpending = GST_STATE(element);
694
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;
699     else curpending>>=1;
700
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;
704
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);
709
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));
714       return return_val;
715     }
716   }
717
718   /* this is redundant, really, it will always return SUCCESS */
719   return return_val;
720 }
721
722 /**
723  * gst_element_get_factory:
724  * @element: element to request the factory
725  *
726  * Retrieves the factory that was used to create this element
727  *
728  * Returns: the factory used for creating this element
729  */
730 GstElementFactory*
731 gst_element_get_factory (GstElement *element)
732 {
733   GstElementClass *oclass;
734
735   g_return_val_if_fail (element != NULL, NULL);
736   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
737
738   oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
739
740   return oclass->elementfactory;
741 }
742
743 /**
744  * gst_element_change_state:
745  * @element: element to change state of
746  *
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.
750  *
751  * Returns: whether or not the state change was successfully set.
752  */
753 GstElementStateReturn
754 gst_element_change_state (GstElement *element)
755 {
756   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
757   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
758
759 //  g_print("gst_element_change_state(\"%s\",%d)\n",
760 //          element->name,state);
761
762   GST_STATE (element) = GST_STATE_PENDING (element);
763   GST_STATE_PENDING (element) = GST_STATE_NONE_PENDING;
764
765   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[STATE_CHANGE],
766                    GST_STATE (element));
767   return TRUE;
768 }
769
770 static void
771 gst_element_real_destroy (GtkObject *object)
772 {
773   GstElement *element = GST_ELEMENT (object);
774   GList *pads;
775   GstPad *pad;
776
777 //  g_print("in gst_element_real_destroy()\n");
778
779   pads = element->pads;
780   while (pads) {
781     pad = GST_PAD (pads->data);
782     gst_pad_destroy (pad);
783     pads = g_list_next (pads);
784   }
785
786   g_list_free (element->pads);
787 }
788
789 /*
790 static gchar *_gst_element_type_names[] = {
791   "invalid",
792   "none",
793   "char",
794   "uchar",
795   "bool",
796   "int",
797   "uint",
798   "long",
799   "ulong",
800   "float",
801   "double",
802   "string",
803 };
804 */
805
806 /**
807  * gst_element_save_thyself:
808  * @element: GstElement to save
809  * @parent: the xml parent node
810  *
811  * Saves the element as part of the given XML structure
812  *
813  * Returns: the new xml node
814  */
815 static xmlNodePtr
816 gst_element_save_thyself (GstObject *object,
817                           xmlNodePtr parent)
818 {
819   GList *pads;
820   GstElementClass *oclass;
821   GtkType type;
822   GstElement *element;
823
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);
827
828   element = GST_ELEMENT (object);
829
830   oclass = GST_ELEMENT_CLASS (GTK_OBJECT (element)->klass);
831
832   xmlNewChild(parent, NULL, "name", gst_object_get_name (GST_OBJECT (element)));
833
834   if (oclass->elementfactory != NULL) {
835     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
836
837     xmlNewChild (parent, NULL, "type", factory->name);
838     xmlNewChild (parent, NULL, "version", factory->details->version);
839   }
840
841   // output all args to the element
842   type = GTK_OBJECT_TYPE (element);
843   while (type != GTK_TYPE_INVALID) {
844     GtkArg *args;
845     guint32 *flags;
846     guint num_args,i;
847
848     args = gtk_object_query_args (type, &flags, &num_args);
849
850     for (i=0; i<num_args; i++) {
851       if ((args[i].type > GTK_TYPE_NONE) &&
852           (flags[i] & GTK_ARG_READABLE)) {
853         xmlNodePtr arg;
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) {
858           case GTK_TYPE_CHAR:
859             xmlNewChild (arg, NULL, "value",
860                          g_strdup_printf ("%c", GTK_VALUE_CHAR (args[i])));
861             break;
862           case GTK_TYPE_UCHAR:
863             xmlNewChild (arg, NULL, "value",
864                          g_strdup_printf ("%d", GTK_VALUE_UCHAR (args[i])));
865             break;
866           case GTK_TYPE_BOOL:
867             xmlNewChild (arg, NULL, "value",
868                         GTK_VALUE_BOOL (args[i]) ? "true" : "false");
869             break;
870           case GTK_TYPE_INT:
871             xmlNewChild (arg, NULL, "value",
872                          g_strdup_printf ("%d", GTK_VALUE_INT (args[i])));
873             break;
874           case GTK_TYPE_LONG:
875             xmlNewChild (arg, NULL, "value",
876                          g_strdup_printf ("%ld", GTK_VALUE_LONG (args[i])));
877             break;
878           case GTK_TYPE_ULONG:
879             xmlNewChild (arg, NULL, "value",
880                          g_strdup_printf ("%lu", GTK_VALUE_ULONG (args[i])));
881             break;
882           case GTK_TYPE_FLOAT:
883             xmlNewChild (arg, NULL, "value",
884                          g_strdup_printf ("%f", GTK_VALUE_FLOAT (args[i])));
885             break;
886           case GTK_TYPE_DOUBLE:
887             xmlNewChild (arg, NULL, "value",
888                          g_strdup_printf ("%g", GTK_VALUE_DOUBLE (args[i])));
889             break;
890           case GTK_TYPE_STRING:
891             xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
892             break;
893           default:
894             if (args[i].type == GST_TYPE_FILENAME) {
895               xmlNewChild (arg, NULL, "value", GTK_VALUE_STRING (args[i]));
896             }
897             break;
898         }
899       }
900     }
901     type = gtk_type_parent (type);
902   }
903
904   pads = element->pads;
905   while (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);
912   }
913
914   return parent;
915 }
916
917 /**
918  * gst_element_load_thyself:
919  * @self: the xml node
920  * @elements: a hashtable to store the elements in. This is used
921  *    to resolve inter element dependecies during the loading.
922  *
923  * Load the element from the XML description
924  *
925  * Returns: the new element
926  */
927 GstElement*
928 gst_element_load_thyself (xmlNodePtr self, GstObject *parent)
929 {
930   xmlNodePtr children = self->xmlChildrenNode;
931   GstElement *element;
932   GstObjectClass *oclass;
933   guchar *name = NULL;
934   guchar *value = NULL;
935   guchar *type = NULL;
936
937   // first get the needed tags to construct the element
938   while (children) {
939     if (!strcmp (children->name, "name")) {
940       name = g_strdup (xmlNodeGetContent (children));
941     } else if (!strcmp (children->name, "type")) {
942       type = g_strdup (xmlNodeGetContent (children));
943     }
944     children = children->next;
945   }
946   g_return_val_if_fail (name != NULL, NULL);
947   g_return_val_if_fail (type != NULL, NULL);
948
949   GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"\n", name, type);
950
951   element = gst_elementfactory_make (type, name);
952
953   g_return_val_if_fail (element != NULL, NULL);
954
955   // ne need to set the parent on this object bacause the pads
956   // will go through the hierarchy to connect to thier peers
957   if (parent)
958     gst_object_set_parent (GST_OBJECT (element), parent);
959
960   // we have the element now, set the arguments
961   children = self->xmlChildrenNode;
962
963   while (children) {
964     if (!strcmp (children->name, "arg")) {
965       xmlNodePtr child = children->xmlChildrenNode;
966
967       while (child) {
968         if (!strcmp (child->name, "name")) {
969           name = g_strdup (xmlNodeGetContent (child));
970         }
971         else if (!strcmp (child->name, "value")) {
972           value = g_strdup (xmlNodeGetContent (child));
973         }
974         child = child->next;
975       }
976       if (name && value) {
977         GtkType type = GTK_OBJECT_TYPE (element);
978         GtkArgInfo *info;
979         gchar *result;
980
981         result = gtk_object_arg_get_info (type, name, &info);
982
983         if (result) {
984           g_print("gstelement: %s\n", result);
985         }
986         else if (info->arg_flags & GTK_ARG_WRITABLE) {
987           switch (info->type) {
988             case GTK_TYPE_STRING:
989               gtk_object_set (GTK_OBJECT (element), name, value, NULL);
990               break;
991             case GTK_TYPE_INT: {
992               gint i;
993               sscanf (value, "%d", &i);
994               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
995               break;
996             }
997             case GTK_TYPE_LONG: {
998               glong i;
999               sscanf (value, "%ld", &i);
1000               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1001               break;
1002             }
1003             case GTK_TYPE_ULONG: {
1004               gulong i;
1005               sscanf (value, "%lu", &i);
1006               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1007               break;
1008             }
1009             case GTK_TYPE_BOOL: {
1010               gboolean i = FALSE;
1011               if (!strcmp ("true", value)) i = TRUE;
1012               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1013               break;
1014             }
1015             case GTK_TYPE_CHAR: {
1016               gchar i;
1017               sscanf (value, "%c", &i);
1018               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1019               break;
1020             }
1021             case GTK_TYPE_UCHAR: {
1022               guchar i;
1023               sscanf (value, "%c", &i);
1024               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1025               break;
1026             }
1027             case GTK_TYPE_FLOAT: {
1028               gfloat i;
1029               sscanf (value, "%f", &i);
1030               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1031               break;
1032             }
1033             case GTK_TYPE_DOUBLE: {
1034               gdouble i;
1035               sscanf (value, "%g", (float *)&i);
1036               gtk_object_set (GTK_OBJECT (element), name, i, NULL);
1037               break;
1038             }
1039             default:
1040               if (info->type == GST_TYPE_FILENAME) {
1041                 gtk_object_set (GTK_OBJECT (element), name, value, NULL);
1042               }
1043               break;
1044           }
1045
1046         }
1047       }
1048     }
1049     children = children->next;
1050   }
1051   // we have the element now, set the pads
1052   children = self->xmlChildrenNode;
1053
1054   while (children) {
1055     if (!strcmp (children->name, "pad")) {
1056       gst_pad_load_and_connect (children, GST_OBJECT (element));
1057     }
1058     children = children->next;
1059   }
1060
1061   oclass = GST_OBJECT_CLASS (GTK_OBJECT (element)->klass);
1062   if (oclass->restore_thyself)
1063     (oclass->restore_thyself) (GST_OBJECT (element), self);
1064
1065   if (parent)
1066     gst_object_unparent (GST_OBJECT (element));
1067
1068   return element;
1069 }
1070
1071 /**
1072  * gst_element_set_manager:
1073  * @element: Element to set manager of.
1074  * @manager: Element to be the manager.
1075  *
1076  * Sets the manager of the element.  For internal use only, unless you're
1077  * writing a new bin subclass.
1078  */
1079 void
1080 gst_element_set_manager (GstElement *element,
1081                          GstElement *manager)
1082 {
1083   element->manager = manager;
1084 }
1085
1086 /**
1087  * gst_element_get_manager:
1088  * @element: Element to get manager of.
1089  *
1090  * Returns the manager of the element.
1091  *
1092  * Returns: Element's manager
1093  */
1094 GstElement*
1095 gst_element_get_manager (GstElement *element)
1096 {
1097   return element->manager;
1098 }
1099
1100 /**
1101  * gst_element_set_loop_function:
1102  * @element: Element to set loop function of.
1103  * @loop: Pointer to loop function.
1104  *
1105  * This sets the loop function for the element.  The function pointed to
1106  * can deviate from the GstElementLoopFunction definition in type of
1107  * pointer only.
1108  *
1109  * NOTE: in order for this to take effect, the current loop function *must*
1110  * exit.  Assuming the loop function itself is the only one who will cause
1111  * a new loopfunc to be assigned, this should be no problem.
1112  */
1113 void
1114 gst_element_set_loop_function(GstElement *element,
1115                               GstElementLoopFunction loop)
1116 {
1117   /* set the loop function */
1118   element->loopfunc = loop;
1119
1120   /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1121   GST_FLAG_SET(element,GST_ELEMENT_NEW_LOOPFUNC);
1122 }
1123
1124 /**
1125  * gst_element_signal_eos:
1126  * @element: element to trigger the eos signal of
1127  *
1128  * Throws the eos signal to indicate that the end of the stream is reached.
1129  */
1130 void
1131 gst_element_signal_eos (GstElement *element)
1132 {
1133   g_return_if_fail (element != NULL);
1134   g_return_if_fail (GST_IS_ELEMENT (element));
1135
1136   gtk_signal_emit (GTK_OBJECT (element), gst_element_signals[EOS]);
1137   GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
1138 }
1139