Documentation updates
[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 enum {
35   TEMPL_PAD_CREATED,
36   /* FILL ME */
37   TEMPL_LAST_SIGNAL
38 };
39
40 static GstObject *padtemplate_parent_class = NULL;
41 static guint gst_pad_template_signals[TEMPL_LAST_SIGNAL] = { 0 };
42
43 GType _gst_pad_type = 0;
44
45 /***** Start with the base GstPad class *****/
46 static void             gst_pad_class_init              (GstPadClass *klass);
47 static void             gst_pad_init                    (GstPad *pad);
48
49 static gboolean         gst_pad_try_reconnect_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, 
50                                                          GstCaps *caps, gboolean clear);
51
52 #ifndef GST_DISABLE_LOADSAVE
53 static xmlNodePtr       gst_pad_save_thyself            (GstObject *object, xmlNodePtr parent);
54 #endif
55
56 static GstObject *pad_parent_class = NULL;
57
58 GType
59 gst_pad_get_type(void) 
60 {
61   if (!_gst_pad_type) {
62     static const GTypeInfo pad_info = {
63       sizeof(GstPadClass),
64       NULL,
65       NULL,
66       (GClassInitFunc)gst_pad_class_init,
67       NULL,
68       NULL,
69       sizeof(GstPad),
70       32,
71       (GInstanceInitFunc)gst_pad_init,
72       NULL
73     };
74     _gst_pad_type = g_type_register_static(GST_TYPE_OBJECT, "GstPad", &pad_info, 0);
75   }
76   return _gst_pad_type;
77 }
78
79 static void
80 gst_pad_class_init (GstPadClass *klass)
81 {
82   pad_parent_class = g_type_class_ref(GST_TYPE_OBJECT);
83 }
84
85 static void
86 gst_pad_init (GstPad *pad)
87 {
88   pad->element_private = NULL;
89
90   pad->padtemplate = NULL;
91 }
92
93
94
95 /***** Then do the Real Pad *****/
96 /* Pad signals and args */
97 enum {
98   REAL_SET_ACTIVE,
99   REAL_CAPS_CHANGED,
100   REAL_CAPS_NEGO_FAILED,
101   REAL_CONNECTED,
102   REAL_DISCONNECTED,
103   REAL_EVENT_RECEIVED,
104   /* FILL ME */
105   REAL_LAST_SIGNAL
106 };
107
108 enum {
109   REAL_ARG_0,
110   REAL_ARG_ACTIVE,
111   /* FILL ME */
112 };
113
114 static void     gst_real_pad_class_init         (GstRealPadClass *klass);
115 static void     gst_real_pad_init               (GstRealPad *pad);
116
117 static void     gst_real_pad_set_property       (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
118 static void     gst_real_pad_get_property       (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
119
120 static void     gst_real_pad_dispose            (GObject *object);
121
122 static void     gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
123
124 GType _gst_real_pad_type = 0;
125
126 static GstPad *real_pad_parent_class = NULL;
127 static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 };
128
129 GType
130 gst_real_pad_get_type(void) {
131   if (!_gst_real_pad_type) {
132     static const GTypeInfo pad_info = {
133       sizeof(GstRealPadClass),
134       NULL,
135       NULL,
136       (GClassInitFunc)gst_real_pad_class_init,
137       NULL,
138       NULL,
139       sizeof(GstRealPad),
140       32,
141       (GInstanceInitFunc)gst_real_pad_init,
142       NULL
143     };
144     _gst_real_pad_type = g_type_register_static(GST_TYPE_PAD, "GstRealPad", &pad_info, 0);
145   }
146   return _gst_real_pad_type;
147 }
148
149 static void
150 gst_real_pad_class_init (GstRealPadClass *klass)
151 {
152   GObjectClass *gobject_class;
153   GstObjectClass *gstobject_class;
154
155   gobject_class = (GObjectClass*) klass;
156   gstobject_class = (GstObjectClass*) klass;
157
158   real_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
159
160   gobject_class->dispose  = GST_DEBUG_FUNCPTR (gst_real_pad_dispose);
161   gobject_class->set_property  = GST_DEBUG_FUNCPTR (gst_real_pad_set_property);
162   gobject_class->get_property  = GST_DEBUG_FUNCPTR (gst_real_pad_get_property);
163
164   gst_real_pad_signals[REAL_SET_ACTIVE] =
165     g_signal_new ("set_active", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
166                     G_STRUCT_OFFSET (GstRealPadClass, set_active), NULL, NULL,
167                     gst_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1,
168                     G_TYPE_BOOLEAN);
169   gst_real_pad_signals[REAL_CAPS_CHANGED] =
170     g_signal_new ("caps_changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
171                     G_STRUCT_OFFSET (GstRealPadClass, caps_changed), NULL, NULL,
172                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
173                     G_TYPE_POINTER);
174   gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
175     g_signal_new ("caps_nego_failed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
176                     G_STRUCT_OFFSET (GstRealPadClass, caps_nego_failed), NULL, NULL,
177                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
178                     G_TYPE_POINTER);
179   gst_real_pad_signals[REAL_CONNECTED] =
180     g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
181                     G_STRUCT_OFFSET (GstRealPadClass, connected), NULL, NULL,
182                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
183                     G_TYPE_POINTER);
184   gst_real_pad_signals[REAL_DISCONNECTED] =
185     g_signal_new ("disconnected", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
186                     G_STRUCT_OFFSET (GstRealPadClass, disconnected), NULL, NULL,
187                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
188                     G_TYPE_POINTER);
189   gst_real_pad_signals[REAL_EVENT_RECEIVED] =
190     g_signal_new ("event_received", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
191                     G_STRUCT_OFFSET (GstRealPadClass, event_received), NULL, NULL,
192                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
193                     G_TYPE_POINTER);
194
195 /*  gtk_object_add_arg_type ("GstRealPad::active", G_TYPE_BOOLEAN, */
196 /*                           GTK_ARG_READWRITE, REAL_ARG_ACTIVE); */
197   g_object_class_install_property (G_OBJECT_CLASS (klass), REAL_ARG_ACTIVE,
198     g_param_spec_boolean ("active", "Active", "Whether the pad is active.",
199                           TRUE,G_PARAM_READWRITE));
200
201 #ifndef GST_DISABLE_LOADSAVE
202   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_pad_save_thyself);
203 #endif
204   gstobject_class->path_string_separator = ".";
205 }
206
207 static void
208 gst_real_pad_init (GstRealPad *pad)
209 {
210   pad->direction = GST_PAD_UNKNOWN;
211   pad->peer = NULL;
212
213   pad->sched = NULL;
214   pad->sched_private = NULL;
215
216   pad->chainfunc = NULL;
217   pad->getfunc = NULL;
218
219   pad->chainhandler = GST_DEBUG_FUNCPTR (gst_pad_push_func);
220   pad->gethandler = NULL;
221
222   pad->bufferpoolfunc = NULL;
223   pad->ghostpads = NULL;
224   pad->caps = NULL;
225
226   pad->connectfunc = NULL;
227   pad->getcapsfunc = NULL;
228
229   pad->convertfunc      = gst_pad_convert_default;
230   pad->eventfunc        = gst_pad_event_default;
231   pad->convertfunc      = gst_pad_convert_default;
232   pad->queryfunc        = gst_pad_query_default;
233   pad->intconnfunc      = gst_pad_get_internal_connections_default;
234 }
235
236 static void
237 gst_real_pad_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
238 {
239   g_return_if_fail (GST_IS_PAD (object));
240
241   switch (prop_id) {
242     case REAL_ARG_ACTIVE:
243       if (g_value_get_boolean (value)) {
244         GST_DEBUG (GST_CAT_PADS, "activating pad %s:%s", GST_DEBUG_PAD_NAME (object));
245         GST_FLAG_UNSET (object, GST_PAD_DISABLED);
246       } else {
247         GST_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s", GST_DEBUG_PAD_NAME (object));
248         GST_FLAG_SET (object, GST_PAD_DISABLED);
249       }
250       g_signal_emit (G_OBJECT (object), gst_real_pad_signals[REAL_SET_ACTIVE], 0,
251                       !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
252       break;
253     default:
254       break;
255   }
256 }
257
258 static void
259 gst_real_pad_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
260 {
261   /* it's not null if we got it, but it might not be ours */
262   g_return_if_fail (GST_IS_PAD (object));
263
264   switch (prop_id) {
265     case REAL_ARG_ACTIVE:
266       g_value_set_boolean (value, !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
267       break;
268     default:
269       break;
270   }
271 }
272
273
274 /**
275  * gst_pad_custom_new:
276  * @type: the type of the pad
277  * @name: name of new pad
278  * @direction: either GST_PAD_SRC or GST_PAD_SINK
279  *
280  * Create a new pad with given name from the given type.
281  *
282  * Returns: new pad
283  */
284 GstPad*
285 gst_pad_custom_new (GType type, const gchar *name,
286                     GstPadDirection direction)
287 {
288   GstRealPad *pad;
289
290   g_return_val_if_fail (name != NULL, NULL);
291   g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
292
293   pad = g_object_new (type, NULL);
294   gst_object_set_name (GST_OBJECT (pad), name);
295   GST_RPAD_DIRECTION (pad) = direction;
296
297   return GST_PAD (pad);
298 }
299
300 /**
301  * gst_pad_new:
302  * @name: name of new pad
303  * @direction: either GST_PAD_SRC or GST_PAD_SINK
304  *
305  * Create a new pad with given name.
306  *
307  * Returns: new pad
308  */
309 GstPad*
310 gst_pad_new (const gchar *name,
311              GstPadDirection direction)
312 {
313   return gst_pad_custom_new (gst_real_pad_get_type (), name, direction);
314 }
315 /**
316  * gst_pad_custom_new_from_template:
317  * @type: the custom GType for this pad
318  * @templ: the pad template to use
319  * @name: the name of the element
320  *
321  * Create a new pad with given name from the given template.
322  *
323  * Returns: new pad
324  */
325 GstPad*
326 gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ,
327                                   const gchar *name)
328 {
329   GstPad *pad;
330
331   g_return_val_if_fail (name != NULL, NULL);
332   g_return_val_if_fail (templ != NULL, NULL);
333
334   pad = gst_pad_new (name, templ->direction);
335   
336   gst_object_ref (GST_OBJECT (templ));
337   GST_PAD_PAD_TEMPLATE (pad) = templ;
338
339   g_signal_emit (G_OBJECT (templ), gst_pad_template_signals[TEMPL_PAD_CREATED], 0, pad);
340   
341   return pad;
342 }
343
344 /**
345  * gst_pad_new_from_template:
346  * @templ: the pad template to use
347  * @name: the name of the element
348  *
349  * Create a new pad with given name from the given template.
350  *
351  * Returns: new pad
352  */
353 GstPad*
354 gst_pad_new_from_template (GstPadTemplate *templ,
355                            const gchar *name)
356 {
357   return gst_pad_custom_new_from_template (gst_real_pad_get_type (), templ, name);
358 }
359
360 /**
361  * gst_pad_get_direction:
362  * @pad: the Pad to get the direction from
363  *
364  * Get the direction of the pad.
365  *
366  * Returns: the direction of the pad
367  */
368 GstPadDirection
369 gst_pad_get_direction (GstPad *pad)
370 {
371   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
372   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
373
374   return GST_PAD_DIRECTION (pad);
375 }
376
377 /**
378  * gst_pad_set_name:
379  * @pad: the pad to set the name of
380  * @name: the name of the pad
381  *
382  * Set the name of a pad.
383  */
384 void
385 gst_pad_set_name (GstPad *pad,
386                   const gchar *name)
387 {
388   g_return_if_fail (pad != NULL);
389   g_return_if_fail (GST_IS_PAD (pad));
390
391   gst_object_set_name (GST_OBJECT (pad), name);
392 }
393
394 /**
395  * gst_pad_get_name:
396  * @pad: the pad to get the name of
397  *
398  * Get the name of a pad.
399  *
400  * Returns: the name of the pad, don't free.
401  */
402 const gchar*
403 gst_pad_get_name (GstPad *pad)
404 {
405   g_return_val_if_fail (pad != NULL, NULL);
406   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
407
408   return GST_OBJECT_NAME (pad);
409 }
410
411 /**
412  * gst_pad_set_chain_function:
413  * @pad: the pad to set the chain function for
414  * @chain: the chain function
415  *
416  * Set the given chain function for the pad.
417  */
418 void 
419 gst_pad_set_chain_function (GstPad *pad,
420                             GstPadChainFunction chain)
421 {
422   g_return_if_fail (pad != NULL);
423   g_return_if_fail (GST_IS_REAL_PAD (pad));
424
425   GST_RPAD_CHAINFUNC(pad) = chain;
426   GST_DEBUG (GST_CAT_PADS, "chainfunc for %s:%s set to %s",
427              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (chain));
428 }
429
430 /**
431  * gst_pad_set_get_function:
432  * @pad: the pad to set the get function for
433  * @get: the get function
434  *
435  * Set the given get function for the pad.
436  */
437 void
438 gst_pad_set_get_function (GstPad *pad,
439                           GstPadGetFunction get)
440 {
441   g_return_if_fail (pad != NULL);
442   g_return_if_fail (GST_IS_REAL_PAD (pad));
443
444   GST_RPAD_GETFUNC(pad) = get;
445   GST_DEBUG (GST_CAT_PADS, "getfunc for %s:%s  set to %s",
446              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (get));
447 }
448
449 /**
450  * gst_pad_set_event_function:
451  * @pad: the pad to set the event handler for
452  * @event: the event handler
453  *
454  * Set the given event handler for the pad.
455  */
456 void
457 gst_pad_set_event_function (GstPad *pad,
458                             GstPadEventFunction event)
459 {
460   g_return_if_fail (pad != NULL);
461   g_return_if_fail (GST_IS_REAL_PAD (pad));
462
463   GST_RPAD_EVENTFUNC(pad) = event;
464   GST_DEBUG (GST_CAT_PADS, "eventfunc for %s:%s  set to %s",
465              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (event));
466 }
467
468 /**
469  * gst_pad_set_convert_function:
470  * @pad: the pad to set the event handler for
471  * @convert: the convert function
472  *
473  * Set the given convert function for the pad.
474  */
475 void
476 gst_pad_set_convert_function (GstPad *pad,
477                               GstPadConvertFunction convert)
478 {
479   g_return_if_fail (pad != NULL);
480   g_return_if_fail (GST_IS_REAL_PAD (pad));
481
482   GST_RPAD_CONVERTFUNC(pad) = convert;
483   GST_DEBUG (GST_CAT_PADS, "convertfunc for %s:%s  set to %s",
484              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (convert));
485 }
486
487 /**
488  * gst_pad_set_query_function:
489  * @pad: the pad to set the event handler for
490  * @query: the query function
491  *
492  * Set the given query function for the pad.
493  */
494 void
495 gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query)
496 {
497   g_return_if_fail (pad != NULL);
498   g_return_if_fail (GST_IS_REAL_PAD (pad));
499
500   GST_RPAD_QUERYFUNC(pad) = query;
501   GST_DEBUG (GST_CAT_PADS, "queryfunc for %s:%s  set to %s",
502              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (query));
503 }
504
505 /**
506  * gst_pad_set_internal_connection_function:
507  * @pad: the pad to set the internal connection function for
508  * @intconn: the internal connection function
509  *
510  * Set the given internal connection function for the pad.
511  */
512 void
513 gst_pad_set_internal_connection_function (GstPad *pad, GstPadIntConnFunction intconn)
514 {
515   g_return_if_fail (pad != NULL);
516   g_return_if_fail (GST_IS_REAL_PAD (pad));
517
518   GST_RPAD_INTCONNFUNC(pad) = intconn;
519   GST_DEBUG (GST_CAT_PADS, "internal connection for %s:%s  set to %s",
520              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (intconn));
521 }
522
523 /**
524  * gst_pad_set_connect_function:
525  * @pad: the pad to set the connect function for
526  * @connect: the connect function
527  *
528  * Set the given connect function for the pad. It will be called
529  * when the pad is connected or reconnected with caps.
530  */
531 void
532 gst_pad_set_connect_function (GstPad *pad,
533                               GstPadConnectFunction connect)
534 {
535   g_return_if_fail (pad != NULL);
536   g_return_if_fail (GST_IS_REAL_PAD (pad));
537
538   GST_RPAD_CONNECTFUNC (pad) = connect;
539   GST_DEBUG (GST_CAT_PADS, "connectfunc for %s:%s set to %s",
540              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (connect));
541 }
542
543 /**
544  * gst_pad_set_getcaps_function:
545  * @pad: the pad to set the getcaps function for
546  * @getcaps: the getcaps function
547  *
548  * Set the given getcaps function for the pad.
549  */
550 void
551 gst_pad_set_getcaps_function (GstPad *pad,
552                               GstPadGetCapsFunction getcaps)
553 {
554   g_return_if_fail (pad != NULL);
555   g_return_if_fail (GST_IS_REAL_PAD (pad));
556
557   GST_RPAD_GETCAPSFUNC (pad) = getcaps;
558   GST_DEBUG (GST_CAT_PADS, "getcapsfunc for %s:%s set to %s",
559              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getcaps));
560 }
561 /**
562  * gst_pad_set_bufferpool_function:
563  * @pad: the pad to set the bufferpool function for
564  * @bufpool: the bufferpool function
565  *
566  * Set the given bufferpool function for the pad.
567  */
568 void
569 gst_pad_set_bufferpool_function (GstPad *pad,
570                                  GstPadBufferPoolFunction bufpool)
571 {
572   g_return_if_fail (pad != NULL);
573   g_return_if_fail (GST_IS_REAL_PAD (pad));
574
575   GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
576   GST_DEBUG (GST_CAT_PADS, "bufferpoolfunc for %s:%s set to %s",
577              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (bufpool));
578 }
579
580 static void
581 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
582 {
583   if (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad)) != NULL) {
584     GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function %s",
585                GST_DEBUG_FUNCPTR_NAME (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))));
586     (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))) (pad, buf);
587   } else {
588     GST_DEBUG (GST_CAT_DATAFLOW, "default pad_push handler in place, no chain function");
589     g_warning ("(internal error) default pad_push in place for pad %s:%s but it has no chain function", 
590                     GST_DEBUG_PAD_NAME (pad));
591   }
592 }
593
594
595 /**
596  * gst_pad_disconnect:
597  * @srcpad: the source pad to disconnect
598  * @sinkpad: the sink pad to disconnect
599  *
600  * Disconnects the source pad from the sink pad.
601  */
602 void
603 gst_pad_disconnect (GstPad *srcpad,
604                     GstPad *sinkpad)
605 {
606   GstRealPad *realsrc, *realsink;
607
608   /* generic checks */
609   g_return_if_fail (srcpad != NULL);
610   g_return_if_fail (GST_IS_PAD (srcpad));
611   g_return_if_fail (sinkpad != NULL);
612   g_return_if_fail (GST_IS_PAD (sinkpad));
613
614   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
615             GST_DEBUG_PAD_NAME (srcpad), srcpad, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
616
617   /* now we need to deal with the real/ghost stuff */
618   realsrc = GST_PAD_REALIZE (srcpad);
619   realsink = GST_PAD_REALIZE (sinkpad);
620
621   g_return_if_fail (GST_RPAD_PEER (realsrc) != NULL);
622   g_return_if_fail (GST_RPAD_PEER (realsink) == realsrc);
623
624   if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
625       (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
626     GstRealPad *temppad;
627
628     temppad = realsrc;
629     realsrc = realsink;
630     realsink = temppad;
631   }
632   g_return_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
633                     (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK));
634
635   /* first clear peers */
636   GST_RPAD_PEER (realsrc) = NULL;
637   GST_RPAD_PEER (realsink) = NULL;
638
639   /* reset the filters, both filters are refcounted once */
640   if (GST_RPAD_FILTER (realsrc)) {
641     gst_caps_unref (GST_RPAD_FILTER (realsrc));
642     GST_RPAD_FILTER (realsink) = NULL;
643     GST_RPAD_FILTER (realsrc) = NULL;
644   }
645
646   /* now tell the scheduler */
647   if (GST_PAD_PARENT (realsrc)->sched)
648     gst_scheduler_pad_disconnect (GST_PAD_PARENT (realsrc)->sched, (GstPad *)realsrc, (GstPad *)realsink);
649   else if (GST_PAD_PARENT (realsink)->sched)
650     gst_scheduler_pad_disconnect (GST_PAD_PARENT (realsink)->sched, (GstPad *)realsrc, (GstPad *)realsink);
651
652   /* hold a reference, as they can go away in the signal handlers */
653   gst_object_ref (GST_OBJECT (realsrc));
654   gst_object_ref (GST_OBJECT (realsink));
655
656   /* fire off a signal to each of the pads telling them that they've been disconnected */
657   g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsink);
658   g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsrc);
659
660   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
661             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
662
663   gst_object_unref (GST_OBJECT (realsrc));
664   gst_object_unref (GST_OBJECT (realsink));
665 }
666
667 /**
668  * gst_pad_can_connect_filtered:
669  * @srcpad: the source pad to connect
670  * @sinkpad: the sink pad to connect
671  * @filtercaps: the filter caps.
672  *
673  * Checks if the source pad and the sink pad can be connected. 
674  * The filter indicates the media type that should flow trought this connection.
675  *
676  * Returns: TRUE if the pad can be connected, FALSE otherwise
677  */
678 gboolean
679 gst_pad_can_connect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
680 {
681   gint num_decoupled = 0;
682   GstRealPad *realsrc, *realsink;
683
684   /* generic checks */
685   g_return_val_if_fail (srcpad != NULL, FALSE);
686   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
687   g_return_val_if_fail (sinkpad != NULL, FALSE);
688   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
689
690   /* now we need to deal with the real/ghost stuff */
691   realsrc = GST_PAD_REALIZE (srcpad);
692   realsink = GST_PAD_REALIZE (sinkpad);
693
694   g_return_val_if_fail (GST_RPAD_PEER (realsrc) == NULL, FALSE);
695   g_return_val_if_fail (GST_RPAD_PEER (realsink) == NULL, FALSE);
696   g_return_val_if_fail (GST_PAD_PARENT (realsrc) != NULL, FALSE);
697   g_return_val_if_fail (GST_PAD_PARENT (realsink) != NULL, FALSE);
698
699   if (realsrc->sched && realsink->sched) {
700     if (GST_FLAG_IS_SET (GST_PAD_PARENT (realsrc), GST_ELEMENT_DECOUPLED))
701       num_decoupled++;
702     if (GST_FLAG_IS_SET (GST_PAD_PARENT (realsink), GST_ELEMENT_DECOUPLED))
703       num_decoupled++;
704
705     if (realsrc->sched != realsink->sched && num_decoupled != 1) {
706       g_warning ("connecting pads with different scheds requires exactly one decoupled element (queue)");
707       return FALSE;
708     }
709   }
710   
711   /* check if the directions are compatible */
712   if (!(((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
713          (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) ||
714         ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
715          (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK))))
716   {
717     return FALSE;
718   }
719   
720   return TRUE;
721 }
722 /**
723  * gst_pad_can_connect:
724  * @srcpad: the source pad to connect
725  * @sinkpad: the sink pad to connect
726  *
727  * Checks if the source pad can be connected to the sink pad.
728  *
729  * Returns: TRUE if the pads can be connected, FALSE otherwise
730  */
731 gboolean
732 gst_pad_can_connect (GstPad *srcpad, GstPad *sinkpad)
733 {
734   return gst_pad_can_connect_filtered (srcpad, sinkpad, NULL);
735 }
736
737 /**
738  * gst_pad_connect_filtered:
739  * @srcpad: the source pad to connect
740  * @sinkpad: the sink pad to connect
741  * @filtercaps: the filter caps.
742  *
743  * Connects the source pad to the sink pad. The filter indicates the media type
744  * that should flow trought this connection.
745  *
746  * Returns: TRUE if the pad could be connected, FALSE otherwise
747  */
748 gboolean
749 gst_pad_connect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
750 {
751   GstRealPad *realsrc, *realsink;
752   gint num_decoupled = 0;
753
754   /* generic checks */
755   g_return_val_if_fail (srcpad != NULL, FALSE);
756   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
757   g_return_val_if_fail (sinkpad != NULL, FALSE);
758   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
759
760   GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
761             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
762
763   /* now we need to deal with the real/ghost stuff */
764   realsrc = GST_PAD_REALIZE (srcpad);
765   realsink = GST_PAD_REALIZE (sinkpad);
766
767   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad)) {
768     GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
769               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
770   }
771
772   g_return_val_if_fail (GST_RPAD_PEER (realsrc) == NULL, FALSE);
773   g_return_val_if_fail (GST_RPAD_PEER (realsink) == NULL, FALSE);
774   g_return_val_if_fail (GST_PAD_PARENT (realsrc) != NULL, FALSE);
775   g_return_val_if_fail (GST_PAD_PARENT (realsink) != NULL, FALSE);
776
777   if (realsrc->sched && realsink->sched) {
778     if (GST_FLAG_IS_SET (GST_PAD_PARENT (realsrc), GST_ELEMENT_DECOUPLED))
779       num_decoupled++;
780     if (GST_FLAG_IS_SET (GST_PAD_PARENT (realsink), GST_ELEMENT_DECOUPLED))
781       num_decoupled++;
782
783     if (realsrc->sched != realsink->sched && num_decoupled != 1) {
784       g_warning ("connecting pads with different scheds requires exactly one decoupled element (queue)\n");
785       return FALSE;
786     }
787   }
788
789   /* check for reversed directions and swap if necessary */
790   if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
791       (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
792     GstRealPad *temppad;
793
794     temppad = realsrc;
795     realsrc = realsink;
796     realsink = temppad;
797   }
798   g_return_val_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
799                         (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK), FALSE);
800
801   /* first set peers */
802   GST_RPAD_PEER (realsrc) = realsink;
803   GST_RPAD_PEER (realsink) = realsrc;
804
805   /* try to negotiate the pads, we don't need to clear the caps here */
806   if (!gst_pad_try_reconnect_filtered_func (realsrc, realsink, filtercaps, FALSE)) {
807     GST_DEBUG (GST_CAT_CAPS, "pads cannot connect");
808
809     GST_RPAD_PEER (realsrc) = NULL;
810     GST_RPAD_PEER (realsink) = NULL;
811
812     return FALSE;
813   }
814
815   /* fire off a signal to each of the pads telling them that they've been connected */
816   g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_CONNECTED], 0, realsink);
817   g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_CONNECTED], 0, realsrc);
818
819   /* now tell the scheduler(s) */
820   if (realsrc->sched)
821     gst_scheduler_pad_connect (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
822   else if (realsink->sched)
823     gst_scheduler_pad_connect (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
824
825   GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
826             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
827   gst_caps_debug (gst_pad_get_caps (GST_PAD_CAST (realsrc)), "caps of newly connected src pad");
828
829   return TRUE;
830 }
831
832 /**
833  * gst_pad_connect:
834  * @srcpad: the source pad to connect
835  * @sinkpad: the sink pad to connect
836  *
837  * Connects the source pad to the sink pad.
838  *
839  * Returns: TRUE if the pad could be connected, FALSE otherwise
840  */
841 gboolean
842 gst_pad_connect (GstPad *srcpad, GstPad *sinkpad)
843 {
844   return gst_pad_connect_filtered (srcpad, sinkpad, NULL);
845 }
846
847 /**
848  * gst_pad_set_parent:
849  * @pad: the pad to set the parent
850  * @parent: the object to set the parent to
851  *
852  * Sets the parent object of a pad.
853  */
854 void
855 gst_pad_set_parent (GstPad *pad,
856                     GstObject *parent)
857 {
858   g_return_if_fail (pad != NULL);
859   g_return_if_fail (GST_IS_PAD (pad));
860   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
861   g_return_if_fail (parent != NULL);
862   g_return_if_fail (GST_IS_OBJECT (parent));
863   g_return_if_fail ((gpointer)pad != (gpointer)parent);
864
865   gst_object_set_parent (GST_OBJECT (pad), parent);
866 }
867
868 /**
869  * gst_pad_get_parent:
870  * @pad: the pad to get the parent from
871  *
872  * Get the parent object of this pad.
873  *
874  * Returns: the parent object
875  */
876 GstElement*
877 gst_pad_get_parent (GstPad *pad)
878 {
879   g_return_val_if_fail (pad != NULL, NULL);
880   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
881
882   return GST_PAD_PARENT (pad);
883 }
884
885 /**
886  * gst_pad_get_pad_template:
887  * @pad: the pad to get the padtemplate from
888  *
889  * Get the padtemplate object of this pad.
890  *
891  * Returns: the padtemplate object
892  */
893 GstPadTemplate*
894 gst_pad_get_pad_template (GstPad *pad)
895 {
896   g_return_val_if_fail (pad != NULL, NULL);
897   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
898
899   return GST_PAD_PAD_TEMPLATE (pad); 
900 }
901
902
903 /**
904  * gst_pad_set_scheduler:
905  * @pad: the pad to set the scheduler for
906  * @sched: The scheduler to set
907  *
908  * Set the scheduler for the pad
909  */
910 void
911 gst_pad_set_scheduler (GstPad *pad, GstScheduler *sched)
912 {
913   g_return_if_fail (pad != NULL);
914   g_return_if_fail (GST_IS_PAD (pad));
915  
916   GST_RPAD_SCHED(pad) = sched;
917 }
918  
919 /**
920  * gst_pad_get_scheduler:
921  * @pad: the pad to get the scheduler from
922  *
923  * Get the scheduler of the pad
924  *
925  * Returns: the scheduler of the pad.
926  */
927 GstScheduler*
928 gst_pad_get_scheduler (GstPad *pad)
929 {
930   g_return_val_if_fail (pad != NULL, NULL);
931   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
932  
933   return GST_RPAD_SCHED(pad);
934 }
935
936 /**
937  * gst_pad_unset_scheduler:
938  * @pad: the pad to unset the scheduler for
939  *
940  * Unset the scheduler for the pad
941  */
942 void
943 gst_pad_unset_scheduler (GstPad *pad)
944 {
945   g_return_if_fail (pad != NULL);
946   g_return_if_fail (GST_IS_PAD (pad));
947  
948   GST_RPAD_SCHED(pad) = NULL;
949 }
950  
951 /**
952  * gst_pad_get_real_parent:
953  * @pad: the pad to get the parent from
954  *
955  * Get the real parent object of this pad. If the pad
956  * is a ghostpad, the actual owner of the real pad is
957  * returned, as opposed to the gst_pad_get_parent().
958  *
959  * Returns: the parent object
960  */
961 GstElement*
962 gst_pad_get_real_parent (GstPad *pad)
963 {
964   g_return_val_if_fail (pad != NULL, NULL);
965   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
966
967   return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad)));
968 }
969
970 /**
971  * gst_pad_add_ghost_pad:
972  * @pad: the pad to set the ghost parent
973  * @ghostpad: the ghost pad to add
974  *
975  * Add a ghost pad to a pad.
976  */
977 void
978 gst_pad_add_ghost_pad (GstPad *pad,
979                        GstPad *ghostpad)
980 {
981   GstRealPad *realpad;
982
983   g_return_if_fail (pad != NULL);
984   g_return_if_fail (GST_IS_PAD (pad));
985   g_return_if_fail (ghostpad != NULL);
986   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
987
988   realpad = GST_PAD_REALIZE (pad);
989
990   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
991 }
992
993
994 /**
995  * gst_pad_remove_ghost_pad:
996  * @pad: the pad to remove the ghost parent
997  * @ghostpad: the ghost pad to remove from the pad
998  *
999  * Remove a ghost pad from a pad.
1000  */
1001 void
1002 gst_pad_remove_ghost_pad (GstPad *pad,
1003                           GstPad *ghostpad)
1004 {
1005   GstRealPad *realpad;
1006
1007   g_return_if_fail (pad != NULL);
1008   g_return_if_fail (GST_IS_PAD (pad));
1009   g_return_if_fail (ghostpad != NULL);
1010   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
1011
1012   realpad = GST_PAD_REALIZE (pad);
1013
1014   realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad);
1015 }
1016
1017 /**
1018  * gst_pad_get_ghost_pad_list:
1019  * @pad: the pad to get the ghost parents from
1020  *
1021  * Get the ghost parents of this pad.
1022  *
1023  * Returns: a GList of ghost pads
1024  */
1025 GList*
1026 gst_pad_get_ghost_pad_list (GstPad *pad)
1027 {
1028   g_return_val_if_fail (pad != NULL, NULL);
1029   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1030
1031   return GST_PAD_REALIZE(pad)->ghostpads;
1032 }
1033
1034 /* an internal caps negotiation helper function does:
1035  * 
1036  * 1. optinally calls the pad connect function with the provided caps
1037  * 2. deal with the result code of the connect function
1038  * 3. set fixed caps on the pad.
1039  */
1040 static GstPadConnectReturn
1041 gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
1042 {
1043   GstCaps *oldcaps;
1044   GstPadTemplate *template;
1045   GstElement *parent = GST_PAD_PARENT (pad);
1046
1047   /* thomas: FIXME: is this the right result to return ? */
1048   g_return_val_if_fail (pad != NULL, GST_PAD_CONNECT_REFUSED);
1049   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_CONNECT_REFUSED);
1050   
1051   /* if this pad has a parent and the parent is not READY, delay the
1052    * negotiation */
1053   if (parent && GST_STATE (parent) < GST_STATE_READY)
1054   {
1055     GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not ready",
1056                GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (pad));
1057     return GST_PAD_CONNECT_DELAYED;
1058   }
1059           
1060   GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
1061             caps, GST_DEBUG_PAD_NAME (pad));
1062   
1063   if ((template = gst_pad_get_pad_template (GST_PAD_CAST (pad)))) {
1064     if (!gst_caps_intersect (caps, gst_pad_template_get_caps (template))) {
1065       GST_INFO (GST_CAT_CAPS, "caps did not intersect with %s:%s's padtemplate",
1066                 GST_DEBUG_PAD_NAME (pad));
1067       gst_caps_debug (caps, "caps themselves (attemped to set)");
1068       gst_caps_debug (gst_pad_template_get_caps (template),
1069                       "pad template caps that did not agree with caps");
1070       return GST_PAD_CONNECT_REFUSED;
1071     }
1072     /* given that the caps are fixed, we know that their intersection with the
1073      * padtemplate caps is the same as caps itself */
1074   }
1075
1076   /* we need to notify the connect function */
1077   if (notify && GST_RPAD_CONNECTFUNC (pad)) {
1078     GstPadConnectReturn res;
1079     gchar *debug_string;
1080
1081     GST_INFO (GST_CAT_CAPS, "calling connect function on pad %s:%s",
1082             GST_DEBUG_PAD_NAME (pad));
1083
1084     /* call the connect function */
1085     res = GST_RPAD_CONNECTFUNC (pad) (GST_PAD (pad), caps);
1086
1087     switch (res) {
1088       case GST_PAD_CONNECT_REFUSED:
1089         debug_string = "REFUSED";
1090         break;
1091       case GST_PAD_CONNECT_OK:
1092         debug_string = "OK";
1093         break;
1094       case GST_PAD_CONNECT_DONE:
1095         debug_string = "DONE";
1096         break;
1097       case GST_PAD_CONNECT_DELAYED:
1098         debug_string = "DELAYED";
1099         break;
1100       default:
1101         g_warning ("unknown return code from connect function of pad %s:%s %d",
1102             GST_DEBUG_PAD_NAME (pad), res);
1103         return GST_PAD_CONNECT_REFUSED;
1104     }
1105
1106     GST_INFO (GST_CAT_CAPS, "got reply %s (%d) from connect function on pad %s:%s",
1107             debug_string, res, GST_DEBUG_PAD_NAME (pad));
1108
1109     /* done means the connect function called another caps negotiate function
1110      * on this pad that succeeded, we dont need to continue */
1111     if (res == GST_PAD_CONNECT_DONE) {
1112       GST_INFO (GST_CAT_CAPS, "pad %s:%s is done", GST_DEBUG_PAD_NAME (pad));
1113       return GST_PAD_CONNECT_DONE;
1114     }
1115     if (res == GST_PAD_CONNECT_REFUSED) {
1116       GST_INFO (GST_CAT_CAPS, "pad %s:%s doesn't accept caps",
1117                     GST_DEBUG_PAD_NAME (pad));
1118       return GST_PAD_CONNECT_REFUSED;
1119     }
1120   }
1121   /* we can only set caps on the pad if they are fixed */
1122   if (GST_CAPS_IS_FIXED (caps)) {
1123
1124     GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s",
1125               GST_DEBUG_PAD_NAME (pad));
1126     /* if we got this far all is ok, remove the old caps, set the new one */
1127     oldcaps = GST_PAD_CAPS (pad);
1128     if (caps) gst_caps_ref (caps);
1129     GST_PAD_CAPS (pad) = caps;
1130     if (oldcaps) gst_caps_unref (oldcaps);
1131   }
1132   else {
1133     GST_INFO (GST_CAT_CAPS, "caps are not fixed on pad %s:%s, not setting them yet",
1134               GST_DEBUG_PAD_NAME (pad));
1135   }
1136
1137   return GST_PAD_CONNECT_OK;
1138 }
1139
1140 /**
1141  * gst_pad_try_set_caps:
1142  * @pad: the pad to try to set the caps on
1143  * @caps: the caps to set
1144  *
1145  * Try to set the caps on the given pad.
1146  *
1147  * Returns: TRUE if the caps could be set
1148  */
1149 gboolean
1150 gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
1151 {
1152   GstRealPad *peer, *realpad;
1153
1154   realpad = GST_PAD_REALIZE (pad);
1155   peer = GST_RPAD_PEER (realpad);
1156
1157   GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
1158             caps, GST_DEBUG_PAD_NAME (realpad));
1159
1160   gst_caps_debug (caps, "caps that we are trying to set");
1161
1162   /* setting non fixed caps on a pad is not allowed */
1163   if (!GST_CAPS_IS_FIXED (caps)) {
1164   GST_INFO (GST_CAT_CAPS, "trying to set unfixed caps on pad %s:%s, not allowed",
1165                   GST_DEBUG_PAD_NAME (realpad));
1166     g_warning ("trying to set non fixed caps on pad %s:%s, not allowed",
1167             GST_DEBUG_PAD_NAME (realpad));
1168     gst_caps_debug (caps, "unfixed caps");
1169     return FALSE;
1170   }
1171
1172   /* if we have a peer try to set the caps, notifying the peerpad
1173    * if it has a connect function */
1174   if (peer && (gst_pad_try_set_caps_func (peer, caps, TRUE) != GST_PAD_CONNECT_OK))
1175   {
1176     GST_INFO (GST_CAT_CAPS, "tried to set caps on peerpad %s:%s but couldn't",
1177               GST_DEBUG_PAD_NAME (peer));
1178     return FALSE;
1179   }
1180
1181   /* then try to set our own caps, we don't need to be notified */
1182   if (gst_pad_try_set_caps_func (realpad, caps, FALSE) != GST_PAD_CONNECT_OK)
1183   {
1184     GST_INFO (GST_CAT_CAPS, "tried to set own caps on pad %s:%s but couldn't",
1185               GST_DEBUG_PAD_NAME (realpad));
1186     return FALSE;
1187   }
1188   GST_INFO (GST_CAT_CAPS, "succeeded setting caps %p on pad %s:%s",
1189             caps, GST_DEBUG_PAD_NAME (realpad));
1190   g_assert (GST_PAD_CAPS (pad));
1191                           
1192   return TRUE;
1193 }
1194
1195 /* this is a caps negotiation convenience routine, it performs:
1196  *
1197  * 1. optionally clear any pad caps
1198  * 2. calculate the intersection between the two pad tamplate/getcaps caps
1199  * 3. calculate the intersection with the (optional) filtercaps.
1200  * 4. store the intersection in the pad filter
1201  * 5. store the app filtercaps in the pad appfilter.
1202  * 6. start the caps negotiation.
1203  */
1204 static gboolean
1205 gst_pad_try_reconnect_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, GstCaps *filtercaps, gboolean clear)
1206 {
1207   GstCaps *srccaps, *sinkcaps;
1208   GstCaps *intersection = NULL;
1209   GstRealPad *realsrc, *realsink;
1210
1211   realsrc = GST_PAD_REALIZE (srcpad);
1212   realsink = GST_PAD_REALIZE (sinkpad);
1213
1214   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
1215   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
1216
1217   /* optinally clear the caps */
1218   if (clear) {
1219     GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s, clearing caps",
1220         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1221
1222     GST_PAD_CAPS (GST_PAD (realsrc)) = NULL;
1223     GST_PAD_CAPS (GST_PAD (realsink)) = NULL;
1224   }
1225   else {
1226     GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s",
1227         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1228   }
1229
1230   srccaps = gst_pad_get_caps (GST_PAD (realsrc));
1231   GST_DEBUG (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsrc));
1232   gst_caps_debug (srccaps, "caps of src pad (pre-reconnect)");
1233   sinkcaps = gst_pad_get_caps (GST_PAD (realsink));
1234   GST_DEBUG (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsink));
1235   gst_caps_debug (sinkcaps, "caps of sink pad (pre-reconnect)");
1236
1237   /* first take the intersection of the pad caps */
1238   intersection = gst_caps_intersect (srccaps, sinkcaps);
1239
1240   /* if we have no intersection but one of the caps was not NULL.. */
1241   if (!intersection && (srccaps || sinkcaps)) {
1242     /* the intersection is NULL but the pad caps were not both NULL,
1243      * this means they have no common format */
1244     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s have no common type",
1245          GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1246     return FALSE;
1247   } else if (intersection) {
1248     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps",
1249          GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink), 
1250          ((intersection && GST_CAPS_IS_FIXED (intersection)) ? "fixed" : "variable"));
1251
1252     /* then filter this against the app filter */
1253     if (filtercaps) {
1254       GstCaps *filtered_intersection = gst_caps_intersect (intersection, filtercaps);
1255
1256       /* get rid of the old intersection here */
1257       gst_caps_unref (intersection);
1258
1259       if (!filtered_intersection) {
1260         GST_INFO (GST_CAT_PADS, "filtered connection between pads %s:%s and %s:%s is empty",
1261              GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1262         return FALSE;
1263       }
1264       intersection = filtered_intersection;
1265
1266       /* keep a reference to the app caps */
1267       GST_RPAD_APPFILTER (realsink) = filtercaps;
1268       GST_RPAD_APPFILTER (realsrc) = filtercaps;
1269     }
1270   }
1271   GST_DEBUG (GST_CAT_CAPS, "setting filter for connection to:");
1272   gst_caps_debug (intersection, "filter for connection");
1273
1274   /* both the app filter and the filter, while stored on both peer pads, are the
1275      equal to the same thing on both */
1276   GST_RPAD_FILTER (realsrc) = intersection; 
1277   GST_RPAD_FILTER (realsink) = intersection; 
1278
1279   return gst_pad_perform_negotiate (GST_PAD (realsrc), GST_PAD (realsink));
1280 }
1281
1282 /**
1283  * gst_pad_perform_negotiate:
1284  * @srcpad: a srcpad
1285  * @sinkpad: a sinkpad 
1286  *
1287  * Try to negotiate the pads.
1288  *
1289  * Returns: a boolean indicating the pad succesfully negotiated.
1290  */
1291 gboolean
1292 gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad) 
1293 {
1294   GstCaps *intersection, *filtered_intersection;
1295   GstRealPad *realsrc, *realsink;
1296   GstCaps *srccaps, *sinkcaps, *filter;
1297
1298   g_return_val_if_fail (srcpad != NULL, FALSE);
1299   g_return_val_if_fail (sinkpad != NULL, FALSE);
1300   
1301   realsrc = GST_PAD_REALIZE (srcpad);
1302   realsink = GST_PAD_REALIZE (sinkpad);
1303     
1304   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
1305   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
1306
1307   filter = GST_RPAD_APPFILTER (realsrc);
1308   if (filter) {
1309     GST_INFO (GST_CAT_PADS, "dumping filter for connection %s:%s-%s:%s",
1310               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
1311     gst_caps_debug (filter, "connection filter caps");
1312   }
1313
1314   /* calculate the new caps here */
1315   srccaps = gst_pad_get_caps (GST_PAD (realsrc));
1316   GST_DEBUG (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsrc));
1317   gst_caps_debug (srccaps, "src caps, awaiting negotiation, after applying filter");
1318   sinkcaps = gst_pad_get_caps (GST_PAD (realsink));
1319   GST_DEBUG (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsink));
1320   gst_caps_debug (sinkcaps, "sink caps, awaiting negotiation, after applying filter");
1321   intersection = gst_caps_intersect (srccaps, sinkcaps);
1322   filtered_intersection = gst_caps_intersect (intersection, filter);
1323   if (filtered_intersection) {
1324     gst_caps_unref (intersection);
1325     intersection = filtered_intersection;
1326   }
1327
1328   /* no negotiation is performed if the pads have filtercaps */
1329   if (intersection) {
1330     GstPadConnectReturn res;
1331
1332     res = gst_pad_try_set_caps_func (realsrc, intersection, TRUE);
1333     if (res == GST_PAD_CONNECT_REFUSED) 
1334       return FALSE;
1335     if (res == GST_PAD_CONNECT_DONE) 
1336       return TRUE;
1337
1338     res = gst_pad_try_set_caps_func (realsink, intersection, TRUE);
1339     if (res == GST_PAD_CONNECT_REFUSED) 
1340       return FALSE;
1341     if (res == GST_PAD_CONNECT_DONE) 
1342       return TRUE;
1343   }
1344   return TRUE;
1345 }
1346
1347 /**
1348  * gst_pad_try_reconnect_filtered:
1349  * @srcpad: the source"pad to reconnect
1350  * @sinkpad: the sink pad to reconnect
1351  * @filtercaps: the capabilities to use in the reconnectiong
1352  *
1353  * Try to reconnect this pad and its peer with the specified caps
1354  *
1355  * Returns: a boolean indicating the peer pad could accept the caps.
1356  */
1357 gboolean
1358 gst_pad_try_reconnect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
1359 {
1360   GstRealPad *realsrc, *realsink;
1361
1362   g_return_val_if_fail (srcpad != NULL, FALSE);
1363   g_return_val_if_fail (sinkpad != NULL, FALSE);
1364
1365   realsrc = GST_PAD_REALIZE (srcpad);
1366   realsink = GST_PAD_REALIZE (sinkpad);
1367
1368   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
1369   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
1370   
1371   return gst_pad_try_reconnect_filtered_func (realsrc, realsink, filtercaps, TRUE);
1372 }
1373
1374 /**
1375  * gst_pad_reconnect_filtered:
1376  * @srcpad: the source"pad to reconnect
1377  * @sinkpad: the sink pad to reconnect
1378  * @filtercaps: the capabilities to use in the reconnectiong
1379  *
1380  * Try to reconnect this pad and its peer with the specified caps. 
1381  *
1382  * Returns: a boolean indicating the peer pad could accept the caps.
1383  *    if FALSE is returned, the pads are disconnected.
1384  */
1385 gboolean
1386 gst_pad_reconnect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
1387 {
1388   GstRealPad *realsrc, *realsink;
1389
1390   g_return_val_if_fail (srcpad != NULL, FALSE);
1391   g_return_val_if_fail (sinkpad != NULL, FALSE);
1392
1393   realsrc = GST_PAD_REALIZE (srcpad);
1394   realsink = GST_PAD_REALIZE (sinkpad);
1395
1396   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
1397   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
1398   
1399   if (!gst_pad_try_reconnect_filtered_func (realsrc, realsink, filtercaps, TRUE)) {
1400     gst_pad_disconnect (srcpad, GST_PAD (GST_PAD_PEER (srcpad)));
1401     return FALSE;
1402   }
1403   return TRUE;
1404 }
1405
1406 /**
1407  * gst_pad_proxy_connect:
1408  * @pad: the pad to proxy to
1409  * @caps: the capabilities to use in the proxying
1410  *
1411  * Proxy the connect function to the specified pad.
1412  *
1413  * Returns: a boolean indicating the peer pad could accept the caps.
1414  */
1415 GstPadConnectReturn
1416 gst_pad_proxy_connect (GstPad *pad, GstCaps *caps)
1417 {
1418   GstRealPad *peer, *realpad;
1419
1420   realpad = GST_PAD_REALIZE (pad);
1421
1422   peer = GST_RPAD_PEER (realpad);
1423
1424   GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s",
1425             GST_DEBUG_PAD_NAME (realpad));
1426
1427   if (peer && gst_pad_try_set_caps_func (peer, caps, TRUE) < 0)
1428     return GST_PAD_CONNECT_REFUSED;
1429   if (gst_pad_try_set_caps_func (realpad, caps, FALSE) < 0)
1430     return GST_PAD_CONNECT_REFUSED;
1431
1432   return GST_PAD_CONNECT_OK;
1433 }
1434
1435 /**
1436  * gst_pad_get_caps:
1437  * @pad: the pad to get the capabilities from
1438  *
1439  * Get the capabilities of this pad.
1440  *
1441  * Returns: the capabilities of this pad
1442  */
1443 GstCaps*
1444 gst_pad_get_caps (GstPad *pad)
1445 {
1446   GstRealPad *realpad;
1447
1448   g_return_val_if_fail (pad != NULL, NULL);
1449   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1450
1451   realpad = GST_PAD_REALIZE (pad);
1452
1453   GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)",
1454             GST_DEBUG_PAD_NAME (realpad), realpad);
1455
1456   if (GST_PAD_CAPS (realpad)) {
1457     GST_DEBUG (GST_CAT_CAPS, "using pad real caps");
1458     return GST_PAD_CAPS (realpad);
1459   }
1460   else if GST_RPAD_GETCAPSFUNC (realpad) {
1461     GST_DEBUG (GST_CAT_CAPS, "using pad get function");
1462     return GST_RPAD_GETCAPSFUNC (realpad) (GST_PAD_CAST (realpad), NULL);
1463   }
1464   else if (GST_PAD_PAD_TEMPLATE (realpad)) {
1465     GST_DEBUG (GST_CAT_CAPS, "using pad template");
1466     return GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (realpad));
1467   }
1468   GST_DEBUG (GST_CAT_CAPS, "pad has no caps");
1469
1470   return NULL;
1471 }
1472
1473 /**
1474  * gst_pad_get_pad_template_caps:
1475  * @pad: the pad to get the capabilities from
1476  *
1477  * Get the capabilities of this pad.
1478  *
1479  * Returns: a list of the capabilities of this pad
1480  */
1481 GstCaps*
1482 gst_pad_get_pad_template_caps (GstPad *pad)
1483 {
1484   g_return_val_if_fail (pad != NULL, NULL);
1485   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1486
1487   if (GST_PAD_PAD_TEMPLATE (pad))
1488     return GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
1489
1490   return NULL;
1491 }
1492
1493
1494 /**
1495  * gst_pad_template_get_caps_by_name:
1496  * @templ: the padtemplate to get the capabilities from
1497  * @name: the name of the capability to get
1498  *
1499  * Get the capability with the given name from this padtemplate.
1500  *
1501  * Returns: a capability or NULL if not found
1502  */
1503 GstCaps*
1504 gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
1505 {
1506   GstCaps *caps;
1507
1508   g_return_val_if_fail (templ != NULL, NULL);
1509
1510   caps = GST_PAD_TEMPLATE_CAPS (templ);
1511   if (!caps) 
1512     return NULL;
1513
1514   return gst_caps_get_by_name (caps, name);
1515 }
1516
1517 /**
1518  * gst_pad_check_compatibility:
1519  * @srcpad: the srcpad to check
1520  * @sinkpad: the sinkpad to check against
1521  *
1522  * Check if two pads have compatible capabilities.
1523  *
1524  * Returns: TRUE if they are compatible or the capabilities
1525  * could not be checked
1526  */
1527 gboolean
1528 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
1529 {
1530   g_return_val_if_fail (srcpad != NULL, FALSE);
1531   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
1532   g_return_val_if_fail (sinkpad != NULL, FALSE);
1533   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
1534
1535   if (GST_PAD_CAPS (srcpad) && GST_PAD_CAPS (sinkpad)) {
1536     if (!gst_caps_check_compatibility (GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad))) {
1537       return FALSE;
1538     }
1539     else {
1540       return TRUE;
1541     }
1542   }
1543   else {
1544     GST_DEBUG (GST_CAT_PADS, "could not check capabilities of pads (%s:%s) and (%s:%s) %p %p",
1545                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), 
1546                     GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
1547     return TRUE;
1548   }
1549 }
1550
1551 /**
1552  * gst_pad_get_peer:
1553  * @pad: the pad to get the peer from
1554  *
1555  * Get the peer pad of this pad.
1556  *
1557  * Returns: the peer pad
1558  */
1559 GstPad*
1560 gst_pad_get_peer (GstPad *pad)
1561 {
1562   g_return_val_if_fail (pad != NULL, NULL);
1563   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1564
1565   return GST_PAD (GST_PAD_PEER (pad));
1566 }
1567
1568 /**
1569  * gst_pad_get_allowed_caps:
1570  * @pad: the pad to get the allowed caps from
1571  *
1572  * Get the caps of the allowed media types that can
1573  * go through this pad.
1574  *
1575  * Returns: the allowed caps, newly allocated
1576  */
1577 GstCaps*
1578 gst_pad_get_allowed_caps (GstPad *pad)
1579 {
1580   g_return_val_if_fail (pad != NULL, NULL);
1581   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1582
1583   GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s", GST_DEBUG_PAD_NAME (pad));
1584
1585   return gst_caps_copy (GST_RPAD_FILTER (pad));
1586 }
1587
1588 /**
1589  * gst_pad_recalc_allowed_caps:
1590  * @pad: the pad to recaculate the caps of
1591  *
1592  * Attempt to reconnect the pad to its peer through its filter, 
1593  * set with gst_pad_[re]connect_filtered. This function is useful when a
1594  * plugin has new capabilities on a pad and wants to notify the peer.
1595  *
1596  * Returns: TRUE on success, FALSE otherwise.
1597  */
1598 gboolean
1599 gst_pad_recalc_allowed_caps (GstPad *pad)
1600 {
1601   GstRealPad *peer;
1602
1603   g_return_val_if_fail (pad != NULL, FALSE);
1604   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
1605
1606   GST_DEBUG (GST_CAT_PROPERTIES, "set allowed caps of %s:%s", GST_DEBUG_PAD_NAME (pad));
1607
1608   peer = GST_RPAD_PEER (pad);
1609   if (peer)
1610     return gst_pad_try_reconnect_filtered (pad, GST_PAD (peer), GST_RPAD_APPFILTER (pad));
1611
1612   return TRUE;
1613 }
1614
1615 /**
1616  * gst_pad_get_bufferpool:
1617  * @pad: the pad to get the bufferpool from
1618  *
1619  * Get the bufferpool of the peer pad of the given
1620  * pad.
1621  *
1622  * Returns: The GstBufferPool or NULL.
1623  */
1624 GstBufferPool*          
1625 gst_pad_get_bufferpool (GstPad *pad)
1626 {
1627   GstRealPad *peer;
1628
1629   g_return_val_if_fail (pad != NULL, NULL);
1630   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1631    
1632   peer = GST_RPAD_PEER (pad);
1633
1634   if (!peer)
1635     return NULL;
1636
1637   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
1638
1639   if (peer->bufferpoolfunc) {
1640     GST_DEBUG (GST_CAT_PADS, "calling bufferpoolfunc &%s (@%p) of peer pad %s:%s",
1641       GST_DEBUG_FUNCPTR_NAME (peer->bufferpoolfunc), &peer->bufferpoolfunc, GST_DEBUG_PAD_NAME (((GstPad*) peer)));
1642     return (peer->bufferpoolfunc) (((GstPad*) peer));
1643   } else {
1644     GST_DEBUG (GST_CAT_PADS, "no bufferpoolfunc for peer pad %s:%s at %p",
1645                     GST_DEBUG_PAD_NAME (((GstPad*) peer)), &peer->bufferpoolfunc);
1646     return NULL;
1647   }
1648 }
1649
1650 static void
1651 gst_real_pad_dispose (GObject *object)
1652 {
1653   GstPad *pad = GST_PAD (object);
1654   
1655   /* No connected pad can ever be disposed.
1656    * It has to have a parent to be connected and a parent would hold a reference */
1657   g_assert (GST_PAD_PEER (pad) == NULL);
1658
1659   GST_DEBUG (GST_CAT_REFCOUNTING, "dispose %s:%s", GST_DEBUG_PAD_NAME(pad));
1660
1661   if (GST_PAD_PAD_TEMPLATE (pad)){
1662     GST_DEBUG (GST_CAT_REFCOUNTING, "unreffing padtemplate'%s'", GST_OBJECT_NAME (GST_PAD_PAD_TEMPLATE (pad)));
1663     gst_object_unref (GST_OBJECT (GST_PAD_PAD_TEMPLATE (pad)));
1664     GST_PAD_PAD_TEMPLATE (pad) = NULL;
1665   }
1666   
1667   /* we destroy the ghostpads, because they are nothing without the real pad  */
1668   if (GST_REAL_PAD (pad)->ghostpads) {
1669     GList *orig, *ghostpads;
1670
1671     orig = ghostpads = g_list_copy (GST_REAL_PAD (pad)->ghostpads);
1672
1673     while (ghostpads) {
1674       GstPad *ghostpad = GST_PAD (ghostpads->data);
1675
1676       if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))){
1677         GST_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'", 
1678                         GST_OBJECT_NAME (GST_OBJECT_PARENT (ghostpad)));
1679
1680         gst_element_remove_ghost_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), GST_PAD (ghostpad));
1681       }
1682       ghostpads = g_list_next (ghostpads);
1683     }
1684     g_list_free (orig);
1685     g_list_free (GST_REAL_PAD(pad)->ghostpads);
1686   }
1687
1688   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))){
1689     GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'",
1690                     GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
1691     
1692     gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
1693   }
1694   
1695   G_OBJECT_CLASS (real_pad_parent_class)->dispose (object);
1696 }
1697
1698
1699 #ifndef GST_DISABLE_LOADSAVE
1700 /**
1701  * gst_pad_load_and_connect:
1702  * @self: the XML node to read the description from
1703  * @parent: the element that has the pad
1704  *
1705  * Read the pad definition from the XML node and connect the given pad
1706  * in element to a pad of an element up in the hierarchy.
1707  */
1708 void
1709 gst_pad_load_and_connect (xmlNodePtr self,
1710                           GstObject *parent)
1711 {
1712   xmlNodePtr field = self->xmlChildrenNode;
1713   GstPad *pad = NULL, *targetpad;
1714   guchar *peer = NULL;
1715   gchar **split;
1716   GstElement *target;
1717   GstObject *grandparent;
1718
1719   while (field) {
1720     if (!strcmp (field->name, "name")) {
1721       pad = gst_element_get_pad (GST_ELEMENT (parent), xmlNodeGetContent (field));
1722     }
1723     else if (!strcmp(field->name, "peer")) {
1724       peer = xmlNodeGetContent (field);
1725     }
1726     field = field->next;
1727   }
1728   g_return_if_fail (pad != NULL);
1729
1730   if (peer == NULL) return;
1731
1732   split = g_strsplit (peer, ".", 2);
1733
1734   g_return_if_fail (split[0] != NULL);
1735   g_return_if_fail (split[1] != NULL);
1736
1737   grandparent = gst_object_get_parent (parent);
1738
1739   if (grandparent && GST_IS_BIN (grandparent)) {
1740     target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
1741   }
1742   else
1743     goto cleanup;
1744
1745   if (target == NULL) goto cleanup;
1746
1747   targetpad = gst_element_get_pad (target, split[1]);
1748
1749   if (targetpad == NULL) goto cleanup;
1750
1751   gst_pad_connect (pad, targetpad);
1752
1753 cleanup:
1754   g_strfreev (split);
1755 }
1756
1757 /**
1758  * gst_pad_save_thyself:
1759  * @pad: the pad to save
1760  * @parent: the parent XML node to save the description in
1761  *
1762  * Saves the pad into an xml representation
1763  *
1764  * Returns: the xml representation of the pad
1765  */
1766 static xmlNodePtr
1767 gst_pad_save_thyself (GstObject *object,
1768                       xmlNodePtr parent)
1769 {
1770   GstRealPad *realpad;
1771   GstPad *peer;
1772
1773   g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
1774
1775   realpad = GST_REAL_PAD(object);
1776
1777   xmlNewChild(parent,NULL,"name", GST_PAD_NAME (realpad));
1778   if (GST_RPAD_PEER(realpad) != NULL) {
1779     peer = GST_PAD(GST_RPAD_PEER(realpad));
1780     /* first check to see if the peer's parent's parent is the same */
1781     /* we just save it off */
1782     xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s",
1783                     GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)));
1784   } else
1785     xmlNewChild(parent,NULL,"peer","");
1786
1787   return parent;
1788 }
1789
1790 /**
1791  * gst_pad_ghost_save_thyself:
1792  * @pad: the pad to save
1793  * @bin: the bin
1794  * @parent: the parent XML node to save the description in
1795  *
1796  * Saves the ghost pad into an xml representation.
1797  *
1798  * Returns: the xml representation of the pad
1799  */
1800 xmlNodePtr
1801 gst_pad_ghost_save_thyself (GstPad *pad,
1802                             GstElement *bin,
1803                             xmlNodePtr parent)
1804 {
1805   xmlNodePtr self;
1806
1807   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
1808
1809   self = xmlNewChild (parent, NULL, "ghostpad", NULL);
1810   xmlNewChild (self, NULL, "name", GST_PAD_NAME (pad));
1811   xmlNewChild (self, NULL, "parent", GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
1812
1813   /* FIXME FIXME FIXME! */
1814
1815   return self;
1816 }
1817 #endif /* GST_DISABLE_LOADSAVE */
1818
1819 #ifndef gst_pad_push
1820 /**
1821  * gst_pad_push:
1822  * @pad: the pad to push
1823  * @buf: the buffer to push
1824  *
1825  * Push a buffer to the peer of the pad.
1826  */
1827 void 
1828 gst_pad_push (GstPad *pad, GstBuffer *buf) 
1829 {
1830   GstRealPad *peer = GST_RPAD_PEER (pad);
1831
1832   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
1833
1834   g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
1835
1836   if (!peer) {
1837     g_warning ("push on pad %s:%s but it is unconnected", GST_DEBUG_PAD_NAME (pad));
1838   }
1839   else {
1840     if (peer->chainhandler) {
1841       if (buf) {
1842         GST_DEBUG (GST_CAT_DATAFLOW, "calling chainhandler &%s of peer pad %s:%s",
1843             GST_DEBUG_FUNCPTR_NAME (peer->chainhandler), GST_DEBUG_PAD_NAME (GST_PAD (peer)));
1844         (peer->chainhandler) (GST_PAD_CAST (peer), buf);
1845         return;
1846       }
1847       else {
1848         g_warning ("trying to push a NULL buffer on pad %s:%s", GST_DEBUG_PAD_NAME (peer));
1849         return;
1850       }
1851     } 
1852     else {
1853       g_warning ("(internal error) push on pad %s:%s but it has no chainhandler", GST_DEBUG_PAD_NAME (peer));
1854     }
1855   }
1856   /* clean up the mess here */
1857   if (buf != NULL) {
1858     if (GST_IS_BUFFER (buf))
1859       gst_buffer_unref (buf);
1860     else
1861       gst_event_free (GST_EVENT (buf));
1862   }
1863 }
1864 #endif
1865
1866 #ifndef gst_pad_pull
1867 /**
1868  * gst_pad_pull:
1869  * @pad: the pad to pull
1870  *
1871  * Pull a buffer from the peer pad.
1872  *
1873  * Returns: a new buffer from the peer pad.
1874  */
1875 GstBuffer*
1876 gst_pad_pull (GstPad *pad) 
1877 {
1878   GstRealPad *peer;
1879
1880   peer = GST_RPAD_PEER (pad);
1881   
1882   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
1883
1884   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1885
1886   if (!peer) {
1887     gst_element_error (GST_PAD_PARENT (pad), 
1888                     "pull on pad %s:%s but it was unconnected", 
1889                     GST_ELEMENT_NAME (GST_PAD_PARENT (pad)), GST_PAD_NAME (pad),
1890                     NULL);
1891   }
1892   else {
1893     if (peer->gethandler) {
1894       GstBuffer *buf;
1895
1896       GST_DEBUG (GST_CAT_DATAFLOW, "calling gethandler %s of peer pad %s:%s",
1897         GST_DEBUG_FUNCPTR_NAME (peer->gethandler), GST_DEBUG_PAD_NAME (peer));
1898
1899       buf = (peer->gethandler) (GST_PAD_CAST (peer));
1900
1901       if (buf)
1902         return buf;
1903
1904       /* no null buffers allowed */
1905       gst_element_error (GST_PAD_PARENT (pad), 
1906                     "NULL buffer during pull on %s:%s", GST_DEBUG_PAD_NAME (pad), NULL);
1907           
1908     } else {
1909       gst_element_error (GST_PAD_PARENT (pad), 
1910                     "(internal error) pull on pad %s:%s but the peer pad %s:%s has no gethandler", 
1911                     GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (peer),
1912                     NULL);
1913     }
1914   }
1915   return NULL;
1916 }
1917 #endif
1918
1919 /**
1920  * gst_pad_peek:
1921  * @pad: the pad to peek
1922  *
1923  * Peek for a buffer from the peer pad.
1924  *
1925  * Returns: a from the peer pad or NULL if the peer has no buffer.
1926  */
1927 GstBuffer*
1928 gst_pad_peek (GstPad *pad)
1929 {
1930   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1931
1932   return GST_RPAD_BUFPEN (GST_RPAD_PEER (pad));
1933 }
1934
1935 /**
1936  * gst_pad_select:
1937  * @padlist: A list of pads 
1938  *
1939  * Wait for a buffer on the list of pads.
1940  *
1941  * Returns: The pad that has a buffer available, use 
1942  * #gst_pad_pull to get the buffer.
1943  */
1944 GstPad*
1945 gst_pad_select (GList *padlist)
1946 {
1947   GstPad *pad;
1948
1949   pad = gst_scheduler_pad_select (GST_PAD_PARENT (padlist->data)->sched, padlist);
1950
1951   return pad;
1952 }
1953
1954 /**
1955  * gst_pad_selectv:
1956  * @pad: The first pad to perform the select on 
1957  * @...: More pads
1958  *
1959  * Wait for a buffer on the given of pads.
1960  *
1961  * Returns: The pad that has a buffer available, use 
1962  * #gst_pad_pull to get the buffer.
1963  */
1964 GstPad*
1965 gst_pad_selectv (GstPad *pad, ...)
1966 {
1967   GstPad *result;
1968   GList *padlist = NULL;
1969   va_list var_args;
1970
1971   if (pad == NULL)
1972     return NULL;
1973
1974   va_start (var_args, pad);
1975
1976   while (pad) {
1977     padlist = g_list_prepend (padlist, pad);
1978     pad = va_arg (var_args, GstPad *);
1979   }
1980   result = gst_pad_select (padlist);
1981   g_list_free (padlist);
1982
1983   va_end (var_args);
1984   
1985   return result;
1986 }
1987
1988 /************************************************************************
1989  *
1990  * templates
1991  *
1992  */
1993 static void             gst_pad_template_class_init     (GstPadTemplateClass *klass);
1994 static void             gst_pad_template_init           (GstPadTemplate *templ);
1995
1996 GType
1997 gst_pad_template_get_type (void)
1998 {
1999   static GType padtemplate_type = 0;
2000
2001   if (!padtemplate_type) {
2002     static const GTypeInfo padtemplate_info = {
2003       sizeof(GstPadTemplateClass),
2004       NULL,
2005       NULL,
2006       (GClassInitFunc)gst_pad_template_class_init,
2007       NULL,
2008       NULL,
2009       sizeof(GstPadTemplate),
2010       32,
2011       (GInstanceInitFunc)gst_pad_template_init,
2012       NULL
2013     };
2014     padtemplate_type = g_type_register_static(GST_TYPE_OBJECT, "GstPadTemplate", &padtemplate_info, 0);
2015   }
2016   return padtemplate_type;
2017 }
2018
2019 static void
2020 gst_pad_template_class_init (GstPadTemplateClass *klass)
2021 {
2022   GObjectClass *gobject_class;
2023   GstObjectClass *gstobject_class;
2024
2025   gobject_class = (GObjectClass*)klass;
2026   gstobject_class = (GstObjectClass*)klass;
2027
2028   padtemplate_parent_class = g_type_class_ref(GST_TYPE_OBJECT);
2029
2030   gst_pad_template_signals[TEMPL_PAD_CREATED] =
2031     g_signal_new ("pad_created", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
2032                     G_STRUCT_OFFSET (GstPadTemplateClass, pad_created), NULL, NULL,
2033                     gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
2034                     G_TYPE_POINTER);
2035
2036
2037   gstobject_class->path_string_separator = "*";
2038 }
2039
2040 static void
2041 gst_pad_template_init (GstPadTemplate *templ)
2042 {
2043 }
2044
2045 /* ALWAYS padtemplates cannot have conversion specifications, it doesn't make
2046  * sense.
2047  * SOMETIMES padtemplates can do whatever they want, they are provided by the
2048  * element.
2049  * REQUEST padtemplates can be reverse-parsed (the user asks for 'sink1', the
2050  * 'sink%d' template is automatically selected), so we need to restrict their
2051  * naming.
2052  */
2053 static gboolean
2054 name_is_valid (const gchar *name, GstPadPresence presence)
2055 {
2056   const gchar *str;
2057   
2058   if (presence == GST_PAD_ALWAYS) {
2059     if (strchr (name, '%')) {
2060       g_warning ("invalid name template %s: conversion specifications are not"
2061                  " allowed for GST_PAD_ALWAYS padtemplates", name);
2062       return FALSE;
2063     }
2064   } else if (presence == GST_PAD_REQUEST) {
2065     if ((str = strchr (name, '%')) && strchr (str + 1, '%')) {
2066       g_warning ("invalid name template %s: only one conversion specification"
2067                  " allowed in GST_PAD_REQUEST padtemplate", name);
2068       return FALSE;
2069     }
2070     if (str && (*(str+1) != 's' && *(str+1) != 'd')) {
2071       g_warning ("invalid name template %s: conversion specification must be of"
2072                  " type '%%d' or '%%s' for GST_PAD_REQUEST padtemplate", name);
2073       return FALSE;
2074     }
2075     if (str && (*(str+2) != '\0')) {
2076       g_warning ("invalid name template %s: conversion specification must appear"
2077                  " at the end of the GST_PAD_REQUEST padtemplate name", name);
2078       return FALSE;
2079     }
2080   }
2081   
2082   return TRUE;
2083 }
2084
2085 /**
2086  * gst_pad_template_new:
2087  * @name_template: the name template
2088  * @direction: the direction for the template
2089  * @presence: the presence of the pad
2090  * @caps: a list of capabilities for the template
2091  * @...: more capabilities
2092  *
2093  * Creates a new padtemplate from the given arguments.
2094  *
2095  * Returns: the new padtemplate
2096  */
2097 GstPadTemplate*
2098 gst_pad_template_new (const gchar *name_template,
2099                      GstPadDirection direction, GstPadPresence presence,
2100                      GstCaps *caps, ...)
2101 {
2102   GstPadTemplate *new;
2103   va_list var_args;
2104   GstCaps *thecaps = NULL;
2105
2106   g_return_val_if_fail (name_template != NULL, NULL);
2107
2108   if (!name_is_valid (name_template, presence))
2109     return NULL;
2110
2111   new = g_object_new (gst_pad_template_get_type (),
2112                       "name", name_template,
2113                       NULL);
2114
2115   GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (name_template);
2116   GST_PAD_TEMPLATE_DIRECTION (new) = direction;
2117   GST_PAD_TEMPLATE_PRESENCE (new) = presence;
2118
2119   va_start (var_args, caps);
2120
2121   while (caps) {
2122     new->fixed &= caps->fixed;
2123     thecaps = gst_caps_append (thecaps, caps);
2124     caps = va_arg (var_args, GstCaps*);
2125   }
2126   va_end (var_args);
2127   
2128   GST_PAD_TEMPLATE_CAPS (new) = thecaps;
2129
2130   return new;
2131 }
2132
2133 /**
2134  * gst_pad_template_get_caps:
2135  * @templ: the padtemplate to use
2136  *
2137  * Get the capabilities of the padtemplate
2138  *
2139  * Returns: a GstCaps*
2140  */
2141 GstCaps*
2142 gst_pad_template_get_caps (GstPadTemplate *templ)
2143 {
2144   g_return_val_if_fail (templ != NULL, NULL);
2145
2146   return GST_PAD_TEMPLATE_CAPS (templ);
2147 }
2148
2149 /**
2150  * gst_pad_set_element_private:
2151  * @pad: the pad to set the private data to
2152  * @priv: The private data to attach to the pad
2153  *
2154  * Set the given private data pointer to the pad. This
2155  * function can only be used by the element that own the
2156  * pad.
2157  */
2158 void
2159 gst_pad_set_element_private (GstPad *pad, gpointer priv)
2160 {
2161   pad->element_private = priv;
2162 }
2163
2164 /**
2165  * gst_pad_get_element_private:
2166  * @pad: the pad to get the private data of
2167  *
2168  * Get the private data of a pad. The private data can
2169  * only be set by the parent element of this pad.
2170  *
2171  * Returns: a pointer to the private data.
2172  */
2173 gpointer
2174 gst_pad_get_element_private (GstPad *pad)
2175 {
2176   return pad->element_private;
2177 }
2178
2179
2180 /***** ghost pads *****/
2181 GType _gst_ghost_pad_type = 0;
2182
2183 static void     gst_ghost_pad_class_init         (GstGhostPadClass *klass);
2184 static void     gst_ghost_pad_init               (GstGhostPad *pad);
2185
2186 static GstPad *ghost_pad_parent_class = NULL;
2187 /* static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 }; */
2188
2189 GType
2190 gst_ghost_pad_get_type (void) 
2191 {
2192   if (!_gst_ghost_pad_type) {
2193     static const GTypeInfo pad_info = {
2194       sizeof (GstGhostPadClass),
2195       NULL,
2196       NULL,
2197       (GClassInitFunc) gst_ghost_pad_class_init,
2198       NULL,
2199       NULL,
2200       sizeof(GstGhostPad),
2201       8,
2202       (GInstanceInitFunc) gst_ghost_pad_init,
2203       NULL
2204     };
2205     _gst_ghost_pad_type = g_type_register_static (GST_TYPE_PAD, "GstGhostPad", &pad_info, 0);
2206   }
2207   return _gst_ghost_pad_type;
2208 }
2209
2210 static void
2211 gst_ghost_pad_class_init (GstGhostPadClass *klass)
2212 {
2213   GObjectClass *gobject_class;
2214
2215   gobject_class = (GObjectClass*) klass;
2216
2217   ghost_pad_parent_class = g_type_class_ref (GST_TYPE_PAD);
2218 }
2219
2220 static void
2221 gst_ghost_pad_init (GstGhostPad *pad)
2222 {
2223   pad->realpad = NULL;
2224 }
2225
2226 /**
2227  * gst_ghost_pad_new:
2228  * @name: name of the new ghost pad
2229  * @pad: the pad to create a ghost pad of
2230  *
2231  * Create a new ghost pad associated with the given pad.
2232  *
2233  * Returns: new ghost pad
2234  */
2235 GstPad*
2236 gst_ghost_pad_new (gchar *name,
2237                    GstPad *pad)
2238 {
2239   GstGhostPad *ghostpad;
2240   GstRealPad *realpad;
2241
2242   g_return_val_if_fail (name != NULL, NULL);
2243   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
2244
2245   ghostpad = g_object_new (gst_ghost_pad_get_type () ,NULL);
2246   gst_pad_set_name (GST_PAD (ghostpad), name);
2247
2248   realpad = (GstRealPad *) pad;
2249
2250   while (!GST_IS_REAL_PAD (realpad)) {
2251     realpad = GST_PAD_REALIZE (realpad);
2252   }
2253   GST_GPAD_REALPAD (ghostpad) = realpad;
2254   GST_PAD_PAD_TEMPLATE (ghostpad) = GST_PAD_PAD_TEMPLATE (pad);
2255
2256   /* add ourselves to the real pad's list of ghostpads */
2257   gst_pad_add_ghost_pad (pad, GST_PAD (ghostpad));
2258
2259   /* FIXME need to ref the real pad here... ? */
2260
2261   GST_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\"", name);
2262
2263   return GST_PAD (ghostpad);
2264 }
2265
2266 /**
2267  * gst_pad_get_internal_connections_default:
2268  * @pad: the pad to get the internal connections of
2269  *
2270  * Get a GList of pads that this pad is connected to internally
2271  * to the parent element.
2272  *
2273  * Returns: a GList of pads, g_list_free after use.
2274  */
2275 GList*
2276 gst_pad_get_internal_connections_default (GstPad *pad)
2277 {
2278   GList *res = NULL;
2279   GstElement *parent;
2280   GList *parent_pads;
2281   GstPadDirection direction;
2282   GstRealPad *rpad;
2283   
2284   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
2285
2286   rpad = GST_PAD_REALIZE (pad);
2287   direction = rpad->direction;
2288
2289   parent = GST_PAD_PARENT (rpad);
2290   parent_pads = parent->pads;
2291
2292   while (parent_pads) {
2293     GstRealPad *parent_pad = GST_PAD_REALIZE (parent_pads->data);
2294     
2295     if (parent_pad->direction != direction) {
2296       res = g_list_prepend (res, parent_pad);
2297     }
2298     
2299     parent_pads = g_list_next (parent_pads);
2300   }
2301
2302   return res;
2303 }
2304
2305 /**
2306  * gst_pad_get_internal_connections:
2307  * @pad: the pad to get the internal connections of
2308  *
2309  * Get a GList of pads that this pad is connected to internally
2310  * to the parent element.
2311  *
2312  * Returns: a GList of pads, g_list_free after use.
2313  */
2314 GList*
2315 gst_pad_get_internal_connections (GstPad *pad)
2316 {
2317   GList *res = NULL;
2318   GstRealPad *rpad;
2319
2320   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
2321
2322   rpad = GST_PAD_REALIZE (pad);
2323
2324   if (GST_RPAD_INTCONNFUNC (rpad))
2325     res = GST_RPAD_INTCONNFUNC (rpad) (GST_PAD_CAST (rpad));
2326
2327   return res;
2328 }
2329
2330
2331 static gboolean 
2332 gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *event)
2333 {
2334   GList *pads = element->pads;
2335
2336   while (pads) {
2337     GstPad *eventpad = GST_PAD (pads->data);
2338     pads = g_list_next (pads);
2339
2340     /* for all pads in the opposite direction that are connected */
2341     if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_IS_CONNECTED (eventpad)) {
2342       if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
2343         gst_pad_push (eventpad, GST_BUFFER (gst_event_copy (event)));
2344       }
2345       else {
2346         GstPad *peerpad = GST_PAD_CAST (GST_RPAD_PEER (eventpad));
2347
2348         /* we only send the event on one pad, multi-sinkpad elements should implement
2349          * a handler */
2350         return gst_pad_send_event (peerpad, event);
2351       }
2352     }
2353   }
2354   return TRUE;
2355 }
2356
2357 /**
2358  * gst_pad_event_default:
2359  * @pad: the pad to operate on
2360  * @event: the event to handle
2361  *
2362  * Invoke the default event handler for the given pad.
2363  *
2364  * Returns: TRUE if the event was sent succesfully.
2365  */
2366 gboolean 
2367 gst_pad_event_default (GstPad *pad, GstEvent *event)
2368 {
2369   GstElement *element = GST_PAD_PARENT (pad);
2370
2371   g_signal_emit (G_OBJECT (pad), gst_real_pad_signals[REAL_EVENT_RECEIVED], 0, event);
2372  
2373   switch (GST_EVENT_TYPE (event)) {
2374     case GST_EVENT_EOS:
2375       gst_pad_event_default_dispatch (pad, element, event);
2376       gst_element_set_eos (element);
2377       /* we have to try to schedule another element because this one is disabled */
2378       gst_element_yield (element);
2379       break;
2380     case GST_EVENT_DISCONTINUOUS:
2381     {
2382       guint64 time;
2383       
2384       if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &time)) {
2385         if (element->setclockfunc && element->clock) {
2386           gst_clock_handle_discont (element->clock, time); 
2387         }
2388       }
2389     }
2390     case GST_EVENT_FLUSH:
2391     default:
2392       return gst_pad_event_default_dispatch (pad, element, event);
2393   }
2394   return TRUE;
2395 }
2396
2397 /**
2398  * gst_pad_dispatcher:
2399  * @pad: the pad to dispatch
2400  * @dispatch: the GstDispatcherFunc to call
2401  * @data: data passed to the dispatcher function.
2402  *
2403  * Invoke the given dispatcher function on all internally connected
2404  * pads of the given pad. The GstPadDispatcherFunc should return
2405  * TRUE when no further pads need to be preocessed.
2406  *
2407  * Returns: TRUE if one of the dispatcher functions returned TRUE.
2408  */
2409 gboolean
2410 gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunc dispatch, gpointer data)
2411 {
2412   gboolean res = FALSE;
2413   GList *int_pads, *orig;
2414   
2415   g_return_val_if_fail (pad, FALSE);
2416   g_return_val_if_fail (data, FALSE);
2417
2418   orig = int_pads = gst_pad_get_internal_connections (pad);
2419
2420   while (int_pads) {
2421     GstRealPad *int_rpad = GST_PAD_REALIZE (int_pads->data);
2422     GstRealPad *int_peer = GST_RPAD_PEER (int_rpad);
2423
2424     if (int_peer && GST_PAD_IS_CONNECTED (int_peer)) {
2425       res = dispatch (GST_PAD_CAST (int_peer), data);
2426       if (res)
2427         break;
2428     }
2429     int_pads = g_list_next (int_pads);
2430   }
2431
2432   g_list_free (orig);
2433   
2434   return res;
2435 }
2436
2437 /**
2438  * gst_pad_send_event:
2439  * @pad: the pad to send the event to
2440  * @event: the event to send to the pad.
2441  *
2442  * Send the event to the pad.
2443  *
2444  * Returns: TRUE if the event was handled.
2445  */
2446 gboolean
2447 gst_pad_send_event (GstPad *pad, GstEvent *event)
2448 {
2449   gboolean success = FALSE;
2450
2451   g_return_val_if_fail (event, FALSE);
2452
2453   if (!pad || (GST_PAD_IS_SINK (pad) && !GST_PAD_IS_CONNECTED (pad))) 
2454     return FALSE;
2455
2456   if (GST_EVENT_SRC (event) == NULL)
2457     GST_EVENT_SRC (event) = gst_object_ref (GST_OBJECT (pad));
2458
2459   GST_DEBUG (GST_CAT_EVENT, "have event %d on pad %s:%s",
2460                   GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad));
2461
2462   if (GST_RPAD_EVENTFUNC (pad))
2463     success = GST_RPAD_EVENTFUNC (pad) (pad, event);
2464   else {
2465     GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s", GST_DEBUG_PAD_NAME (pad));
2466   }
2467
2468   return success;
2469 }
2470
2471 typedef struct 
2472 {
2473   GstFormat      src_format;
2474   gint64         src_value;
2475   GstFormat      *dest_format;
2476   gint64         *dest_value;
2477 } GstPadConvertData;
2478
2479 static gboolean
2480 gst_pad_convert_dispatcher (GstPad *pad, GstPadConvertData *data)
2481 {
2482   return gst_pad_convert (pad, data->src_format, data->src_value, 
2483                                data->dest_format, data->dest_value);
2484 }
2485
2486 /**
2487  * gst_pad_convert_default:
2488  * @pad: the pad to invoke the default converter on
2489  * @src_format: the source format
2490  * @src_value: the source value
2491  * @dest_format: a pointer to the destination format
2492  * @dest_value: a pointer to the destination value
2493  *
2494  * Invoke the default converter on a pad. This will forward the
2495  * call to the pad obtained using the internal connection of
2496  * the element.
2497  *
2498  * Returns: TRUE if the conversion could be performed.
2499  */
2500 gboolean
2501 gst_pad_convert_default (GstPad *pad, 
2502                          GstFormat src_format,  gint64  src_value,
2503                          GstFormat *dest_format, gint64 *dest_value)
2504 {
2505   GstPadConvertData data;
2506
2507   g_return_val_if_fail (pad, FALSE);
2508   g_return_val_if_fail (dest_format, FALSE);
2509   g_return_val_if_fail (dest_value, FALSE);
2510
2511   data.src_format = src_format;
2512   data.src_value = src_value;
2513   data.dest_format = dest_format;
2514   data.dest_value = dest_value;
2515
2516   return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_convert_dispatcher, &data);
2517 }
2518
2519 /**
2520  * gst_pad_convert:
2521  * @pad: the pad to invoke the converter on
2522  * @src_format: the source format
2523  * @src_value: the source value
2524  * @dest_format: a pointer to the destination format
2525  * @dest_value: a pointer to the destination value
2526  *
2527  * Invoke a conversion on the pad. 
2528  *
2529  * Returns: TRUE if the conversion could be performed.
2530  */
2531 gboolean
2532 gst_pad_convert (GstPad *pad, 
2533                  GstFormat src_format,  gint64  src_value,
2534                  GstFormat *dest_format, gint64 *dest_value)
2535 {
2536   GstRealPad *rpad;
2537   
2538   g_return_val_if_fail (pad, FALSE);
2539   g_return_val_if_fail (dest_format, FALSE);
2540   g_return_val_if_fail (dest_value, FALSE);
2541
2542   if (src_format == *dest_format) {
2543     *dest_value = src_value; 
2544     return TRUE;
2545   }     
2546
2547   rpad = GST_PAD_REALIZE (pad);
2548
2549   g_return_val_if_fail (rpad, FALSE);
2550
2551   if (GST_RPAD_CONVERTFUNC (rpad)) {
2552     return GST_RPAD_CONVERTFUNC (rpad) (GST_PAD_CAST (rpad), src_format, src_value, dest_format, dest_value);
2553   }
2554
2555   return FALSE;
2556 }
2557
2558 typedef struct 
2559 {
2560   GstPadQueryType type;
2561   GstFormat      *format;
2562   gint64         *value;
2563 } GstPadQueryData;
2564
2565 static gboolean
2566 gst_pad_query_dispatcher (GstPad *pad, GstPadQueryData *data)
2567 {
2568   return gst_pad_query (pad, data->type, data->format, data->value);
2569 }
2570
2571 /**
2572  * gst_pad_query_default:
2573  * @pad: the pad to invoke the default query on
2574  * @type: the type of query to perform
2575  * @format: a pointer to the format of the query
2576  * @value: a pointer to the result of the query
2577  *
2578  * Invoke the default query function on a pad. 
2579  *
2580  * Returns: TRUE if the query could be performed.
2581  */
2582 gboolean
2583 gst_pad_query_default (GstPad *pad, GstPadQueryType type,
2584                        GstFormat *format,  gint64 *value)
2585 {
2586   GstPadQueryData data;
2587
2588   g_return_val_if_fail (pad, FALSE);
2589   g_return_val_if_fail (format, FALSE);
2590   g_return_val_if_fail (value, FALSE);
2591
2592   data.type = type;
2593   data.format = format;
2594   data.value = value;
2595
2596   return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_query_dispatcher, &data);
2597 }
2598
2599 /**
2600  * gst_pad_query:
2601  * @pad: the pad to invoke the query on
2602  * @type: the type of query to perform
2603  * @format: a pointer to the format of the query
2604  * @value: a pointer to the result of the query
2605  *
2606  * Query a pad for one of the available GstPadQuery properties.
2607  *
2608  * Returns: TRUE if the query could be performed.
2609  */
2610 gboolean
2611 gst_pad_query (GstPad *pad, GstPadQueryType type,
2612                GstFormat *format, gint64 *value) 
2613 {
2614   GstRealPad *rpad;
2615   
2616   if (pad == NULL)
2617     return FALSE;
2618
2619   g_return_val_if_fail (format, FALSE);
2620   g_return_val_if_fail (value, FALSE);
2621
2622   rpad = GST_PAD_REALIZE (pad);
2623
2624   g_return_val_if_fail (rpad, FALSE);
2625
2626   if (GST_RPAD_QUERYFUNC (rpad))
2627     return GST_RPAD_QUERYFUNC (rpad) (GST_PAD_CAST (pad), type, format, value);
2628
2629   return FALSE;
2630 }