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