added gstevent.h
[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 #include "gstscheduler.h"
30 #include "gstutils.h"
31
32 /* Element signals and args */
33 enum {
34   STATE_CHANGE,
35   NEW_PAD,
36   PAD_REMOVED,
37   NEW_GHOST_PAD,
38   GHOST_PAD_REMOVED,
39   ERROR,
40   EOS,
41   LAST_SIGNAL
42 };
43
44 enum {
45   ARG_0,
46   /* FILL ME */
47 };
48
49
50 static void                     gst_element_class_init          (GstElementClass *klass);
51 static void                     gst_element_init                (GstElement *element);
52 static void                     gst_element_base_class_init     (GstElementClass *klass);
53
54 static void                     gst_element_set_property        (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
55 static void                     gst_element_get_property        (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
56
57 static void                     gst_element_shutdown            (GObject *object);
58 static void                     gst_element_real_destroy        (GObject *object);
59
60 static GstElementStateReturn    gst_element_change_state        (GstElement *element);
61
62 #ifndef GST_DISABLE_LOADSAVE
63 static xmlNodePtr               gst_element_save_thyself        (GstObject *object, xmlNodePtr parent);
64 GstElement*                     gst_element_restore_thyself     (xmlNodePtr self, GstObject *parent);
65 #endif
66
67 static GstObjectClass *parent_class = NULL;
68 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
69
70 GType gst_element_get_type(void) {
71   static GType element_type = 0;
72
73   if (!element_type) {
74     static const GTypeInfo element_info = {
75       sizeof(GstElementClass),
76       (GBaseInitFunc)gst_element_base_class_init,
77       NULL,
78       (GClassInitFunc)gst_element_class_init,
79       NULL,
80       NULL,
81       sizeof(GstElement),
82       0,
83       (GInstanceInitFunc)gst_element_init,
84     };
85     element_type = g_type_register_static(GST_TYPE_OBJECT, "GstElement", &element_info, G_TYPE_FLAG_ABSTRACT);
86   }
87   return element_type;
88 }
89
90 static void
91 gst_element_class_init (GstElementClass *klass)
92 {
93   GObjectClass *gobject_class;
94   GstObjectClass *gstobject_class;
95
96   gobject_class = (GObjectClass*) klass;
97   gstobject_class = (GstObjectClass*) klass;
98
99   parent_class = g_type_class_ref(GST_TYPE_OBJECT);
100
101   gst_element_signals[STATE_CHANGE] =
102     g_signal_newc ("state_change", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
103                     G_STRUCT_OFFSET (GstElementClass, state_change), NULL, NULL,
104                     g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1,
105                     G_TYPE_INT);
106   gst_element_signals[NEW_PAD] =
107     g_signal_newc ("new_pad", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
108                     G_STRUCT_OFFSET (GstElementClass, new_pad), NULL, NULL,
109                     g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
110                     GST_TYPE_PAD);
111   gst_element_signals[PAD_REMOVED] =
112     g_signal_newc ("pad_removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
113                     G_STRUCT_OFFSET (GstElementClass, pad_removed), NULL, NULL,
114                     g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
115                     GST_TYPE_PAD);
116   gst_element_signals[NEW_GHOST_PAD] =
117     g_signal_newc ("new_ghost_pad", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
118                     G_STRUCT_OFFSET (GstElementClass, new_ghost_pad), NULL, NULL,
119                     g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
120                     GST_TYPE_PAD);
121   gst_element_signals[GHOST_PAD_REMOVED] =
122     g_signal_newc ("ghost_pad_removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
123                     G_STRUCT_OFFSET (GstElementClass, ghost_pad_removed), NULL, NULL,
124                     g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
125                     GST_TYPE_PAD);
126   gst_element_signals[ERROR] =
127     g_signal_newc ("error", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
128                     G_STRUCT_OFFSET (GstElementClass, error), NULL, NULL,
129                     g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,1,
130                     G_TYPE_STRING);
131   gst_element_signals[EOS] =
132     g_signal_newc ("eos", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
133                     G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
134                     g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
135
136
137
138   gobject_class->set_property =         GST_DEBUG_FUNCPTR(gst_element_set_property);
139   gobject_class->get_property =         GST_DEBUG_FUNCPTR(gst_element_get_property);
140   gobject_class->shutdown =             GST_DEBUG_FUNCPTR(gst_element_shutdown);
141 // FIXME!
142 //  gobject_class->destroy =            GST_DEBUG_FUNCPTR(gst_element_real_destroy);
143
144 #ifndef GST_DISABLE_LOADSAVE
145   gstobject_class->save_thyself =       GST_DEBUG_FUNCPTR(gst_element_save_thyself);
146   gstobject_class->restore_thyself =    GST_DEBUG_FUNCPTR(gst_element_restore_thyself);
147 #endif
148
149   klass->change_state =                 GST_DEBUG_FUNCPTR(gst_element_change_state);
150   klass->elementfactory = NULL;
151   klass->padtemplates = NULL;
152   klass->numpadtemplates = 0;
153 }
154
155 static void
156 gst_element_base_class_init (GstElementClass *klass)
157 {
158   GObjectClass *gobject_class;
159
160   gobject_class = (GObjectClass*) klass;
161
162   gobject_class->set_property =         GST_DEBUG_FUNCPTR(gst_element_set_property);
163   gobject_class->get_property =         GST_DEBUG_FUNCPTR(gst_element_get_property);
164 }
165
166 static void
167 gst_element_init (GstElement *element)
168 {
169   element->current_state = GST_STATE_NULL;
170   element->pending_state = -1;
171   element->numpads = 0;
172   element->numsrcpads = 0;
173   element->numsinkpads = 0;
174   element->pads = NULL;
175   element->loopfunc = NULL;
176   element->threadstate = NULL;
177   element->sched = NULL;
178 }
179
180
181 static void
182 gst_element_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
183 {
184   GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object);
185
186   GST_SCHEDULE_LOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
187
188   if (oclass->set_property)
189     (oclass->set_property)(object,prop_id,value,pspec);
190
191   GST_SCHEDULE_UNLOCK_ELEMENT ( GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
192 }
193
194
195 static void
196 gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
197 {
198   GstElementClass *oclass = (GstElementClass *)G_OBJECT_GET_CLASS(object);
199
200   GST_SCHEDULE_LOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
201
202   if (oclass->get_property)
203     (oclass->get_property)(object,prop_id,value,pspec);
204
205   GST_SCHEDULE_UNLOCK_ELEMENT (GST_ELEMENT_SCHED(object), GST_ELEMENT(object) );
206 }
207
208
209 /**
210  * gst_element_new:
211  *
212  * Create a new element.  Should never be used, as it does no good.
213  *
214  * Returns: new element
215  */
216 GstElement*
217 gst_element_new(void)
218 {
219   return GST_ELEMENT (g_object_new(GST_TYPE_ELEMENT,NULL));
220 }
221
222 /**
223  * gst_element_set_name:
224  * @element: GstElement to set name of
225  * @name: new name of element
226  *
227  * Set the name of the element, getting rid of the old name if there was
228  * one.
229  */
230 void
231 gst_element_set_name (GstElement *element, const gchar *name)
232 {
233   g_return_if_fail (element != NULL);
234   g_return_if_fail (GST_IS_ELEMENT (element));
235   g_return_if_fail (name != NULL);
236
237   gst_object_set_name (GST_OBJECT (element), name);
238 }
239
240 /**
241  * gst_element_get_name:
242  * @element: GstElement to get name of
243  *
244  * Get the name of the element.
245  *
246  * Returns: name of the element
247  */
248 const gchar*
249 gst_element_get_name (GstElement *element)
250 {
251   g_return_val_if_fail (element != NULL, NULL);
252   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
253
254   return GST_OBJECT_NAME (element);
255 }
256
257 /**
258  * gst_element_set_parent:
259  * @element: GstElement to set parent of
260  * @parent: new parent of the object
261  *
262  * Set the parent of the element.
263  */
264 void
265 gst_element_set_parent (GstElement *element, GstObject *parent)
266 {
267   g_return_if_fail (element != NULL);
268   g_return_if_fail (GST_IS_ELEMENT (element));
269   g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
270   g_return_if_fail (parent != NULL);
271   g_return_if_fail (GST_IS_OBJECT (parent));
272   g_return_if_fail ((gpointer)element != (gpointer)parent);
273
274   gst_object_set_parent (GST_OBJECT (element), parent);
275 }
276
277 /**
278  * gst_element_get_parent:
279  * @element: GstElement to get the parent of
280  *
281  * Get the parent of the element.
282  *
283  * Returns: parent of the element
284  */
285 GstObject*
286 gst_element_get_parent (GstElement *element)
287 {
288   g_return_val_if_fail (element != NULL, NULL);
289   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
290
291   return GST_OBJECT_PARENT (element);
292 }
293
294 /**
295  * gst_element_add_pad:
296  * @element: element to add pad to
297  * @pad: pad to add
298  *
299  * Add a pad (connection point) to the element, setting the parent of the
300  * pad to the element (and thus adding a reference).
301  */
302 void
303 gst_element_add_pad (GstElement *element, GstPad *pad)
304 {
305   g_return_if_fail (element != NULL);
306   g_return_if_fail (GST_IS_ELEMENT (element));
307   g_return_if_fail (pad != NULL);
308   g_return_if_fail (GST_IS_PAD (pad));
309
310   // first check to make sure the pad's parent is already set
311   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
312
313   // then check to see if there's already a pad by that name here
314   g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
315
316   /* set the pad's parent */
317   GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'\n",
318         GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
319   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
320
321   /* add it to the list */
322   element->pads = g_list_append (element->pads, pad);
323   element->numpads++;
324   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
325     element->numsrcpads++;
326   else
327     element->numsinkpads++;
328
329   /* emit the NEW_PAD signal */
330   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
331 }
332
333 /**
334  * gst_element_remove_pad:
335  * @element: element to remove pad from
336  * @pad: pad to remove
337  *
338  * Remove a pad (connection point) from the element, 
339  */
340 void
341 gst_element_remove_pad (GstElement *element, GstPad *pad)
342 {
343   g_return_if_fail (element != NULL);
344   g_return_if_fail (GST_IS_ELEMENT (element));
345   g_return_if_fail (pad != NULL);
346   g_return_if_fail (GST_IS_PAD (pad));
347
348   g_return_if_fail (GST_PAD_PARENT (pad) == element);
349
350   /* add it to the list */
351   element->pads = g_list_remove (element->pads, pad);
352   element->numpads--;
353   if (gst_pad_get_direction (pad) == GST_PAD_SRC)
354     element->numsrcpads--;
355   else
356     element->numsinkpads--;
357
358   g_signal_emit (G_OBJECT (element), gst_element_signals[PAD_REMOVED], 0, pad);
359
360   gst_object_unparent (GST_OBJECT (pad));
361 }
362
363 /**
364  * gst_element_add_ghost_pad:
365  * @element: element to add ghost pad to
366  * @pad: pad from which the new ghost pad will be created
367  * @name: name of the new ghost pad
368  *
369  * Create a ghost pad from the given pad, and add it to the list of pads
370  * for this element.
371  */
372 void
373 gst_element_add_ghost_pad (GstElement *element, GstPad *pad, gchar *name)
374 {
375   GstPad *ghostpad;
376
377   g_return_if_fail (element != NULL);
378   g_return_if_fail (GST_IS_ELEMENT (element));
379   g_return_if_fail (pad != NULL);
380   g_return_if_fail (GST_IS_PAD (pad));
381
382   // then check to see if there's already a pad by that name here
383   g_return_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE);
384
385   GST_DEBUG(GST_CAT_ELEMENT_PADS,"creating new ghost pad called %s, from pad %s:%s\n",
386             name,GST_DEBUG_PAD_NAME(pad));
387   ghostpad = gst_ghost_pad_new (name, pad);
388
389   /* add it to the list */
390   GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s\n",
391             name, GST_ELEMENT_NAME (element));
392   element->pads = g_list_append (element->pads, ghostpad);
393   element->numpads++;
394   // set the parent of the ghostpad
395   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
396
397   GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s\n",GST_DEBUG_PAD_NAME(ghostpad));
398
399   /* emit the NEW_GHOST_PAD signal */
400   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_GHOST_PAD], 0, ghostpad);
401 }
402
403 /**
404  * gst_element_remove_ghost_pad:
405  * @element: element to remove the ghost pad from
406  * @pad: ghost pad to remove
407  *
408  * removes a ghost pad from an element
409  *
410  */
411 void
412 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
413 {
414   g_return_if_fail (element != NULL);
415   g_return_if_fail (GST_IS_ELEMENT (element));
416   g_return_if_fail (pad != NULL);
417   g_return_if_fail (GST_IS_GHOST_PAD (pad));
418
419   // FIXME this is redundant?
420   // wingo 10-july-2001: I don't think so, you have to actually remove the pad
421   // from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
422   // the real pad's ghost pad list
423   gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
424   gst_element_remove_pad (element, pad);
425 }
426
427
428 /**
429  * gst_element_get_pad:
430  * @element: element to find pad of
431  * @name: name of pad to retrieve
432  *
433  * Retrieve a pad from the element by name.
434  *
435  * Returns: requested pad if found, otherwise NULL.
436  */
437 GstPad*
438 gst_element_get_pad (GstElement *element, const gchar *name)
439 {
440   GList *walk;
441
442   g_return_val_if_fail (element != NULL, NULL);
443   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
444   g_return_val_if_fail (name != NULL, NULL);
445
446   // if there aren't any pads, well, we're not likely to find one
447   if (!element->numpads)
448     return NULL;
449
450   // look through the list, matching by name
451   walk = element->pads;
452   while (walk) {
453     GstPad *pad = GST_PAD(walk->data);
454     if (!strcmp (GST_PAD_NAME(pad), name)) {
455       GST_INFO(GST_CAT_ELEMENT_PADS,"found pad %s:%s",GST_DEBUG_PAD_NAME(pad));
456       return pad;
457     }
458     walk = g_list_next (walk);
459   }
460
461   GST_INFO(GST_CAT_ELEMENT_PADS,"no such pad '%s' in element \"%s\"",name,GST_ELEMENT_NAME(element));
462   return NULL;
463 }
464
465 /**
466  * gst_element_get_pad_list:
467  * @element: element to get pads of
468  *
469  * Retrieve a list of the pads associated with the element.
470  *
471  * Returns: GList of pads
472  */
473 GList*
474 gst_element_get_pad_list (GstElement *element)
475 {
476   g_return_val_if_fail (element != NULL, NULL);
477   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
478
479   /* return the list of pads */
480   return element->pads;
481 }
482
483 /**
484  * gst_element_class_add_padtemplate:
485  * @klass: element class to add padtemplate to
486  * @templ: padtemplate to add
487  *
488  * Add a padtemplate to an element class. This is useful if you have derived a custom
489  * bin and wish to provide an on-request pad at runtime. Plugin writers should use
490  * gst_elementfactory_add_padtemplate instead.
491  */
492 void
493 gst_element_class_add_padtemplate (GstElementClass *klass, GstPadTemplate *templ)
494 {
495   g_return_if_fail (klass != NULL);
496   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
497   g_return_if_fail (templ != NULL);
498   g_return_if_fail (GST_IS_PADTEMPLATE (templ));
499   
500   klass->padtemplates = g_list_append (klass->padtemplates, templ);
501   klass->numpadtemplates++;
502 }
503
504 /**
505  * gst_element_get_padtemplate_list:
506  * @element: element to get padtemplates of
507  *
508  * Retrieve a list of the padtemplates associated with the element.
509  *
510  * Returns: GList of padtemplates
511  */
512 GList*
513 gst_element_get_padtemplate_list (GstElement *element)
514 {
515   GstElementClass *oclass;
516
517   g_return_val_if_fail (element != NULL, NULL);
518   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
519
520   oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
521
522   return oclass->padtemplates;
523 }
524
525 /**
526  * gst_element_get_padtemplate_by_name:
527  * @element: element to get padtemplate of
528  * @name: the name of the padtemplate to get.
529  *
530  * Retrieve a padtemplate from this element with the
531  * given name.
532  *
533  * Returns: the padtemplate with the given name
534  */
535 GstPadTemplate*
536 gst_element_get_padtemplate_by_name (GstElement *element, const guchar *name)
537 {
538   GList *padlist;
539
540   g_return_val_if_fail (element != NULL, NULL);
541   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
542   g_return_val_if_fail (name != NULL, NULL);
543
544   padlist = gst_element_get_padtemplate_list (element);
545
546   while (padlist) {
547     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
548
549     if (!strcmp (padtempl->name_template, name))
550       return padtempl;
551
552     padlist = g_list_next (padlist);
553   }
554
555   return NULL;
556 }
557
558 /**
559  * gst_element_get_padtemplate_by_compatible:
560  * @element: element to get padtemplate of
561  * @templ: a template to find a compatible template for
562  *
563  * Generate a padtemplate for this element compatible with the given
564  * template, ie able to link to it.
565  *
566  * Returns: the padtemplate
567  */
568 static GstPadTemplate*
569 gst_element_get_padtemplate_by_compatible (GstElement *element, GstPadTemplate *compattempl)
570 {
571   GstPadTemplate *newtempl = NULL;
572   GList *padlist;
573
574   GST_DEBUG(GST_CAT_ELEMENT_PADS,"gst_element_get_padtemplate_by_compatible()\n");
575
576   g_return_val_if_fail (element != NULL, NULL);
577   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
578   g_return_val_if_fail (compattempl != NULL, NULL);
579
580   padlist = gst_element_get_padtemplate_list (element);
581
582   while (padlist) {
583     GstPadTemplate *padtempl = (GstPadTemplate*) padlist->data;
584     gboolean compat = FALSE;
585
586     // Ignore name
587     // Ignore presence
588     // Check direction (must be opposite)
589     // Check caps
590
591     GST_DEBUG(GST_CAT_CAPS,"checking direction and caps\n");
592     if (padtempl->direction == GST_PAD_SRC &&
593       compattempl->direction == GST_PAD_SINK) {
594       GST_DEBUG(GST_CAT_CAPS,"compatible direction: found src pad template\n");
595       compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (padtempl),
596                                             GST_PADTEMPLATE_CAPS (compattempl));
597       GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
598     } else if (padtempl->direction == GST_PAD_SINK &&
599                compattempl->direction == GST_PAD_SRC) {
600       GST_DEBUG(GST_CAT_CAPS,"compatible direction: found sink pad template\n");
601       compat = gst_caps_check_compatibility(GST_PADTEMPLATE_CAPS (compattempl),
602                                             GST_PADTEMPLATE_CAPS (padtempl));
603       GST_DEBUG(GST_CAT_CAPS,"caps are %scompatible\n", (compat?"":"not "));
604     }
605
606     if (compat) {
607       newtempl = padtempl;
608       break;
609     }
610
611     padlist = g_list_next (padlist);
612   }
613
614   return newtempl;
615 }
616
617 static GstPad*
618 gst_element_request_pad (GstElement *element, GstPadTemplate *templ)
619 {
620   GstPad *newpad = NULL;
621   GstElementClass *oclass;
622
623   oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
624   if (oclass->request_new_pad)
625     newpad = (oclass->request_new_pad)(element, templ);
626
627   return newpad;
628 }
629
630 /**
631  * gst_element_request_compatible_pad:
632  * @element: element to request a new pad from
633  * @templ: a pad template to which the new pad should be able to connect
634  *
635  * Request a new pad from the element. The template will
636  * be used to decide what type of pad to create. This function
637  * is typically used for elements with a padtemplate with presence
638  * GST_PAD_REQUEST.
639  *
640  * Returns: the new pad that was created.
641  */
642 GstPad*
643 gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
644 {
645   GstPadTemplate *templ_new;
646   GstPad *pad = NULL;
647
648   g_return_val_if_fail (element != NULL, NULL);
649   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
650   g_return_val_if_fail (templ != NULL, NULL);
651
652   templ_new = gst_element_get_padtemplate_by_compatible (element, templ);
653   if (templ_new != NULL)
654       pad = gst_element_request_pad (element, templ_new);
655
656   return pad;
657 }
658
659 /**
660  * gst_element_request_pad_by_name:
661  * @element: element to request a new pad from
662  * @name: the name of the padtemplate to use.
663  *
664  * Request a new pad from the element. The name argument will
665  * be used to decide what padtemplate to use. This function
666  * is typically used for elements with a padtemplate with presence
667  * GST_PAD_REQUEST.
668  *
669  * Returns: the new pad that was created.
670  */
671 GstPad*
672 gst_element_request_pad_by_name (GstElement *element, const gchar *name)
673 {
674   GstPadTemplate *templ;
675   GstPad *pad;
676
677   g_return_val_if_fail (element != NULL, NULL);
678   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
679   g_return_val_if_fail (name != NULL, NULL);
680
681   templ = gst_element_get_padtemplate_by_name (element, name);
682   if (templ == NULL)
683     return NULL;
684
685   pad = gst_element_request_pad (element, templ);
686
687   return pad;
688 }
689
690 /**
691  * gst_element_connect:
692  * @src: element containing source pad
693  * @srcpadname: name of pad in source element
694  * @dest: element containing destination pad
695  * @destpadname: name of pad in destination element
696  *
697  * Connect the two named pads of the source and destination elements.
698  * Side effect is that if one of the pads has no parent, it becomes a
699  * child of the parent of the other element.  If they have different
700  * parents, the connection fails.
701  */
702 void
703 gst_element_connect (GstElement *src, const gchar *srcpadname,
704                      GstElement *dest, const gchar *destpadname)
705 {
706   GstPad *srcpad,*destpad;
707
708   g_return_if_fail (src != NULL);
709   g_return_if_fail (GST_IS_ELEMENT(src));
710   g_return_if_fail (srcpadname != NULL);
711   g_return_if_fail (dest != NULL);
712   g_return_if_fail (GST_IS_ELEMENT(dest));
713   g_return_if_fail (destpadname != NULL);
714
715   /* obtain the pads requested */
716   srcpad = gst_element_get_pad (src, srcpadname);
717   if (srcpad == NULL) {
718     GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
719     return;
720   }
721   destpad = gst_element_get_pad (dest, destpadname);
722   if (srcpad == NULL) {
723     GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
724     return;
725   }
726
727   /* we're satisified they can be connected, let's do it */
728   gst_pad_connect(srcpad,destpad);
729 }
730
731 /**
732  * gst_element_disconnect:
733  * @src: element containing source pad
734  * @srcpadname: name of pad in source element
735  * @dest: element containing destination pad
736  * @destpadname: name of pad in destination element
737  *
738  * Disconnect the two named pads of the source and destination elements.
739  */
740 void
741 gst_element_disconnect (GstElement *src, const gchar *srcpadname,
742                         GstElement *dest, const gchar *destpadname)
743 {
744   GstPad *srcpad,*destpad;
745
746   g_return_if_fail (src != NULL);
747   g_return_if_fail (GST_IS_ELEMENT(src));
748   g_return_if_fail (srcpadname != NULL);
749   g_return_if_fail (dest != NULL);
750   g_return_if_fail (GST_IS_ELEMENT(dest));
751   g_return_if_fail (destpadname != NULL);
752
753   /* obtain the pads requested */
754   srcpad = gst_element_get_pad (src, srcpadname);
755   if (srcpad == NULL) {
756     GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
757     return;
758   }
759   destpad = gst_element_get_pad (dest, destpadname);
760   if (srcpad == NULL) {
761     GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
762     return;
763   }
764
765   /* we're satisified they can be disconnected, let's do it */
766   gst_pad_disconnect(srcpad,destpad);
767 }
768
769 /**
770  * gst_element_error:
771  * @element: Element with the error
772  * @error: String describing the error
773  *
774  * This function is used internally by elements to signal an error
775  * condition.  It results in the "error" signal.
776  */
777 void
778 gst_element_error (GstElement *element, const gchar *error)
779 {
780   g_error("GstElement: error in element '%s': %s\n", GST_ELEMENT_NAME(element), error);
781
782   /* FIXME: this is not finished!!! */
783
784   g_signal_emit (G_OBJECT (element), gst_element_signals[ERROR], 0, error);
785 }
786
787
788 /**
789  * gst_element_set_state:
790  * @element: element to change state of
791  * @state: new element state
792  *
793  * Sets the state of the element. This function will only set
794  * the elements pending state.
795  *
796  * Returns: whether or not the state was successfully set.
797  */
798 gint
799 gst_element_set_state (GstElement *element, GstElementState state)
800 {
801   GstElementClass *oclass;
802   GstElementState curpending;
803   GstElementStateReturn return_val = GST_STATE_SUCCESS;
804
805 //  g_print("gst_element_set_state(\"%s\",%08lx)\n",
806 //          element->name,state);
807
808   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
809   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
810   g_return_val_if_fail (element->sched != NULL, GST_STATE_FAILURE);
811
812   GST_DEBUG_ELEMENT (GST_CAT_STATES,element, "setting state from %s to %s\n",
813                      gst_element_statename(GST_STATE(element)),
814                      gst_element_statename(state));
815
816   /* start with the current state */
817   curpending = GST_STATE(element);
818
819   /* loop until the final requested state is set */
820   while (GST_STATE(element) != state) {
821     /* move the curpending state in the correct direction */
822     if (curpending < state) curpending<<=1;
823     else curpending>>=1;
824
825     /* set the pending state variable */
826     // FIXME: should probably check to see that we don't already have one
827     GST_STATE_PENDING (element) = curpending;
828     if (curpending != state)
829       GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"intermediate: setting state to %s\n",
830                          gst_element_statename(curpending));
831
832     /* call the state change function so it can set the state */
833     oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
834     if (oclass->change_state)
835       return_val = (oclass->change_state)(element);
836
837     /* if that outright didn't work, we need to bail right away */
838     /* NOTE: this will bail on ASYNC as well! */
839     if (return_val == GST_STATE_FAILURE) {
840       GST_DEBUG_ELEMENT (GST_CAT_STATES,element,"have failed change_state return\n");
841       return return_val;
842     }
843
844     /* Last thing we do is verify that a successful state change really
845      * did change the state... */
846     if (GST_STATE(element) != curpending) {
847       GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "element claimed state-change success, but state didn't change\n");
848       return GST_STATE_FAILURE;
849     }
850   }
851
852   /* this is redundant, really, it will always return SUCCESS */
853   return return_val;
854 }
855
856 /**
857  * gst_element_get_factory:
858  * @element: element to request the factory
859  *
860  * Retrieves the factory that was used to create this element
861  *
862  * Returns: the factory used for creating this element
863  */
864 GstElementFactory*
865 gst_element_get_factory (GstElement *element)
866 {
867   GstElementClass *oclass;
868
869   g_return_val_if_fail (element != NULL, NULL);
870   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
871
872   oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
873
874   return oclass->elementfactory;
875 }
876
877
878 /**
879  * gst_element_change_state:
880  * @element: element to change state of
881  *
882  * Changes the state of the element, but more importantly fires off a signal
883  * indicating the new state.
884  * The element will have no pending states anymore.
885  *
886  * Returns: whether or not the state change was successfully set.
887  */
888 GstElementStateReturn
889 gst_element_change_state (GstElement *element)
890 {
891   g_return_val_if_fail (element != NULL, GST_STATE_FAILURE);
892   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
893
894 //  GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "default handler sets state to %s\n",
895 //                     gst_element_statename(GST_STATE_PENDING(element)));
896
897   if (GST_STATE_TRANSITION(element) == GST_STATE_PAUSED_TO_PLAYING) {
898     g_return_val_if_fail(GST_ELEMENT_SCHED(element), GST_STATE_FAILURE);
899     if (GST_ELEMENT_PARENT(element))
900       GST_DEBUG(GST_CAT_STATES,"PAUSED->PLAYING: element \"%s\" has parent \"%s\" and sched %p\n",
901 GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
902     GST_SCHEDULE_ENABLE_ELEMENT (element->sched,element);
903   }
904   else if (GST_STATE_TRANSITION(element) == GST_STATE_PLAYING_TO_PAUSED) {
905     if (GST_ELEMENT_PARENT(element))
906       GST_DEBUG(GST_CAT_STATES,"PLAYING->PAUSED: element \"%s\" has parent \"%s\" and sched %p\n",
907 GST_ELEMENT_NAME(element),GST_ELEMENT_NAME(GST_ELEMENT_PARENT(element)),GST_ELEMENT_SCHED(element));
908     GST_SCHEDULE_DISABLE_ELEMENT (element->sched,element);
909   }
910
911   GST_STATE (element) = GST_STATE_PENDING (element);
912   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
913
914   // note: queues' state_change is a special case because it needs to lock
915   // for synchronization (from another thread).  since this signal may block
916   // or (worse) make another state change, the queue needs to unlock before
917   // calling.  thus, gstqueue.c::gst_queue_state_change() blocks, unblocks,
918   // unlocks, then emits this. 
919   g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE], 0,
920                    GST_STATE (element));
921   return GST_STATE_SUCCESS;
922 }
923
924 static void
925 gst_element_shutdown (GObject *object)
926 {
927   GstElement *element = GST_ELEMENT (object);
928
929   GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "shutdown\n");
930
931   if (GST_IS_BIN (GST_OBJECT_PARENT (element)))
932     gst_bin_remove (GST_BIN (GST_OBJECT_PARENT (element)), element);
933
934   if (G_OBJECT_CLASS (parent_class)->shutdown)
935     G_OBJECT_CLASS (parent_class)->shutdown (G_OBJECT (object));
936 }
937
938 static void
939 gst_element_real_destroy (GObject *object)
940 {
941   GstElement *element = GST_ELEMENT (object);
942   GList *pads;
943   GstPad *pad;
944
945   GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "destroy\n");
946
947   if (element->pads) {
948     GList *orig;
949     orig = pads = g_list_copy (element->pads);
950     while (pads) {
951       pad = GST_PAD (pads->data);
952       //gst_object_destroy (GST_OBJECT (pad));
953       gst_object_ref (GST_OBJECT (pad));
954       gst_element_remove_pad (element, pad);
955       gst_object_unref (GST_OBJECT (pad));
956       pads = g_list_next (pads);
957     }
958     g_list_free (orig);
959     g_list_free (element->pads);
960     element->pads = NULL;
961   }
962
963   element->numsrcpads = 0;
964   element->numsinkpads = 0;
965
966 // FIXME!
967 //  if (G_OBJECT_CLASS (parent_class)->destroy)
968 //    G_OBJECT_CLASS (parent_class)->destroy (object);
969 }
970
971 /*
972 static gchar *_gst_element_type_names[] = {
973   "invalid",
974   "none",
975   "char",
976   "uchar",
977   "bool",
978   "int",
979   "uint",
980   "long",
981   "ulong",
982   "float",
983   "double",
984   "string",
985 };
986 */
987
988 #ifndef GST_DISABLE_LOADSAVE
989 /**
990  * gst_element_save_thyself:
991  * @element: GstElement to save
992  * @parent: the xml parent node
993  *
994  * Saves the element as part of the given XML structure
995  *
996  * Returns: the new xml node
997  */
998 static xmlNodePtr
999 gst_element_save_thyself (GstObject *object,
1000                           xmlNodePtr parent)
1001 {
1002   GList *pads;
1003   GstElementClass *oclass;
1004 //  GType type;
1005   GstElement *element;
1006
1007   g_return_val_if_fail (object != NULL, parent);
1008   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
1009   g_return_val_if_fail (parent != NULL, parent);
1010
1011   element = GST_ELEMENT (object);
1012
1013   oclass = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS(element));
1014
1015   xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
1016
1017   if (oclass->elementfactory != NULL) {
1018     GstElementFactory *factory = (GstElementFactory *)oclass->elementfactory;
1019
1020     xmlNewChild (parent, NULL, "type", factory->name);
1021     xmlNewChild (parent, NULL, "version", factory->details->version);
1022   }
1023
1024 //  if (element->manager)
1025 //    xmlNewChild(parent, NULL, "manager", GST_ELEMENT_NAME(element->manager));
1026
1027 /* FIXME FIXME FIXME!
1028   // output all args to the element
1029   type = G_OBJECT_TYPE (element);
1030   while (type != G_TYPE_INVALID) {
1031     GtkArg *args;
1032     guint32 *flags;
1033     guint num_args,i;
1034
1035     args = gtk_object_query_args (type, &flags, &num_args);
1036
1037     for (i=0; i<num_args; i++) {
1038       if ((args[i].type > G_TYPE_NONE) &&
1039           (flags[i] & GTK_ARG_READABLE)) {
1040         xmlNodePtr arg;
1041         gtk_object_getv (G_OBJECT (element), 1, &args[i]);
1042         arg = xmlNewChild (parent, NULL, "arg", NULL);
1043         xmlNewChild (arg, NULL, "name", args[i].name);
1044         switch (args[i].type) {
1045           case G_TYPE_CHAR:
1046             xmlNewChild (arg, NULL, "value",
1047                          g_strdup_printf ("%c", G_VALUE_CHAR (args[i])));
1048             break;
1049           case G_TYPE_UCHAR:
1050             xmlNewChild (arg, NULL, "value",
1051                          g_strdup_printf ("%d", G_VALUE_UCHAR (args[i])));
1052             break;
1053           case G_TYPE_BOOL:
1054             xmlNewChild (arg, NULL, "value",
1055                         G_VALUE_BOOL (args[i]) ? "true" : "false");
1056             break;
1057           case G_TYPE_INT:
1058             xmlNewChild (arg, NULL, "value",
1059                          g_strdup_printf ("%d", G_VALUE_INT (args[i])));
1060             break;
1061           case G_TYPE_LONG:
1062             xmlNewChild (arg, NULL, "value",
1063                          g_strdup_printf ("%ld", G_VALUE_LONG (args[i])));
1064             break;
1065           case G_TYPE_ULONG:
1066             xmlNewChild (arg, NULL, "value",
1067                          g_strdup_printf ("%lu", G_VALUE_ULONG (args[i])));
1068             break;
1069           case G_TYPE_FLOAT:
1070             xmlNewChild (arg, NULL, "value",
1071                          g_strdup_printf ("%f", G_VALUE_FLOAT (args[i])));
1072             break;
1073           case G_TYPE_DOUBLE:
1074             xmlNewChild (arg, NULL, "value",
1075                          g_strdup_printf ("%g", G_VALUE_DOUBLE (args[i])));
1076             break;
1077           case G_TYPE_STRING:
1078             xmlNewChild (arg, NULL, "value", G_VALUE_STRING (args[i]));
1079             break;
1080           default:
1081             if (args[i].type == GST_TYPE_FILENAME) {
1082               xmlNewChild (arg, NULL, "value", G_VALUE_STRING (args[i]));
1083             }
1084             break;
1085         }
1086       }
1087     }
1088     type = gtk_type_parent (type);
1089   }
1090 */
1091
1092   pads = GST_ELEMENT_PADS (element);
1093
1094   while (pads) {
1095     GstPad *pad = GST_PAD (pads->data);
1096     // figure out if it's a direct pad or a ghostpad
1097     if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
1098       xmlNodePtr padtag = xmlNewChild (parent, NULL, "pad", NULL);
1099       gst_object_save_thyself (GST_OBJECT (pad), padtag);
1100     }
1101     pads = g_list_next (pads);
1102   }
1103
1104   return parent;
1105 }
1106
1107 /**
1108  * gst_element_restore_thyself:
1109  * @self: the xml node
1110  * @parent: the parent of this object when it's loaded
1111  *
1112  * Load the element from the XML description
1113  *
1114  * Returns: the new element
1115  */
1116 GstElement*
1117 gst_element_restore_thyself (xmlNodePtr self, GstObject *parent)
1118 {
1119   xmlNodePtr children = self->xmlChildrenNode;
1120   GstElement *element;
1121   GstObjectClass *oclass;
1122   guchar *name = NULL;
1123   guchar *value = NULL;
1124   guchar *type = NULL;
1125
1126   // first get the needed tags to construct the element
1127   while (children) {
1128     if (!strcmp (children->name, "name")) {
1129       name = g_strdup (xmlNodeGetContent (children));
1130     } else if (!strcmp (children->name, "type")) {
1131       type = g_strdup (xmlNodeGetContent (children));
1132     }
1133     children = children->next;
1134   }
1135   g_return_val_if_fail (name != NULL, NULL);
1136   g_return_val_if_fail (type != NULL, NULL);
1137
1138   GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
1139
1140   element = gst_elementfactory_make (type, name);
1141
1142   g_return_val_if_fail (element != NULL, NULL);
1143
1144   // ne need to set the parent on this object bacause the pads
1145   // will go through the hierarchy to connect to thier peers
1146   if (parent)
1147     gst_object_set_parent (GST_OBJECT (element), parent);
1148
1149   // we have the element now, set the arguments
1150   children = self->xmlChildrenNode;
1151
1152   while (children) {
1153     if (!strcmp (children->name, "arg")) {
1154       xmlNodePtr child = children->xmlChildrenNode;
1155
1156       while (child) {
1157         if (!strcmp (child->name, "name")) {
1158           name = g_strdup (xmlNodeGetContent (child));
1159         }
1160         else if (!strcmp (child->name, "value")) {
1161           value = g_strdup (xmlNodeGetContent (child));
1162         }
1163         child = child->next;
1164       }
1165       gst_util_set_object_arg ((GObject *)G_OBJECT (element), name, value);
1166     }
1167     children = children->next;
1168   }
1169   // we have the element now, set the pads
1170   children = self->xmlChildrenNode;
1171
1172   while (children) {
1173     if (!strcmp (children->name, "pad")) {
1174       gst_pad_load_and_connect (children, GST_OBJECT (element));
1175     }
1176     children = children->next;
1177   }
1178
1179   oclass = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS(element));
1180   if (oclass->restore_thyself)
1181     (oclass->restore_thyself) (GST_OBJECT (element), self);
1182
1183   if (parent)
1184     gst_object_unparent (GST_OBJECT (element));
1185
1186   gst_class_signal_emit_by_name (GST_OBJECT (element), "object_loaded", self);
1187
1188   return element;
1189 }
1190 #endif // GST_DISABLE_LOADSAVE
1191
1192 /**
1193  * gst_element_set_sched:
1194  * @element: Element to set manager of.
1195  * @sched: @GstSchedule to set.
1196  *
1197  * Sets the scheduler of the element.  For internal use only, unless you're
1198  * writing a new bin subclass.
1199  */
1200 void
1201 gst_element_set_sched (GstElement *element,
1202                          GstSchedule *sched)
1203 {
1204   GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p",sched);
1205   element->sched = sched;
1206 }
1207
1208 /**
1209  * gst_element_get_sched:
1210  * @element: Element to get manager of.
1211  *
1212  * Returns the scheduler of the element.
1213  *
1214  * Returns: Element's scheduler
1215  */
1216 GstSchedule*
1217 gst_element_get_sched (GstElement *element)
1218 {
1219   return element->sched;
1220 }
1221
1222 /**
1223  * gst_element_set_loop_function:
1224  * @element: Element to set loop function of.
1225  * @loop: Pointer to loop function.
1226  *
1227  * This sets the loop function for the element.  The function pointed to
1228  * can deviate from the GstElementLoopFunction definition in type of
1229  * pointer only.
1230  *
1231  * NOTE: in order for this to take effect, the current loop function *must*
1232  * exit.  Assuming the loop function itself is the only one who will cause
1233  * a new loopfunc to be assigned, this should be no problem.
1234  */
1235 void
1236 gst_element_set_loop_function(GstElement *element,
1237                               GstElementLoopFunction loop)
1238 {
1239   /* set the loop function */
1240   element->loopfunc = loop;
1241
1242   /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
1243   GST_FLAG_SET(element,GST_ELEMENT_NEW_LOOPFUNC);
1244 }
1245
1246 /**
1247  * gst_element_signal_eos:
1248  * @element: element to trigger the eos signal of
1249  *
1250  * Throws the eos signal to indicate that the end of the stream is reached.
1251  */
1252 void
1253 gst_element_signal_eos (GstElement *element)
1254 {
1255   g_return_if_fail (element != NULL);
1256   g_return_if_fail (GST_IS_ELEMENT (element));
1257
1258   GST_DEBUG(GST_CAT_EVENT, "signaling EOS on element %s\n",GST_OBJECT_NAME(element));
1259   g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
1260   GST_FLAG_SET(element,GST_ELEMENT_COTHREAD_STOPPING);
1261 }
1262
1263
1264 const gchar *gst_element_statename(int state) {
1265   switch (state) {
1266 #ifdef GST_DEBUG_COLOR
1267     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1268     case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
1269     case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
1270     case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
1271     case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
1272     default: return "\033[01;37;41mUNKNOWN!\033[00m";
1273 #else
1274     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
1275     case GST_STATE_NULL: return "NULL";break;
1276     case GST_STATE_READY: return "READY";break;
1277     case GST_STATE_PLAYING: return "PLAYING";break;
1278     case GST_STATE_PAUSED: return "PAUSED";break;
1279     default: return "UNKNOWN!";
1280 #endif
1281   }
1282   return "";
1283 }