Landed the new improved capsnegotiation system.
[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 "gstutils.h"
28 #include "gstelement.h"
29 #include "gsttype.h"
30 #include "gstbin.h"
31 #include "gstscheduler.h"
32 #include "gstevent.h"
33
34 GType _gst_pad_type = 0;
35
36 /***** Start with the base GstPad class *****/
37 static void             gst_pad_class_init              (GstPadClass *klass);
38 static void             gst_pad_init                    (GstPad *pad);
39
40 static gboolean         gst_pad_try_reconnect_filtered_func (GstPad *pad, GstCaps *caps, gboolean clear);
41
42 #ifndef GST_DISABLE_LOADSAVE
43 static xmlNodePtr       gst_pad_save_thyself            (GstObject *object, xmlNodePtr parent);
44 #endif
45
46 static GstObject *pad_parent_class = NULL;
47
48 GType
49 gst_pad_get_type(void) 
50 {
51   if (!_gst_pad_type) {
52     static const GTypeInfo pad_info = {
53       sizeof(GstPadClass),
54       NULL,
55       NULL,
56       (GClassInitFunc)gst_pad_class_init,
57       NULL,
58       NULL,
59       sizeof(GstPad),
60       32,
61       (GInstanceInitFunc)gst_pad_init,
62       NULL
63     };
64     _gst_pad_type = g_type_register_static(GST_TYPE_OBJECT, "GstPad", &pad_info, 0);
65   }
66   return _gst_pad_type;
67 }
68
69 static void
70 gst_pad_class_init (GstPadClass *klass)
71 {
72   pad_parent_class = g_type_class_ref(GST_TYPE_OBJECT);
73 }
74
75 static void
76 gst_pad_init (GstPad *pad)
77 {
78   pad->element_private = NULL;
79
80   pad->padtemplate = NULL;
81 }
82
83
84
85 /***** Then do the Real Pad *****/
86 /* Pad signals and args */
87 enum {
88   REAL_SET_ACTIVE,
89   REAL_CAPS_CHANGED,
90   REAL_CAPS_NEGO_FAILED,
91   REAL_CONNECTED,
92   REAL_DISCONNECTED,
93   REAL_EVENT_RECEIVED,
94   /* FILL ME */
95   REAL_LAST_SIGNAL
96 };
97
98 enum {
99   REAL_ARG_0,
100   REAL_ARG_ACTIVE,
101   /* FILL ME */
102 };
103
104 static void     gst_real_pad_class_init         (GstRealPadClass *klass);
105 static void     gst_real_pad_init               (GstRealPad *pad);
106
107 static void     gst_real_pad_set_property       (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
108 static void     gst_real_pad_get_property       (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
109
110 static void     gst_real_pad_dispose            (GObject *object);
111
112 static void     gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
113
114 GType _gst_real_pad_type = 0;
115
116 static GstPad *real_pad_parent_class = NULL;
117 static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 };
118
119 GType
120 gst_real_pad_get_type(void) {
121   if (!_gst_real_pad_type) {
122     static const GTypeInfo pad_info = {
123       sizeof(GstRealPadClass),
124       NULL,
125       NULL,
126       (GClassInitFunc)gst_real_pad_class_init,
127       NULL,
128       NULL,
129       sizeof(GstRealPad),
130       32,
131       (GInstanceInitFunc)gst_real_pad_init,
132       NULL
133     };
134     _gst_real_pad_type = g_type_register_static(GST_TYPE_PAD, "GstRealPad", &pad_info, 0);
135   }
136   return _gst_real_pad_type;
137 }
138
139 static void
140 gst_real_pad_class_init (GstRealPadClass *klass)
141 {
142   GObjectClass *gobject_class;
143   GstObjectClass *gstobject_class;
144
145   gobject_class = (GObjectClass*) klass;
146   gstobject_class = (GstObjectClass*) klass;
147
148   real_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
149
150   gobject_class->dispose  = GST_DEBUG_FUNCPTR (gst_real_pad_dispose);
151   gobject_class->set_property  = GST_DEBUG_FUNCPTR (gst_real_pad_set_property);
152   gobject_class->get_property  = GST_DEBUG_FUNCPTR (gst_real_pad_get_property);
153
154   gst_real_pad_signals[REAL_SET_ACTIVE] =
155     g_signal_new ("set_active", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
156                     G_STRUCT_OFFSET (GstRealPadClass, set_active), NULL, NULL,
157                     gst_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1,
158                     G_TYPE_BOOLEAN);
159   gst_real_pad_signals[REAL_CAPS_CHANGED] =
160     g_signal_new ("caps_changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
161                     G_STRUCT_OFFSET (GstRealPadClass, caps_changed), NULL, NULL,
162                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
163                     G_TYPE_POINTER);
164   gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
165     g_signal_new ("caps_nego_failed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
166                     G_STRUCT_OFFSET (GstRealPadClass, caps_nego_failed), NULL, NULL,
167                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
168                     G_TYPE_POINTER);
169   gst_real_pad_signals[REAL_CONNECTED] =
170     g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
171                     G_STRUCT_OFFSET (GstRealPadClass, connected), NULL, NULL,
172                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
173                     G_TYPE_POINTER);
174   gst_real_pad_signals[REAL_DISCONNECTED] =
175     g_signal_new ("disconnected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
176                     G_STRUCT_OFFSET (GstRealPadClass, disconnected), NULL, NULL,
177                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
178                     G_TYPE_POINTER);
179   gst_real_pad_signals[REAL_EVENT_RECEIVED] =
180     g_signal_new ("event_received", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
181                     G_STRUCT_OFFSET (GstRealPadClass, event_received), NULL, NULL,
182                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
183                     G_TYPE_POINTER);
184
185 /*  gtk_object_add_arg_type ("GstRealPad::active", G_TYPE_BOOLEAN, */
186 /*                           GTK_ARG_READWRITE, REAL_ARG_ACTIVE); */
187   g_object_class_install_property (G_OBJECT_CLASS (klass), REAL_ARG_ACTIVE,
188     g_param_spec_boolean ("active", "Active", "Whether the pad is active.",
189                           TRUE,G_PARAM_READWRITE));
190
191 #ifndef GST_DISABLE_LOADSAVE
192   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_pad_save_thyself);
193 #endif
194   gstobject_class->path_string_separator = ".";
195 }
196
197 static void
198 gst_real_pad_init (GstRealPad *pad)
199 {
200   pad->direction = GST_PAD_UNKNOWN;
201   pad->peer = NULL;
202
203   pad->sched = NULL;
204   pad->sched_private = NULL;
205
206   pad->chainfunc = NULL;
207   pad->getfunc = NULL;
208   pad->getregionfunc = NULL;
209
210   pad->chainhandler = GST_DEBUG_FUNCPTR (gst_pad_push_func);
211   pad->gethandler = NULL;
212   pad->pullregionfunc = NULL;
213
214   pad->bufferpoolfunc = NULL;
215   pad->ghostpads = NULL;
216   pad->caps = NULL;
217
218   pad->connectfunc = NULL;
219   pad->getcapsfunc = NULL;
220 }
221
222 static void
223 gst_real_pad_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
224 {
225   g_return_if_fail (GST_IS_PAD (object));
226
227   switch (prop_id) {
228     case REAL_ARG_ACTIVE:
229       if (g_value_get_boolean (value)) {
230         GST_DEBUG (GST_CAT_PADS, "activating pad %s:%s\n", GST_DEBUG_PAD_NAME (object));
231         GST_FLAG_UNSET (object, GST_PAD_DISABLED);
232       } else {
233         GST_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s\n", GST_DEBUG_PAD_NAME (object));
234         GST_FLAG_SET (object, GST_PAD_DISABLED);
235       }
236       g_signal_emit (G_OBJECT (object), gst_real_pad_signals[REAL_SET_ACTIVE], 0,
237                       !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
238       break;
239     default:
240       break;
241   }
242 }
243
244 static void
245 gst_real_pad_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
246 {
247   /* it's not null if we got it, but it might not be ours */
248   g_return_if_fail (GST_IS_PAD (object));
249
250   switch (prop_id) {
251     case REAL_ARG_ACTIVE:
252       g_value_set_boolean (value, !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
253       break;
254     default:
255       break;
256   }
257 }
258
259
260 /**
261  * gst_pad_new:
262  * @name: name of new pad
263  * @direction: either GST_PAD_SRC or GST_PAD_SINK
264  *
265  * Create a new pad with given name.
266  *
267  * Returns: new pad
268  */
269 GstPad*
270 gst_pad_new (gchar *name,
271              GstPadDirection direction)
272 {
273   GstRealPad *pad;
274
275   g_return_val_if_fail (name != NULL, NULL);
276   g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
277
278   pad = g_object_new (gst_real_pad_get_type (), NULL);
279   gst_object_set_name (GST_OBJECT (pad), name);
280   GST_RPAD_DIRECTION (pad) = direction;
281
282   return GST_PAD (pad);
283 }
284
285 /**
286  * gst_pad_new_from_template:
287  * @templ: the pad template to use
288  * @name: the name of the element
289  *
290  * Create a new pad with given name from the given template.
291  *
292  * Returns: new pad
293  */
294 GstPad*
295 gst_pad_new_from_template (GstPadTemplate *templ,
296                            gchar *name)
297 {
298   GstPad *pad;
299
300   g_return_val_if_fail (name != NULL, NULL);
301   g_return_val_if_fail (templ != NULL, NULL);
302
303   pad = gst_pad_new (name, templ->direction);
304   
305   gst_object_ref (GST_OBJECT (templ));
306   GST_PAD_PADTEMPLATE (pad) = templ;
307   
308   return pad;
309 }
310
311 /**
312  * gst_pad_get_direction:
313  * @pad: the Pad to get the direction from
314  *
315  * Get the direction of the pad.
316  *
317  * Returns: the direction of the pad
318  */
319 GstPadDirection
320 gst_pad_get_direction (GstPad *pad)
321 {
322   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
323   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
324
325   return GST_PAD_DIRECTION (pad);
326 }
327
328 /**
329  * gst_pad_set_name:
330  * @pad: the pad to set the name of
331  * @name: the name of the pad
332  *
333  * Set the name of a pad.
334  */
335 void
336 gst_pad_set_name (GstPad *pad,
337                   const gchar *name)
338 {
339   g_return_if_fail (pad != NULL);
340   g_return_if_fail (GST_IS_PAD (pad));
341
342   gst_object_set_name (GST_OBJECT (pad), name);
343 }
344
345 /**
346  * gst_pad_get_name:
347  * @pad: the pad to get the name of
348  *
349  * Get the name of a pad.
350  *
351  * Returns: the name of the pad, don't free.
352  */
353 const gchar*
354 gst_pad_get_name (GstPad *pad)
355 {
356   g_return_val_if_fail (pad != NULL, NULL);
357   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
358
359   return GST_OBJECT_NAME (pad);
360 }
361
362 /**
363  * gst_pad_set_chain_function:
364  * @pad: the pad to set the chain function for
365  * @chain: the chain function
366  *
367  * Set the given chain function for the pad.
368  */
369 void gst_pad_set_chain_function (GstPad *pad,
370                                  GstPadChainFunction chain)
371 {
372   g_return_if_fail (pad != NULL);
373   g_return_if_fail (GST_IS_REAL_PAD (pad));
374
375   GST_RPAD_CHAINFUNC(pad) = chain;
376   GST_DEBUG (GST_CAT_PADS, "chainfunc for %s:%s set to %s\n",
377              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (chain));
378 }
379
380 /**
381  * gst_pad_set_get_function:
382  * @pad: the pad to set the get function for
383  * @get: the get function
384  *
385  * Set the given get function for the pad.
386  */
387 void
388 gst_pad_set_get_function (GstPad *pad,
389                           GstPadGetFunction get)
390 {
391   g_return_if_fail (pad != NULL);
392   g_return_if_fail (GST_IS_REAL_PAD (pad));
393
394   GST_RPAD_GETFUNC(pad) = get;
395   GST_DEBUG (GST_CAT_PADS, "getfunc for %s:%s  set to %s\n",
396              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (get));
397 }
398
399 /**
400  * gst_pad_set_event_function:
401  * @pad: the pad to set the event handler for
402  * @event: the event handler
403  *
404  * Set the given event handler for the pad.
405  */
406 void
407 gst_pad_set_event_function (GstPad *pad,
408                             GstPadEventFunction event)
409 {
410   g_return_if_fail (pad != NULL);
411   g_return_if_fail (GST_IS_REAL_PAD (pad));
412
413   GST_RPAD_EVENTFUNC(pad) = event;
414   GST_DEBUG (GST_CAT_PADS, "eventfunc for %s:%s  set to %s\n",
415              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (event));
416 }
417
418 /**
419  * gst_pad_set_getregion_function:
420  * @pad: the pad to set the getregion function for
421  * @getregion: the getregion function
422  *
423  * Set the given getregion function for the pad.
424  */
425 void
426 gst_pad_set_getregion_function (GstPad *pad,
427                                 GstPadGetRegionFunction getregion)
428 {
429   g_return_if_fail (pad != NULL);
430   g_return_if_fail (GST_IS_REAL_PAD (pad));
431
432   GST_RPAD_GETREGIONFUNC(pad) = getregion;
433   GST_DEBUG (GST_CAT_PADS, "getregionfunc for %s:%s set to %s\n",
434              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getregion));
435 }
436
437 /**
438  * gst_pad_set_connect_function:
439  * @pad: the pad to set the connect function for
440  * @connect: the connect function
441  *
442  * Set the given connect function for the pad. It will be called
443  * when the pad is connected or reconnected with caps.
444  */
445 void
446 gst_pad_set_connect_function (GstPad *pad,
447                               GstPadConnectFunction connect)
448 {
449   g_return_if_fail (pad != NULL);
450   g_return_if_fail (GST_IS_REAL_PAD (pad));
451
452   GST_RPAD_CONNECTFUNC (pad) = connect;
453   GST_DEBUG (GST_CAT_PADS, "connectfunc for %s:%s set to %s\n",
454              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (connect));
455 }
456
457 /**
458  * gst_pad_set_getcaps_function:
459  * @pad: the pad to set the getcaps function for
460  * @getcaps: the getcaps function
461  *
462  * Set the given getcaps function for the pad.
463  */
464 void
465 gst_pad_set_getcaps_function (GstPad *pad,
466                               GstPadGetCapsFunction getcaps)
467 {
468   g_return_if_fail (pad != NULL);
469   g_return_if_fail (GST_IS_REAL_PAD (pad));
470
471   GST_RPAD_GETCAPSFUNC (pad) = getcaps;
472   GST_DEBUG (GST_CAT_PADS, "getcapsfunc for %s:%s set to %s\n",
473              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getcaps));
474 }
475 /**
476  * gst_pad_set_bufferpool_function:
477  * @pad: the pad to set the bufferpool function for
478  * @bufpool: the bufferpool function
479  *
480  * Set the given bufferpool function for the pad.
481  */
482 void
483 gst_pad_set_bufferpool_function (GstPad *pad,
484                                  GstPadBufferPoolFunction bufpool)
485 {
486   g_return_if_fail (pad != NULL);
487   g_return_if_fail (GST_IS_REAL_PAD (pad));
488
489   GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
490   GST_DEBUG (GST_CAT_PADS, "bufferpoolfunc for %s:%s set to %s\n",
491              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (bufpool));
492 }
493
494 static void
495 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
496 {
497   if (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad)) != NULL) {
498     GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function %s\n",
499                GST_DEBUG_FUNCPTR_NAME (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))));
500     (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))) (pad, buf);
501   } else {
502     GST_DEBUG (GST_CAT_DATAFLOW, "default pad_push handler in place, no chain function\n");
503     g_warning ("(internal error) default pad_push in place for pad %s:%s but it has no chain function", 
504                     GST_DEBUG_PAD_NAME (pad));
505   }
506 }
507
508
509 /**
510  * gst_pad_disconnect:
511  * @srcpad: the source pad to disconnect
512  * @sinkpad: the sink pad to disconnect
513  *
514  * Disconnects the source pad from the sink pad.
515  */
516 void
517 gst_pad_disconnect (GstPad *srcpad,
518                     GstPad *sinkpad)
519 {
520   GstRealPad *realsrc, *realsink;
521
522   /* generic checks */
523   g_return_if_fail (srcpad != NULL);
524   g_return_if_fail (GST_IS_PAD (srcpad));
525   g_return_if_fail (sinkpad != NULL);
526   g_return_if_fail (GST_IS_PAD (sinkpad));
527
528   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
529             GST_DEBUG_PAD_NAME (srcpad), srcpad, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
530
531   /* now we need to deal with the real/ghost stuff */
532   realsrc = GST_PAD_REALIZE (srcpad);
533   realsink = GST_PAD_REALIZE (sinkpad);
534
535   g_return_if_fail (GST_RPAD_PEER (realsrc) != NULL);
536   g_return_if_fail (GST_RPAD_PEER (realsink) != NULL);
537
538   if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
539       (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
540     GstRealPad *temppad;
541
542     temppad = realsrc;
543     realsrc = realsink;
544     realsink = temppad;
545   }
546   g_return_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
547                     (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK));
548
549   /* first clear peers */
550   GST_RPAD_PEER (realsrc) = NULL;
551   GST_RPAD_PEER (realsink) = NULL;
552
553   /* reset the filters, both filters are refcounted once */
554   if (GST_RPAD_FILTER (realsrc)) {
555     gst_caps_unref (GST_RPAD_FILTER (realsrc));
556     GST_RPAD_FILTER (realsink) = NULL;
557     GST_RPAD_FILTER (realsrc) = NULL;
558   }
559
560   /* now tell the scheduler */
561   if (GST_PAD_PARENT (realsrc)->sched)
562     gst_scheduler_pad_disconnect (GST_PAD_PARENT (realsrc)->sched, (GstPad *)realsrc, (GstPad *)realsink);
563   else if (GST_PAD_PARENT (realsink)->sched)
564     gst_scheduler_pad_disconnect (GST_PAD_PARENT (realsink)->sched, (GstPad *)realsrc, (GstPad *)realsink);
565
566   /* fire off a signal to each of the pads telling them that they've been disconnected */
567   g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsink);
568   g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsrc);
569
570   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
571             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
572 }
573
574 /**
575  * gst_pad_connect_filtered:
576  * @srcpad: the source pad to connect
577  * @sinkpad: the sink pad to connect
578  * @filtercaps: the filter caps.
579  *
580  * Connects the source pad to the sink pad. The filter indicates the media type
581  * that should flow trought this connection.
582  *
583  * Returns: TRUE if the pad could be connected, FALSE otherwise
584  */
585 gboolean
586 gst_pad_connect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
587 {
588   GstRealPad *realsrc, *realsink;
589   gboolean negotiated = FALSE;
590
591   /* generic checks */
592   g_return_val_if_fail (srcpad != NULL, FALSE);
593   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
594   g_return_val_if_fail (sinkpad != NULL, FALSE);
595   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
596
597   GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
598             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
599
600   /* now we need to deal with the real/ghost stuff */
601   realsrc = GST_PAD_REALIZE (srcpad);
602   realsink = GST_PAD_REALIZE (sinkpad);
603
604   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
605     GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
606               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
607
608   g_return_val_if_fail (GST_RPAD_PEER (realsrc) == NULL, FALSE);
609   g_return_val_if_fail (GST_RPAD_PEER (realsink) == NULL, FALSE);
610
611   /* check for reversed directions and swap if necessary */
612   if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
613       (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
614     GstRealPad *temppad;
615
616     temppad = realsrc;
617     realsrc = realsink;
618     realsink = temppad;
619   }
620   g_return_val_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
621                         (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK), FALSE);
622
623   /* first set peers */
624   GST_RPAD_PEER (realsrc) = realsink;
625   GST_RPAD_PEER (realsink) = realsrc;
626
627   if (!gst_pad_try_reconnect_filtered_func (GST_PAD (realsrc), filtercaps, FALSE)) {
628     GST_DEBUG (GST_CAT_CAPS, "pads cannot connect\n");
629
630     GST_RPAD_PEER (realsrc) = NULL;
631     GST_RPAD_PEER (realsink) = NULL;
632
633     return FALSE;
634   }
635     
636   /* fire off a signal to each of the pads telling them that they've been connected */
637   g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_CONNECTED], 0, realsink);
638   g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_CONNECTED], 0, realsrc);
639
640   /* now tell the scheduler(s) */
641   if (realsrc->sched)
642     gst_scheduler_pad_connect (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
643   else if (realsink->sched)
644     gst_scheduler_pad_connect (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
645
646   GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
647             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
648
649   return TRUE;
650 }
651
652 /**
653  * gst_pad_connect:
654  * @srcpad: the source pad to connect
655  * @sinkpad: the sink pad to connect
656  *
657  * Connects the source pad to the sink pad.
658  *
659  * Returns: TRUE if the pad could be connected, FALSE otherwise
660  */
661 gboolean
662 gst_pad_connect (GstPad *srcpad, GstPad *sinkpad)
663 {
664   return gst_pad_connect_filtered (srcpad, sinkpad, NULL);
665 }
666
667 /**
668  * gst_pad_set_parent:
669  * @pad: the pad to set the parent
670  * @parent: the object to set the parent to
671  *
672  * Sets the parent object of a pad.
673  */
674 void
675 gst_pad_set_parent (GstPad *pad,
676                     GstObject *parent)
677 {
678   g_return_if_fail (pad != NULL);
679   g_return_if_fail (GST_IS_PAD (pad));
680   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
681   g_return_if_fail (parent != NULL);
682   g_return_if_fail (GST_IS_OBJECT (parent));
683   g_return_if_fail ((gpointer)pad != (gpointer)parent);
684
685   gst_object_set_parent (GST_OBJECT (pad), parent);
686 }
687
688 /**
689  * gst_pad_get_parent:
690  * @pad: the pad to get the parent from
691  *
692  * Get the parent object of this pad.
693  *
694  * Returns: the parent object
695  */
696 GstElement*
697 gst_pad_get_parent (GstPad *pad)
698 {
699   g_return_val_if_fail (pad != NULL, NULL);
700   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
701
702   return GST_PAD_PARENT (pad);
703 }
704
705 /**
706  * gst_pad_get_padtemplate:
707  * @pad: the pad to get the padtemplate from
708  *
709  * Get the padtemplate object of this pad.
710  *
711  * Returns: the padtemplate object
712  */
713 GstPadTemplate*
714 gst_pad_get_padtemplate (GstPad *pad)
715 {
716   g_return_val_if_fail (pad != NULL, NULL);
717   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
718
719   return GST_PAD_PADTEMPLATE (pad); 
720 }
721
722
723 /**
724  * gst_pad_set_sched:
725  * @pad: the pad to set the scheduler for
726  * @sched: The scheduler to set
727  *
728  * Set the sceduler for the pad
729  */
730 void
731 gst_pad_set_sched (GstPad *pad, GstScheduler *sched)
732 {
733   g_return_if_fail (pad != NULL);
734   g_return_if_fail (GST_IS_PAD (pad));
735  
736   GST_RPAD_SCHED(pad) = sched;
737 }
738  
739 /**
740  * gst_pad_get_sched:
741  * @pad: the pad to get the scheduler from
742  *
743  * Get the scheduler of the pad
744  *
745  * Returns: the scheduler of the pad.
746  */
747 GstScheduler*
748 gst_pad_get_sched (GstPad *pad)
749 {
750   g_return_val_if_fail (pad != NULL, NULL);
751   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
752  
753   return GST_RPAD_SCHED(pad);
754 }
755
756 /**
757  * gst_pad_get_real_parent:
758  * @pad: the pad to get the parent from
759  *
760  * Get the real parent object of this pad. If the pad
761  * is a ghostpad, the actual owner of the real pad is
762  * returned, as opposed to the gst_pad_get_parent().
763  *
764  * Returns: the parent object
765  */
766 GstElement*
767 gst_pad_get_real_parent (GstPad *pad)
768 {
769   g_return_val_if_fail (pad != NULL, NULL);
770   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
771
772   return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad)));
773 }
774
775 /**
776  * gst_pad_add_ghost_pad:
777  * @pad: the pad to set the ghost parent
778  * @ghostpad: the ghost pad to add
779  *
780  * Add a ghost pad to a pad.
781  */
782 void
783 gst_pad_add_ghost_pad (GstPad *pad,
784                        GstPad *ghostpad)
785 {
786   GstRealPad *realpad;
787
788   g_return_if_fail (pad != NULL);
789   g_return_if_fail (GST_IS_PAD (pad));
790   g_return_if_fail (ghostpad != NULL);
791   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
792
793   realpad = GST_PAD_REALIZE (pad);
794
795   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
796 }
797
798
799 /**
800  * gst_pad_remove_ghost_pad:
801  * @pad: the pad to remove the ghost parent
802  * @ghostpad: the ghost pad to remove from the pad
803  *
804  * Remove a ghost pad from a pad.
805  */
806 void
807 gst_pad_remove_ghost_pad (GstPad *pad,
808                           GstPad *ghostpad)
809 {
810   GstRealPad *realpad;
811
812   g_return_if_fail (pad != NULL);
813   g_return_if_fail (GST_IS_PAD (pad));
814   g_return_if_fail (ghostpad != NULL);
815   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
816
817   realpad = GST_PAD_REALIZE (pad);
818
819   realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad);
820 }
821
822 /**
823  * gst_pad_get_ghost_pad_list:
824  * @pad: the pad to get the ghost parents from
825  *
826  * Get the ghost parents of this pad.
827  *
828  * Returns: a GList of ghost pads
829  */
830 GList*
831 gst_pad_get_ghost_pad_list (GstPad *pad)
832 {
833   g_return_val_if_fail (pad != NULL, NULL);
834   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
835
836   return GST_PAD_REALIZE(pad)->ghostpads;
837 }
838
839 static GstPadConnectReturn
840 gst_pad_try_set_caps_func (GstPad *pad, GstCaps *caps, gboolean notify, gboolean set_caps)
841 {
842   GstCaps *oldcaps;
843
844   GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
845             caps, GST_DEBUG_PAD_NAME (pad));
846
847   if (notify && GST_RPAD_CONNECTFUNC (pad)) {
848     GstPadConnectReturn res;
849     gchar *debug_string;
850
851     GST_INFO (GST_CAT_CAPS, "calling connect function on pad %s:%s",
852             GST_DEBUG_PAD_NAME (pad));
853
854     res = GST_RPAD_CONNECTFUNC (pad) (pad, caps);
855
856     switch (res) {
857       case GST_PAD_CONNECT_REFUSED:
858         debug_string = "REFUSED";
859         break;
860       case GST_PAD_CONNECT_OK:
861         debug_string = "OK";
862         break;
863       case GST_PAD_CONNECT_DONE:
864         debug_string = "DONE";
865         break;
866       case GST_PAD_CONNECT_DELAYED:
867         debug_string = "DELAYED";
868         break;
869       default:
870         g_warning ("unknown return code from connect function of pad %s:%s",
871             GST_DEBUG_PAD_NAME (pad));
872         return GST_PAD_CONNECT_REFUSED;
873     }
874
875     GST_INFO (GST_CAT_CAPS, "got reply %s (%d) from connect function on pad %s:%s",
876             debug_string, res, GST_DEBUG_PAD_NAME (pad));
877
878     if (res == GST_PAD_CONNECT_DONE) {
879       GST_INFO (GST_CAT_CAPS, "pad %s:%s is done", GST_DEBUG_PAD_NAME (pad));
880       return GST_PAD_CONNECT_DONE;
881     }
882     if (res == GST_PAD_CONNECT_REFUSED) {
883       GST_INFO (GST_CAT_CAPS, "pad %s:%s doesn't accept caps",
884                     GST_DEBUG_PAD_NAME (pad));
885       return GST_PAD_CONNECT_REFUSED;
886     }
887   }
888   /* we can only set caps on the pad if they are ficed */
889   if (GST_CAPS_IS_FIXED (caps)) {
890
891     if (set_caps) {
892       GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s",
893               GST_DEBUG_PAD_NAME (pad));
894       /* if we got this far all is ok */
895       oldcaps = GST_PAD_CAPS (pad);
896       if (caps) gst_caps_ref (caps);
897       GST_PAD_CAPS (pad) = caps;
898       if (oldcaps) gst_caps_unref (oldcaps);
899     }
900     else {
901       GST_INFO (GST_CAT_CAPS, "NOT setting caps on pad %s:%s, as requested",
902               GST_DEBUG_PAD_NAME (pad));
903     }
904   }
905   else {
906     GST_INFO (GST_CAT_CAPS, "caps are not fixed on pad %s:%s, not setting them yet",
907               GST_DEBUG_PAD_NAME (pad));
908   }
909
910   return GST_PAD_CONNECT_OK;
911 }
912
913 gboolean
914 gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
915 {
916   GstCaps *oldcaps;
917   GstPad *peer;
918
919   peer = GST_PAD (GST_RPAD_PEER (pad));
920
921   GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
922             caps, GST_DEBUG_PAD_NAME (pad));
923
924   if (!GST_CAPS_IS_FIXED (caps)) {
925     g_warning ("trying to set non fixed caps on pad %s:%s, caps dump follow",
926             GST_DEBUG_PAD_NAME (pad));
927     gst_caps_debug (caps);
928     return FALSE;
929   }
930   if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE, TRUE))
931     return FALSE;
932   if (!gst_pad_try_set_caps_func (pad, caps, FALSE, TRUE))
933     return FALSE;
934           
935   return TRUE;
936 }
937
938
939 static gboolean
940 gst_pad_try_reconnect_filtered_func (GstPad *pad, GstCaps *filtercaps, gboolean clear)
941 {
942   GstCaps *srccaps, *sinkcaps;
943   GstCaps *intersection = NULL;
944   GstRealPad *realsrc, *realsink;
945
946   g_return_val_if_fail (pad != NULL, FALSE);
947
948   realsrc = GST_PAD_REALIZE (pad);
949   realsink = GST_PAD_REALIZE (GST_RPAD_PEER (realsrc));
950
951   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
952   g_return_val_if_fail (GST_RPAD_PEER (realsink) != NULL, FALSE);
953
954   GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s",
955         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
956
957   if (clear) {
958     GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s, clearing caps",
959         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
960
961     GST_PAD_CAPS (GST_PAD (realsrc)) = NULL;
962     GST_PAD_CAPS (GST_PAD (realsink)) = NULL;
963   }
964
965   srccaps = gst_pad_get_caps (GST_PAD (realsrc));
966   GST_INFO (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsrc));
967   gst_caps_debug (srccaps);
968   sinkcaps = gst_pad_get_caps (GST_PAD (realsink));
969   GST_INFO (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsink));
970   gst_caps_debug (sinkcaps);
971
972   intersection = gst_caps_intersect (srccaps, sinkcaps);
973
974   /* if we have no intersection but one of the caps was not NULL.. */
975   if (!intersection && (srccaps || sinkcaps )) {
976     /* the intersection is NULL, this means they have no common format */
977     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s have no common type",
978          GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
979     return FALSE;
980   }
981   else {
982     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps",
983          GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink), 
984          ((intersection && GST_CAPS_IS_FIXED (intersection)) ? "fixed" : "variable"));
985
986     if (filtercaps) {
987       GstCaps *filtered_intersection = gst_caps_intersect (intersection, filtercaps);
988
989       /* get rid of the old intersection here */
990       gst_caps_unref (intersection);
991
992       if (!filtered_intersection) {
993         GST_INFO (GST_CAT_PADS, "filtered connection between pads %s:%s and %s:%s is empty, disconnecting",
994              GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
995         return FALSE;
996       }
997       intersection = filtered_intersection;
998
999       GST_RPAD_APPFILTER (realsink) = filtercaps;
1000       GST_RPAD_APPFILTER (realsrc) = filtercaps;
1001     }
1002   }
1003   GST_DEBUG (GST_CAT_CAPS, "setting filter for connection to:\n");
1004   gst_caps_debug (intersection);
1005
1006   GST_RPAD_FILTER (realsrc) = intersection; 
1007   GST_RPAD_FILTER (realsink) = intersection; 
1008
1009   if (intersection) {
1010     GstPadConnectReturn res;
1011
1012     res = gst_pad_try_set_caps_func (GST_PAD (realsrc), intersection, TRUE, TRUE);
1013     if (res == GST_PAD_CONNECT_REFUSED) 
1014       return FALSE;
1015     if (res == GST_PAD_CONNECT_DONE) 
1016       return TRUE;
1017
1018     res = gst_pad_try_set_caps_func (GST_PAD (realsink), intersection, TRUE, TRUE);
1019     if (res == GST_PAD_CONNECT_REFUSED) 
1020       return FALSE;
1021     if (res == GST_PAD_CONNECT_DONE) 
1022       return TRUE;
1023   }
1024
1025   return TRUE;
1026 }
1027
1028 /**
1029  * gst_pad_try_reconnect_filtered:
1030  * @pad: the pad to reconnect
1031  * @caps: the capabilities to use in the reconnectiong
1032  *
1033  * Try to reconnect this pad and its peer with the specified caps
1034  *
1035  * Returns: a boolean indicating the peer pad could accept the caps.
1036  */
1037 gboolean
1038 gst_pad_try_reconnect_filtered (GstPad *pad, GstCaps *filtercaps)
1039 {
1040   g_return_val_if_fail (pad != NULL, FALSE);
1041   g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);  
1042   g_return_val_if_fail (GST_PAD_IS_CONNECTED (pad), FALSE);
1043   
1044   return gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE);
1045 }
1046
1047 /**
1048  * gst_pad_reconnect_filtered:
1049  * @pad: the pad to reconnect
1050  * @caps: the capabilities to use in the reconnectiong
1051  *
1052  * Try to reconnect this pad and its peer with the specified caps. 
1053  *
1054  * Returns: a boolean indicating the peer pad could accept the caps.
1055  *    if FALSE is returned, the pads are disconnected.
1056  */
1057 gboolean
1058 gst_pad_reconnect_filtered (GstPad *pad, GstCaps *filtercaps)
1059 {
1060   g_return_val_if_fail (pad != NULL, FALSE);
1061   g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
1062   g_return_val_if_fail (GST_PAD_IS_CONNECTED (pad), FALSE);
1063
1064   if (!gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE)) {
1065     gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
1066     return FALSE;
1067   }
1068   return TRUE;
1069 }
1070
1071 /**
1072  * gst_pad_proxy_connect:
1073  * @pad: the pad to proxy to
1074  * @caps: the capabilities to use in the proxying
1075  *
1076  * Proxy the connect function to the specified pad.
1077  *
1078  * Returns: a boolean indicating the peer pad could accept the caps.
1079  */
1080 GstPadConnectReturn
1081 gst_pad_proxy_connect (GstPad *pad, GstCaps *caps)
1082 {
1083   GstPad *peer;
1084
1085   peer = GST_PAD (GST_RPAD_PEER (pad));
1086
1087   GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s",
1088             GST_DEBUG_PAD_NAME (pad));
1089
1090   if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE, TRUE))
1091     return GST_PAD_CONNECT_REFUSED;
1092   if (!gst_pad_try_set_caps_func (pad, caps, FALSE, TRUE))
1093     return GST_PAD_CONNECT_REFUSED;
1094
1095   return GST_PAD_CONNECT_OK;
1096 }
1097
1098 /**
1099  * gst_pad_get_caps:
1100  * @pad: the pad to get the capabilities from
1101  *
1102  * Get the capabilities of this pad.
1103  *
1104  * Returns: the capabilities of this pad
1105  */
1106 GstCaps*
1107 gst_pad_get_caps (GstPad *pad)
1108 {
1109   g_return_val_if_fail (pad != NULL, NULL);
1110   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1111
1112   GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)\n",
1113             GST_DEBUG_PAD_NAME (pad), pad);
1114
1115   if (GST_PAD_CAPS (pad)) {
1116     GST_DEBUG (GST_CAT_CAPS, "using pad real caps\n");
1117     return GST_PAD_CAPS (pad);
1118   }
1119   else if GST_RPAD_GETCAPSFUNC (pad) {
1120     GST_DEBUG (GST_CAT_CAPS, "using pad get function\n");
1121     return GST_RPAD_GETCAPSFUNC (pad) (pad, NULL);
1122   }
1123   else if (GST_PAD_PADTEMPLATE (pad)) {
1124     GST_DEBUG (GST_CAT_CAPS, "using pad template\n");
1125     return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad));
1126   }
1127   GST_DEBUG (GST_CAT_CAPS, "pad has no caps\n");
1128
1129   return NULL;
1130 }
1131
1132 /**
1133  * gst_pad_get_padtemplate_caps:
1134  * @pad: the pad to get the capabilities from
1135  *
1136  * Get the capabilities of this pad.
1137  *
1138  * Returns: a list of the capabilities of this pad
1139  */
1140 GstCaps*
1141 gst_pad_get_padtemplate_caps (GstPad *pad)
1142 {
1143   g_return_val_if_fail (pad != NULL, NULL);
1144   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1145
1146   if (GST_PAD_PADTEMPLATE (pad))
1147     return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad));
1148
1149   return NULL;
1150 }
1151
1152
1153 /**
1154  * gst_padtemplate_get_caps_by_name:
1155  * @templ: the padtemplate to get the capabilities from
1156  * @name: the name of the capability to get
1157  *
1158  * Get the capability with the given name from this padtemplate.
1159  *
1160  * Returns: a capability or NULL if not found
1161  */
1162 GstCaps*
1163 gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
1164 {
1165   GstCaps *caps;
1166
1167   g_return_val_if_fail (templ != NULL, NULL);
1168
1169   caps = GST_PADTEMPLATE_CAPS (templ);
1170   if (!caps) 
1171     return NULL;
1172
1173   return gst_caps_get_by_name (caps, name);
1174 }
1175
1176 /**
1177  * gst_pad_check_compatibility:
1178  * @srcpad: the srcpad to check
1179  * @sinkpad: the sinkpad to check against
1180  *
1181  * Check if two pads have compatible capabilities.
1182  *
1183  * Returns: TRUE if they are compatible or the capabilities
1184  * could not be checked
1185  */
1186 gboolean
1187 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
1188 {
1189   g_return_val_if_fail (srcpad != NULL, FALSE);
1190   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
1191   g_return_val_if_fail (sinkpad != NULL, FALSE);
1192   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
1193
1194   if (GST_PAD_CAPS (srcpad) && GST_PAD_CAPS (sinkpad)) {
1195     if (!gst_caps_check_compatibility (GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad))) {
1196       return FALSE;
1197     }
1198     else {
1199       return TRUE;
1200     }
1201   }
1202   else {
1203     GST_DEBUG (GST_CAT_PADS, "could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
1204                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), 
1205                     GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
1206     return TRUE;
1207   }
1208 }
1209
1210 /**
1211  * gst_pad_get_peer:
1212  * @pad: the pad to get the peer from
1213  *
1214  * Get the peer pad of this pad.
1215  *
1216  * Returns: the peer pad
1217  */
1218 GstPad*
1219 gst_pad_get_peer (GstPad *pad)
1220 {
1221   g_return_val_if_fail (pad != NULL, NULL);
1222   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1223
1224   return GST_PAD (GST_PAD_PEER (pad));
1225 }
1226
1227 /**
1228  * gst_pad_get_allowed_caps:
1229  * @pad: the pad to get the allowed caps from
1230  *
1231  * Gst the caps of the allowed media types that can
1232  * go through this pad.
1233  *
1234  * Returns: the allowed caps
1235  */
1236 GstCaps*
1237 gst_pad_get_allowed_caps (GstPad *pad)
1238 {
1239   GstRealPad *peer;
1240   
1241   g_return_val_if_fail (pad != NULL, NULL);
1242   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1243
1244   peer = GST_RPAD_PEER (pad);
1245
1246   GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s\n", GST_DEBUG_PAD_NAME (pad));
1247   /* this is not very correct: ... 
1248   if (peer && GST_RPAD_GETCAPSFUNC (peer)) {
1249     GST_DEBUG (GST_CAT_PROPERTIES, "using getcaps function of peer %s:%s\n", 
1250                     GST_DEBUG_PAD_NAME (peer));
1251     return GST_RPAD_GETCAPSFUNC (peer) (GST_PAD (peer), NULL);
1252   }
1253   */
1254   return gst_caps_copy (GST_RPAD_FILTER (pad));
1255 }
1256
1257 /**
1258  * gst_pad_get_allowed_caps:
1259  * @pad: the pad to get the allowed caps from
1260  *
1261  * Gst the caps of the allowed media types that can
1262  * go through this pad.
1263  *
1264  * Returns: the allowed caps
1265  */
1266 gboolean
1267 gst_pad_recalc_allowed_caps (GstPad *pad)
1268 {
1269   GstRealPad *peer;
1270
1271   g_return_if_fail (pad != NULL);
1272   g_return_if_fail (GST_IS_PAD (pad));
1273
1274   GST_DEBUG (GST_CAT_PROPERTIES, "set allowed caps of %s:%s\n", GST_DEBUG_PAD_NAME (pad));
1275
1276   peer = GST_RPAD_PEER (pad);
1277   if (peer)
1278     gst_pad_try_reconnect_filtered (pad, GST_RPAD_APPFILTER (pad));
1279 }
1280
1281 /**
1282  * gst_pad_get_bufferpool:
1283  * @pad: the pad to get the bufferpool from
1284  *
1285  * Get the bufferpool of the peer pad of the given
1286  * pad
1287  *
1288  * Returns: The GstBufferPool or NULL.
1289  */
1290 GstBufferPool*          
1291 gst_pad_get_bufferpool (GstPad *pad)
1292 {
1293   GstRealPad *peer;
1294
1295   g_return_val_if_fail (pad != NULL, NULL);
1296   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1297    
1298   peer = GST_RPAD_PEER (pad);
1299
1300   if (!peer)
1301     return NULL;
1302
1303   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
1304
1305   if (peer->bufferpoolfunc) {
1306     GST_DEBUG (GST_CAT_PADS, "calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
1307       GST_DEBUG_FUNCPTR_NAME (peer->bufferpoolfunc), &peer->bufferpoolfunc, GST_DEBUG_PAD_NAME (((GstPad*) peer)));
1308     return (peer->bufferpoolfunc) (((GstPad*) peer));
1309   } else {
1310     GST_DEBUG (GST_CAT_PADS, "no bufferpoolfunc for peer pad %s:%s at %p\n",
1311                     GST_DEBUG_PAD_NAME (((GstPad*) peer)), &peer->bufferpoolfunc);
1312     return NULL;
1313   }
1314 }
1315
1316 static void
1317 gst_real_pad_dispose (GObject *object)
1318 {
1319   GstPad *pad = GST_PAD (object);
1320   
1321   GST_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s\n", GST_DEBUG_PAD_NAME(pad));
1322
1323   if (GST_PAD (pad)->padtemplate){
1324     GST_DEBUG (GST_CAT_REFCOUNTING, "unreffing padtemplate'%s'\n",GST_OBJECT_NAME(GST_OBJECT (GST_PAD (pad)->padtemplate)));
1325     gst_object_unref (GST_OBJECT (GST_PAD (pad)->padtemplate));
1326   }
1327   
1328   if (GST_PAD_PEER (pad)){
1329     GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'\n",GST_OBJECT_NAME(GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
1330     gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
1331   }
1332   
1333   /* we destroy the ghostpads, because they are nothing without the real pad  */
1334   if (GST_REAL_PAD (pad)->ghostpads) {
1335     GList *orig, *ghostpads;
1336
1337     orig = ghostpads = g_list_copy (GST_REAL_PAD (pad)->ghostpads);
1338
1339     while (ghostpads) {
1340       GstPad *ghostpad = GST_PAD (ghostpads->data);
1341
1342       if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))){
1343         GST_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'\n", 
1344                         GST_OBJECT_NAME (GST_OBJECT_PARENT (ghostpad)));
1345
1346         gst_element_remove_ghost_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), GST_PAD (ghostpad));
1347       }
1348       ghostpads = g_list_next (ghostpads);
1349     }
1350     g_list_free (orig);
1351     g_list_free (GST_REAL_PAD(pad)->ghostpads);
1352   }
1353
1354   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))){
1355     GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'\n",
1356                     GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
1357     
1358     gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
1359   }
1360   
1361   G_OBJECT_CLASS (real_pad_parent_class)->dispose (object);
1362 }
1363
1364
1365 #ifndef GST_DISABLE_LOADSAVE
1366 /**
1367  * gst_pad_load_and_connect:
1368  * @self: the XML node to read the description from
1369  * @parent: the element that has the pad
1370  *
1371  * Read the pad definition from the XML node and connect the given pad
1372  * in element to a pad of an element up in the hierarchy.
1373  */
1374 void
1375 gst_pad_load_and_connect (xmlNodePtr self,
1376                           GstObject *parent)
1377 {
1378   xmlNodePtr field = self->xmlChildrenNode;
1379   GstPad *pad = NULL, *targetpad;
1380   guchar *peer = NULL;
1381   gchar **split;
1382   GstElement *target;
1383   GstObject *grandparent;
1384
1385   while (field) {
1386     if (!strcmp (field->name, "name")) {
1387       pad = gst_element_get_pad (GST_ELEMENT (parent), xmlNodeGetContent (field));
1388     }
1389     else if (!strcmp(field->name, "peer")) {
1390       peer = xmlNodeGetContent (field);
1391     }
1392     field = field->next;
1393   }
1394   g_return_if_fail (pad != NULL);
1395
1396   if (peer == NULL) return;
1397
1398   split = g_strsplit (peer, ".", 2);
1399
1400   g_return_if_fail (split[0] != NULL);
1401   g_return_if_fail (split[1] != NULL);
1402
1403   grandparent = gst_object_get_parent (parent);
1404
1405   if (grandparent && GST_IS_BIN (grandparent)) {
1406     target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
1407   }
1408   else
1409     goto cleanup;
1410
1411   if (target == NULL) goto cleanup;
1412
1413   targetpad = gst_element_get_pad (target, split[1]);
1414
1415   if (targetpad == NULL) goto cleanup;
1416
1417   gst_pad_connect (pad, targetpad);
1418
1419 cleanup:
1420   g_strfreev (split);
1421 }
1422
1423 /**
1424  * gst_pad_save_thyself:
1425  * @pad: the pad to save
1426  * @parent: the parent XML node to save the description in
1427  *
1428  * Saves the pad into an xml representation
1429  *
1430  * Returns: the xml representation of the pad
1431  */
1432 static xmlNodePtr
1433 gst_pad_save_thyself (GstObject *object,
1434                       xmlNodePtr parent)
1435 {
1436   GstRealPad *realpad;
1437   GstPad *peer;
1438
1439   g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
1440
1441   realpad = GST_REAL_PAD(object);
1442
1443   xmlNewChild(parent,NULL,"name", GST_PAD_NAME (realpad));
1444   if (GST_RPAD_PEER(realpad) != NULL) {
1445     peer = GST_PAD(GST_RPAD_PEER(realpad));
1446     /* first check to see if the peer's parent's parent is the same */
1447     /* we just save it off */
1448     xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s",
1449                     GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)));
1450   } else
1451     xmlNewChild(parent,NULL,"peer","");
1452
1453   return parent;
1454 }
1455
1456 /**
1457  * gst_pad_ghost_save_thyself:
1458  * @pad: the pad to save
1459  * @bin: the bin
1460  * @parent: the parent XML node to save the description in
1461  *
1462  * Saves the ghost pad into an xml representation.
1463  *
1464  * Returns: the xml representation of the pad
1465  */
1466 xmlNodePtr
1467 gst_pad_ghost_save_thyself (GstPad *pad,
1468                             GstElement *bin,
1469                             xmlNodePtr parent)
1470 {
1471   xmlNodePtr self;
1472
1473   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
1474
1475   self = xmlNewChild(parent,NULL,"ghostpad",NULL);
1476   xmlNewChild(self,NULL,"name", GST_PAD_NAME (pad));
1477   xmlNewChild(self,NULL,"parent", GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
1478
1479   /* FIXME FIXME FIXME! */
1480
1481   return self;
1482 }
1483 #endif /* GST_DISABLE_LOADSAVE */
1484
1485 #ifndef gst_pad_push
1486 /**
1487  * gst_pad_push:
1488  * @pad: the pad to push
1489  * @buf: the buffer to push
1490  *
1491  * Push a buffer to the peer of the pad.
1492  */
1493 void 
1494 gst_pad_push (GstPad *pad, GstBuffer *buf) 
1495 {
1496   GstRealPad *peer = GST_RPAD_PEER (pad);
1497
1498   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
1499
1500   g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
1501
1502   if (!peer) {
1503     g_warning ("push on pad %s:%s but it is unconnected", GST_DEBUG_PAD_NAME (pad));
1504   }
1505   else {
1506     if (peer->chainhandler) {
1507       if (buf) {
1508         GST_DEBUG (GST_CAT_DATAFLOW, "calling chainhandler &%s of peer pad %s:%s\n",
1509             GST_DEBUG_FUNCPTR_NAME (peer->chainhandler), GST_DEBUG_PAD_NAME (GST_PAD (peer)));
1510         (peer->chainhandler) (GST_PAD_CAST (peer), buf);
1511         return;
1512       }
1513       else {
1514         g_warning ("trying to push a NULL buffer on pad %s:%s", GST_DEBUG_PAD_NAME (peer));
1515         return;
1516       }
1517     } 
1518     else {
1519       g_warning ("(internal error) push on pad %s:%s but it has no chainhandler", GST_DEBUG_PAD_NAME (peer));
1520     }
1521   }
1522   /* clean up the mess here */
1523   if (buf != NULL) {
1524     if (GST_IS_BUFFER (buf))
1525       gst_buffer_unref (buf);
1526     else
1527       gst_event_free (GST_EVENT (buf));
1528   }
1529 }
1530 #endif
1531
1532 #ifndef gst_pad_pull
1533 /**
1534  * gst_pad_pull:
1535  * @pad: the pad to pull
1536  *
1537  * Pull a buffer from the peer pad.
1538  *
1539  * Returns: a new buffer from the peer pad.
1540  */
1541 GstBuffer*
1542 gst_pad_pull (GstPad *pad) 
1543 {
1544   GstRealPad *peer = GST_RPAD_PEER(pad);
1545   
1546   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
1547
1548   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1549
1550   if (!peer) {
1551     gst_element_error (GST_PAD_PARENT (pad), 
1552                     "pull on pad %s:%s but it was unconnected", 
1553                     GST_ELEMENT_NAME (GST_PAD_PARENT (pad)), GST_PAD_NAME (pad),
1554                     NULL);
1555   }
1556   else {
1557     if (peer->gethandler) {
1558       GstBuffer *buf;
1559
1560       GST_DEBUG (GST_CAT_DATAFLOW, "calling gethandler %s of peer pad %s:%s\n",
1561         GST_DEBUG_FUNCPTR_NAME (peer->gethandler), GST_DEBUG_PAD_NAME (peer));
1562
1563       buf = (peer->gethandler) (GST_PAD_CAST (peer));
1564       if (buf)
1565         return buf;
1566       /* no null buffers allowed */
1567       gst_element_error (GST_PAD_PARENT (pad), 
1568                     "NULL buffer during pull on %s:%s", GST_DEBUG_PAD_NAME (pad), NULL);
1569           
1570     } else {
1571       gst_element_error (GST_PAD_PARENT (pad), 
1572                     "(internal error) pull on pad %s:%s but the peer pad %s:%s has no gethandler", 
1573                     GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer),
1574                     NULL);
1575     }
1576   }
1577   return NULL;
1578 }
1579 #endif
1580
1581 #ifndef gst_pad_pullregion
1582 /**
1583  * gst_pad_pullregion:
1584  * @pad: the pad to pull the region from
1585  * @type: the regiontype
1586  * @offset: the offset/start of the buffer to pull
1587  * @len: the length of the buffer to pull
1588  *
1589  * Pull a buffer region from the peer pad. The region to pull can be 
1590  * specified with a offset/lenght pair or with a start/legnth time
1591  * indicator as specified by the type parameter.
1592  *
1593  * Returns: a new buffer from the peer pad with data in the specified
1594  * region.
1595  */
1596 GstBuffer*
1597 gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len) 
1598 {
1599   GstRealPad *peer;
1600   GstBuffer *result = NULL;
1601   
1602   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1603
1604   do {
1605     peer = GST_RPAD_PEER(pad);
1606     g_return_val_if_fail (peer != NULL, NULL);
1607
1608     if (result) 
1609       gst_buffer_unref (result);
1610
1611     GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
1612
1613     if (peer->pullregionfunc) {
1614       GST_DEBUG (GST_CAT_DATAFLOW, "calling pullregionfunc &%s of peer pad %s:%s\n",
1615           GST_DEBUG_FUNCPTR_NAME (peer->pullregionfunc), GST_DEBUG_PAD_NAME(GST_PAD_CAST (peer)));
1616       result = (peer->pullregionfunc) (GST_PAD_CAST (peer), type, offset, len);
1617     } else {
1618       GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc\n");
1619       result = NULL;
1620       break;
1621     }
1622   }
1623   /* FIXME */
1624   while (result && !(GST_BUFFER_OFFSET (result) == offset && 
1625            GST_BUFFER_SIZE (result) == len));
1626
1627   return result;
1628 }
1629 #endif
1630
1631 /**
1632  * gst_pad_peek:
1633  * @pad: the pad to peek
1634  *
1635  * Peek for a buffer from the peer pad.
1636  *
1637  * Returns: a from the peer pad or NULL if the peer has no buffer.
1638  */
1639 GstBuffer*
1640 gst_pad_peek (GstPad *pad)
1641 {
1642   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1643
1644   return GST_RPAD_BUFPEN (GST_RPAD_PEER (pad));
1645 }
1646
1647 /**
1648  * gst_pad_select:
1649  * @padlist: A list of pads 
1650  *
1651  * Wait for a buffer on the list of pads.
1652  *
1653  * Returns: The pad that has a buffer available, use 
1654  * #gst_pad_pull to get the buffer.
1655  */
1656 GstPad*
1657 gst_pad_select (GList *padlist)
1658 {
1659   GstPad *pad;
1660
1661   pad = gst_scheduler_pad_select (GST_PAD_PARENT (padlist->data)->sched, padlist);
1662
1663   return pad;
1664 }
1665
1666 /**
1667  * gst_pad_selectv:
1668  * @pad: The first pad to perform the select on 
1669  * @...: More pads
1670  *
1671  * Wait for a buffer on the given of pads.
1672  *
1673  * Returns: The pad that has a buffer available, use 
1674  * #gst_pad_pull to get the buffer.
1675  */
1676 GstPad*
1677 gst_pad_selectv (GstPad *pad, ...)
1678 {
1679   GstPad *result;
1680   GList *padlist = NULL;
1681   va_list var_args;
1682
1683   if (pad == NULL)
1684     return NULL;
1685
1686   va_start (var_args, pad);
1687
1688   while (pad) {
1689     padlist = g_list_prepend (padlist, pad);
1690     pad = va_arg (var_args, GstPad *);
1691   }
1692   result = gst_pad_select (padlist);
1693   g_list_free (padlist);
1694
1695   va_end (var_args);
1696   
1697   return result;
1698 }
1699
1700 /************************************************************************
1701  *
1702  * templates
1703  *
1704  */
1705 static void             gst_padtemplate_class_init      (GstPadTemplateClass *klass);
1706 static void             gst_padtemplate_init            (GstPadTemplate *templ);
1707
1708 enum {
1709   TEMPL_PAD_CREATED,
1710   /* FILL ME */
1711   TEMPL_LAST_SIGNAL
1712 };
1713
1714 static GstObject *padtemplate_parent_class = NULL;
1715 static guint gst_padtemplate_signals[TEMPL_LAST_SIGNAL] = { 0 };
1716
1717 GType
1718 gst_padtemplate_get_type (void)
1719 {
1720   static GType padtemplate_type = 0;
1721
1722   if (!padtemplate_type) {
1723     static const GTypeInfo padtemplate_info = {
1724       sizeof(GstPadTemplateClass),
1725       NULL,
1726       NULL,
1727       (GClassInitFunc)gst_padtemplate_class_init,
1728       NULL,
1729       NULL,
1730       sizeof(GstPadTemplate),
1731       32,
1732       (GInstanceInitFunc)gst_padtemplate_init,
1733       NULL
1734     };
1735     padtemplate_type = g_type_register_static(GST_TYPE_OBJECT, "GstPadTemplate", &padtemplate_info, 0);
1736   }
1737   return padtemplate_type;
1738 }
1739
1740 static void
1741 gst_padtemplate_class_init (GstPadTemplateClass *klass)
1742 {
1743   GObjectClass *gobject_class;
1744   GstObjectClass *gstobject_class;
1745
1746   gobject_class = (GObjectClass*)klass;
1747   gstobject_class = (GstObjectClass*)klass;
1748
1749   padtemplate_parent_class = g_type_class_ref(GST_TYPE_OBJECT);
1750
1751   gst_padtemplate_signals[TEMPL_PAD_CREATED] =
1752     g_signal_new ("pad_created", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
1753                     G_STRUCT_OFFSET (GstPadTemplateClass, pad_created), NULL, NULL,
1754                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
1755                     G_TYPE_POINTER);
1756
1757
1758   gstobject_class->path_string_separator = "*";
1759 }
1760
1761 static void
1762 gst_padtemplate_init (GstPadTemplate *templ)
1763 {
1764 }
1765
1766 /**
1767  * gst_padtemplate_new:
1768  * @name_template: the name template
1769  * @direction: the direction for the template
1770  * @presence: the presence of the pad
1771  * @caps: a list of capabilities for the template
1772  * @...: more capabilities
1773  *
1774  * Creates a new padtemplate from the given arguments.
1775  *
1776  * Returns: the new padtemplate
1777  */
1778 GstPadTemplate*
1779 gst_padtemplate_new (gchar *name_template,
1780                      GstPadDirection direction, GstPadPresence presence,
1781                      GstCaps *caps, ...)
1782 {
1783   GstPadTemplate *new;
1784   va_list var_args;
1785   GstCaps *thecaps = NULL;
1786
1787   g_return_val_if_fail (name_template != NULL, NULL);
1788
1789   new = g_object_new(gst_padtemplate_get_type () ,NULL);
1790
1791   GST_PADTEMPLATE_NAME_TEMPLATE (new) = name_template;
1792   GST_PADTEMPLATE_DIRECTION (new) = direction;
1793   GST_PADTEMPLATE_PRESENCE (new) = presence;
1794
1795   va_start (var_args, caps);
1796
1797   while (caps) {
1798     new->fixed &= caps->fixed;
1799     thecaps = gst_caps_append (thecaps, caps);
1800     caps = va_arg (var_args, GstCaps*);
1801   }
1802   va_end (var_args);
1803   
1804   GST_PADTEMPLATE_CAPS (new) = thecaps;
1805
1806   return new;
1807 }
1808
1809 /**
1810  * gst_padtemplate_get_caps:
1811  * @templ: the padtemplate to use
1812  *
1813  * Get the capabilities of the padtemplate
1814  *
1815  * Returns: a GstCaps*
1816  */
1817 GstCaps*
1818 gst_padtemplate_get_caps (GstPadTemplate *templ)
1819 {
1820   g_return_val_if_fail (templ != NULL, NULL);
1821
1822   return GST_PADTEMPLATE_CAPS (templ);
1823 }
1824
1825 #ifndef GST_DISABLE_LOADSAVE
1826 /**
1827  * gst_padtemplate_save_thyself:
1828  * @templ: the padtemplate to save
1829  * @parent: the parent XML tree
1830  *
1831  * Saves the padtemplate into XML.
1832  *
1833  * Returns: the new XML tree
1834  */
1835 xmlNodePtr
1836 gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
1837 {
1838   xmlNodePtr subtree;
1839   guchar *presence;
1840
1841   GST_DEBUG (GST_CAT_XML,"saving padtemplate %s\n", templ->name_template);
1842
1843   xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
1844   xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
1845
1846   switch (templ->presence) {
1847     case GST_PAD_ALWAYS:
1848       presence = "always";
1849       break;
1850     case GST_PAD_SOMETIMES:
1851       presence = "sometimes";
1852       break;
1853     case GST_PAD_REQUEST:
1854       presence = "request";
1855       break;
1856     default:
1857       presence = "unknown";
1858       break;
1859   }
1860   xmlNewChild(parent,NULL,"presence", presence);
1861
1862   if (GST_PADTEMPLATE_CAPS (templ)) {
1863     subtree = xmlNewChild (parent, NULL, "caps", NULL);
1864     gst_caps_save_thyself (GST_PADTEMPLATE_CAPS (templ), subtree);
1865   }
1866
1867   return parent;
1868 }
1869
1870 /**
1871  * gst_padtemplate_load_thyself:
1872  * @parent: the source XML tree
1873  *
1874  * Loads a padtemplate from the XML tree.
1875  *
1876  * Returns: the new padtemplate
1877  */
1878 GstPadTemplate*
1879 gst_padtemplate_load_thyself (xmlNodePtr parent)
1880 {
1881   xmlNodePtr field = parent->xmlChildrenNode;
1882   GstPadTemplate *factory;
1883   gchar *name_template = NULL;
1884   GstPadDirection direction = GST_PAD_UNKNOWN;
1885   GstPadPresence presence = GST_PAD_ALWAYS;
1886   GstCaps *caps = NULL;
1887
1888   while (field) {
1889     if (!strcmp(field->name, "nametemplate")) {
1890       name_template = xmlNodeGetContent(field);
1891     }
1892     if (!strcmp(field->name, "direction")) {
1893       gchar *value = xmlNodeGetContent(field);
1894
1895       if (!strcmp(value, "sink")) {
1896         direction = GST_PAD_SINK;
1897       }
1898       else if (!strcmp(value, "src")) {
1899         direction = GST_PAD_SRC;
1900       }
1901       g_free (value);
1902     }
1903     if (!strcmp(field->name, "presence")) {
1904       gchar *value = xmlNodeGetContent(field);
1905
1906       if (!strcmp(value, "always")) {
1907         presence = GST_PAD_ALWAYS;
1908       }
1909       else if (!strcmp(value, "sometimes")) {
1910         presence = GST_PAD_SOMETIMES;
1911       }
1912       else if (!strcmp(value, "request")) {
1913         presence = GST_PAD_REQUEST;
1914       }
1915       g_free (value);
1916     }
1917     else if (!strcmp(field->name, "caps")) {
1918       caps = gst_caps_load_thyself (field);
1919     }
1920     field = field->next;
1921   }
1922
1923   factory = gst_padtemplate_new (name_template, direction, presence, caps, NULL);
1924
1925   return factory;
1926 }
1927 #endif /* !GST_DISABLE_LOADSAVE */
1928
1929
1930 /**
1931  * gst_pad_set_element_private:
1932  * @pad: the pad to set the private data to
1933  * @priv: The private data to attach to the pad
1934  *
1935  * Set the given private data pointer to the pad. This
1936  * function can only be used by the element that own the
1937  * pad.
1938  */
1939 void
1940 gst_pad_set_element_private (GstPad *pad, gpointer priv)
1941 {
1942   pad->element_private = priv;
1943 }
1944
1945 /**
1946  * gst_pad_get_element_private:
1947  * @pad: the pad to get the private data of
1948  *
1949  * Get the private data of a pad. The private data can
1950  * only be set by the parent element of this pad.
1951  *
1952  * Returns: a pointer to the private data.
1953  */
1954 gpointer
1955 gst_pad_get_element_private (GstPad *pad)
1956 {
1957   return pad->element_private;
1958 }
1959
1960
1961 /***** ghost pads *****/
1962 GType _gst_ghost_pad_type = 0;
1963
1964 static void     gst_ghost_pad_class_init         (GstGhostPadClass *klass);
1965 static void     gst_ghost_pad_init               (GstGhostPad *pad);
1966
1967 static GstPad *ghost_pad_parent_class = NULL;
1968 /* static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; */
1969
1970 GType
1971 gst_ghost_pad_get_type(void) {
1972   if (!_gst_ghost_pad_type) {
1973     static const GTypeInfo pad_info = {
1974       sizeof(GstGhostPadClass),
1975       NULL,
1976       NULL,
1977       (GClassInitFunc)gst_ghost_pad_class_init,
1978       NULL,
1979       NULL,
1980       sizeof(GstGhostPad),
1981       8,
1982       (GInstanceInitFunc)gst_ghost_pad_init,
1983       NULL
1984     };
1985     _gst_ghost_pad_type = g_type_register_static(GST_TYPE_PAD, "GstGhostPad", &pad_info, 0);
1986   }
1987   return _gst_ghost_pad_type;
1988 }
1989
1990 static void
1991 gst_ghost_pad_class_init (GstGhostPadClass *klass)
1992 {
1993   GObjectClass *gobject_class;
1994
1995   gobject_class = (GObjectClass*)klass;
1996
1997   ghost_pad_parent_class = g_type_class_ref(GST_TYPE_PAD);
1998 }
1999
2000 static void
2001 gst_ghost_pad_init (GstGhostPad *pad)
2002 {
2003   pad->realpad = NULL;
2004 }
2005
2006 /**
2007  * gst_ghost_pad_new:
2008  * @name: name of the new ghost pad
2009  * @pad: the pad to create a ghost pad of
2010  *
2011  * Create a new ghost pad associated with the given pad.
2012  *
2013  * Returns: new ghost pad
2014  */
2015 GstPad*
2016 gst_ghost_pad_new (gchar *name,
2017                    GstPad *pad)
2018 {
2019   GstGhostPad *ghostpad;
2020
2021   g_return_val_if_fail (name != NULL, NULL);
2022   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
2023
2024   ghostpad = g_object_new (gst_ghost_pad_get_type () ,NULL);
2025   gst_pad_set_name (GST_PAD (ghostpad), name);
2026   GST_GPAD_REALPAD (ghostpad) = GST_PAD_REALIZE (pad);
2027   GST_PAD_PADTEMPLATE (ghostpad) = GST_PAD_PADTEMPLATE (pad);
2028
2029   /* add ourselves to the real pad's list of ghostpads */
2030   gst_pad_add_ghost_pad (pad, GST_PAD (ghostpad));
2031
2032   /* FIXME need to ref the real pad here... ? */
2033
2034   GST_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\"\n", name);
2035
2036   return GST_PAD (ghostpad);
2037 }
2038
2039 static void 
2040 gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *event)
2041 {
2042   GList *pads = element->pads;
2043
2044   while (pads) {
2045     GstPad *eventpad = GST_PAD (pads->data);
2046     pads = g_list_next (pads);
2047
2048     /* for all pads in the opposite direction that are connected */
2049     if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_IS_CONNECTED (eventpad)) {
2050       if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
2051         gst_pad_push (eventpad, GST_BUFFER (gst_event_new (GST_EVENT_TYPE (event))));
2052         
2053       }
2054       else {
2055         GstPad *peerpad = GST_PAD_CAST (GST_RPAD_PEER (eventpad));
2056
2057         gst_pad_send_event (peerpad, gst_event_new (GST_EVENT_TYPE (event)));
2058       }
2059     }
2060   }
2061 }
2062
2063 /**
2064  * gst_pad_event_default:
2065  * @pad: the pad to operate on
2066  * @event: the event to handle
2067  *
2068  * Invoke the default event handler for the given pad.
2069  */
2070 void 
2071 gst_pad_event_default (GstPad *pad, GstEvent *event)
2072 {
2073   GstElement *element = GST_PAD_PARENT (pad);
2074
2075   g_signal_emit (G_OBJECT (pad), gst_real_pad_signals[REAL_EVENT_RECEIVED], 0, event);
2076  
2077   switch (GST_EVENT_TYPE (event)) {
2078     case GST_EVENT_EOS:
2079       gst_element_set_eos (element);
2080       gst_pad_event_default_dispatch (pad, element, event);
2081       gst_event_free (event);
2082       /* we have to try to schedule another element because this one is disabled */
2083       gst_element_yield (element);
2084       break;
2085     case GST_EVENT_FLUSH:
2086     default:
2087       gst_pad_event_default_dispatch (pad, element, event);
2088       gst_event_free (event);
2089       break;
2090   }
2091 }
2092
2093 /**
2094  * gst_pad_send_event:
2095  * @pad: the pad to send the event to
2096  * @event: the event to send to the pad.
2097  *
2098  * Send the event to the pad.
2099  *
2100  * Returns: TRUE if the event was handled.
2101  */
2102 gboolean
2103 gst_pad_send_event (GstPad *pad, GstEvent *event)
2104 {
2105   gboolean handled = FALSE;
2106
2107   g_return_val_if_fail (event, FALSE);
2108
2109   if (GST_EVENT_SRC (event) == NULL)
2110     GST_EVENT_SRC (event) = gst_object_ref (GST_OBJECT (pad));
2111
2112   GST_DEBUG (GST_CAT_EVENT, "have event %d on pad %s:%s\n",
2113                   GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad));
2114
2115   if (GST_RPAD_EVENTFUNC (pad))
2116     handled = GST_RPAD_EVENTFUNC (pad) (pad, event);
2117   else {
2118     GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s\n", GST_DEBUG_PAD_NAME (pad));
2119   }
2120
2121   if (!handled) {
2122     GST_DEBUG(GST_CAT_EVENT, "proceeding with default event behavior here\n");
2123     gst_pad_event_default (pad, event);
2124     handled = TRUE;
2125   }
2126
2127   return handled;
2128 }
2129