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