83ea559a19260285f4f79ab817650cb504a849da
[platform/upstream/gstreamer.git] / gst / gstpad.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstpad.c: Pads for connecting elements together
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 "gstpad.h"
27 #include "gstelement.h"
28 #include "gsttype.h"
29
30
31 /* Pad signals and args */
32 enum {
33   SET_ACTIVE,
34   CAPS_CHANGED,
35   /* FILL ME */
36   LAST_SIGNAL
37 };
38
39 enum {
40   ARG_0,
41   ARG_ACTIVE,
42   /* FILL ME */
43 };
44
45
46 static void     gst_pad_class_init              (GstPadClass *klass);
47 static void     gst_pad_init                    (GstPad *pad);
48
49 static void     gst_pad_set_arg                 (GtkObject *object,GtkArg *arg,guint id);
50 static void     gst_pad_get_arg                 (GtkObject *object,GtkArg *arg,guint id);
51
52 static void     gst_pad_real_destroy            (GtkObject *object);
53
54 static void     gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
55
56 static GstObject *pad_parent_class = NULL;
57 static guint gst_pad_signals[LAST_SIGNAL] = { 0 };
58
59 GtkType
60 gst_pad_get_type(void) {
61   static GtkType pad_type = 0;
62
63   if (!pad_type) {
64     static const GtkTypeInfo pad_info = {
65       "GstPad",
66       sizeof(GstPad),
67       sizeof(GstPadClass),
68       (GtkClassInitFunc)gst_pad_class_init,
69       (GtkObjectInitFunc)gst_pad_init,
70       (GtkArgSetFunc)NULL,
71       (GtkArgGetFunc)NULL,
72       (GtkClassInitFunc)NULL,
73     };
74     pad_type = gtk_type_unique(GST_TYPE_OBJECT,&pad_info);
75   }
76   return pad_type;
77 }
78
79 static void
80 gst_pad_class_init (GstPadClass *klass) 
81 {
82   GtkObjectClass *gtkobject_class;
83
84   gtkobject_class = (GtkObjectClass*)klass;
85
86   pad_parent_class = gtk_type_class(GST_TYPE_OBJECT);
87
88   gst_pad_signals[SET_ACTIVE] =
89     gtk_signal_new ("set_active", GTK_RUN_LAST, gtkobject_class->type,
90                     GTK_SIGNAL_OFFSET (GstPadClass, set_active),
91                     gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1,
92                     GTK_TYPE_BOOL);
93   gst_pad_signals[CAPS_CHANGED] =
94     gtk_signal_new ("caps_changed", GTK_RUN_LAST, gtkobject_class->type,
95                     GTK_SIGNAL_OFFSET (GstPadClass, caps_changed),
96                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
97                     GTK_TYPE_POINTER);
98
99   gtk_object_add_arg_type ("GstPad::active", GTK_TYPE_BOOL,
100                            GTK_ARG_READWRITE, ARG_ACTIVE);
101
102   gtkobject_class->destroy = gst_pad_real_destroy;
103   gtkobject_class->set_arg = gst_pad_set_arg;
104   gtkobject_class->get_arg = gst_pad_get_arg;
105 }
106
107 static void 
108 gst_pad_init (GstPad *pad) 
109 {
110   pad->direction = GST_PAD_UNKNOWN;
111   pad->peer = NULL;
112
113   pad->chainfunc = NULL;
114   pad->getfunc = NULL;
115   pad->getregionfunc = NULL;
116   pad->qosfunc = NULL;
117   pad->eosfunc = gst_pad_eos_func;
118
119   pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
120   pad->pullfunc = NULL;
121   pad->pullregionfunc = NULL;
122
123   pad->parent = NULL;
124   pad->ghostparents = NULL;
125   pad->caps = NULL;
126
127   pad->padtemplate = NULL;
128 }
129
130 static void
131 gst_pad_set_arg (GtkObject *object,GtkArg *arg,guint id) {
132   g_return_if_fail(GST_IS_PAD(object));
133
134   switch (id) {
135     case ARG_ACTIVE:
136       if (GTK_VALUE_BOOL(*arg)) {
137         gst_info("gstpad: activating pad\n");
138         GST_FLAG_UNSET(object,GST_PAD_DISABLED);
139       } else {
140         gst_info("gstpad: de-activating pad\n");
141         GST_FLAG_SET(object,GST_PAD_DISABLED);
142       }
143       gtk_signal_emit(GTK_OBJECT(object), gst_pad_signals[SET_ACTIVE],
144                       ! GST_FLAG_IS_SET(object,GST_PAD_DISABLED));
145       break;
146     default:
147       break;
148   }
149 }
150
151 static void
152 gst_pad_get_arg (GtkObject *object,
153                     GtkArg *arg,
154                     guint id)
155 {
156   /* it's not null if we got it, but it might not be ours */
157   g_return_if_fail (GST_IS_PAD (object));
158
159   switch (id) {
160     case ARG_ACTIVE:
161       GTK_VALUE_BOOL (*arg) = ! GST_FLAG_IS_SET (object, GST_PAD_DISABLED);
162       break;
163     default:
164       break;
165   }
166 }
167
168
169 /**
170  * gst_pad_new:
171  * @name: name of new pad
172  * @direction: either GST_PAD_SRC or GST_PAD_SINK
173  *
174  * Create a new pad with given name.
175  *
176  * Returns: new pad
177  */
178 GstPad*
179 gst_pad_new (gchar *name,
180              GstPadDirection direction) 
181 {
182   GstPad *pad;
183
184   g_return_val_if_fail (name != NULL, NULL);
185   g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
186
187   pad = GST_PAD (gtk_type_new (gst_pad_get_type ()));
188   pad->name = g_strdup (name);
189   pad->direction = direction;
190
191   return pad;
192 }
193
194 /**
195  * gst_pad_new_from_template:
196  * @temp: the pad template to use
197  * @name: the name of the element
198  *
199  * Create a new pad with given name from the given template.
200  *
201  * Returns: new pad
202  */
203 GstPad*
204 gst_pad_new_from_template (GstPadTemplate *temp,
205                            gchar *name) 
206 {
207   GstPad *pad;
208
209   g_return_val_if_fail (name != NULL, NULL);
210   g_return_val_if_fail (temp != NULL, NULL);
211
212   pad = gst_pad_new (name, temp->direction);
213   pad->caps = temp->caps;
214   pad->padtemplate = temp;
215
216   return pad;
217 }
218
219 /**
220  * gst_pad_get_direction:
221  * @pad: the Pad to get the direction from
222  *
223  * get the direction of the pad
224  *
225  * Returns: the direction of the pad
226  */
227 GstPadDirection 
228 gst_pad_get_direction (GstPad *pad) 
229 {
230   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
231   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
232
233   return pad->direction;
234 }
235
236 /**
237  * gst_pad_set_name:
238  * @pad: the pad to set the name of
239  * @name: the name of the pad
240  *
241  * set the name of a pad
242  */
243 void 
244 gst_pad_set_name (GstPad *pad, 
245                   const gchar *name) 
246 {
247   g_return_if_fail (pad != NULL);
248   g_return_if_fail (GST_IS_PAD (pad));
249
250   if (pad->name != NULL)
251     g_free (pad->name);
252
253   pad->name = g_strdup (name);
254 }
255
256 /**
257  * gst_pad_get_name:
258  * @pad: the pad to get the name of
259  *
260  * get the name of a pad
261  *
262  * Returns: the name of the pad, don't free.
263  */
264 const gchar*
265 gst_pad_get_name (GstPad *pad) 
266 {
267   g_return_val_if_fail (pad != NULL, NULL);
268   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
269
270   return pad->name;
271 }
272
273 /**
274  * gst_pad_set_chain_function:
275  * @pad: the pad to set the chain function for
276  * @chain: the chain function
277  *
278  * Set the given chain function for the pad
279  */
280 void gst_pad_set_chain_function (GstPad *pad,
281                                  GstPadChainFunction chain) 
282 {
283   g_return_if_fail (pad != NULL);
284   g_return_if_fail (GST_IS_PAD (pad));
285   
286   pad->chainfunc = chain;
287 }
288
289 /**
290  * gst_pad_set_get_function:
291  * @pad: the pad to set the get function for
292  * @get: the get function
293  *
294  * Set the given get function for the pad
295  */
296 void 
297 gst_pad_set_get_function (GstPad *pad,
298                           GstPadGetFunction get) 
299 {
300   g_return_if_fail (pad != NULL);
301   g_return_if_fail (GST_IS_PAD (pad));
302
303   // the if and such should optimize out when DEBUG is off
304   GST_DEBUG (0,"setting get function for %s:%s\n",GST_DEBUG_PAD_NAME(pad));
305
306   pad->getfunc = get;
307   GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n",GST_DEBUG_PAD_NAME(pad),pad,&pad->getfunc,get);
308 }
309
310 /**
311  * gst_pad_set_getregion_function:
312  * @pad: the pad to set the getregion function for
313  * @getregion: the getregion function
314  *
315  * Set the given getregion function for the pad
316  */
317 void 
318 gst_pad_set_getregion_function (GstPad *pad,
319                                 GstPadGetRegionFunction getregion) 
320 {
321   g_return_if_fail (pad != NULL);
322   g_return_if_fail (GST_IS_PAD (pad));
323
324   GST_DEBUG (0,"gstpad: pad setting getregion function\n");
325
326   pad->getregionfunc = getregion;
327 }
328
329 /**
330  * gst_pad_set_qos_function:
331  * @pad: the pad to set the qos function for
332  * @qos: the qos function
333  *
334  * Set the given qos function for the pad
335  */
336 void 
337 gst_pad_set_qos_function (GstPad *pad,
338                           GstPadQoSFunction qos) 
339 {
340   g_return_if_fail (pad != NULL);
341   g_return_if_fail (GST_IS_PAD (pad));
342   
343   pad->qosfunc = qos;
344 }
345
346 /**
347  * gst_pad_set_eos_function:
348  * @pad: the pad to set the eos function for
349  * @eos: the eos function
350  *
351  * Set the given EOS function for the pad
352  */
353 void 
354 gst_pad_set_eos_function (GstPad *pad,
355                           GstPadEOSFunction eos) 
356 {
357   g_return_if_fail (pad != NULL);
358   g_return_if_fail (GST_IS_PAD (pad));
359   
360   pad->eosfunc = eos;
361 }
362
363
364
365 static void
366 gst_pad_push_func(GstPad *pad, GstBuffer *buf) 
367 {
368   if (pad->peer->chainfunc != NULL) {
369     GST_DEBUG (0,"calling chain function\n");
370     (pad->peer->chainfunc)(pad,buf);
371   } else {
372     GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n");
373   }
374 }
375
376 /**
377  * gst_pad_chain:
378  * @pad: the pad to chain
379  *
380  * call the chain function of the given pad
381  */
382 void 
383 gst_pad_chain (GstPad *pad) 
384 {
385   g_return_if_fail (pad != NULL);
386   g_return_if_fail (GST_IS_PAD (pad));
387   g_return_if_fail (pad->peer != NULL);
388   g_return_if_fail (pad->chainfunc != NULL);
389
390   if (pad->bufpen && pad->chainfunc)
391     (pad->chainfunc) (pad,pad->bufpen);
392 }
393
394
395 /**
396  * gst_pad_handle_qos:
397  * @pad: the pad to handle the QoS message
398  * @qos_message: the QoS message to handle
399  *
400  * pass the qos message downstream
401  */
402 void 
403 gst_pad_handle_qos(GstPad *pad,
404                    glong qos_message)
405 {
406   GstElement *element;
407   GList *pads;
408   GstPad *target_pad;
409
410   GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_ELEMENT(pad->parent)->name,qos_message);
411
412   if (pad->qosfunc) {
413     (pad->qosfunc) (pad,qos_message);
414   }
415   else {
416     element = GST_ELEMENT (pad->peer->parent);
417
418     pads = element->pads;
419     GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", element->name,qos_message);
420     while (pads) {
421       target_pad = GST_PAD (pads->data);
422       if (target_pad->direction == GST_PAD_SINK) {
423         gst_pad_handle_qos (target_pad, qos_message);
424       }
425       pads = g_list_next (pads);
426     }
427   }
428
429   return;
430 }
431
432 /**
433  * gst_pad_disconnect:
434  * @srcpad: the source pad to disconnect
435  * @sinkpad: the sink pad to disconnect
436  *
437  * disconnects the source pad from the sink pad
438  */
439 void 
440 gst_pad_disconnect (GstPad *srcpad,
441                     GstPad *sinkpad) 
442 {
443   /* generic checks */
444   g_return_if_fail (srcpad != NULL);
445   g_return_if_fail (GST_IS_PAD (srcpad));
446   g_return_if_fail (srcpad->peer != NULL);
447   g_return_if_fail (sinkpad != NULL);
448   g_return_if_fail (GST_IS_PAD (sinkpad));
449   g_return_if_fail (sinkpad->peer != NULL);
450
451   g_return_if_fail ((srcpad->direction == GST_PAD_SRC) &&
452                     (sinkpad->direction == GST_PAD_SINK));
453
454   /* first clear peers */
455   srcpad->peer = NULL;
456   sinkpad->peer = NULL;
457
458   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
459             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
460 }
461
462 /**
463  * gst_pad_connect:
464  * @srcpad: the source pad to connect
465  * @sinkpad: the sink pad to connect
466  *
467  * connects the source pad to the sink pad
468  */
469 void 
470 gst_pad_connect (GstPad *srcpad,
471                  GstPad *sinkpad) 
472 {
473   GstPad *temppad;
474
475   /* generic checks */
476   g_return_if_fail(srcpad != NULL);
477   g_return_if_fail(GST_IS_PAD(srcpad));
478   g_return_if_fail(srcpad->peer == NULL);
479   g_return_if_fail(sinkpad != NULL);
480   g_return_if_fail(GST_IS_PAD(sinkpad));
481   g_return_if_fail(sinkpad->peer == NULL);
482 //  g_return_if_fail(sinkpad->chain != NULL);
483
484   /* check for reversed directions and swap if necessary */
485   if ((srcpad->direction == GST_PAD_SINK) &&
486       (sinkpad->direction == GST_PAD_SRC)) {
487     temppad = srcpad;
488     srcpad = sinkpad;
489     sinkpad = temppad;
490   }
491   g_return_if_fail((srcpad->direction == GST_PAD_SRC) &&
492                    (sinkpad->direction == GST_PAD_SINK));
493  
494   if (!gst_pad_check_compatibility (srcpad, sinkpad)) {
495     g_warning ("gstpad: connecting incompatible pads (%s:%s) and (%s:%s)\n",
496                        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
497   }
498   else {
499     GST_DEBUG (0,"gstpad: connecting compatible pads (%s:%s) and (%s:%s)\n",
500                        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
501   }
502
503   /* first set peers */
504   srcpad->peer = sinkpad;
505   sinkpad->peer = srcpad;
506
507   /* now copy the chain pointer from sink to src */
508   srcpad->chainfunc = sinkpad->chainfunc;
509   /* and the pull function */
510   //srcpad->pullfunc = sinkpad->pullfunc;
511
512   /* set the connected flag */
513   /* FIXME: set connected flag */
514
515   GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s",
516             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
517 }
518
519 /**
520  * gst_pad_set_parent:
521  * @pad: the pad to set the parent 
522  * @parent: the object to set the parent to
523  *
524  * sets the parent object of a pad.
525  */
526 void 
527 gst_pad_set_parent (GstPad *pad,
528                     GstObject *parent) 
529 {
530   g_return_if_fail (pad != NULL);
531   g_return_if_fail (GST_IS_PAD (pad));
532   g_return_if_fail (pad->parent == NULL);
533   g_return_if_fail (parent != NULL);
534   g_return_if_fail (GTK_IS_OBJECT (parent));
535   g_return_if_fail ((gpointer)pad != (gpointer)parent);
536
537   //g_print("set parent %s\n", gst_element_get_name(parent));
538
539   pad->parent = parent;
540 }
541
542 /**
543  * gst_pad_add_ghost_parent:
544  * @pad: the pad to set the ghost parent 
545  * @parent: the object to set the ghost parent to
546  *
547  * add a ghost parent object to a pad.
548  */
549 void 
550 gst_pad_add_ghost_parent (GstPad *pad,
551                           GstObject *parent) 
552 {
553   g_return_if_fail (pad != NULL);
554   g_return_if_fail (GST_IS_PAD (pad));
555   g_return_if_fail (parent != NULL);
556   g_return_if_fail (GTK_IS_OBJECT (parent));
557
558   pad->ghostparents = g_list_prepend (pad->ghostparents, parent);
559 }
560
561
562 /**
563  * gst_pad_remove_ghost_parent:
564  * @pad: the pad to remove the ghost parent 
565  * @parent: the object to remove the ghost parent from
566  *
567  * remove a ghost parent object from a pad.
568  */
569 void 
570 gst_pad_remove_ghost_parent (GstPad *pad,
571                              GstObject *parent) 
572 {
573   g_return_if_fail (pad != NULL);
574   g_return_if_fail (GST_IS_PAD (pad));
575   g_return_if_fail (parent != NULL);
576   g_return_if_fail (GTK_IS_OBJECT (parent));
577
578   pad->ghostparents = g_list_remove (pad->ghostparents, parent);
579 }
580
581 /**
582  * gst_pad_get_parent:
583  * @pad: the pad to get the parent from
584  *
585  * get the parent object of this pad
586  *
587  * Returns: the parent object
588  */
589 GstObject*
590 gst_pad_get_parent (GstPad *pad) 
591 {
592   g_return_val_if_fail (pad != NULL, NULL);
593   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
594
595   return pad->parent;
596 }
597
598 /**
599  * gst_pad_get_ghost_parents:
600  * @pad: the pad to get the ghost parents from
601  *
602  * get the ghost parents of this pad
603  *
604  * Returns: a list of ghost parent objects
605  */
606 GList*
607 gst_pad_get_ghost_parents (GstPad *pad) 
608 {
609   g_return_val_if_fail (pad != NULL, NULL);
610   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
611
612   return pad->ghostparents;
613 }
614
615 /**
616  * gst_pad_set_caps_list:
617  * @pad: the pad to set the caps to
618  * @caps: the capslist to attach to this pad 
619  *
620  * set the capabilities of this pad
621  */
622 void 
623 gst_pad_set_caps_list (GstPad *pad, 
624                        GList *caps) 
625 {
626   g_return_if_fail (pad != NULL);
627   g_return_if_fail (GST_IS_PAD (pad));
628
629   pad->caps = caps;
630 }
631
632 /**
633  * gst_pad_get_caps_list:
634  * @pad: the pad to get the capabilities from
635  *
636  * get the capabilities of this pad
637  *
638  * Returns: a list of capabilities of this pad
639  */
640 GList * 
641 gst_pad_get_caps_list (GstPad *pad) 
642 {
643   g_return_val_if_fail (pad != NULL, NULL);
644   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
645
646   return pad->caps;
647 }
648
649 /**
650  * gst_pad_get_caps_by_name:
651  * @pad: the pad to get the capabilities from
652  * @name: the name of the capability to get
653  *
654  * get the capabilities  with the given name from this pad
655  *
656  * Returns: a capability or NULL if not found
657  */
658 GstCaps * 
659 gst_pad_get_caps_by_name (GstPad *pad, gchar *name) 
660 {
661   GList *caps;
662   
663   g_return_val_if_fail (pad != NULL, NULL);
664   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
665
666   caps = pad->caps;
667
668   while (caps) {
669     GstCaps *cap = (GstCaps *)caps->data;
670
671     if (!strcmp (cap->name, name))
672       return cap;
673
674     caps = g_list_next (caps);
675   }
676   
677   return NULL;
678 }
679
680 /**
681  * gst_pad_check_compatibility:
682  * @srcpad: the srcpad to check
683  * @sinkpad: the sinkpad to check against
684  *
685  * check if two pads have compatible capabilities
686  *
687  * Returns: TRUE if they are compatible ot the capabilities
688  * could not be checked
689  */
690 gboolean  
691 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad) 
692 {
693   g_return_val_if_fail (srcpad != NULL, FALSE);
694   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
695   g_return_val_if_fail (sinkpad != NULL, FALSE);
696   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
697
698   if (srcpad->caps && sinkpad->caps) {
699     if (!gst_caps_list_check_compatibility (srcpad->caps, sinkpad->caps)) {
700       return FALSE;
701     }
702     else {
703       return TRUE;
704     }
705   }
706   else {
707     GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s)\n", 
708                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
709     return TRUE;
710   }
711 }
712
713 /**
714  * gst_pad_get_peer:
715  * @pad: the pad to get the peer from
716  *
717  * Get the peer pad of this pad
718  *
719  * Returns: the peer pad
720  */
721 GstPad*
722 gst_pad_get_peer (GstPad *pad) 
723 {
724   g_return_val_if_fail (pad != NULL, NULL);
725   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
726
727   return pad->peer;
728 }
729
730 static void 
731 gst_pad_real_destroy (GtkObject *object) 
732 {
733   GstPad *pad = GST_PAD (object);
734
735 //  g_print("in gst_pad_real_destroy()\n");
736
737   if (pad->name)
738     g_free (pad->name);
739   g_list_free (pad->ghostparents);
740 }
741
742
743 /**
744  * gst_pad_load_and_connect:
745  * @parent: the parent XML node to read the description from
746  * @element: the element that has the source pad
747  * @elements: a hashtable with elements
748  *
749  * Read the pad definition from the XML node and connect the given pad
750  * in element to a pad of an element in the hashtable.
751  */
752 void 
753 gst_pad_load_and_connect (xmlNodePtr parent, 
754                           GstObject *element, 
755                           GHashTable *elements) 
756 {
757   xmlNodePtr field = parent->childs;
758   GstPad *pad = NULL, *targetpad;
759   guchar *peer = NULL;
760   gchar **split;
761   GstElement *target;
762
763   while (field) {
764     if (!strcmp(field->name, "name")) {
765       pad = gst_element_get_pad(GST_ELEMENT(element), xmlNodeGetContent(field));
766     }
767     else if (!strcmp(field->name, "peer")) {
768       peer = g_strdup(xmlNodeGetContent(field));
769     }
770     field = field->next;
771   }
772   g_return_if_fail(pad != NULL);
773
774   if (peer == NULL) return;
775
776   split = g_strsplit(peer, ".", 2);
777
778   g_return_if_fail(split[0] != NULL);
779   g_return_if_fail(split[1] != NULL);
780
781   target = (GstElement *)g_hash_table_lookup(elements, split[0]);
782
783   if (target == NULL) goto cleanup;
784
785   targetpad = gst_element_get_pad(target, split[1]);
786
787   if (targetpad == NULL) goto cleanup;
788
789   gst_pad_connect(pad, targetpad);
790
791 cleanup:
792   g_strfreev(split);
793 }
794
795
796 /**
797  * gst_pad_save_thyself:
798  * @pad: the pad to save
799  * @parent: the parent XML node to save the description in
800  *
801  * Saves the pad into an xml representation
802  *
803  * Returns: the xml representation of the pad
804  */
805 xmlNodePtr 
806 gst_pad_save_thyself (GstPad *pad,
807                       xmlNodePtr parent) 
808 {
809   GstPad *peer;
810
811   xmlNewChild(parent,NULL,"name",pad->name);
812   if (pad->peer != NULL) {
813     peer = pad->peer;
814     // first check to see if the peer's parent's parent is the same
815     //if (pad->parent->parent == peer->parent->parent)
816       // we just save it off
817       xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s",
818                     GST_ELEMENT(peer->parent)->name,peer->name));
819   } else
820     xmlNewChild(parent,NULL,"peer","");
821
822   return parent;
823 }
824
825 /**
826  * gst_pad_ghost_save_thyself:
827  * @pad: the pad to save
828  * @bin: the bin
829  * @parent: the parent XML node to save the description in
830  *
831  * Saves the ghost pad into an xml representation
832  *
833  * Returns: the xml representation of the pad
834  */
835 xmlNodePtr 
836 gst_pad_ghost_save_thyself (GstPad *pad,
837                             GstElement *bin,
838                             xmlNodePtr parent) 
839 {
840   xmlNodePtr self;
841
842   self = xmlNewChild(parent,NULL,"ghostpad",NULL);
843   xmlNewChild(self,NULL,"name",pad->name);
844   xmlNewChild(self,NULL,"parent",GST_ELEMENT(pad->parent)->name);
845
846   return self;
847 }
848
849 #ifndef gst_pad_push
850 void gst_pad_push(GstPad *pad,GstBuffer *buf) {
851   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
852   if (pad->peer->pushfunc) {
853     GST_DEBUG (0,"calling pushfunc &%s of peer pad %s:%s\n",
854           GST_DEBUG_FUNCPTR_NAME(pad->peer->pushfunc),GST_DEBUG_PAD_NAME(pad->peer));
855     (pad->peer->pushfunc)(pad->peer,buf);
856   } else
857     GST_DEBUG (0,"no pushfunc\n");
858 }
859 #endif
860
861 #ifndef gst_pad_pull
862 GstBuffer *gst_pad_pull(GstPad *pad) {
863   GstPad *peer = pad->peer;
864   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
865   if (peer->pullfunc) {
866     GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n",
867       GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(peer));
868     return (peer->pullfunc)(peer);
869   } else {
870     GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(peer),&peer->pullfunc);
871     return NULL;
872   }
873 }
874 #endif
875
876 #ifndef gst_pad_pullregion
877 GstBuffer *gst_pad_pullregion(GstPad *pad,gulong offset,gulong size) {
878   GST_DEBUG_ENTER("(%s:%s,%ld,%ld)",GST_DEBUG_PAD_NAME(pad),offset,size);
879   if (pad->peer->pullregionfunc) {
880     GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n",
881           GST_DEBUG_FUNCPTR_NAME(pad->peer->pullregionfunc),GST_DEBUG_PAD_NAME(pad->peer));
882     return (pad->peer->pullregionfunc)(pad->peer,offset,size);
883   } else {
884     GST_DEBUG (0,"no pullregionfunc\n");
885     return NULL;
886   }
887 }
888 #endif
889
890 /************************************************************************
891  * 
892  * templates
893  *
894  */
895
896 /**
897  * gst_padtemplate_new:
898  * @factory: the padfactory to use
899  *
900  * creates a new padtemplate from the factory
901  *
902  * Returns: the new padtemplate
903  */
904 GstPadTemplate*   
905 gst_padtemplate_new (GstPadFactory *factory) 
906 {
907   GstPadTemplate *new;
908   GstPadFactoryEntry tag;
909   gint i = 0;
910   guint counter = 0;
911
912   g_return_val_if_fail (factory != NULL, NULL);
913
914   new = g_new0 (GstPadTemplate, 1);
915
916   tag = (*factory)[i++];
917   g_return_val_if_fail (tag != NULL, new);
918   new->name_template = g_strdup ((gchar *)tag);
919
920   tag = (*factory)[i++];
921   new->direction = GPOINTER_TO_UINT (tag);
922
923   tag = (*factory)[i++];
924   new->presence = GPOINTER_TO_UINT (tag);
925
926   tag = (*factory)[i++];
927
928   while (GPOINTER_TO_INT (tag) == 1) {
929     new->caps = g_list_append (new->caps, gst_caps_register_count ((GstCapsFactory *)&(*factory)[i], &counter));
930     i+=counter;
931     tag = (*factory)[i++];
932   }
933
934   return new;
935 }
936
937 /**
938  * gst_padtemplate_create:
939  * @name_template: the name template 
940  * @direction: the direction for the template
941  * @presence: the presence of the pad
942  * @caps: a list of capabilities for the template
943  *
944  * creates a new padtemplate from the given arguments
945  *
946  * Returns: the new padtemplate
947  */
948 GstPadTemplate*
949 gst_padtemplate_create (gchar *name_template,
950                         GstPadDirection direction, GstPadPresence presence,
951                         GList *caps)
952 {
953   GstPadTemplate *new;
954   
955   new = g_new0 (GstPadTemplate, 1);
956
957   new->name_template = name_template;
958   new->direction = direction;
959   new->presence = presence;
960   new->caps = caps;
961
962   return new;
963 }
964
965
966 /**
967  * gst_padtemplate_save_thyself:
968  * @pad: the padtemplate to save
969  * @parent: the parent XML tree
970  *
971  * saves the padtemplate into XML
972  *
973  * Returns: the new XML tree
974  */
975 xmlNodePtr
976 gst_padtemplate_save_thyself (GstPadTemplate *pad, xmlNodePtr parent)
977 {
978   xmlNodePtr subtree;
979   GList *caps;
980
981   xmlNewChild(parent,NULL,"nametemplate", pad->name_template);
982   xmlNewChild(parent,NULL,"direction", (pad->direction == GST_PAD_SINK? "sink":"src"));
983   xmlNewChild(parent,NULL,"presence", (pad->presence == GST_PAD_ALWAYS? "always":"sometimes"));
984
985   caps = pad->caps;
986   while (caps) {
987     GstCaps *cap = (GstCaps *)caps->data;
988     
989     subtree = xmlNewChild(parent,NULL,"caps", NULL);
990     gst_caps_save_thyself (cap, subtree);
991
992     caps = g_list_next (caps);
993   }
994
995   return parent;
996 }
997
998 /**
999  * gst_padtemplate_load_thyself:
1000  * @parent: the source XML tree
1001  *
1002  * loads a padtemplate from the XML tree
1003  *
1004  * Returns: the new padtemplate
1005  */
1006 GstPadTemplate*   
1007 gst_padtemplate_load_thyself (xmlNodePtr parent)
1008 {
1009   xmlNodePtr field = parent->childs;
1010   GstPadTemplate *factory = g_new0 (GstPadTemplate, 1);
1011
1012   while (field) {
1013     if (!strcmp(field->name, "nametemplate")) {
1014       factory->name_template = g_strdup(xmlNodeGetContent(field));
1015     }
1016     if (!strcmp(field->name, "direction")) {
1017       gchar *value = xmlNodeGetContent(field);
1018
1019       factory->direction = GST_PAD_UNKNOWN;
1020       if (!strcmp(value, "sink")) {
1021         factory->direction = GST_PAD_SINK;
1022       }
1023       else if (!strcmp(value, "src")) {
1024         factory->direction = GST_PAD_SRC;
1025       }
1026     }
1027     if (!strcmp(field->name, "presence")) {
1028       gchar *value = xmlNodeGetContent(field);
1029
1030       if (!strcmp(value, "always")) {
1031         factory->presence = GST_PAD_ALWAYS;
1032       }
1033       else if (!strcmp(value, "sometimes")) {
1034         factory->presence = GST_PAD_SOMETIMES;
1035       }
1036     }
1037     else if (!strcmp(field->name, "caps")) {
1038       factory->caps = g_list_append(factory->caps, gst_caps_load_thyself (field));
1039     }
1040     field = field->next;
1041   }
1042   return factory;
1043 }
1044
1045
1046 gboolean
1047 gst_pad_eos_func(GstPad *pad)
1048 {
1049   GstElement *element;
1050   GList *pads;
1051   GstPad *srcpad;
1052   gboolean result = TRUE, success;
1053
1054   g_return_val_if_fail (pad != NULL, FALSE);
1055   g_return_val_if_fail (GST_IS_PAD(pad), FALSE);
1056
1057   GST_INFO (GST_CAT_PADS,"attempting to set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1058
1059   element = GST_ELEMENT(gst_pad_get_parent (pad));
1060 //  g_return_val_if_fail (element != NULL, FALSE);
1061 //  g_return_val_if_fail (GST_IS_ELEMENT(element), FALSE);
1062
1063   pads = gst_element_get_pad_list(element);
1064   while (pads) {
1065     srcpad = GST_PAD(pads->data);
1066     pads = g_list_next(pads);
1067
1068     if (gst_pad_get_direction(srcpad) == GST_PAD_SRC) {
1069       result = gst_pad_eos(srcpad);
1070       if (result == FALSE) success = FALSE;
1071     }
1072   }
1073
1074   if (result == FALSE) return FALSE;
1075
1076   GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1077   GST_FLAG_SET (pad, GST_PAD_EOS);
1078
1079   return TRUE;
1080 }
1081
1082 /**
1083  * gst_pad_set_eos:
1084  * @pad: the pad to set to eos
1085  *
1086  * sets the given pad to the  eos state
1087  *
1088  * Returns: TRUE if it succeeded
1089  */
1090 gboolean
1091 gst_pad_set_eos(GstPad *pad) 
1092 {
1093   g_return_val_if_fail (pad != NULL, FALSE);
1094   g_return_val_if_fail (GST_IS_PAD(pad), FALSE);
1095   g_return_val_if_fail (GST_PAD_CONNECTED(pad), FALSE);
1096
1097   GST_INFO (GST_CAT_PADS,"attempting to set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1098
1099   if (!gst_pad_eos(pad)) return FALSE;
1100
1101   GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1102   GST_FLAG_SET (pad, GST_PAD_EOS);
1103
1104   gst_element_signal_eos (GST_ELEMENT (pad->parent));
1105
1106   return TRUE;
1107 }