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