This is a megapatch with the following changes:
[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
31
32 /***** Start with the base GstPad class *****/
33 static void             gst_pad_class_init              (GstPadClass *klass);
34 static void             gst_pad_init                    (GstPad *pad);
35
36 static xmlNodePtr       gst_pad_save_thyself            (GstObject *object, xmlNodePtr parent);
37
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   /* FILL ME */
83   REAL_LAST_SIGNAL
84 };
85
86 enum {
87   REAL_ARG_0,
88   REAL_ARG_ACTIVE,
89   /* FILL ME */
90 };
91
92 static void             gst_real_pad_class_init         (GstRealPadClass *klass);
93 static void             gst_real_pad_init               (GstRealPad *pad);
94
95 static void             gst_real_pad_set_arg            (GtkObject *object,GtkArg *arg,guint id);
96 static void             gst_real_pad_get_arg            (GtkObject *object,GtkArg *arg,guint id);
97
98 static void             gst_real_pad_destroy            (GtkObject *object);
99
100 static void             gst_pad_push_func               (GstPad *pad, GstBuffer *buf);
101 static gboolean         gst_pad_eos_func                (GstPad *pad);
102
103
104 static GstPad *real_pad_parent_class = NULL;
105 static guint gst_real_pad_signals[REAL_LAST_SIGNAL] = { 0 };
106
107 GtkType
108 gst_real_pad_get_type(void) {
109   static GtkType pad_type = 0;
110
111   if (!pad_type) {
112     static const GtkTypeInfo pad_info = {
113       "GstRealPad",
114       sizeof(GstRealPad),
115       sizeof(GstRealPadClass),
116       (GtkClassInitFunc)gst_real_pad_class_init,
117       (GtkObjectInitFunc)gst_real_pad_init,
118       (GtkArgSetFunc)NULL,
119       (GtkArgGetFunc)NULL,
120       (GtkClassInitFunc)NULL,
121     };
122     pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info);
123   }
124   return pad_type;
125 }
126
127 static void
128 gst_real_pad_class_init (GstRealPadClass *klass)
129 {
130   GtkObjectClass *gtkobject_class;
131   GstObjectClass *gstobject_class;
132
133   gtkobject_class = (GtkObjectClass*)klass;
134   gstobject_class = (GstObjectClass*)klass;
135
136   real_pad_parent_class = gtk_type_class(GST_TYPE_PAD);
137
138   gst_real_pad_signals[REAL_SET_ACTIVE] =
139     gtk_signal_new ("set_active", GTK_RUN_LAST, gtkobject_class->type,
140                     GTK_SIGNAL_OFFSET (GstRealPadClass, set_active),
141                     gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1,
142                     GTK_TYPE_BOOL);
143   gst_real_pad_signals[REAL_CAPS_CHANGED] =
144     gtk_signal_new ("caps_changed", GTK_RUN_LAST, gtkobject_class->type,
145                     GTK_SIGNAL_OFFSET (GstRealPadClass, caps_changed),
146                     gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
147                     GTK_TYPE_POINTER);
148   gtk_object_class_add_signals (gtkobject_class, gst_real_pad_signals, REAL_LAST_SIGNAL);
149
150   gtk_object_add_arg_type ("GstRealPad::active", GTK_TYPE_BOOL,
151                            GTK_ARG_READWRITE, REAL_ARG_ACTIVE);
152
153   gtkobject_class->destroy = gst_real_pad_destroy;
154   gtkobject_class->set_arg = gst_real_pad_set_arg;
155   gtkobject_class->get_arg = gst_real_pad_get_arg;
156
157   gstobject_class->save_thyself = gst_pad_save_thyself;
158   gstobject_class->path_string_separator = ".";
159 }
160
161 static void
162 gst_real_pad_init (GstRealPad *pad)
163 {
164   pad->direction = GST_PAD_UNKNOWN;
165   pad->peer = NULL;
166
167   pad->chainfunc = NULL;
168   pad->getfunc = NULL;
169   pad->getregionfunc = NULL;
170   pad->qosfunc = NULL;
171   pad->eosfunc = gst_pad_eos_func;
172
173   pad->pushfunc = GST_DEBUG_FUNCPTR(gst_pad_push_func);
174   pad->pullfunc = NULL;
175   pad->pullregionfunc = NULL;
176
177   pad->ghostpads = NULL;
178   pad->caps = NULL;
179 }
180
181 static void
182 gst_real_pad_set_arg (GtkObject *object, GtkArg *arg, guint id)
183 {
184   g_return_if_fail(GST_IS_PAD(object));
185
186   switch (id) {
187     case REAL_ARG_ACTIVE:
188       if (GTK_VALUE_BOOL(*arg)) {
189         gst_info("gstpad: activating pad\n");
190         GST_FLAG_UNSET(object,GST_PAD_DISABLED);
191       } else {
192         gst_info("gstpad: de-activating pad\n");
193         GST_FLAG_SET(object,GST_PAD_DISABLED);
194       }
195       gtk_signal_emit(GTK_OBJECT(object), gst_real_pad_signals[REAL_SET_ACTIVE],
196                       ! GST_FLAG_IS_SET(object,GST_PAD_DISABLED));
197       break;
198     default:
199       break;
200   }
201 }
202
203 static void
204 gst_real_pad_get_arg (GtkObject *object, GtkArg *arg, guint id)
205 {
206   /* it's not null if we got it, but it might not be ours */
207   g_return_if_fail (GST_IS_PAD (object));
208
209   switch (id) {
210     case REAL_ARG_ACTIVE:
211       GTK_VALUE_BOOL (*arg) = ! GST_FLAG_IS_SET (object, GST_PAD_DISABLED);
212       break;
213     default:
214       break;
215   }
216 }
217
218
219 /**
220  * gst_pad_new:
221  * @name: name of new pad
222  * @direction: either GST_PAD_SRC or GST_PAD_SINK
223  *
224  * Create a new pad with given name.
225  *
226  * Returns: new pad
227  */
228 GstPad*
229 gst_pad_new (gchar *name,
230              GstPadDirection direction)
231 {
232   GstRealPad *pad;
233
234   g_return_val_if_fail (name != NULL, NULL);
235   g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL);
236
237   pad = gtk_type_new (gst_real_pad_get_type ());
238   gst_object_set_name (GST_OBJECT (pad), name);
239   GST_RPAD_DIRECTION(pad) = direction;
240
241   return GST_PAD(pad);
242 }
243
244 /**
245  * gst_pad_new_from_template:
246  * @templ: the pad template to use
247  * @name: the name of the element
248  *
249  * Create a new pad with given name from the given template.
250  *
251  * Returns: new pad
252  */
253 GstPad*
254 gst_pad_new_from_template (GstPadTemplate *templ,
255                            gchar *name)
256 {
257   GstPad *pad;
258
259   g_return_val_if_fail (name != NULL, NULL);
260   g_return_val_if_fail (templ != NULL, NULL);
261
262   pad = gst_pad_new (name, templ->direction);
263   GST_PAD_CAPS(pad) = templ->caps;
264   GST_PAD_PADTEMPLATE(pad) = templ;
265
266   return pad;
267 }
268
269 /**
270  * gst_pad_get_direction:
271  * @pad: the Pad to get the direction from
272  *
273  * Get the direction of the pad.
274  *
275  * Returns: the direction of the pad
276  */
277 GstPadDirection
278 gst_pad_get_direction (GstPad *pad)
279 {
280   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
281   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
282
283   return GST_PAD_DIRECTION(pad);
284 }
285
286 /**
287  * gst_pad_set_name:
288  * @pad: the pad to set the name of
289  * @name: the name of the pad
290  *
291  * Set the name of a pad.
292  */
293 void
294 gst_pad_set_name (GstPad *pad,
295                   const gchar *name)
296 {
297   g_return_if_fail (pad != NULL);
298   g_return_if_fail (GST_IS_PAD (pad));
299
300   gst_object_set_name (GST_OBJECT (pad), name);
301 }
302
303 /**
304  * gst_pad_get_name:
305  * @pad: the pad to get the name of
306  *
307  * Get the name of a pad.
308  *
309  * Returns: the name of the pad, don't free.
310  */
311 const gchar*
312 gst_pad_get_name (GstPad *pad)
313 {
314   g_return_val_if_fail (pad != NULL, NULL);
315   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
316
317   return GST_OBJECT_NAME (pad);
318 }
319
320 /**
321  * gst_pad_set_chain_function:
322  * @pad: the pad to set the chain function for
323  * @chain: the chain function
324  *
325  * Set the given chain function for the pad.
326  */
327 void gst_pad_set_chain_function (GstPad *pad,
328                                  GstPadChainFunction chain)
329 {
330   g_return_if_fail (pad != NULL);
331   g_return_if_fail (GST_IS_REAL_PAD (pad));
332
333   GST_RPAD_CHAINFUNC(pad) = chain;
334   GST_DEBUG (0,"chainfunc for %s:%s(@%p) at %p is set to %p\n",
335              GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_CHAINFUNC(pad),chain);
336 }
337
338 /**
339  * gst_pad_set_get_function:
340  * @pad: the pad to set the get function for
341  * @get: the get function
342  *
343  * Set the given get function for the pad.
344  */
345 void
346 gst_pad_set_get_function (GstPad *pad,
347                           GstPadGetFunction get)
348 {
349   g_return_if_fail (pad != NULL);
350   g_return_if_fail (GST_IS_REAL_PAD (pad));
351
352   GST_RPAD_GETFUNC(pad) = get;
353   GST_DEBUG (0,"getfunc for %s:%s(@%p) at %p is set to %p\n",
354              GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETFUNC(pad),get);
355 }
356
357 /**
358  * gst_pad_set_getregion_function:
359  * @pad: the pad to set the getregion function for
360  * @getregion: the getregion function
361  *
362  * Set the given getregion function for the pad.
363  */
364 void
365 gst_pad_set_getregion_function (GstPad *pad,
366                                 GstPadGetRegionFunction getregion)
367 {
368   g_return_if_fail (pad != NULL);
369   g_return_if_fail (GST_IS_REAL_PAD (pad));
370
371   GST_RPAD_GETREGIONFUNC(pad) = getregion;
372   GST_DEBUG (0,"getregionfunc for %s:%s(@%p) at %p is set to %p\n",
373              GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_GETREGIONFUNC(pad),getregion);
374 }
375
376 /**
377  * gst_pad_set_qos_function:
378  * @pad: the pad to set the qos function for
379  * @qos: the qos function
380  *
381  * Set the given qos function for the pad.
382  */
383 void
384 gst_pad_set_qos_function (GstPad *pad,
385                           GstPadQoSFunction qos)
386 {
387   g_return_if_fail (pad != NULL);
388   g_return_if_fail (GST_IS_REAL_PAD (pad));
389
390   GST_RPAD_QOSFUNC(pad) = qos;
391   GST_DEBUG (0,"qosfunc for %s:%s(@%p) at %p is set to %p\n",
392              GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_QOSFUNC(pad),qos);
393 }
394
395 /**
396  * gst_pad_set_eos_function:
397  * @pad: the pad to set the eos function for
398  * @eos: the eos function
399  *
400  * Set the given EOS function for the pad.
401  */
402 void
403 gst_pad_set_eos_function (GstPad *pad,
404                           GstPadEOSFunction eos)
405 {
406   g_return_if_fail (pad != NULL);
407   g_return_if_fail (GST_IS_REAL_PAD (pad));
408
409   GST_RPAD_EOSFUNC(pad) = eos;
410   GST_DEBUG (0,"eosfunc for %s:%s(@%p) at %p is set to %p\n",
411              GST_DEBUG_PAD_NAME(pad),pad,&GST_RPAD_EOSFUNC(pad),eos);
412 }
413
414
415
416 static void
417 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
418 {
419   if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
420     GST_DEBUG (0,"calling chain function\n");
421     (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
422   } else {
423     GST_DEBUG (0,"got a problem here: default pad_push handler in place, no chain function\n");
424   }
425 }
426
427
428 /**
429  * gst_pad_handle_qos:
430  * @pad: the pad to handle the QoS message
431  * @qos_message: the QoS message to handle
432  *
433  * Pass the qos message downstream.
434  */
435 void
436 gst_pad_handle_qos(GstPad *pad,
437                    glong qos_message)
438 {
439   GstElement *element;
440   GList *pads;
441   GstPad *target_pad;
442
443   GST_DEBUG (0,"gst_pad_handle_qos(\"%s\",%08ld)\n", GST_OBJECT_NAME (GST_PAD_PARENT (pad)),qos_message);
444
445   if (GST_RPAD_QOSFUNC(pad)) {
446     (GST_RPAD_QOSFUNC(pad)) (pad,qos_message);
447   } else {
448     element = GST_ELEMENT (GST_PAD_PARENT(GST_RPAD_PEER(pad)));
449
450     pads = element->pads;
451     GST_DEBUG (0,"gst_pad_handle_qos recurse(\"%s\",%08ld)\n", GST_ELEMENT_NAME (element), qos_message);
452     while (pads) {
453       target_pad = GST_PAD (pads->data);
454       if (GST_RPAD_DIRECTION(target_pad) == GST_PAD_SINK) {
455         gst_pad_handle_qos (target_pad, qos_message);
456       }
457       pads = g_list_next (pads);
458     }
459   }
460
461   return;
462 }
463
464 /**
465  * gst_pad_disconnect:
466  * @srcpad: the source pad to disconnect
467  * @sinkpad: the sink pad to disconnect
468  *
469  * Disconnects the source pad from the sink pad.
470  */
471 void
472 gst_pad_disconnect (GstPad *srcpad,
473                     GstPad *sinkpad)
474 {
475   GstRealPad *realsrc, *realsink;
476
477   /* generic checks */
478   g_return_if_fail (srcpad != NULL);
479   g_return_if_fail (GST_IS_PAD (srcpad));
480   g_return_if_fail (sinkpad != NULL);
481   g_return_if_fail (GST_IS_PAD (sinkpad));
482
483   // now we need to deal with the real/ghost stuff
484   realsrc = GST_PAD_REALIZE(srcpad);
485   realsink = GST_PAD_REALIZE(sinkpad);
486
487   g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
488   g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
489
490   g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
491                     (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
492
493   /* first clear peers */
494   GST_RPAD_PEER(realsrc) = NULL;
495   GST_RPAD_PEER(realsink) = NULL;
496
497   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
498             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
499 }
500
501 /**
502  * gst_pad_connect:
503  * @srcpad: the source pad to connect
504  * @sinkpad: the sink pad to connect
505  *
506  * Connects the source pad to the sink pad.
507  */
508 void
509 gst_pad_connect (GstPad *srcpad,
510                  GstPad *sinkpad)
511 {
512   GstRealPad *realsrc, *realsink;
513   GstRealPad *temppad;
514
515   /* generic checks */
516   g_return_if_fail(srcpad != NULL);
517   g_return_if_fail(GST_IS_PAD(srcpad));
518   g_return_if_fail(sinkpad != NULL);
519   g_return_if_fail(GST_IS_PAD(sinkpad));
520
521   // now we need to deal with the real/ghost stuff
522   realsrc = GST_PAD_REALIZE(srcpad);
523   realsink = GST_PAD_REALIZE(sinkpad);
524
525   g_return_if_fail(GST_RPAD_PEER(realsrc) == NULL);
526   g_return_if_fail(GST_RPAD_PEER(realsink) == NULL);
527
528   /* check for reversed directions and swap if necessary */
529   if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
530       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
531     temppad = realsrc;
532     realsrc = realsink;
533     realsink = temppad;
534   }
535   g_return_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
536                    (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
537
538   if (!gst_pad_check_compatibility (srcpad, sinkpad)) {
539     g_warning ("gstpad: connecting incompatible pads (%s:%s) and (%s:%s)\n",
540                        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
541   }
542   else {
543     GST_DEBUG (0,"gstpad: connecting compatible pads (%s:%s) and (%s:%s)\n",
544                        GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
545   }
546
547   /* first set peers */
548   GST_RPAD_PEER(realsrc) = realsink;
549   GST_RPAD_PEER(realsink) = realsrc;
550
551   /* set the connected flag */
552   /* FIXME: set connected flag */
553
554   GST_INFO (GST_CAT_ELEMENT_PADS, "connected %s:%s and %s:%s",
555             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
556 }
557
558 /**
559  * gst_pad_set_parent:
560  * @pad: the pad to set the parent
561  * @parent: the object to set the parent to
562  *
563  * Sets the parent object of a pad.
564  */
565 void
566 gst_pad_set_parent (GstPad *pad,
567                     GstObject *parent)
568 {
569   g_return_if_fail (pad != NULL);
570   g_return_if_fail (GST_IS_PAD (pad));
571   g_return_if_fail (GST_PAD_PARENT (pad) == NULL);
572   g_return_if_fail (parent != NULL);
573   g_return_if_fail (GTK_IS_OBJECT (parent));
574   g_return_if_fail ((gpointer)pad != (gpointer)parent);
575
576   gst_object_set_parent (GST_OBJECT (pad), parent);
577 }
578
579 /**
580  * gst_pad_get_parent:
581  * @pad: the pad to get the parent from
582  *
583  * Get the parent object of this pad.
584  *
585  * Returns: the parent object
586  */
587 GstObject*
588 gst_pad_get_parent (GstPad *pad)
589 {
590   g_return_val_if_fail (pad != NULL, NULL);
591   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
592
593   return GST_OBJECT_PARENT (pad);
594 }
595
596 /**
597  * gst_pad_add_ghost_pad:
598  * @pad: the pad to set the ghost parent
599  * @ghostpad: the ghost pad to add
600  *
601  * Add a ghost pad to a pad.
602  */
603 void
604 gst_pad_add_ghost_pad (GstPad *pad,
605                        GstPad *ghostpad)
606 {
607   GstRealPad *realpad;
608
609   g_return_if_fail (pad != NULL);
610   g_return_if_fail (GST_IS_PAD (pad));
611   g_return_if_fail (ghostpad != NULL);
612   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
613
614   realpad = GST_PAD_REALIZE(pad);
615
616   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
617 }
618
619
620 /**
621  * gst_pad_remove_ghost_pad:
622  * @pad: the pad to remove the ghost parent
623  * @ghostpad: the ghost pad to remove from the pad
624  *
625  * Remove a ghost pad from a pad.
626  */
627 void
628 gst_pad_remove_ghost_pad (GstPad *pad,
629                           GstPad *ghostpad)
630 {
631   GstRealPad *realpad;
632
633   g_return_if_fail (pad != NULL);
634   g_return_if_fail (GST_IS_PAD (pad));
635   g_return_if_fail (ghostpad != NULL);
636   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
637
638   realpad = GST_PAD_REALIZE (pad);
639
640   realpad->ghostpads = g_list_remove (realpad->ghostpads, ghostpad);
641 }
642
643 /**
644  * gst_pad_get_ghost_pad_list:
645  * @pad: the pad to get the ghost parents from
646  *
647  * Get the ghost parents of this pad.
648  *
649  * Returns: a GList of ghost pads
650  */
651 GList*
652 gst_pad_get_ghost_pad_list (GstPad *pad)
653 {
654   g_return_val_if_fail (pad != NULL, NULL);
655   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
656
657   return GST_PAD_REALIZE(pad)->ghostpads;
658 }
659
660 /**
661  * gst_pad_set_caps_list:
662  * @pad: the pad to set the caps to
663  * @caps: a GList of the capabilities to attach to this pad
664  *
665  * Set the capabilities of this pad.
666  */
667 void
668 gst_pad_set_caps_list (GstPad *pad,
669                        GList *caps)
670 {
671   g_return_if_fail (pad != NULL);
672   g_return_if_fail (GST_IS_REAL_PAD (pad));             // NOTE this restriction
673
674   GST_PAD_CAPS(pad) = caps;
675 }
676
677 /**
678  * gst_pad_get_caps_list:
679  * @pad: the pad to get the capabilities from
680  *
681  * Get the capabilities of this pad.
682  *
683  * Returns: a list of the capabilities of this pad
684  */
685 GList *
686 gst_pad_get_caps_list (GstPad *pad)
687 {
688   g_return_val_if_fail (pad != NULL, NULL);
689   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
690
691   return GST_PAD_CAPS(pad);
692 }
693
694 /**
695  * gst_pad_get_caps_by_name:
696  * @pad: the pad to get the capabilities from
697  * @name: the name of the capability to get
698  *
699  * Get the capabilities  with the given name from this pad.
700  *
701  * Returns: a capability or NULL if not found
702  */
703 GstCaps *
704 gst_pad_get_caps_by_name (GstPad *pad, gchar *name)
705 {
706   GList *caps;
707
708   g_return_val_if_fail (pad != NULL, NULL);
709   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
710
711   caps = GST_PAD_CAPS(pad);
712
713   while (caps) {
714     GstCaps *cap = (GstCaps *)caps->data;
715
716     if (!strcmp (cap->name, name))
717       return cap;
718
719     caps = g_list_next (caps);
720   }
721
722   return NULL;
723 }
724
725 /**
726  * gst_pad_check_compatibility:
727  * @srcpad: the srcpad to check
728  * @sinkpad: the sinkpad to check against
729  *
730  * Check if two pads have compatible capabilities.
731  *
732  * Returns: TRUE if they are compatible or the capabilities
733  * could not be checked
734  */
735 gboolean
736 gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
737 {
738   GstRealPad *realsrc, *realsink;
739
740   g_return_val_if_fail (srcpad != NULL, FALSE);
741   g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
742   g_return_val_if_fail (sinkpad != NULL, FALSE);
743   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
744
745   realsrc = GST_PAD_REALIZE(srcpad);
746   realsink = GST_PAD_REALIZE(sinkpad);
747
748   if (GST_RPAD_CAPS(realsrc) && GST_RPAD_CAPS(realsink)) {
749     if (!gst_caps_list_check_compatibility (GST_RPAD_CAPS(realsrc), GST_RPAD_CAPS(realsink))) {
750       return FALSE;
751     }
752     else {
753       return TRUE;
754     }
755   }
756   else {
757     GST_DEBUG (0,"gstpad: could not check capabilities of pads (%s:%s) and (%s:%s)\n",
758                     GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
759     return TRUE;
760   }
761 }
762
763 /**
764  * gst_pad_get_peer:
765  * @pad: the pad to get the peer from
766  *
767  * Get the peer pad of this pad.
768  *
769  * Returns: the peer pad
770  */
771 GstPad*
772 gst_pad_get_peer (GstPad *pad)
773 {
774   g_return_val_if_fail (pad != NULL, NULL);
775   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
776
777   return GST_PAD(GST_PAD_PEER(pad));
778 }
779
780 // FIXME this needs to be rethought soon
781 static void
782 gst_real_pad_destroy (GtkObject *object)
783 {
784   GstPad *pad = GST_PAD (object);
785
786 //  g_print("in gst_pad_real_destroy()\n");
787
788   g_list_free (GST_REAL_PAD(pad)->ghostpads);
789 }
790
791
792 /**
793  * gst_pad_load_and_connect:
794  * @self: the XML node to read the description from
795  * @parent: the element that has the pad
796  *
797  * Read the pad definition from the XML node and connect the given pad
798  * in element to a pad of an element up in the hierarchy.
799  */
800 void
801 gst_pad_load_and_connect (xmlNodePtr self,
802                           GstObject *parent)
803 {
804   xmlNodePtr field = self->childs;
805   GstPad *pad = NULL, *targetpad;
806   guchar *peer = NULL;
807   gchar **split;
808   GstElement *target;
809   GstObject *grandparent;
810
811   while (field) {
812     if (!strcmp (field->name, "name")) {
813       pad = gst_element_get_pad (GST_ELEMENT (parent), xmlNodeGetContent (field));
814     }
815     else if (!strcmp(field->name, "peer")) {
816       peer = g_strdup (xmlNodeGetContent (field));
817     }
818     field = field->next;
819   }
820   g_return_if_fail (pad != NULL);
821
822   if (peer == NULL) return;
823
824   split = g_strsplit (peer, ".", 2);
825
826   g_return_if_fail (split[0] != NULL);
827   g_return_if_fail (split[1] != NULL);
828
829   grandparent = gst_object_get_parent (parent);
830
831   if (grandparent && GST_IS_BIN (grandparent)) {
832     target = gst_bin_get_by_name_recurse_up (GST_BIN (grandparent), split[0]);
833   }
834   else
835     goto cleanup;
836
837   if (target == NULL) goto cleanup;
838
839   targetpad = gst_element_get_pad (target, split[1]);
840
841   if (targetpad == NULL) goto cleanup;
842
843   gst_pad_connect (pad, targetpad);
844
845 cleanup:
846   g_strfreev (split);
847 }
848
849
850 /**
851  * gst_pad_save_thyself:
852  * @pad: the pad to save
853  * @parent: the parent XML node to save the description in
854  *
855  * Saves the pad into an xml representation
856  *
857  * Returns: the xml representation of the pad
858  */
859 static xmlNodePtr
860 gst_pad_save_thyself (GstObject *object,
861                       xmlNodePtr parent)
862 {
863   GstRealPad *realpad;
864   GstPad *peer;
865
866   g_return_val_if_fail (GST_IS_REAL_PAD (object), NULL);
867
868   realpad = GST_REAL_PAD(object);
869
870   xmlNewChild(parent,NULL,"name", GST_PAD_NAME (realpad));
871   if (GST_RPAD_PEER(realpad) != NULL) {
872     peer = GST_PAD(GST_RPAD_PEER(realpad));
873     // first check to see if the peer's parent's parent is the same
874     // we just save it off
875     xmlNewChild(parent,NULL,"peer",g_strdup_printf("%s.%s",
876                     GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer)));
877   } else
878     xmlNewChild(parent,NULL,"peer","");
879
880   return parent;
881 }
882
883 /**
884  * gst_pad_ghost_save_thyself:
885  * @pad: the pad to save
886  * @bin: the bin
887  * @parent: the parent XML node to save the description in
888  *
889  * Saves the ghost pad into an xml representation.
890  *
891  * Returns: the xml representation of the pad
892  */
893 xmlNodePtr
894 gst_pad_ghost_save_thyself (GstPad *pad,
895                             GstElement *bin,
896                             xmlNodePtr parent)
897 {
898   xmlNodePtr self;
899
900   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), NULL);
901
902   self = xmlNewChild(parent,NULL,"ghostpad",NULL);
903   xmlNewChild(self,NULL,"name", GST_PAD_NAME (pad));
904   xmlNewChild(self,NULL,"parent", GST_OBJECT_NAME (GST_PAD_PARENT (pad)));
905
906   // FIXME FIXME FIXME!
907
908   return self;
909 }
910
911 #ifndef gst_pad_push
912 void gst_pad_push(GstPad *pad,GstBuffer *buf) {
913   GstRealPad *peer = GST_RPAD_PEER(pad);
914   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
915   if (peer->pushfunc) {
916     GST_DEBUG (0,"calling pushfunc &%s of peer pad %s:%s\n",
917           GST_DEBUG_FUNCPTR_NAME(peer->pushfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
918     (peer->pushfunc)(((GstPad*)peer),buf);
919   } else
920     GST_DEBUG (0,"no pushfunc\n");
921 }
922 #endif
923
924 #ifndef gst_pad_pull
925 GstBuffer *gst_pad_pull(GstPad *pad) {
926   GstRealPad *peer = GST_RPAD_PEER(pad);
927   GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
928   if (peer->pullfunc) {
929     GST_DEBUG (0,"calling pullfunc &%s (@%p) of peer pad %s:%s\n",
930       GST_DEBUG_FUNCPTR_NAME(peer->pullfunc),&peer->pullfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
931     return (peer->pullfunc)(((GstPad*)peer));
932   } else {
933     GST_DEBUG (0,"no pullfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->pullfunc);
934     return NULL;
935   }
936 }
937 #endif
938
939 #ifndef gst_pad_pullregion
940 GstBuffer *gst_pad_pullregion(GstPad *pad,gulong offset,gulong size) {
941   GstRealPad *peer = GST_RPAD_PEER(pad);
942   GST_DEBUG_ENTER("(%s:%s,%ld,%ld)",GST_DEBUG_PAD_NAME(pad),offset,size);
943   if (peer->pullregionfunc) {
944     GST_DEBUG (0,"calling pullregionfunc &%s of peer pad %s:%s\n",
945           GST_DEBUG_FUNCPTR_NAME(peer->pullregionfunc),GST_DEBUG_PAD_NAME(((GstPad*)peer)));
946     return (peer->pullregionfunc)(((GstPad*)peer),offset,size);
947   } else {
948     GST_DEBUG (0,"no pullregionfunc\n");
949     return NULL;
950   }
951 }
952 #endif
953
954 /************************************************************************
955  *
956  * templates
957  *
958  */
959
960 /**
961  * gst_padtemplate_new:
962  * @factory: the padfactory to use
963  *
964  * Creates a new padtemplate from the factory.
965  *
966  * Returns: the new padtemplate
967  */
968 GstPadTemplate*
969 gst_padtemplate_new (GstPadFactory *factory)
970 {
971   GstPadTemplate *new;
972   GstPadFactoryEntry tag;
973   gint i = 0;
974   guint counter = 0;
975
976   g_return_val_if_fail (factory != NULL, NULL);
977
978   new = g_new0 (GstPadTemplate, 1);
979
980   tag = (*factory)[i++];
981   g_return_val_if_fail (tag != NULL, new);
982   new->name_template = g_strdup ((gchar *)tag);
983
984   tag = (*factory)[i++];
985   new->direction = GPOINTER_TO_UINT (tag);
986
987   tag = (*factory)[i++];
988   new->presence = GPOINTER_TO_UINT (tag);
989
990   tag = (*factory)[i++];
991
992   while (GPOINTER_TO_INT (tag) == 1) {
993     new->caps = g_list_append (new->caps, gst_caps_register_count ((GstCapsFactory *)&(*factory)[i], &counter));
994     i+=counter;
995     tag = (*factory)[i++];
996   }
997
998   return new;
999 }
1000
1001 /**
1002  * gst_padtemplate_create:
1003  * @name_template: the name template
1004  * @direction: the direction for the template
1005  * @presence: the presence of the pad
1006  * @caps: a list of capabilities for the template
1007  *
1008  * Creates a new padtemplate from the given arguments.
1009  *
1010  * Returns: the new padtemplate
1011  */
1012 GstPadTemplate*
1013 gst_padtemplate_create (gchar *name_template,
1014                         GstPadDirection direction, GstPadPresence presence,
1015                         GList *caps)
1016 {
1017   GstPadTemplate *new;
1018
1019   new = g_new0 (GstPadTemplate, 1);
1020
1021   new->name_template = name_template;
1022   new->direction = direction;
1023   new->presence = presence;
1024   new->caps = caps;
1025
1026   return new;
1027 }
1028
1029
1030 /**
1031  * gst_padtemplate_save_thyself:
1032  * @templ: the padtemplate to save
1033  * @parent: the parent XML tree
1034  *
1035  * Saves the padtemplate into XML.
1036  *
1037  * Returns: the new XML tree
1038  */
1039 xmlNodePtr
1040 gst_padtemplate_save_thyself (GstPadTemplate *templ, xmlNodePtr parent)
1041 {
1042   xmlNodePtr subtree;
1043   GList *caps;
1044   guchar *presence;
1045
1046   xmlNewChild(parent,NULL,"nametemplate", templ->name_template);
1047   xmlNewChild(parent,NULL,"direction", (templ->direction == GST_PAD_SINK? "sink":"src"));
1048
1049   switch (templ->presence) {
1050     case GST_PAD_ALWAYS:
1051       presence = "always";
1052       break;
1053     case GST_PAD_SOMETIMES:
1054       presence = "sometimes";
1055       break;
1056     case GST_PAD_REQUEST:
1057       presence = "request";
1058       break;
1059     default:
1060       presence = "unknown";
1061       break;
1062   }
1063   xmlNewChild(parent,NULL,"presence", presence);
1064
1065   caps = templ->caps;
1066   while (caps) {
1067     GstCaps *cap = (GstCaps *)caps->data;
1068
1069     subtree = xmlNewChild (parent, NULL, "caps", NULL);
1070     gst_caps_save_thyself (cap, subtree);
1071
1072     caps = g_list_next (caps);
1073   }
1074
1075   return parent;
1076 }
1077
1078 /**
1079  * gst_padtemplate_load_thyself:
1080  * @parent: the source XML tree
1081  *
1082  * Loads a padtemplate from the XML tree.
1083  *
1084  * Returns: the new padtemplate
1085  */
1086 GstPadTemplate*
1087 gst_padtemplate_load_thyself (xmlNodePtr parent)
1088 {
1089   xmlNodePtr field = parent->childs;
1090   GstPadTemplate *factory = g_new0 (GstPadTemplate, 1);
1091
1092   while (field) {
1093     if (!strcmp(field->name, "nametemplate")) {
1094       factory->name_template = xmlNodeGetContent(field);
1095     }
1096     if (!strcmp(field->name, "direction")) {
1097       gchar *value = xmlNodeGetContent(field);
1098
1099       factory->direction = GST_PAD_UNKNOWN;
1100       if (!strcmp(value, "sink")) {
1101         factory->direction = GST_PAD_SINK;
1102       }
1103       else if (!strcmp(value, "src")) {
1104         factory->direction = GST_PAD_SRC;
1105       }
1106       g_free (value);
1107     }
1108     if (!strcmp(field->name, "presence")) {
1109       gchar *value = xmlNodeGetContent(field);
1110
1111       if (!strcmp(value, "always")) {
1112         factory->presence = GST_PAD_ALWAYS;
1113       }
1114       else if (!strcmp(value, "sometimes")) {
1115         factory->presence = GST_PAD_SOMETIMES;
1116       }
1117       else if (!strcmp(value, "request")) {
1118         factory->presence = GST_PAD_REQUEST;
1119       }
1120       g_free (value);
1121     }
1122     else if (!strcmp(field->name, "caps")) {
1123       factory->caps = g_list_append(factory->caps, gst_caps_load_thyself (field));
1124     }
1125     field = field->next;
1126   }
1127   return factory;
1128 }
1129
1130
1131 static gboolean
1132 gst_pad_eos_func(GstPad *pad)
1133 {
1134   GstElement *element;
1135   GList *pads;
1136   GstPad *srcpad;
1137   gboolean result = TRUE, success;
1138
1139   g_return_val_if_fail (pad != NULL, FALSE);
1140   g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE);   // NOTE the restriction
1141
1142   GST_INFO (GST_CAT_PADS,"attempting to set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1143
1144   element = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad)));
1145 //  g_return_val_if_fail (element != NULL, FALSE);
1146 //  g_return_val_if_fail (GST_IS_ELEMENT(element), FALSE);
1147
1148   pads = gst_element_get_pad_list(element);
1149   while (pads) {
1150     srcpad = GST_PAD(pads->data);
1151     pads = g_list_next(pads);
1152
1153     if (gst_pad_get_direction(srcpad) == GST_PAD_SRC) {
1154       result = gst_pad_eos(GST_REAL_PAD(srcpad));
1155       if (result == FALSE) success = FALSE;
1156     }
1157   }
1158
1159   if (result == FALSE) return FALSE;
1160
1161   GST_INFO (GST_CAT_PADS,"set EOS on sink pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1162   GST_FLAG_SET (pad, GST_PAD_EOS);
1163
1164   return TRUE;
1165 }
1166
1167 /**
1168  * gst_pad_set_eos:
1169  * @pad: the pad to set to eos
1170  *
1171  * Sets the given pad to the EOS state.
1172  *
1173  * Returns: TRUE if it succeeded
1174  */
1175 gboolean
1176 gst_pad_set_eos(GstPad *pad)
1177 {
1178   g_return_val_if_fail (pad != NULL, FALSE);
1179   g_return_val_if_fail (GST_IS_REAL_PAD(pad), FALSE);           // NOTE the restriction
1180   g_return_val_if_fail (GST_PAD_CONNECTED(pad), FALSE);
1181
1182   GST_INFO (GST_CAT_PADS,"attempting to set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1183
1184   if (!gst_pad_eos(GST_REAL_PAD(pad))) {
1185     return FALSE;
1186   }
1187
1188   GST_INFO (GST_CAT_PADS,"set EOS on src pad %s:%s",GST_DEBUG_PAD_NAME(pad));
1189   GST_FLAG_SET (pad, GST_PAD_EOS);
1190
1191   gst_element_signal_eos (GST_ELEMENT (GST_PAD_PARENT (pad)));
1192
1193   return TRUE;
1194 }
1195
1196 /*
1197 GstPad *
1198 gst_pad_select(GstPad *nextpad, ...) {
1199   va_list args;
1200   GstPad *pad;
1201   GSList *pads = NULL;
1202
1203   // construct the list of pads
1204   va_start (args, nextpad);
1205   while ((pad = va_arg (args, GstPad*)))
1206     pads = g_slist_prepend (pads, pad);
1207   va_end (args);
1208
1209   // now switch to the nextpad
1210 */
1211
1212
1213 /**
1214  * gst_pad_set_element_private:
1215  * @pad: the pad to set the private data to
1216  * @priv: The private data to attach to the pad
1217  *
1218  * Set the given private data pointer to the pad. This
1219  * function can only be used by the element that own the
1220  * pad.
1221  */
1222 void
1223 gst_pad_set_element_private (GstPad *pad, gpointer priv)
1224 {
1225   pad->element_private = priv;
1226 }
1227
1228 /**
1229  * gst_pad_get_element_private:
1230  * @pad: the pad to get the private data of
1231  *
1232  * Get the private data of a pad. The private data can
1233  * only be set by the parent element of this pad.
1234  *
1235  * Returns: a pointer to the private data.
1236  */
1237 gpointer
1238 gst_pad_get_element_private (GstPad *pad)
1239 {
1240   return pad->element_private;
1241 }
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251 /***** ghost pads *****/
1252
1253 static void     gst_ghost_pad_class_init         (GstGhostPadClass *klass);
1254 static void     gst_ghost_pad_init               (GstGhostPad *pad);
1255
1256 static GstPad *ghost_pad_parent_class = NULL;
1257 //static guint gst_ghost_pad_signals[LAST_SIGNAL] = { 0 };
1258
1259 GtkType
1260 gst_ghost_pad_get_type(void) {
1261   static GtkType pad_type = 0;
1262
1263   if (!pad_type) {
1264     static const GtkTypeInfo pad_info = {
1265       "GstGhostPad",
1266       sizeof(GstGhostPad),
1267       sizeof(GstGhostPadClass),
1268       (GtkClassInitFunc)gst_ghost_pad_class_init,
1269       (GtkObjectInitFunc)gst_ghost_pad_init,
1270       (GtkArgSetFunc)NULL,
1271       (GtkArgGetFunc)NULL,
1272       (GtkClassInitFunc)NULL,
1273     };
1274     pad_type = gtk_type_unique(GST_TYPE_PAD,&pad_info);
1275   }
1276   return pad_type;
1277 }
1278
1279 static void
1280 gst_ghost_pad_class_init (GstGhostPadClass *klass)
1281 {
1282   GtkObjectClass *gtkobject_class;
1283
1284   gtkobject_class = (GtkObjectClass*)klass;
1285
1286   ghost_pad_parent_class = gtk_type_class(GST_TYPE_PAD);
1287 }
1288
1289 static void
1290 gst_ghost_pad_init (GstGhostPad *pad)
1291 {
1292   pad->realpad = NULL;
1293 }
1294
1295 /**
1296  * gst_ghost_pad_new:
1297  * @name: name of the new ghost pad
1298  * @pad: the pad to create a ghost pad of
1299  *
1300  * Create a new ghost pad associated with the given pad.
1301  *
1302  * Returns: new ghost pad
1303  */
1304 GstPad*
1305 gst_ghost_pad_new (gchar *name,
1306                    GstPad *pad)
1307 {
1308   GstGhostPad *ghostpad;
1309
1310   g_return_val_if_fail (name != NULL, NULL);
1311   g_return_val_if_fail (GST_IS_PAD(pad), NULL);
1312
1313   ghostpad = gtk_type_new (gst_ghost_pad_get_type ());
1314   gst_pad_set_name (GST_PAD (ghostpad), name);
1315   GST_GPAD_REALPAD(ghostpad) = GST_PAD_REALIZE(pad);
1316
1317   // add ourselves to the real pad's list of ghostpads
1318   gst_pad_add_ghost_pad (pad, GST_PAD(ghostpad));
1319
1320   // FIXME need to ref the real pad here... ?
1321
1322   GST_DEBUG(0,"created ghost pad \"%s\"\n",name);
1323
1324   return GST_PAD(ghostpad);
1325 }