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