- added urls to the required libs, with a lot of added libs
[platform/upstream/gstreamer.git] / gst / gstpad.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstpad.c: Pads for connecting elements together
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
25
26 #include "gstpad.h"
27 #include "gstelement.h"
28 #include "gsttype.h"
29 #include "gstbin.h"
30 #include "gstscheduler.h"
31
32
33 /***** Start with the base GstPad class *****/
34 static void             gst_pad_class_init              (GstPadClass *klass);
35 static void             gst_pad_init                    (GstPad *pad);
36
37 static xmlNodePtr       gst_pad_save_thyself            (GstObject *object, xmlNodePtr parent);
38
39 static GstObject *pad_parent_class = NULL;
40
41 GtkType
42 gst_pad_get_type(void) {
43   static GtkType pad_type = 0;
44
45   if (!pad_type) {
46     static const GtkTypeInfo pad_info = {
47       "GstPad",
48       sizeof(GstPad),
49       sizeof(GstPadClass),
50       (GtkClassInitFunc)gst_pad_class_init,
51       (GtkObjectInitFunc)gst_pad_init,
52       (GtkArgSetFunc)NULL,
53       (GtkArgGetFunc)NULL,
54       (GtkClassInitFunc)NULL,
55     };
56     pad_type = gtk_type_unique(GST_TYPE_OBJECT,&pad_info);
57   }
58   return pad_type;
59 }
60
61 static void
62 gst_pad_class_init (GstPadClass *klass)
63 {
64   pad_parent_class = gtk_type_class(GST_TYPE_OBJECT);
65 }
66
67 static void
68 gst_pad_init (GstPad *pad)
69 {
70   pad->element_private = NULL;
71
72   pad->padtemplate = NULL;
73 }
74
75
76
77 /***** Then do the Real Pad *****/
78 /* Pad signals and args */
79 enum {
80   REAL_SET_ACTIVE,
81   REAL_CAPS_CHANGED,
82   REAL_CAPS_NEGO_FAILED,
83   REAL_CONNECTED,
84   REAL_DISCONNECTED,
85   /* FILL ME */
86   REAL_LAST_SIGNAL
87 };
88
89 enum {
90   REAL_ARG_0,
91   REAL_ARG_ACTIVE,
92   /* FILL ME */
93 };
94
95 static void             gst_real_pad_class_init         (GstRealPadClass *klass);
96 static void             gst_real_pad_init               (GstRealPad *pad);
97
98 static void             gst_real_pad_set_arg            (GtkObject *object,GtkArg *arg,guint id);
99 static void             gst_real_pad_get_arg            (GtkObject *object,GtkArg *arg,guint id);
100
101 static void             gst_real_pad_destroy            (GtkObject *object);
102
103 static void             gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
104
105
106 static GstPad *real_pad_parent_class = NULL;
107 static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 };
108
109 GtkType
110 gst_real_pad_get_type(void) {
111   static GtkType pad_type = 0;
112
113   if (!pad_type) {
114     static const GtkTypeInfo pad_info = {
115       "GstRealPad",
116       sizeof(GstRealPad),
117       sizeof(GstRealPadClass),
118       (GtkClassInitFunc)gst_real_pad_class_init,
119       (GtkObjectInitFunc)gst_real_pad_init,
120       (GtkArgSetFunc)NULL,
121       (GtkArgGetFunc)NULL,
122       (GtkClassInitFunc)NULL,
123     };
124     pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info);
125   }
126   return pad_type;
127 }
128
129 static void
130 gst_real_pad_class_init (GstRealPadClass *klass)
131 {
132   GtkObjectClass *gtkobject_class;
133   GstObjectClass *gstobject_class;
134
135   gtkobject_class = (GtkObjectClass*)klass;
136   gstobject_class = (GstObjectClass*)klass;
137
138   real_pad_parent_class = gtk_type_class(GST_TYPE_PAD);
139
140   gst_real_pad_signals[REAL_SET_ACTIVE] =
141     gtk_signal_new ("set_active", GTK_RUN_LAST, gtkobject_class->type,
142                     GTK_SIGNAL_OFFSET (GstRealPadClass, set_active),
143                     gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1,
144                     GTK_TYPE_BOOL);
145   gst_real_pad_signals[REAL_CAPS_CHANGED] =
146     gtk_signal_new ("caps_changed", GTK_RUN_LAST, gtkobject_class->type,
147                     GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed),
148                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
149                     GTK_TYPE_POINTER);
150   gst_real_pad_signals[REAL_CAPS_NEGO_FAILED] =
151     gtk_signal_new ("caps_nego_failed", GTK_RUN_LAST, gtkobject_class->type,
152                     GTK_SIGNAL_OFFSET (GstRealPadClass, caps_nego_failed),
153                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
154                     GTK_TYPE_POINTER);
155   gst_real_pad_signals[REAL_CONNECTED] =
156     gtk_signal_new ("connected", GTK_RUN_LAST, gtkobject_class->type,
157                     GTK_SIGNAL_OFFSET (GstRealPadClass, connected),
158                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
159                     GTK_TYPE_POINTER);
160   gst_real_pad_signals[REAL_DISCONNECTED] =
161     gtk_signal_new ("disconnected", GTK_RUN_LAST, gtkobject_class->type,
162                     GTK_SIGNAL_OFFSET (GstRealPadClass, disconnected),
163                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
164                     GTK_TYPE_POINTER);
165   gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL);
166
167   gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL,
168                            GTK_ARG_READWRITE, REAL_ARG_ACTIVE);
169
170   gtkobject_class->destroy  = GST_DEBUG_FUNCPTR(gst_real_pad_destroy);
171   gtkobject_class->set_arg  = GST_DEBUG_FUNCPTR(gst_real_pad_set_arg);
172   gtkobject_class->get_arg  = GST_DEBUG_FUNCPTR(gst_real_pad_get_arg);
173
174   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_pad_save_thyself);
175   gstobject_class->path_string_separator = ".";
176 }
177
178 static void
179 gst_real_pad_init (GstRealPad *pad)
180 {
181   pad->direction = GST_PAD_UNKNOWN;
182   pad->peer = NULL;
183
184   pad->chainfunc = NULL;
185   pad->getfunc = NULL;
186   pad->getregionfunc = NULL;
187   pad->qosfunc = NULL;
188   pad->eosfunc = GST_DEBUG_FUNCPTR(gst_pad_eos_func);
189
190   pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
191   pad->pullfunc = NULL;
192   pad->pullregionfunc = NULL;
193
194   pad->bufferpoolfunc = NULL;
195   pad->ghostpads = NULL;
196   pad->caps = NULL;
197 }
198
199 static void
200 gst_real_pad_set_arg (GtkObject *object, GtkArg *arg, guint id)
201 {
202   g_return_if_fail(GST_IS_PAD(object));
203
204   switch (id) {
205     case REAL_ARG_ACTIVE:
206       if (GTK_VALUE_BOOL(*arg)) {
207         gst_info("gstpad: activating pad\n");
208         GST_FLAG_UNSET(object,GST_PAD_DISABLED);
209       } else {
210         gst_info("gstpad: de-activating pad\n");
211         GST_FLAG_SET(object,GST_PAD_DISABLED);
212       }
213       gtk_signal_emit(GTK_OBJECT(object), gst_real_pad_signals[REAL_SET_ACTIVE],
214                       ! GST_FLAG_IS_SET(object,GST_PAD_DISABLED));
215       break;
216     default:
217       break;
218   }
219 }
220
221 static void
222 gst_real_pad_get_arg (GtkObject *object, GtkArg *arg, guint id)
223 {
224   /* it's not null if we got it, but it might not be ours */
225   g_return_if_fail (GST_IS_PAD (object));
226
227   switch (id) {
228     case REAL_ARG_ACTIVE:
229       GTK_VALUE_BOOL (*arg) = ! GST_FLAG_IS_SET (object, GST_PAD_DISABLED);
230       break;
231     default:
232       break;
233   }
234 }
235
236
237 /**
238  * gst_pad_new:
239  * @name: name of new pad
240  * @direction: either GST_PAD_SRC or GST_PAD_SINK
241  *
242  * Create a new pad with given name.
243  *
244  * Returns: new pad
245  */
246 GstPad*
247 gst_pad_new (gchar *name,
248              GstPadDirection direction)
249 {
250   GstRealPad *pad;
251
252   g_return_val_if_fail (name != NULL, NULL);
253   g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
254
255   pad = gtk_type_new (gst_real_pad_get_type ());
256   gst_object_set_name (GST_OBJECT (pad), name);
257   GST_RPAD_DIRECTION(pad) = direction;
258
259   return GST_PAD(pad);
260 }
261
262 /**
263  * gst_pad_new_from_template:
264  * @templ: the pad template to use
265  * @name: the name of the element
266  *
267  * Create a new pad with given name from the given template.
268  *
269  * Returns: new pad
270  */
271 GstPad*
272 gst_pad_new_from_template (GstPadTemplate *templ,
273                            gchar *name)
274 {
275   GstPad *pad;
276
277   g_return_val_if_fail (name != NULL, NULL);
278   g_return_val_if_fail (templ != NULL, NULL);
279
280   pad = gst_pad_new (name, templ->direction);
281   gst_object_ref (GST_OBJECT (templ));
282   gst_object_sink (GST_OBJECT (templ));
283   GST_PAD_PADTEMPLATE(pad) = templ;
284
285   return pad;
286 }
287
288 /**
289  * gst_pad_get_direction:
290  * @pad: the Pad to get the direction from
291  *
292  * Get the direction of the pad.
293  *
294  * Returns: the direction of the pad
295  */
296 GstPadDirection
297 gst_pad_get_direction (GstPad *pad)
298 {
299   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
300   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
301
302   return GST_PAD_DIRECTION(pad);
303 }
304
305 /**
306  * gst_pad_set_name:
307  * @pad: the pad to set the name of
308  * @name: the name of the pad
309  *
310  * Set the name of a pad.
311  */
312 void
313 gst_pad_set_name (GstPad *pad,
314                   const gchar *name)
315 {
316   g_return_if_fail (pad != NULL);
317   g_return_if_fail (GST_IS_PAD (pad));
318
319   gst_object_set_name (GST_OBJECT (pad), name);
320 }
321
322 /**
323  * gst_pad_get_name:
324  * @pad: the pad to get the name of
325  *
326  * Get the name of a pad.
327  *
328  * Returns: the name of the pad, don't free.
329  */
330 const gchar*
331 gst_pad_get_name (GstPad *pad)
332 {
333   g_return_val_if_fail (pad != NULL, NULL);
334   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
335
336   return GST_OBJECT_NAME (pad);
337 }
338
339 /**
340  * gst_pad_set_chain_function:
341  * @pad: the pad to set the chain function for
342  * @chain: the chain function
343  *
344  * Set the given chain function for the pad.
345  */
346 void gst_pad_set_chain_function (GstPad *pad,
347                                  GstPadChainFunction chain)
348 {
349   g_return_if_fail (pad != NULL);
350   g_return_if_fail (GST_IS_REAL_PAD (pad));
351
352   GST_RPAD_CHAINFUNC(pad) = chain;
353   GST_DEBUG (GST_CAT_PADS,"chainfunc for %s:%s set to %s\n",
354              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(chain));
355 }
356
357 /**
358  * gst_pad_set_get_function:
359  * @pad: the pad to set the get function for
360  * @get: the get function
361  *
362  * Set the given get function for the pad.
363  */
364 void
365 gst_pad_set_get_function (GstPad *pad,
366                           GstPadGetFunction get)
367 {
368   g_return_if_fail (pad != NULL);
369   g_return_if_fail (GST_IS_REAL_PAD (pad));
370
371   GST_RPAD_GETFUNC(pad) = get;
372   GST_DEBUG (GST_CAT_PADS,"getfunc for %s:%s  set to %s\n",
373              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(get));
374 }
375
376 /**
377  * gst_pad_set_getregion_function:
378  * @pad: the pad to set the getregion function for
379  * @getregion: the getregion function
380  *
381  * Set the given getregion function for the pad.
382  */
383 void
384 gst_pad_set_getregion_function (GstPad *pad,
385                                 GstPadGetRegionFunction getregion)
386 {
387   g_return_if_fail (pad != NULL);
388   g_return_if_fail (GST_IS_REAL_PAD (pad));
389
390   GST_RPAD_GETREGIONFUNC(pad) = getregion;
391   GST_DEBUG (GST_CAT_PADS,"getregionfunc for %s:%s set to %s\n",
392              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(getregion));
393 }
394
395 /**
396  * gst_pad_set_qos_function:
397  * @pad: the pad to set the qos function for
398  * @qos: the qos function
399  *
400  * Set the given qos function for the pad.
401  */
402 void
403 gst_pad_set_qos_function (GstPad *pad,
404                           GstPadQoSFunction qos)
405 {
406   g_return_if_fail (pad != NULL);
407   g_return_if_fail (GST_IS_REAL_PAD (pad));
408
409   GST_RPAD_QOSFUNC(pad) = qos;
410   GST_DEBUG (GST_CAT_PADS,"qosfunc for %s:%s set to %s\n",
411              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(qos));
412 }
413
414 /**
415  * gst_pad_set_eos_function:
416  * @pad: the pad to set the eos function for
417  * @eos: the eos function
418  *
419  * Set the given EOS function for the pad.
420  */
421 void
422 gst_pad_set_eos_function (GstPad *pad,
423                           GstPadEOSFunction eos)
424 {
425   g_return_if_fail (pad != NULL);
426   g_return_if_fail (GST_IS_REAL_PAD (pad));
427
428   GST_RPAD_EOSFUNC(pad) = eos;
429   GST_DEBUG (GST_CAT_PADS,"eosfunc for %s:%s set to %s\n",
430              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(eos));
431 }
432
433 /**
434  * gst_pad_set_negotiate_function:
435  * @pad: the pad to set the negotiate function for
436  * @nego: the negotiate function
437  *
438  * Set the given negotiate function for the pad.
439  */
440 void
441 gst_pad_set_negotiate_function (GstPad *pad,
442                                 GstPadNegotiateFunction nego)
443 {
444   g_return_if_fail (pad != NULL);
445   g_return_if_fail (GST_IS_REAL_PAD (pad));
446
447   GST_RPAD_NEGOTIATEFUNC(pad) = nego;
448   GST_DEBUG (GST_CAT_PADS,"negotiatefunc for %s:%s set to %s\n",
449              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(nego));
450 }
451
452 /**
453  * gst_pad_set_newcaps_function:
454  * @pad: the pad to set the newcaps function for
455  * @newcaps: the newcaps function
456  *
457  * Set the given newcaps function for the pad.
458  */
459 void
460 gst_pad_set_newcaps_function (GstPad *pad,
461                               GstPadNewCapsFunction newcaps)
462 {
463   g_return_if_fail (pad != NULL);
464   g_return_if_fail (GST_IS_REAL_PAD (pad));
465
466   GST_RPAD_NEWCAPSFUNC (pad) = newcaps;
467   GST_DEBUG (GST_CAT_PADS,"newcapsfunc for %s:%s set to %s\n",
468              GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(newcaps));
469 }
470
471 /**
472  * gst_pad_set_bufferpool_function:
473  * @pad: the pad to set the bufferpool function for
474  * @bufpool: the bufferpool function
475  *
476  * Set the given bufferpool function for the pad.
477  */
478 void
479 gst_pad_set_bufferpool_function (GstPad *pad,
480                                  GstPadBufferPoolFunction bufpool)
481 {
482   g_return_if_fail (pad != NULL);
483   g_return_if_fail (GST_IS_REAL_PAD (pad));
484
485   GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
486   GST_DEBUG (GST_CAT_PADS,"bufferpoolfunc for %s:%s set to %s\n",
487              GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME(bufpool));
488 }
489
490 static void
491 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
492 {
493   if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
494     GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function %s\n",
495                GST_DEBUG_FUNCPTR_NAME(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))));
496     (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
497   } else {
498     GST_DEBUG (GST_CAT_DATAFLOW,"got a problem here: default pad_push handler in place, no chain function\n");
499   }
500 }
501
502
503 /**
504  * gst_pad_handle_qos:
505  * @pad: the pad to handle the QoS message
506  * @qos_message: the QoS message to handle
507  *
508  * Pass the qos message downstream.
509  */
510 void
511 gst_pad_handle_qos(GstPad *pad,
512                    glong qos_message)
513 {
514   GstElement *element;
515   GList *pads;
516   GstPad *target_pad;
517
518   GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
519
520   if (GST_RPAD_QOSFUNC(pad)) {
521     (GST_RPAD_QOSFUNC(pad)) (pad,qos_message);
522   } else {
523     element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad)));
524
525     pads = element->pads;
526     GST_DEBUG (GST_CAT_PADS,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
527     while (pads) {
528       target_pad = GST_PAD (pads->data);
529       if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) {
530         gst_pad_handle_qos (target_pad, qos_message);
531       }
532       pads = g_list_next (pads);
533     }
534   }
535
536   return;
537 }
538
539 /**
540  * gst_pad_disconnect:
541  * @srcpad: the source pad to disconnect
542  * @sinkpad: the sink pad to disconnect
543  *
544  * Disconnects the source pad from the sink pad.
545  */
546 void
547 gst_pad_disconnect (GstPad *srcpad,
548                     GstPad *sinkpad)
549 {
550   GstRealPad *realsrc, *realsink;
551
552   /* generic checks */
553   g_return_if_fail (srcpad != NULL);
554   g_return_if_fail (GST_IS_PAD (srcpad));
555   g_return_if_fail (sinkpad != NULL);
556   g_return_if_fail (GST_IS_PAD (sinkpad));
557
558   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
559             GST_DEBUG_PAD_NAME(srcpad), srcpad, GST_DEBUG_PAD_NAME(sinkpad), sinkpad);
560
561   // now we need to deal with the real/ghost stuff
562   realsrc = GST_PAD_REALIZE(srcpad);
563   realsink = GST_PAD_REALIZE(sinkpad);
564
565   g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
566   g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
567
568   if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
569       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
570     GstRealPad *temppad;
571
572     temppad = realsrc;
573     realsrc = realsink;
574     realsink = temppad;
575   }
576   g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
577                     (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
578
579   /* first clear peers */
580   GST_RPAD_PEER(realsrc) = NULL;
581   GST_RPAD_PEER(realsink) = NULL;
582
583   /* fire off a signal to each of the pads telling them that they've been disconnected */
584   gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_DISCONNECTED], realsink);
585   gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_DISCONNECTED], realsrc);
586
587   // now tell the scheduler
588   if (realsrc->sched)
589     GST_SCHEDULE_PAD_DISCONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
590 //  if (realsink->sched)
591 //    GST_SCHEDULE_PAD_DISCONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
592
593   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
594             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
595 }
596
597 /**
598  * gst_pad_connect:
599  * @srcpad: the source pad to connect
600  * @sinkpad: the sink pad to connect
601  *
602  * Connects the source pad to the sink pad.
603  *
604  * Returns: TRUE if the pad could be connected
605  */
606 gboolean
607 gst_pad_connect (GstPad *srcpad,
608                  GstPad *sinkpad)
609 {
610   GstRealPad *realsrc, *realsink;
611   gboolean negotiated = FALSE;
612
613   /* generic checks */
614   g_return_val_if_fail(srcpad != NULL, FALSE);
615   g_return_val_if_fail(GST_IS_PAD(srcpad), FALSE);
616   g_return_val_if_fail(sinkpad != NULL, FALSE);
617   g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE);
618
619   GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
620             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
621
622   // now we need to deal with the real/ghost stuff
623   realsrc = GST_PAD_REALIZE(srcpad);
624   realsink = GST_PAD_REALIZE(sinkpad);
625
626   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
627     GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
628               GST_DEBUG_PAD_NAME(realsrc), GST_DEBUG_PAD_NAME(realsink));
629
630   g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE);
631   g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE);
632
633   /* check for reversed directions and swap if necessary */
634   if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
635       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
636     GstRealPad *temppad;
637
638     temppad = realsrc;
639     realsrc = realsink;
640     realsink = temppad;
641   }
642   g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
643                        (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE);
644
645
646   /* first set peers */
647   GST_RPAD_PEER(realsrc) = realsink;
648   GST_RPAD_PEER(realsink) = realsrc;
649
650   if (GST_PAD_CAPS (srcpad)) {
651     GST_DEBUG(GST_CAT_PADS, "renegotiation from srcpad\n");
652     negotiated = gst_pad_renegotiate (srcpad);
653   }
654   else if (GST_PAD_CAPS (sinkpad)) {
655     GST_DEBUG(GST_CAT_PADS, "renegotiation from sinkpad\n");
656     negotiated = gst_pad_renegotiate (sinkpad);
657   }
658   else {
659     GST_DEBUG(GST_CAT_PADS, "not renegotiating connection\n");
660     negotiated = TRUE;
661   }
662
663   if (!negotiated) {
664     GST_INFO(GST_CAT_PADS, "pads %s:%s and %s:%s failed to negotiate, disconnecting",
665              GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
666     gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink));
667     return FALSE;
668   }
669
670   /* fire off a signal to each of the pads telling them that they've been connected */
671   gtk_signal_emit(GTK_OBJECT(realsrc), gst_real_pad_signals[REAL_CONNECTED], realsink);
672   gtk_signal_emit(GTK_OBJECT(realsink), gst_real_pad_signals[REAL_CONNECTED], realsrc);
673
674   // now tell the scheduler(s)
675   if (realsrc->sched)
676     GST_SCHEDULE_PAD_CONNECT (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink);
677   else if (realsink->sched)
678     GST_SCHEDULE_PAD_CONNECT (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
679
680   GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
681             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
682   return TRUE;
683 }
684
685 /**
686  * gst_pad_set_parent:
687  * @pad: the pad to set the parent
688  * @parent: the object to set the parent to
689  *
690  * Sets the parent object of a pad.
691  */
692 void
693 gst_pad_set_parent (GstPad *pad,
694                     GstObject *parent)
695 {
696   g_return_if_fail (pad != NULL);
697   g_return_if_fail (GST_IS_PAD (pad));
698   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
699   g_return_if_fail (parent != NULL);
700   g_return_if_fail (GTK_IS_OBJECT (parent));
701   g_return_if_fail ((gpointer)pad != (gpointer)parent);
702
703   gst_object_set_parent (GST_OBJECT (pad), parent);
704 }
705
706 /**
707  * gst_pad_get_parent:
708  * @pad: the pad to get the parent from
709  *
710  * Get the parent object of this pad.
711  *
712  * Returns: the parent object
713  */
714 GstElement*
715 gst_pad_get_parent (GstPad *pad)
716 {
717   g_return_val_if_fail (pad != NULL, NULL);
718   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
719
720   return GST_PAD_PARENT (pad);
721 }
722
723 /**
724  * gst_pad_get_padtemplate:
725  * @pad: the pad to get the padtemplate from
726  *
727  * Get the padtemplate object of this pad.
728  *
729  * Returns: the padtemplate object
730  */
731 GstPadTemplate*
732 gst_pad_get_padtemplate (GstPad *pad)
733 {
734   g_return_val_if_fail (pad != NULL, NULL);
735   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
736
737   return GST_PAD_PADTEMPLATE (pad); 
738 }
739
740 /**
741  * gst_pad_set_sched:
742  * @pad: the pad to set the scheduler for
743  * @sched: The scheduler to set
744  *
745  * Set the sceduler for the pad
746  */
747 void
748 gst_pad_set_sched (GstPad *pad, GstSchedule *sched)
749 {
750   g_return_if_fail (pad != NULL);
751   g_return_if_fail (GST_IS_PAD (pad));
752
753   GST_RPAD_SCHED(pad) = sched;
754 }
755
756 /**
757  * gst_pad_get_sched:
758  * @pad: the pad to get the scheduler from
759  *
760  * Get the scheduler of the pad
761  *
762  * Returns: the scheduler of the pad.
763  */
764 GstSchedule*
765 gst_pad_get_sched (GstPad *pad)
766 {
767   g_return_val_if_fail (pad != NULL, NULL);
768   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
769
770   return GST_RPAD_SCHED(pad);
771 }
772
773 /**
774  * gst_pad_get_real_parent:
775  * @pad: the pad to get the parent from
776  *
777  * Get the real parent object of this pad. If the pad
778  * is a ghostpad, the actual owner of the real pad is
779  * returned, as opposed to the gst_pad_get_parent().
780  *
781  * Returns: the parent object
782  */
783 GstElement*
784 gst_pad_get_real_parent (GstPad *pad)
785 {
786   g_return_val_if_fail (pad != NULL, NULL);
787   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
788
789   return GST_PAD_PARENT (GST_PAD (GST_PAD_REALIZE (pad)));
790 }
791
792 /**
793  * gst_pad_add_ghost_pad:
794  * @pad: the pad to set the ghost parent
795  * @ghostpad: the ghost pad to add
796  *
797  * Add a ghost pad to a pad.
798  */
799 void
800 gst_pad_add_ghost_pad (GstPad *pad,
801                        GstPad *ghostpad)
802 {
803   GstRealPad *realpad;
804
805   g_return_if_fail (pad != NULL);
806   g_return_if_fail (GST_IS_PAD (pad));
807   g_return_if_fail (ghostpad != NULL);
808   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
809
810   realpad = GST_PAD_REALIZE(pad);
811
812   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
813 }
814
815
816 /**
817  * gst_pad_remove_ghost_pad:
818  * @pad: the pad to remove the ghost parent
819  * @ghostpad: the ghost pad to remove from the pad
820  *
821  * Remove a ghost pad from a pad.
822  */
823 void
824 gst_pad_remove_ghost_pad (GstPad *pad,
825                           GstPad *ghostpad)
826 {
827   GstRealPad *realpad;
828
829   g_return_if_fail (pad != NULL);
830   g_return_if_fail (GST_IS_PAD (pad));
831   g_return_if_fail (ghostpad != NULL);
832   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
833
834   realpad = GST_PAD_REALIZE (pad);
835
836   realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad);
837 }
838
839 /**
840  * gst_pad_get_ghost_pad_list:
841  * @pad: the pad to get the ghost parents from
842  *
843  * Get the ghost parents of this pad.
844  *
845  * Returns: a GList of ghost pads
846  */
847 GList*
848 gst_pad_get_ghost_pad_list (GstPad *pad)
849 {
850   g_return_val_if_fail (pad != NULL, NULL);
851   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
852
853   return GST_PAD_REALIZE(pad)->ghostpads;
854 }
855
856 /**
857  * gst_pad_set_caps:
858  * @pad: the pad to set the caps to
859  * @caps: the capabilities to attach to this pad
860  *
861  * Set the capabilities of this pad.
862  *
863  * Returns: a boolean indicating the caps could be set on the pad
864  */
865 gboolean
866 gst_pad_set_caps (GstPad *pad,
867                   GstCaps *caps)
868 {
869   GstCaps *oldcaps;
870
871   g_return_val_if_fail (pad != NULL, FALSE);
872   g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);          // NOTE this restriction
873
874   GST_INFO (GST_CAT_CAPS, "setting caps %p on pad %s:%s",
875             caps, GST_DEBUG_PAD_NAME(pad));
876
877   if (!gst_caps_check_compatibility (caps, gst_pad_get_padtemplate_caps (pad))) {
878     g_warning ("pad %s:%s tried to set caps incompatible with its padtemplate\n",
879                     GST_DEBUG_PAD_NAME (pad));
880     //return FALSE;
881   }
882   
883   oldcaps = GST_PAD_CAPS (pad);
884
885   if (caps)
886     gst_caps_ref (caps);
887   GST_PAD_CAPS(pad) = caps;
888
889   if (oldcaps)
890     gst_caps_unref (oldcaps);
891
892   return gst_pad_renegotiate (pad);
893 }
894
895 /**
896  * gst_pad_get_caps:
897  * @pad: the pad to get the capabilities from
898  *
899  * Get the capabilities of this pad.
900  *
901  * Returns: the capabilities of this pad
902  */
903 GstCaps*
904 gst_pad_get_caps (GstPad *pad)
905 {
906   g_return_val_if_fail (pad != NULL, NULL);
907   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
908
909   if (GST_PAD_CAPS (pad))
910     return GST_PAD_CAPS (pad);
911   else if (GST_PAD_PADTEMPLATE (pad))
912     return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad));
913
914   return NULL;
915 }
916
917 /**
918  * gst_pad_get_padtemplate_caps:
919  * @pad: the pad to get the capabilities from
920  *
921  * Get the capabilities of this pad.
922  *
923  * Returns: a list of the capabilities of this pad
924  */
925 GstCaps*
926 gst_pad_get_padtemplate_caps (GstPad *pad)
927 {
928   g_return_val_if_fail (pad != NULL, NULL);
929   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
930
931   if (GST_PAD_PADTEMPLATE (pad))
932     return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad));
933
934   return NULL;
935 }
936
937
938 /**
939  * gst_padtemplate_get_caps_by_name:
940  * @templ: the padtemplate to get the capabilities from
941  * @name: the name of the capability to get
942  *
943  * Get the capability with the given name from this padtemplate.
944  *
945  * Returns: a capability or NULL if not found
946  */
947 GstCaps*
948 gst_padtemplate_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
949 {
950   GstCaps *caps;
951
952   g_return_val_if_fail (templ != NULL, NULL);
953
954   caps = GST_PADTEMPLATE_CAPS (templ);
955   if (!caps) 
956     return NULL;
957
958   return gst_caps_get_by_name (caps, name);
959 }
960
961 /**
962  * gst_pad_check_compatibility:
963  * @srcpad: the srcpad to check
964  * @sinkpad: the sinkpad to check against
965  *
966  * Check if two pads have compatible capabilities.
967  *
968  * Returns: TRUE if they are compatible or the capabilities
969  * could not be checked
970  */
971 gboolean
972 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
973 {
974   g_return_val_if_fail (srcpad != NULL, FALSE);
975   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
976   g_return_val_if_fail (sinkpad != NULL, FALSE);
977   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
978
979   if (GST_PAD_CAPS(srcpad) && GST_PAD_CAPS(sinkpad)) {
980     if (!gst_caps_check_compatibility (GST_PAD_CAPS(srcpad), GST_PAD_CAPS(sinkpad))) {
981       return FALSE;
982     }
983     else {
984       return TRUE;
985     }
986   }
987   else {
988     GST_DEBUG (GST_CAT_PADS,"could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
989                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), 
990                     GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
991     return TRUE;
992   }
993 }
994
995 /**
996  * gst_pad_get_peer:
997  * @pad: the pad to get the peer from
998  *
999  * Get the peer pad of this pad.
1000  *
1001  * Returns: the peer pad
1002  */
1003 GstPad*
1004 gst_pad_get_peer (GstPad *pad)
1005 {
1006   g_return_val_if_fail (pad != NULL, NULL);
1007   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1008
1009   return GST_PAD(GST_PAD_PEER(pad));
1010 }
1011
1012 /**
1013  * gst_pad_get_bufferpool:
1014  * @pad: the pad to get the bufferpool from
1015  *
1016  * Get the bufferpool of the peer pad of the given
1017  * pad
1018  *
1019  * Returns: The GstBufferPool or NULL.
1020  */
1021 GstBufferPool*          
1022 gst_pad_get_bufferpool (GstPad *pad)
1023 {
1024   GstRealPad *peer;
1025
1026   g_return_val_if_fail (pad != NULL, NULL);
1027   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
1028    
1029   peer = GST_RPAD_PEER(pad);
1030
1031   g_return_val_if_fail (peer != NULL, NULL);
1032
1033   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
1034
1035   if (peer->bufferpoolfunc) {
1036     GST_DEBUG (GST_CAT_PADS,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
1037       GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
1038     return (peer->bufferpoolfunc)(((GstPad*)peer));
1039   } else {
1040     GST_DEBUG (GST_CAT_PADS,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
1041     return NULL;
1042   }
1043 }
1044
1045 static void
1046 gst_real_pad_destroy (GtkObject *object)
1047 {
1048   GstPad *pad = GST_PAD (object);
1049
1050   GST_DEBUG (GST_CAT_REFCOUNTING, "destroy %s:%s\n", GST_DEBUG_PAD_NAME(pad));
1051
1052   if (GST_PAD (pad)->padtemplate)
1053     gst_object_unref (GST_OBJECT (GST_PAD (pad)->padtemplate));
1054
1055   if (GST_PAD_PEER (pad))
1056     gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
1057
1058   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad)))
1059     gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
1060
1061   // FIXME we should destroy the ghostpads, because they are nothing without the real pad
1062   if (GST_REAL_PAD (pad)->ghostpads) {
1063     GList *orig, *ghostpads;
1064
1065     orig = ghostpads = g_list_copy (GST_REAL_PAD (pad)->ghostpads);
1066
1067     while (ghostpads) {
1068       GstPad *ghostpad = GST_PAD (ghostpads->data);
1069
1070       if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad)))
1071         gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), ghostpad);
1072
1073       ghostpads = g_list_next (ghostpads);
1074     }
1075     g_list_free (orig);
1076     g_list_free (GST_REAL_PAD(pad)->ghostpads);
1077   }
1078
1079   if (GTK_OBJECT_CLASS (real_pad_parent_class)->destroy)
1080     GTK_OBJECT_CLASS (real_pad_parent_class)->destroy (object);
1081 }
1082
1083
1084 /**
1085  * gst_pad_load_and_connect:
1086  * @self: the XML node to read the description from
1087  * @parent: the element that has the pad
1088  *
1089  * Read the pad definition from the XML node and connect the given pad
1090  * in element to a pad of an element up in the hierarchy.
1091  */
1092 void
1093 gst_pad_load_and_connect (xmlNodePtr self,
1094                           GstObject *parent)
1095 {
1096   xmlNodePtr field = self->xmlChildrenNode;
1097   GstPad *pad = NULL, *targetpad;
1098   guchar *peer = NULL;
1099   gchar **split;
1100   GstElement *target;
1101   GstObject *grandparent;
1102
1103   while (field) {
1104     if (!strcmp (field->name, "name")) {
1105       pad = gst_element_get_pad (GST_ELEMENT (parent), xmlNodeGetContent (field));
1106     }
1107     else if (!strcmp(field->name, "peer")) {
1108       peer = g_strdup (xmlNodeGetContent (field));
1109     }
1110     field = field->next;
1111   }
1112   g_return_if_fail (pad != NULL);
1113
1114   if (peer == NULL) return;
1115
1116   split = g_strsplit (peer, ".", 2);
1117
1118   g_return_if_fail (split[0] != NULL);
1119   g_return_if_fail (split[1] != NULL);
1120
1121   grandparent = gst_object_get_parent (parent);
1122
1123   if (grandparent && GST_IS_BIN (grandparent)) {
1124     target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
1125   }
1126   else
1127     goto cleanup;
1128
1129   if (target == NULL) goto cleanup;
1130
1131   targetpad = gst_element_get_pad (target, split[1]);
1132
1133   if (targetpad == NULL) goto cleanup;
1134
1135   gst_pad_connect (pad, targetpad);
1136
1137 cleanup:
1138   g_strfreev (split);
1139 }
1140
1141 static gboolean
1142 gst_pad_renegotiate_func (GstPad *pad, gpointer *data1, GstPad *peerpad, gpointer *data2, GstCaps **newcaps)
1143 {
1144   GstRealPad *currentpad, *otherpad;
1145   gpointer *currentdata, *otherdata;
1146   GstPadNegotiateReturn result;
1147   gint counter = 0;
1148   
1149   g_return_val_if_fail (pad != NULL, FALSE);
1150
1151   currentpad = GST_PAD_REALIZE (pad);
1152   otherpad = GST_REAL_PAD (peerpad);
1153   currentdata = data1;
1154   otherdata = data2;
1155
1156   GST_DEBUG (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s data:%p\n",
1157             GST_DEBUG_PAD_NAME(currentpad), GST_DEBUG_PAD_NAME(otherpad), currentdata);
1158
1159   do {
1160     gboolean matchtempl;
1161     
1162     if (!*newcaps) {
1163       if (otherpad->negotiatefunc) {
1164         GstRealPad *temp;
1165         gpointer *tempdata;
1166
1167         GST_DEBUG (GST_CAT_NEGOTIATION, "requesting other caps from pad %s:%s data:%p\n",
1168                         GST_DEBUG_PAD_NAME(otherpad), otherdata);
1169         otherpad->negotiatefunc (GST_PAD (otherpad), newcaps, otherdata);
1170
1171         temp = otherpad;
1172         otherpad = currentpad;
1173         currentpad = temp;
1174
1175         tempdata = otherdata;
1176         otherdata = currentdata;
1177         currentdata = tempdata;
1178       }
1179     }
1180
1181     GST_DEBUG (GST_CAT_NEGOTIATION, "checking compatibility with pad %s:%s\n",
1182                      GST_DEBUG_PAD_NAME(otherpad));
1183     matchtempl = gst_caps_check_compatibility (*newcaps, gst_pad_get_padtemplate_caps (GST_PAD (otherpad)));
1184
1185     GST_DEBUG (GST_CAT_NEGOTIATION, "caps compatibility check %s\n", (matchtempl?"ok":"fail"));
1186
1187     if (matchtempl) {
1188       GST_DEBUG (GST_CAT_NEGOTIATION, "checking if other pad %s:%s can negotiate data:%p\n",
1189                      GST_DEBUG_PAD_NAME(otherpad), otherdata);
1190       if (otherpad->negotiatefunc) {
1191         GstRealPad *temp;
1192         gpointer *tempdata;
1193
1194         GST_DEBUG (GST_CAT_NEGOTIATION, "switching pad for next phase\n");
1195
1196         temp = currentpad;
1197         currentpad = otherpad;
1198         otherpad = temp;
1199
1200         tempdata = otherdata;
1201         otherdata = currentdata;
1202         currentdata = tempdata;
1203       }
1204       else if (gst_caps_check_compatibility (*newcaps, GST_PAD_CAPS (otherpad))) {
1205         GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n");
1206         return TRUE;
1207       }
1208       else {
1209         *newcaps = GST_PAD_CAPS (otherpad);
1210         if (*newcaps) gst_caps_ref(*newcaps);
1211       }
1212     }
1213     else {
1214       *newcaps = GST_PAD_CAPS (otherpad);
1215       if (*newcaps) gst_caps_ref(*newcaps);
1216     }
1217
1218     counter++;
1219
1220     if (currentpad->negotiatefunc) {
1221       GST_DEBUG (GST_CAT_NEGOTIATION, "calling negotiate function on pad %s:%s data: %p\n",
1222                       GST_DEBUG_PAD_NAME (currentpad), currentdata);
1223       result = currentpad->negotiatefunc (GST_PAD (currentpad), newcaps, currentdata);
1224
1225       switch (result) {
1226         case GST_PAD_NEGOTIATE_FAIL:
1227           GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed\n");
1228           return FALSE;
1229         case GST_PAD_NEGOTIATE_AGREE:
1230           GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n");
1231           return TRUE;
1232         case GST_PAD_NEGOTIATE_TRY:
1233           GST_DEBUG (GST_CAT_NEGOTIATION, "try another option\n");
1234           break;
1235         default:
1236           GST_DEBUG (GST_CAT_NEGOTIATION, "invalid return\n");
1237           break;
1238       }
1239     }
1240     else {
1241       GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, no more options\n");
1242       return FALSE;
1243     }
1244       
1245   } while (counter < 100);
1246
1247   g_warning ("negotiation between (%s:%s) and (%s:%s) failed: too many attempts (%d)\n",
1248             GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad), counter);
1249
1250   GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, too many attempts\n");
1251   
1252   return FALSE;
1253 }
1254
1255 /**
1256  * gst_pad_renegotiate:
1257  * @pad: the pad to perform the negotiation on
1258  *
1259  * Perform the negotiation process with the peer pad.
1260  *
1261  * Returns: TRUE if the negotiation process succeded
1262  */
1263 gboolean
1264 gst_pad_renegotiate (GstPad *pad)
1265 {
1266   GstCaps *newcaps = NULL;
1267   GstRealPad *peerpad, *currentpad, *otherpad;
1268   gboolean result;
1269   gpointer data1 = NULL, data2 = NULL;
1270   
1271   g_return_val_if_fail (pad != NULL, FALSE);
1272
1273   peerpad = GST_PAD_PEER (pad);
1274
1275   currentpad = GST_PAD_REALIZE (pad);
1276
1277   if (!peerpad) {
1278     GST_DEBUG (GST_CAT_NEGOTIATION, "no peer pad for pad %s:%s\n",
1279                  GST_DEBUG_PAD_NAME(currentpad));
1280     return TRUE;
1281   }
1282    
1283   otherpad = GST_REAL_PAD (peerpad);
1284
1285   GST_INFO (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s",
1286             GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad));
1287
1288   newcaps = GST_PAD_CAPS (pad);
1289   
1290   result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps);
1291
1292   if (!result) {
1293     GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_nego_failed signal on %s:%s and %s:%s to give it a chance to succeed\n",
1294                GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
1295     gtk_signal_emit (GTK_OBJECT(currentpad), 
1296                      gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
1297     gtk_signal_emit (GTK_OBJECT(otherpad), 
1298                      gst_real_pad_signals[REAL_CAPS_NEGO_FAILED],&result);
1299     if (result)
1300       GST_DEBUG (GST_CAT_NEGOTIATION, "caps_nego_failed handler claims success at renego, believing\n");
1301   }
1302
1303   if (result) {
1304     GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n");
1305
1306   newcaps = GST_PAD_CAPS (pad);
1307     g_return_val_if_fail(newcaps != NULL, FALSE);       // FIXME is this valid?
1308
1309     /* here we have some sort of aggreement of the caps */
1310     GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps);
1311     if (GST_RPAD_NEWCAPSFUNC (currentpad))
1312       GST_RPAD_NEWCAPSFUNC (currentpad) (GST_PAD (currentpad), newcaps);
1313
1314     GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps);
1315     if (GST_RPAD_NEWCAPSFUNC (otherpad))
1316       GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps);
1317
1318     GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_changed signal on %s:%s and %s:%s\n",
1319                GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
1320     gtk_signal_emit (GTK_OBJECT(currentpad), 
1321                      gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(currentpad));
1322     gtk_signal_emit (GTK_OBJECT(otherpad), 
1323                      gst_real_pad_signals[REAL_CAPS_CHANGED],GST_PAD_CAPS(otherpad));
1324   }
1325
1326   return result;
1327 }
1328
1329 /**
1330  * gst_pad_negotiate_proxy:
1331  * @srcpad: the pad that proxies
1332  * @destpad: the pad to proxy the negotiation to
1333  * @caps: the current caps
1334  *
1335  * Proxies the negotiation pad from srcpad to destpad. Further
1336  * negotiation is done on the peers of both pad instead.
1337  *
1338  * Returns: the result of the negotiation preocess.
1339  */
1340 GstPadNegotiateReturn
1341 gst_pad_negotiate_proxy (GstPad *srcpad, GstPad *destpad, GstCaps **caps)
1342 {
1343   GstRealPad *srcpeer;
1344   GstRealPad *destpeer;
1345   gboolean result;
1346   gpointer data1 = NULL, data2 = NULL;
1347
1348   g_return_val_if_fail (srcpad != NULL, GST_PAD_NEGOTIATE_FAIL);
1349   g_return_val_if_fail (destpad != NULL, GST_PAD_NEGOTIATE_FAIL);
1350
1351   GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation proxied from pad (%s:%s) to pad (%s:%s)\n", 
1352                   GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1353
1354   srcpeer = GST_RPAD_PEER (srcpad);
1355   destpeer = GST_RPAD_PEER (destpad);
1356
1357   if (srcpeer && destpeer) {
1358     result = gst_pad_renegotiate_func (GST_PAD (srcpeer), &data1, GST_PAD (destpeer), &data2, caps);
1359
1360     if (result) {
1361       GST_DEBUG (GST_CAT_NEGOTIATION, "pads (%s:%s) and (%s:%s) aggreed on caps :)\n",
1362                   GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
1363
1364       /* here we have some sort of aggreement of the caps */
1365       GST_PAD_CAPS (destpeer) = *caps;
1366       if (GST_RPAD_NEWCAPSFUNC (destpeer))
1367         GST_RPAD_NEWCAPSFUNC (destpeer) (GST_PAD (destpeer), *caps);
1368
1369       GST_PAD_CAPS (destpad) = *caps;
1370       if (GST_RPAD_NEWCAPSFUNC (destpad))
1371         GST_RPAD_NEWCAPSFUNC (destpad) (GST_PAD (destpad), *caps);
1372     }
1373     else {
1374       GST_DEBUG (GST_CAT_NEGOTIATION, "pads did not aggree on caps :(\n");
1375       return GST_PAD_NEGOTIATE_FAIL;
1376     }
1377   }
1378
1379   return GST_PAD_NEGOTIATE_AGREE;
1380 }
1381
1382 /**
1383  * gst_pad_save_thyself:
1384  * @pad: the pad to save
1385  * @parent: the parent XML node to save the description in
1386  *
1387  * Saves the pad into an xml representation
1388  *
1389  * Returns: the xml representation of the pad
1390  */
1391 static xmlNodePtr
1392 gst_pad_save_thyself (GstObject *object,
1393                       xmlNodePtr parent)
1394 {
1395   GstRealPad *realpad;
1396   GstPad *peer;
1397
1398   g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
1399
1400   realpad = GST_REAL_PAD(object);
1401
1402   xmlNewChild(parent,NULL,"name", GST_PAD_NAME (realpad));
1403   if (GST_RPAD_PEER(realpad) != NULL) {
1404     peer = GST_PAD(GST_RPAD_PEER(realpad));
1405     // first check to see if the peer's parent's parent is the same
1406     // we just save it off
1407     xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s",
1408                     GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)));
1409   } else
1410     xmlNewChild(parent,NULL,"peer","");
1411
1412   return parent;
1413 }
1414
1415 /**
1416  * gst_pad_ghost_save_thyself:
1417  * @pad: the pad to save
1418  * @bin: the bin
1419  * @parent: the parent XML node to save the description in
1420  *
1421  * Saves the ghost pad into an xml representation.
1422  *
1423  * Returns: the xml representation of the pad
1424  */
1425 xmlNodePtr
1426 gst_pad_ghost_save_thyself (GstPad *pad,
1427                             GstElement *bin,
1428                             xmlNodePtr parent)
1429 {
1430   xmlNodePtr self;
1431
1432   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
1433
1434   self = xmlNewChild(parent,NULL,"ghostpad",NULL);
1435   xmlNewChild(self,NULL,"name", GST_PAD_NAME (pad));
1436   xmlNewChild(self,NULL,"parent", GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
1437
1438   // FIXME FIXME FIXME!
1439
1440   return self;
1441 }
1442
1443 #ifndef gst_pad_push
1444 /**
1445  * gst_pad_push:
1446  * @pad: the pad to push
1447  * @buf: the buffer to push
1448  *
1449  * Push a buffer to the peer of the pad.
1450  */
1451 void 
1452 gst_pad_push (GstPad *pad, GstBuffer *buf) 
1453 {
1454   GstRealPad *peer = GST_RPAD_PEER (pad);
1455
1456   GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
1457
1458   g_return_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SRC);
1459   g_return_if_fail (peer != NULL);
1460   
1461   if (peer->pushfunc) {
1462     GST_DEBUG (GST_CAT_DATAFLOW, "calling pushfunc &%s of peer pad %s:%s\n",
1463           GST_DEBUG_FUNCPTR_NAME (peer->pushfunc), GST_DEBUG_PAD_NAME (((GstPad*)peer)));
1464     (peer->pushfunc) (((GstPad*)peer), buf);
1465   } else
1466     GST_DEBUG (GST_CAT_DATAFLOW, "no pushfunc\n");
1467 }
1468 #endif
1469
1470 #ifndef gst_pad_pull
1471 /**
1472  * gst_pad_pull:
1473  * @pad: the pad to pull
1474  *
1475  * Pull a buffer from the peer pad.
1476  *
1477  * Returns: a new buffer from the peer pad.
1478  */
1479 GstBuffer*
1480 gst_pad_pull (GstPad *pad) 
1481 {
1482   GstRealPad *peer = GST_RPAD_PEER(pad);
1483   
1484   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
1485
1486   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1487   g_return_val_if_fail (peer != NULL, NULL);
1488
1489   if (peer->pullfunc) {
1490     GST_DEBUG (GST_CAT_DATAFLOW,"calling pullfunc %s of peer pad %s:%s\n",
1491       GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),GST_DEBUG_PAD_NAME(peer));
1492     return (peer->pullfunc)(((GstPad*)peer));
1493   } else {
1494     GST_DEBUG (GST_CAT_DATAFLOW,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
1495     return NULL;
1496   }
1497 }
1498 #endif
1499
1500 #ifndef gst_pad_pullregion
1501 /**
1502  * gst_pad_pullregion:
1503  * @pad: the pad to pull the region from
1504  * @type: the regiontype
1505  * @offset: the offset/start of the buffer to pull
1506  * @len: the length of the buffer to pull
1507  *
1508  * Pull a buffer region from the peer pad. The region to pull can be 
1509  * specified with a offset/lenght pair or with a start/legnth time
1510  * indicator as specified by the type parameter.
1511  *
1512  * Returns: a new buffer from the peer pad with data in the specified
1513  * region.
1514  */
1515 GstBuffer*
1516 gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len) 
1517 {
1518   GstRealPad *peer = GST_RPAD_PEER(pad);
1519   
1520   g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL);
1521   g_return_val_if_fail (peer != NULL, NULL);
1522
1523   GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len);
1524
1525   if (peer->pullregionfunc) {
1526     GST_DEBUG (GST_CAT_DATAFLOW,"calling pullregionfunc &%s of peer pad %s:%s\n",
1527           GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
1528     return (peer->pullregionfunc)(((GstPad*)peer),type,offset,len);
1529   } else {
1530     GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc\n");
1531     return NULL;
1532   }
1533 }
1534 #endif
1535
1536 /************************************************************************
1537  *
1538  * templates
1539  *
1540  */
1541 static void             gst_padtemplate_class_init      (GstPadTemplateClass *klass);
1542 static void             gst_padtemplate_init            (GstPadTemplate *templ);
1543
1544 enum {
1545   TEMPL_PAD_CREATED,
1546   /* FILL ME */
1547   TEMPL_LAST_SIGNAL
1548 };
1549
1550 static GstObject *padtemplate_parent_class = NULL;
1551 static guint gst_padtemplate_signals[TEMPL_LAST_SIGNAL] = { 0 };
1552
1553 GtkType
1554 gst_padtemplate_get_type (void)
1555 {
1556   static GtkType padtemplate_type = 0;
1557
1558   if (!padtemplate_type) {
1559     static const GtkTypeInfo padtemplate_info = {
1560       "GstPadTemplate",
1561       sizeof(GstPadTemplate),
1562       sizeof(GstPadTemplateClass),
1563       (GtkClassInitFunc)gst_padtemplate_class_init,
1564       (GtkObjectInitFunc)gst_padtemplate_init,
1565       (GtkArgSetFunc)NULL,
1566       (GtkArgGetFunc)NULL,
1567       (GtkClassInitFunc)NULL,
1568     };
1569     padtemplate_type = gtk_type_unique(GST_TYPE_OBJECT,&padtemplate_info);
1570   }
1571   return padtemplate_type;
1572 }
1573
1574 static void
1575 gst_padtemplate_class_init (GstPadTemplateClass *klass)
1576 {
1577   GtkObjectClass *gtkobject_class;
1578   GstObjectClass *gstobject_class;
1579
1580   gtkobject_class = (GtkObjectClass*)klass;
1581   gstobject_class = (GstObjectClass*)klass;
1582
1583   padtemplate_parent_class = gtk_type_class(GST_TYPE_OBJECT);
1584
1585   gst_padtemplate_signals[TEMPL_PAD_CREATED] =
1586     gtk_signal_new ("pad_created", GTK_RUN_LAST, gtkobject_class->type,
1587                     GTK_SIGNAL_OFFSET (GstPadTemplateClass, pad_created),
1588                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
1589                     GST_TYPE_PAD);
1590
1591   gtk_object_class_add_signals (gtkobject_class, gst_padtemplate_signals, TEMPL_LAST_SIGNAL);
1592
1593   gstobject_class->path_string_separator = "*";
1594 }
1595
1596 static void
1597 gst_padtemplate_init (GstPadTemplate *templ)
1598 {
1599 }
1600
1601 /**
1602  * gst_padtemplate_new:
1603  * @name_template: the name template
1604  * @direction: the direction for the template
1605  * @presence: the presence of the pad
1606  * @caps: a list of capabilities for the template
1607  * @...: more capabilities
1608  *
1609  * Creates a new padtemplate from the given arguments.
1610  *
1611  * Returns: the new padtemplate
1612  */
1613 GstPadTemplate*
1614 gst_padtemplate_new (gchar *name_template,
1615                      GstPadDirection direction, GstPadPresence presence,
1616                      GstCaps *caps, ...)
1617 {
1618   GstPadTemplate *new;
1619   va_list var_args;
1620   GstCaps *thecaps = NULL;
1621
1622   g_return_val_if_fail (name_template != NULL, NULL);
1623
1624   new = gtk_type_new (gst_padtemplate_get_type ());
1625
1626   GST_PADTEMPLATE_NAME_TEMPLATE (new) = name_template;
1627   GST_PADTEMPLATE_DIRECTION (new) = direction;
1628   GST_PADTEMPLATE_PRESENCE (new) = presence;
1629
1630   va_start (var_args, caps);
1631
1632   while (caps) {
1633     thecaps = gst_caps_append (thecaps, caps);
1634     caps = va_arg (var_args, GstCaps*);
1635   }
1636   va_end (var_args);
1637   
1638   GST_PADTEMPLATE_CAPS (new) = thecaps;
1639
1640   return new;
1641 }
1642
1643 /**
1644  * gst_padtemplate_get_caps:
1645  * @templ: the padtemplate to use
1646  *
1647  * Get the capabilities of the padtemplate
1648  *
1649  * Returns: a GstCaps*
1650  */
1651 GstCaps*
1652 gst_padtemplate_get_caps (GstPadTemplate *templ)
1653 {
1654   g_return_val_if_fail (templ != NULL, NULL);
1655
1656   return GST_PADTEMPLATE_CAPS (templ);
1657 }
1658
1659 /**
1660  * gst_padtemplate_save_thyself:
1661  * @templ: the padtemplate to save
1662  * @parent: the parent XML tree
1663  *
1664  * Saves the padtemplate into XML.
1665  *
1666  * Returns: the new XML tree
1667  */
1668 xmlNodePtr
1669 gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
1670 {
1671   xmlNodePtr subtree;
1672   guchar *presence;
1673
1674   GST_DEBUG (GST_CAT_XML,"saving padtemplate %s\n", templ->name_template);
1675
1676   xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
1677   xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
1678
1679   switch (templ->presence) {
1680     case GST_PAD_ALWAYS:
1681       presence = "always";
1682       break;
1683     case GST_PAD_SOMETIMES:
1684       presence = "sometimes";
1685       break;
1686     case GST_PAD_REQUEST:
1687       presence = "request";
1688       break;
1689     default:
1690       presence = "unknown";
1691       break;
1692   }
1693   xmlNewChild(parent,NULL,"presence", presence);
1694
1695   if (GST_PADTEMPLATE_CAPS (templ)) {
1696     subtree = xmlNewChild (parent, NULL, "caps", NULL);
1697     gst_caps_save_thyself (GST_PADTEMPLATE_CAPS (templ), subtree);
1698   }
1699
1700   return parent;
1701 }
1702
1703 /**
1704  * gst_padtemplate_load_thyself:
1705  * @parent: the source XML tree
1706  *
1707  * Loads a padtemplate from the XML tree.
1708  *
1709  * Returns: the new padtemplate
1710  */
1711 GstPadTemplate*
1712 gst_padtemplate_load_thyself (xmlNodePtr parent)
1713 {
1714   xmlNodePtr field = parent->xmlChildrenNode;
1715   GstPadTemplate *factory;
1716   gchar *name_template = NULL;
1717   GstPadDirection direction = GST_PAD_UNKNOWN;
1718   GstPadPresence presence = GST_PAD_ALWAYS;
1719   GstCaps *caps = NULL;
1720
1721   while (field) {
1722     if (!strcmp(field->name, "nametemplate")) {
1723       name_template = xmlNodeGetContent(field);
1724     }
1725     if (!strcmp(field->name, "direction")) {
1726       gchar *value = xmlNodeGetContent(field);
1727
1728       if (!strcmp(value, "sink")) {
1729         direction = GST_PAD_SINK;
1730       }
1731       else if (!strcmp(value, "src")) {
1732         direction = GST_PAD_SRC;
1733       }
1734       g_free (value);
1735     }
1736     if (!strcmp(field->name, "presence")) {
1737       gchar *value = xmlNodeGetContent(field);
1738
1739       if (!strcmp(value, "always")) {
1740         presence = GST_PAD_ALWAYS;
1741       }
1742       else if (!strcmp(value, "sometimes")) {
1743         presence = GST_PAD_SOMETIMES;
1744       }
1745       else if (!strcmp(value, "request")) {
1746         presence = GST_PAD_REQUEST;
1747       }
1748       g_free (value);
1749     }
1750     else if (!strcmp(field->name, "caps")) {
1751       caps = gst_caps_load_thyself (field);
1752     }
1753     field = field->next;
1754   }
1755
1756   factory = gst_padtemplate_new (name_template, direction, presence, caps, NULL);
1757
1758   return factory;
1759 }
1760
1761
1762 gboolean
1763 gst_pad_eos_func(GstPad *pad)
1764 {
1765   GstElement *element;
1766   GList *pads;
1767   GstPad *srcpad;
1768   gboolean result = TRUE, success;
1769
1770   g_return_val_if_fail (pad != NULL, FALSE);
1771   g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE);   // NOTE the restriction
1772
1773   GST_INFO (GST_CAT_PADS,"attempting to set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1774
1775   element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad)));
1776 //  g_return_val_if_fail (element != NULL, FALSE);
1777 //  g_return_val_if_fail (GST_IS_ELEMENT(element), FALSE);
1778
1779   pads = gst_element_get_pad_list(element);
1780   while (pads) {
1781     srcpad = GST_PAD(pads->data);
1782     pads = g_list_next(pads);
1783
1784     if (gst_pad_get_direction(srcpad) == GST_PAD_SRC) {
1785       result = gst_pad_eos(GST_REAL_PAD(srcpad));
1786       if (result == FALSE) success = FALSE;
1787     }
1788   }
1789
1790   if (result == FALSE) return FALSE;
1791
1792   GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1793   GST_FLAG_SET (pad, GST_PAD_EOS);
1794
1795   gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
1796
1797   return TRUE;
1798 }
1799
1800 /**
1801  * gst_pad_set_eos:
1802  * @pad: the pad to set to eos
1803  *
1804  * Sets the given pad to the EOS state.
1805  *
1806  * Returns: TRUE if it succeeded
1807  */
1808 gboolean
1809 gst_pad_set_eos(GstPad *pad)
1810 {
1811   g_return_val_if_fail (pad != NULL, FALSE);
1812   g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE);           // NOTE the restriction
1813   g_return_val_if_fail (GST_PAD_CONNECTED(pad), FALSE);
1814
1815   GST_INFO (GST_CAT_PADS,"attempting to set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1816
1817   if (!gst_pad_eos(GST_REAL_PAD(pad))) {
1818     return FALSE;
1819   }
1820
1821   GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1822   GST_FLAG_SET (pad, GST_PAD_EOS);
1823
1824   gst_element_set_state (GST_ELEMENT(GST_PAD_PARENT(pad)), GST_STATE_READY);
1825
1826   gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad)));
1827
1828   return TRUE;
1829 }
1830
1831 /**
1832  * gst_pad_set_element_private:
1833  * @pad: the pad to set the private data to
1834  * @priv: The private data to attach to the pad
1835  *
1836  * Set the given private data pointer to the pad. This
1837  * function can only be used by the element that own the
1838  * pad.
1839  */
1840 void
1841 gst_pad_set_element_private (GstPad *pad, gpointer priv)
1842 {
1843   pad->element_private = priv;
1844 }
1845
1846 /**
1847  * gst_pad_get_element_private:
1848  * @pad: the pad to get the private data of
1849  *
1850  * Get the private data of a pad. The private data can
1851  * only be set by the parent element of this pad.
1852  *
1853  * Returns: a pointer to the private data.
1854  */
1855 gpointer
1856 gst_pad_get_element_private (GstPad *pad)
1857 {
1858   return pad->element_private;
1859 }
1860
1861
1862 /***** ghost pads *****/
1863
1864 static void     gst_ghost_pad_class_init         (GstGhostPadClass *klass);
1865 static void     gst_ghost_pad_init               (GstGhostPad *pad);
1866
1867 static GstPad *ghost_pad_parent_class = NULL;
1868 //static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 };
1869
1870 GtkType
1871 gst_ghost_pad_get_type(void) {
1872   static GtkType pad_type = 0;
1873
1874   if (!pad_type) {
1875     static const GtkTypeInfo pad_info = {
1876       "GstGhostPad",
1877       sizeof(GstGhostPad),
1878       sizeof(GstGhostPadClass),
1879       (GtkClassInitFunc)gst_ghost_pad_class_init,
1880       (GtkObjectInitFunc)gst_ghost_pad_init,
1881       (GtkArgSetFunc)NULL,
1882       (GtkArgGetFunc)NULL,
1883       (GtkClassInitFunc)NULL,
1884     };
1885     pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info);
1886   }
1887   return pad_type;
1888 }
1889
1890 static void
1891 gst_ghost_pad_class_init (GstGhostPadClass *klass)
1892 {
1893   GtkObjectClass *gtkobject_class;
1894
1895   gtkobject_class = (GtkObjectClass*)klass;
1896
1897   ghost_pad_parent_class = gtk_type_class(GST_TYPE_PAD);
1898 }
1899
1900 static void
1901 gst_ghost_pad_init (GstGhostPad *pad)
1902 {
1903   pad->realpad = NULL;
1904 }
1905
1906 /**
1907  * gst_ghost_pad_new:
1908  * @name: name of the new ghost pad
1909  * @pad: the pad to create a ghost pad of
1910  *
1911  * Create a new ghost pad associated with the given pad.
1912  *
1913  * Returns: new ghost pad
1914  */
1915 GstPad*
1916 gst_ghost_pad_new (gchar *name,
1917                    GstPad *pad)
1918 {
1919   GstGhostPad *ghostpad;
1920
1921   g_return_val_if_fail (name != NULL, NULL);
1922   g_return_val_if_fail (GST_IS_PAD(pad), NULL);
1923
1924   ghostpad = gtk_type_new (gst_ghost_pad_get_type ());
1925   gst_pad_set_name (GST_PAD (ghostpad), name);
1926   GST_GPAD_REALPAD(ghostpad) = GST_PAD_REALIZE(pad);
1927
1928   // add ourselves to the real pad's list of ghostpads
1929   gst_pad_add_ghost_pad (pad, GST_PAD(ghostpad));
1930
1931   // FIXME need to ref the real pad here... ?
1932
1933   GST_DEBUG(GST_CAT_PADS,"created ghost pad \"%s\"\n",name);
1934
1935   return GST_PAD(ghostpad);
1936 }