Make the ghostpad a parent of the internal pad again for better backward compatibilit...
[platform/upstream/gstreamer.git] / gst / gstghostpad.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Andy Wingo <wingo@pobox.com>
5  *                    2006 Edward Hervey <bilboed@bilboed.com>
6  *
7  * gstghostpad.c: Proxy pads
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:gstghostpad
27  * @short_description: Pseudo link pads
28  * @see_also: #GstPad
29  *
30  * GhostPads are useful when organizing pipelines with #GstBin like elements.
31  * The idea here is to create hierarchical element graphs. The bin element
32  * contains a sub-graph. Now one would like to treat the bin-element like other
33  * #GstElements. This is where GhostPads come into play. A GhostPad acts as a
34  * proxy for another pad. Thus the bin can have sink and source ghost-pads that
35  * are associated with sink and source pads of the child elements.
36  *
37  * If the target pad is known at creation time, gst_ghost_pad_new() is the
38  * function to use to get a ghost-pad. Otherwise one can use gst_ghost_pad_new_no_target()
39  * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
40  * association later on.
41  *
42  * Note that GhostPads add overhead to the data processing of a pipeline.
43  *
44  * Last reviewed on 2005-11-18 (0.9.5)
45  */
46
47 #include "gst_private.h"
48 #include "gstinfo.h"
49
50 #include "gstghostpad.h"
51
52 #define GST_CAT_DEFAULT GST_CAT_PADS
53
54 #define GST_TYPE_PROXY_PAD              (gst_proxy_pad_get_type ())
55 #define GST_IS_PROXY_PAD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD))
56 #define GST_IS_PROXY_PAD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
57 #define GST_PROXY_PAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
58 #define GST_PROXY_PAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
59 #define GST_PROXY_PAD_CAST(obj)         ((GstProxyPad *)obj)
60
61 #define GST_PROXY_PAD_TARGET(pad)       (GST_PROXY_PAD_CAST (pad)->target)
62 #define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD_CAST (pad)->internal)
63
64 typedef struct _GstProxyPad GstProxyPad;
65 typedef struct _GstProxyPadClass GstProxyPadClass;
66
67 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_CAST (pad)->proxy_lock)
68 #define GST_PROXY_LOCK(pad)     (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
69 #define GST_PROXY_UNLOCK(pad)   (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
70
71 struct _GstProxyPad
72 {
73   GstPad pad;
74
75   /* with PROXY_LOCK */
76   GMutex *proxy_lock;
77   GstPad *target;
78   GstPad *internal;
79 };
80
81 struct _GstProxyPadClass
82 {
83   GstPadClass parent_class;
84
85   /*< private > */
86   gpointer _gst_reserved[1];
87 };
88
89
90 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
91
92 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
93
94 static void gst_proxy_pad_dispose (GObject * object);
95 static void gst_proxy_pad_finalize (GObject * object);
96
97 #ifndef GST_DISABLE_LOADSAVE
98 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
99     xmlNodePtr parent);
100 #endif
101
102
103 static void
104 gst_proxy_pad_class_init (GstProxyPadClass * klass)
105 {
106   GObjectClass *gobject_class = (GObjectClass *) klass;
107
108   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
109   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
110
111 #ifndef GST_DISABLE_LOADSAVE
112   {
113     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
114
115     gstobject_class->save_thyself =
116         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
117   }
118 #endif
119 }
120
121 const GstQueryType *
122 gst_proxy_pad_do_query_type (GstPad * pad)
123 {
124   GstPad *target = gst_proxy_pad_get_target (pad);
125   const GstQueryType *res = NULL;
126
127   if (target) {
128     res = gst_pad_get_query_types (target);
129     gst_object_unref (target);
130   }
131   return res;
132 }
133
134 static gboolean
135 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
136 {
137   gboolean res = FALSE;
138   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
139
140   res = gst_pad_push_event (internal, event);
141
142   return res;
143 }
144
145 static gboolean
146 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
147 {
148   gboolean res = FALSE;
149   GstPad *target = gst_proxy_pad_get_target (pad);
150
151   if (target) {
152     res = gst_pad_query (target, query);
153     gst_object_unref (target);
154   }
155
156   return res;
157 }
158
159 static GList *
160 gst_proxy_pad_do_internal_link (GstPad * pad)
161 {
162   GList *res = NULL;
163   GstPad *target = gst_proxy_pad_get_target (pad);
164
165   if (target) {
166     res = gst_pad_get_internal_links (target);
167     gst_object_unref (target);
168   }
169
170   return res;
171 }
172
173 static GstFlowReturn
174 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
175     GstCaps * caps, GstBuffer ** buf)
176 {
177   GstFlowReturn result;
178   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
179
180   result = gst_pad_alloc_buffer (internal, offset, size, caps, buf);
181
182   return result;
183 }
184
185 static GstFlowReturn
186 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
187 {
188   GstFlowReturn res;
189   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
190
191   res = gst_pad_push (internal, buffer);
192
193   return res;
194 }
195
196 static GstFlowReturn
197 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
198     GstBuffer ** buffer)
199 {
200   GstFlowReturn res;
201   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
202
203   res = gst_pad_pull_range (internal, offset, size, buffer);
204
205   return res;
206 }
207
208 static gboolean
209 gst_proxy_pad_do_checkgetrange (GstPad * pad)
210 {
211   gboolean result;
212   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
213
214   result = gst_pad_check_pull_range (internal);
215
216   return result;
217 }
218
219 static GstCaps *
220 gst_proxy_pad_do_getcaps (GstPad * pad)
221 {
222   GstPad *target = gst_proxy_pad_get_target (pad);
223   GstCaps *res;
224   GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
225
226   if (target) {
227     /* if we have a real target, proxy the call */
228     res = gst_pad_get_caps (target);
229     gst_object_unref (target);
230
231     GST_DEBUG_OBJECT (pad, "get caps of target: %" GST_PTR_FORMAT, res);
232
233     /* filter against the template */
234     if (templ && res) {
235       GstCaps *filt, *tmp;
236
237       filt = GST_PAD_TEMPLATE_CAPS (templ);
238       if (filt) {
239         tmp = gst_caps_intersect (filt, res);
240         gst_caps_unref (res);
241         res = tmp;
242         GST_DEBUG_OBJECT (pad,
243             "filtered against template gives %" GST_PTR_FORMAT, res);
244       }
245     }
246   } else {
247     /* else, if we have a template, use its caps. */
248     if (templ) {
249       res = GST_PAD_TEMPLATE_CAPS (templ);
250       GST_DEBUG_OBJECT (pad,
251           "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
252           res);
253       res = gst_caps_ref (res);
254       goto done;
255     }
256
257     /* last resort, any caps */
258     GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
259     res = gst_caps_new_any ();
260   }
261
262 done:
263   return res;
264 }
265
266 static gboolean
267 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
268 {
269   GstPad *target = gst_proxy_pad_get_target (pad);
270   gboolean res;
271
272   if (target) {
273     res = gst_pad_accept_caps (target, caps);
274     gst_object_unref (target);
275   } else {
276     /* We don't have a target, we return TRUE and we assume that any future
277      * target will be able to deal with any configured caps. */
278     res = TRUE;
279   }
280
281   return res;
282 }
283
284 static void
285 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
286 {
287   GstPad *target = gst_proxy_pad_get_target (pad);
288
289   if (target) {
290     gst_pad_fixate_caps (target, caps);
291     gst_object_unref (target);
292   }
293 }
294
295 static gboolean
296 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
297 {
298   GstPad *target = gst_proxy_pad_get_target (pad);
299   gboolean res;
300
301   if (target) {
302     res = gst_pad_set_caps (target, caps);
303     gst_object_unref (target);
304   } else {
305     /* We don't have any target, but we shouldn't return FALSE since this
306      * would stop the actual push of a buffer (which might trigger a pad block
307      * or probe, or properly return GST_FLOW_NOT_LINKED.
308      */
309     res = TRUE;
310   }
311   return res;
312 }
313
314 static gboolean
315 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
316 {
317   GstPad *oldtarget;
318
319   if (target) {
320     GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
321
322     if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
323       goto wrong_direction;
324   } else
325     GST_LOG_OBJECT (pad, "clearing target");
326
327   /* clear old target */
328   if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
329     gst_object_unref (oldtarget);
330   }
331   /* set and ref new target if any */
332   if (target)
333     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
334   else
335     GST_PROXY_PAD_TARGET (pad) = NULL;
336
337   return TRUE;
338
339   /* ERRORS */
340 wrong_direction:
341   {
342     GST_ERROR_OBJECT (pad,
343         "target pad doesn't have the same direction as ourself");
344     return FALSE;
345   }
346 }
347
348 static gboolean
349 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
350 {
351   gboolean result;
352
353   GST_PROXY_LOCK (pad);
354   result = gst_proxy_pad_set_target_unlocked (pad, target);
355   GST_PROXY_UNLOCK (pad);
356
357   return result;
358 }
359
360 static GstPad *
361 gst_proxy_pad_get_target (GstPad * pad)
362 {
363   GstPad *target;
364
365   GST_PROXY_LOCK (pad);
366   target = GST_PROXY_PAD_TARGET (pad);
367   if (target)
368     gst_object_ref (target);
369   GST_PROXY_UNLOCK (pad);
370
371   return target;
372 }
373
374 static void
375 gst_proxy_pad_dispose (GObject * object)
376 {
377   GstPad *pad = GST_PAD (object);
378   GstPad **target_p;
379
380   GST_PROXY_LOCK (pad);
381   /* remove and unref the target */
382   target_p = &GST_PROXY_PAD_TARGET (pad);
383   gst_object_replace ((GstObject **) target_p, NULL);
384   /* The internal is only cleared by GstGhostPad::dispose, since it is the 
385    * parent of non-ghost GstProxyPad and owns the refcount on the internal.
386    */
387   GST_PROXY_UNLOCK (pad);
388
389   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
390 }
391
392 static void
393 gst_proxy_pad_finalize (GObject * object)
394 {
395   GstProxyPad *pad = GST_PROXY_PAD (object);
396
397   g_mutex_free (pad->proxy_lock);
398   pad->proxy_lock = NULL;
399
400   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
401 }
402
403 static void
404 gst_proxy_pad_init (GstProxyPad * ppad)
405 {
406   GstPad *pad = (GstPad *) ppad;
407
408   ppad->proxy_lock = g_mutex_new ();
409
410   gst_pad_set_query_type_function (pad,
411       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
412   gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
413   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
414   gst_pad_set_internal_link_function (pad,
415       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
416
417   gst_pad_set_getcaps_function (pad,
418       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
419   gst_pad_set_acceptcaps_function (pad,
420       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
421   gst_pad_set_fixatecaps_function (pad,
422       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
423   gst_pad_set_setcaps_function (pad,
424       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
425 }
426
427 #ifndef GST_DISABLE_LOADSAVE
428 /**
429  * gst_proxy_pad_save_thyself:
430  * @pad: a ghost #GstPad to save.
431  * @parent: the parent #xmlNodePtr to save the description in.
432  *
433  * Saves the ghost pad into an xml representation.
434  *
435  * Returns: the #xmlNodePtr representation of the pad.
436  */
437 static xmlNodePtr
438 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
439 {
440   xmlNodePtr self;
441
442   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
443
444   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
445   xmlNewChild (self, NULL, (xmlChar *) "name",
446       (xmlChar *) GST_OBJECT_NAME (object));
447   xmlNewChild (self, NULL, (xmlChar *) "parent",
448       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
449
450   /* FIXME FIXME FIXME! */
451
452   return self;
453 }
454 #endif /* GST_DISABLE_LOADSAVE */
455
456
457 /***********************************************************************
458  * Ghost pads, implemented as a pair of proxy pads (sort of)
459  */
460
461
462 struct _GstGhostPad
463 {
464   GstProxyPad pad;
465
466   /* with PROXY_LOCK */
467   gulong notify_id;
468
469   /*< private > */
470   gpointer _gst_reserved[GST_PADDING];
471 };
472
473 struct _GstGhostPadClass
474 {
475   GstProxyPadClass parent_class;
476
477   /*< private > */
478   gpointer _gst_reserved[GST_PADDING];
479 };
480
481
482 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
483
484 static void gst_ghost_pad_dispose (GObject * object);
485
486 static void
487 gst_ghost_pad_class_init (GstGhostPadClass * klass)
488 {
489   GObjectClass *gobject_class = (GObjectClass *) klass;
490
491   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
492 }
493
494 /* see gstghostpad design docs */
495 static gboolean
496 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
497 {
498   gboolean ret;
499   GstPad *other;
500
501   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
502       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
503
504   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
505    * will be activated later (or already in case of a ghost sinkpad). */
506   other = GST_PROXY_PAD_INTERNAL (pad);
507   ret = gst_pad_activate_push (other, active);
508
509   return ret;
510 }
511
512 static gboolean
513 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
514 {
515   gboolean ret;
516   GstPad *other;
517
518   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
519       GST_DEBUG_PAD_NAME (pad));
520
521   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
522     /* we are activated in pull mode by our peer element, which is a sinkpad
523      * that wants to operate in pull mode. This activation has to propagate
524      * upstream throught the pipeline. We call the internal activation function,
525      * which will trigger gst_ghost_pad_do_activate_pull, which propagates even
526      * further upstream */
527     GST_LOG_OBJECT (pad, "pad is src, activate internal");
528     other = GST_PROXY_PAD_INTERNAL (pad);
529     ret = gst_pad_activate_pull (other, active);
530   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
531     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
532      * since we hold a pointer to the upstream peer. */
533     GST_LOG_OBJECT (pad, "activating peer");
534     ret = gst_pad_activate_pull (other, active);
535     gst_object_unref (other);
536   } else {
537     /* this is failure, we can't activate pull if there is no peer */
538     GST_LOG_OBJECT (pad, "not src and no peer, failing");
539     ret = FALSE;
540   }
541
542   return ret;
543 }
544
545 static gboolean
546 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
547 {
548   gboolean ret;
549   GstPad *other;
550
551   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
552       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
553
554   /* just activate the internal pad */
555   other = GST_PROXY_PAD_INTERNAL (pad);
556   ret = gst_pad_activate_push (other, active);
557
558   return ret;
559 }
560
561 static gboolean
562 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
563 {
564   gboolean ret;
565   GstPad *other;
566
567   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
568       GST_DEBUG_PAD_NAME (pad));
569
570   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
571     /* the ghostpad is SRC and activated in pull mode by its peer, call the
572      * activation function of the internal pad to propagate the activation
573      * upstream */
574     GST_LOG_OBJECT (pad, "pad is src, activate internal");
575     other = GST_PROXY_PAD_INTERNAL (pad);
576     ret = gst_pad_activate_pull (other, active);
577   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
578     /* We are SINK and activated by the internal pad, propagate activation
579      * upstream because we hold a ref to the upstream peer */
580     GST_LOG_OBJECT (pad, "activating peer");
581     ret = gst_pad_activate_pull (other, active);
582     gst_object_unref (other);
583   } else {
584     /* no peer, we fail */
585     GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
586     ret = FALSE;
587   }
588
589   return ret;
590 }
591
592 static GstPadLinkReturn
593 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
594 {
595   GstPadLinkReturn ret;
596   GstPad *internal;
597
598   GST_DEBUG_OBJECT (pad, "linking ghostpad");
599
600   internal = GST_PROXY_PAD_INTERNAL (pad);
601   if (!gst_proxy_pad_set_target (internal, peer))
602     goto target_failed;
603
604   ret = GST_PAD_LINK_OK;
605   /* if we are a source pad, we should call the peer link function
606    * if the peer has one, see design docs. */
607   if (GST_PAD_IS_SRC (pad)) {
608     if (GST_PAD_LINKFUNC (peer)) {
609       ret = GST_PAD_LINKFUNC (peer) (peer, pad);
610       if (ret != GST_PAD_LINK_OK)
611         goto link_failed;
612     }
613   }
614   return ret;
615
616   /* ERRORS */
617 target_failed:
618   {
619     GST_DEBUG_OBJECT (pad, "setting target failed");
620     return GST_PAD_LINK_REFUSED;
621   }
622 link_failed:
623   {
624     GST_DEBUG_OBJECT (pad, "linking failed");
625     /* clear target again */
626     gst_proxy_pad_set_target (internal, NULL);
627     return ret;
628   }
629 }
630
631 static void
632 gst_ghost_pad_do_unlink (GstPad * pad)
633 {
634   GstPad *target;
635   GstPad *internal;
636
637   target = gst_proxy_pad_get_target (pad);
638   internal = GST_PROXY_PAD_INTERNAL (pad);
639
640   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
641
642   /* The target of the internal pad is no longer valid */
643   gst_proxy_pad_set_target (internal, NULL);
644
645   if (target) {
646     if (GST_PAD_UNLINKFUNC (target))
647       GST_PAD_UNLINKFUNC (target) (target);
648
649     gst_object_unref (target);
650   }
651 }
652
653 static void
654 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
655 {
656   GstCaps *caps;
657
658   g_object_get (internal, "caps", &caps, NULL);
659
660   GST_OBJECT_LOCK (pad);
661   gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
662   GST_OBJECT_UNLOCK (pad);
663
664   g_object_notify (G_OBJECT (pad), "caps");
665   if (caps)
666     gst_caps_unref (caps);
667 }
668
669 static void
670 gst_ghost_pad_init (GstGhostPad * pad)
671 {
672   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
673       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
674   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
675       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
676 }
677
678 static void
679 gst_ghost_pad_dispose (GObject * object)
680 {
681   GstPad *pad;
682   GstPad *internal;
683   GstPad *intpeer;
684
685   pad = GST_PAD (object);
686
687   GST_DEBUG_OBJECT (pad, "dispose");
688
689   GST_PROXY_LOCK (pad);
690   internal = GST_PROXY_PAD_INTERNAL (pad);
691
692   gst_pad_set_activatepull_function (internal, NULL);
693   gst_pad_set_activatepush_function (internal, NULL);
694
695   g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id);
696
697   intpeer = gst_pad_get_peer (internal);
698   if (intpeer) {
699     if (GST_PAD_IS_SRC (internal))
700       gst_pad_unlink (internal, intpeer);
701     else
702       gst_pad_unlink (intpeer, internal);
703
704     gst_object_unref (intpeer);
705   }
706
707   GST_PROXY_PAD_INTERNAL (internal) = NULL;
708
709   /* disposes of the internal pad, since the ghostpad is the only possible object
710    * that has a refcount on the internal pad. */
711   gst_object_unparent (GST_OBJECT_CAST (internal));
712
713   GST_PROXY_UNLOCK (pad);
714
715   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
716 }
717
718 static GstPad *
719 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
720     GstPadTemplate * templ)
721 {
722   GstPad *ret;
723   GstPad *internal;
724   GstPadDirection otherdir;
725
726   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
727
728   /* OBJECT CREATION */
729   if (templ) {
730     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
731         "direction", dir, "template", templ, NULL);
732   } else {
733     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
734         "direction", dir, NULL);
735   }
736
737   /* Set directional padfunctions for ghostpad */
738   if (dir == GST_PAD_SINK) {
739     gst_pad_set_bufferalloc_function (ret,
740         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
741     gst_pad_set_chain_function (ret,
742         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
743   } else {
744     gst_pad_set_getrange_function (ret,
745         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
746     gst_pad_set_checkgetrange_function (ret,
747         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
748   }
749
750   /* link/unlink functions */
751   gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
752   gst_pad_set_unlink_function (ret,
753       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
754
755
756   /* INTERNAL PAD, it always exists and is child of the ghostpad */
757   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
758   if (templ) {
759     internal =
760         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
761         "direction", otherdir, "template", templ, NULL);
762   } else {
763     internal =
764         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
765         "direction", otherdir, NULL);
766   }
767   GST_PAD_UNSET_FLUSHING (internal);
768
769   /* Set directional padfunctions for internal pad */
770   if (dir == GST_PAD_SRC) {
771     gst_pad_set_bufferalloc_function (internal,
772         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
773     gst_pad_set_chain_function (internal,
774         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
775   } else {
776     gst_pad_set_getrange_function (internal,
777         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
778     gst_pad_set_checkgetrange_function (internal,
779         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
780   }
781
782   GST_PROXY_LOCK (ret);
783
784   /* now make the ghostpad a parent of the internal pad */
785   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
786           GST_OBJECT_CAST (ret)))
787     goto parent_failed;
788
789   /* The ghostpad is the parent of the internal pad and is the only object that
790    * can have a refcount on the internal pad.
791    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
792    * a refcount of 1.
793    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
794    * it's refcount on the internal pad in the dispose method by un-parenting it.
795    * This is why we don't take extra refcounts in the assignments below
796    */
797   GST_PROXY_PAD_INTERNAL (ret) = internal;
798   GST_PROXY_PAD_INTERNAL (internal) = ret;
799
800   /* could be more general here, iterating over all writable properties...
801    * taking the short road for now tho */
802   GST_GHOST_PAD_CAST (ret)->notify_id =
803       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
804       ret);
805
806   /* call function to init values of the pad caps */
807   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (ret));
808
809   /* special activation functions for the internal pad */
810   gst_pad_set_activatepull_function (internal,
811       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
812   gst_pad_set_activatepush_function (internal,
813       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
814
815   GST_PROXY_UNLOCK (ret);
816
817   return ret;
818
819   /* ERRORS */
820 parent_failed:
821   {
822     GST_WARNING_OBJECT (ret, "Could not set internal pad %s:%s",
823         GST_DEBUG_PAD_NAME (internal));
824     g_critical ("Could not set internal pad %s:%s",
825         GST_DEBUG_PAD_NAME (internal));
826     GST_PROXY_UNLOCK (ret);
827     gst_object_unref (ret);
828     gst_object_unref (internal);
829     return NULL;
830   }
831 }
832
833 /**
834  * gst_ghost_pad_new_no_target:
835  * @name: the name of the new pad, or NULL to assign a default name.
836  * @dir: the direction of the ghostpad
837  *
838  * Create a new ghostpad without a target with the given direction.
839  * A target can be set on the ghostpad later with the
840  * gst_ghost_pad_set_target() function.
841  *
842  * The created ghostpad will not have a padtemplate.
843  *
844  * Returns: a new #GstPad, or NULL in case of an error.
845  */
846 GstPad *
847 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
848 {
849   GstPad *ret;
850
851   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
852
853   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
854
855   ret = gst_ghost_pad_new_full (name, dir, NULL);
856
857   return ret;
858 }
859
860 /**
861  * gst_ghost_pad_new:
862  * @name: the name of the new pad, or NULL to assign a default name.
863  * @target: the pad to ghost.
864  *
865  * Create a new ghostpad with @target as the target. The direction will be taken
866  * from the target pad. @target must be unlinked.
867  *
868  * Will ref the target.
869  *
870  * Returns: a new #GstPad, or NULL in case of an error.
871  */
872 GstPad *
873 gst_ghost_pad_new (const gchar * name, GstPad * target)
874 {
875   GstPad *ret;
876
877   g_return_val_if_fail (GST_IS_PAD (target), NULL);
878   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
879
880   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
881       GST_DEBUG_PAD_NAME (target));
882
883   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
884     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
885       goto set_target_failed;
886
887   return ret;
888
889   /* ERRORS */
890 set_target_failed:
891   {
892     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
893         GST_DEBUG_PAD_NAME (target));
894     gst_object_unref (ret);
895     return NULL;
896   }
897 }
898
899 /**
900  * gst_ghost_pad_new_from_template:
901  * @name: the name of the new pad, or NULL to assign a default name.
902  * @target: the pad to ghost.
903  * @templ: the #GstPadTemplate to use on the ghostpad.
904  *
905  * Create a new ghostpad with @target as the target. The direction will be taken
906  * from the target pad. The template used on the ghostpad will be @template.
907  *
908  * Will ref the target.
909  *
910  * Returns: a new #GstPad, or NULL in case of an error.
911  *
912  * Since: 0.10.10
913  */
914
915 GstPad *
916 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
917     GstPadTemplate * templ)
918 {
919   GstPad *ret;
920
921   g_return_val_if_fail (GST_IS_PAD (target), NULL);
922   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
923   g_return_val_if_fail (templ != NULL, NULL);
924   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
925       GST_PAD_DIRECTION (target), NULL);
926
927   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
928       GST_DEBUG_PAD_NAME (target), templ);
929
930   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
931     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
932       goto set_target_failed;
933
934   return ret;
935
936   /* ERRORS */
937 set_target_failed:
938   {
939     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
940         GST_DEBUG_PAD_NAME (target));
941     gst_object_unref (ret);
942     return NULL;
943   }
944 }
945
946 /**
947  * gst_ghost_pad_new_no_target_from_template:
948  * @name: the name of the new pad, or NULL to assign a default name.
949  * @templ: the #GstPadTemplate to create the ghostpad from.
950  *
951  * Create a new ghostpad based on @templ, without setting a target. The
952  * direction will be taken from the @templ.
953  *
954  * Returns: a new #GstPad, or NULL in case of an error.
955  *
956  * Since: 0.10.10
957  */
958 GstPad *
959 gst_ghost_pad_new_no_target_from_template (const gchar * name,
960     GstPadTemplate * templ)
961 {
962   GstPad *ret;
963
964   g_return_val_if_fail (templ != NULL, NULL);
965
966   ret =
967       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
968
969   return ret;
970 }
971
972 /**
973  * gst_ghost_pad_get_target:
974  * @gpad: the #GstGhostpad
975  *
976  * Get the target pad of #gpad. Unref target pad after usage.
977  *
978  * Returns: the target #GstPad, can be NULL if the ghostpad
979  * has no target set. Unref target pad after usage.
980  */
981 GstPad *
982 gst_ghost_pad_get_target (GstGhostPad * gpad)
983 {
984   GstPad *ret;
985
986   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
987
988   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
989
990   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
991
992   return ret;
993 }
994
995 /**
996  * gst_ghost_pad_set_target:
997  * @gpad: the #GstGhostpad
998  * @newtarget: the new pad target
999  *
1000  * Set the new target of the ghostpad @gpad. Any existing target
1001  * is unlinked and links to the new target are established.
1002  *
1003  * Returns: TRUE if the new target could be set. This function can return FALSE
1004  * when the internal pads could not be linked.
1005  */
1006 gboolean
1007 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1008 {
1009   GstPad *internal;
1010   GstPad *oldtarget;
1011   gboolean result;
1012   GstPadLinkReturn lret;
1013
1014   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1015
1016   GST_PROXY_LOCK (gpad);
1017   internal = GST_PROXY_PAD_INTERNAL (gpad);
1018
1019   GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1020
1021   /* clear old target */
1022   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1023     /* if we have an internal pad, unlink */
1024     if (internal) {
1025       if (GST_PAD_IS_SRC (internal))
1026         gst_pad_unlink (internal, oldtarget);
1027       else
1028         gst_pad_unlink (oldtarget, internal);
1029     }
1030   }
1031
1032   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1033
1034   if (result && newtarget) {
1035     /* and link to internal pad */
1036     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
1037
1038     if (GST_PAD_IS_SRC (internal))
1039       lret = gst_pad_link (internal, newtarget);
1040     else
1041       lret = gst_pad_link (newtarget, internal);
1042
1043     if (lret != GST_PAD_LINK_OK)
1044       goto link_failed;
1045   }
1046   GST_PROXY_UNLOCK (gpad);
1047
1048   return result;
1049
1050   /* ERRORS */
1051 link_failed:
1052   {
1053     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
1054         lret);
1055     /* and unset target again */
1056     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
1057     GST_PROXY_UNLOCK (gpad);
1058     return FALSE;
1059   }
1060 }