do not call the unlink function on the target pad when the ghostpad
[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 #include "gst.h"
52
53 #define GST_CAT_DEFAULT GST_CAT_PADS
54
55 #define GST_PROXY_PAD_CAST(obj)         ((GstProxyPad *)obj)
56 #define GST_PROXY_PAD_PRIVATE(obj)      (GST_PROXY_PAD_CAST (obj)->priv)
57 #define GST_PROXY_PAD_TARGET(pad)       (GST_PROXY_PAD_PRIVATE (pad)->target)
58 #define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD_PRIVATE (pad)->internal)
59 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_PRIVATE (pad)->proxy_lock)
60 #define GST_PROXY_LOCK(pad)     (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
61 #define GST_PROXY_UNLOCK(pad)   (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
62
63 struct _GstProxyPadPrivate
64 {
65   /* with PROXY_LOCK */
66   GMutex *proxy_lock;
67   GstPad *target;
68   GstPad *internal;
69 };
70
71 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
72
73 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
74
75 static void gst_proxy_pad_dispose (GObject * object);
76 static void gst_proxy_pad_finalize (GObject * object);
77
78 #ifndef GST_DISABLE_LOADSAVE
79 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
80     xmlNodePtr parent);
81 #endif
82
83 static void on_src_target_notify (GstPad * target,
84     GParamSpec * unused, GstGhostPad * pad);
85
86
87 static void
88 gst_proxy_pad_class_init (GstProxyPadClass * klass)
89 {
90   GObjectClass *gobject_class = (GObjectClass *) klass;
91
92   g_type_class_add_private (klass, sizeof (GstProxyPadPrivate));
93
94   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
95   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
96
97 #ifndef GST_DISABLE_LOADSAVE
98   {
99     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
100
101     gstobject_class->save_thyself =
102         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
103   }
104 #endif
105 }
106
107 static const GstQueryType *
108 gst_proxy_pad_do_query_type (GstPad * pad)
109 {
110   GstPad *target = gst_proxy_pad_get_target (pad);
111   const GstQueryType *res = NULL;
112
113   if (target) {
114     res = gst_pad_get_query_types (target);
115     gst_object_unref (target);
116   }
117   return res;
118 }
119
120 static gboolean
121 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
122 {
123   gboolean res = FALSE;
124   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
125
126   res = gst_pad_push_event (internal, event);
127
128   return res;
129 }
130
131 static gboolean
132 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
133 {
134   gboolean res = FALSE;
135   GstPad *target = gst_proxy_pad_get_target (pad);
136
137   if (target) {
138     res = gst_pad_query (target, query);
139     gst_object_unref (target);
140   }
141
142   return res;
143 }
144
145 static GList *
146 gst_proxy_pad_do_internal_link (GstPad * pad)
147 {
148   GList *res = NULL;
149   GstPad *target = gst_proxy_pad_get_target (pad);
150
151   if (target) {
152     res = gst_pad_get_internal_links (target);
153     gst_object_unref (target);
154   }
155
156   return res;
157 }
158
159 static GstIterator *
160 gst_proxy_pad_do_iterate_internal_links (GstPad * pad)
161 {
162   GstIterator *res = NULL;
163   GstPad *target = gst_proxy_pad_get_target (pad);
164
165   if (target) {
166     res = gst_pad_iterate_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 (GST_PROXY_GET_LOCK (pad));
398   GST_PROXY_GET_LOCK (pad) = 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   GST_PROXY_PAD_PRIVATE (ppad) = G_TYPE_INSTANCE_GET_PRIVATE (ppad,
409       GST_TYPE_PROXY_PAD, GstProxyPadPrivate);
410   GST_PROXY_GET_LOCK (pad) = g_mutex_new ();
411
412   gst_pad_set_query_type_function (pad,
413       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
414   gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
415   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
416   gst_pad_set_internal_link_function (pad,
417       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
418   gst_pad_set_iterate_internal_links_function (pad,
419       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_iterate_internal_links));
420
421   gst_pad_set_getcaps_function (pad,
422       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
423   gst_pad_set_acceptcaps_function (pad,
424       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
425   gst_pad_set_fixatecaps_function (pad,
426       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
427   gst_pad_set_setcaps_function (pad,
428       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
429 }
430
431 #ifndef GST_DISABLE_LOADSAVE
432 /**
433  * gst_proxy_pad_save_thyself:
434  * @pad: a ghost #GstPad to save.
435  * @parent: the parent #xmlNodePtr to save the description in.
436  *
437  * Saves the ghost pad into an xml representation.
438  *
439  * Returns: the #xmlNodePtr representation of the pad.
440  */
441 static xmlNodePtr
442 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
443 {
444   xmlNodePtr self;
445   GstProxyPad *proxypad;
446   GstPad *pad;
447   GstPad *peer;
448
449   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
450
451   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
452   xmlNewChild (self, NULL, (xmlChar *) "name",
453       (xmlChar *) GST_OBJECT_NAME (object));
454   xmlNewChild (self, NULL, (xmlChar *) "parent",
455       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
456
457   proxypad = GST_PROXY_PAD_CAST (object);
458   pad = GST_PAD_CAST (proxypad);
459   peer = GST_PAD_CAST (pad->peer);
460
461   if (GST_IS_PAD (pad)) {
462     if (GST_PAD_IS_SRC (pad))
463       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source");
464     else if (GST_PAD_IS_SINK (pad))
465       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink");
466     else
467       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
468   } else {
469     xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
470   }
471   if (GST_IS_PAD (peer)) {
472     gchar *content = g_strdup_printf ("%s.%s",
473         GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
474
475     xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content);
476     g_free (content);
477   } else {
478     xmlNewChild (self, NULL, (xmlChar *) "peer", NULL);
479   }
480
481   return self;
482 }
483 #endif /* GST_DISABLE_LOADSAVE */
484
485
486 /***********************************************************************
487  * Ghost pads, implemented as a pair of proxy pads (sort of)
488  */
489
490
491 #define GST_GHOST_PAD_PRIVATE(obj)      (GST_GHOST_PAD_CAST (obj)->priv)
492
493 struct _GstGhostPadPrivate
494 {
495   /* with PROXY_LOCK */
496   gulong notify_id;
497
498   gboolean constructed;
499 };
500
501 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
502
503 static void gst_ghost_pad_dispose (GObject * object);
504
505 static void
506 gst_ghost_pad_class_init (GstGhostPadClass * klass)
507 {
508   GObjectClass *gobject_class = (GObjectClass *) klass;
509
510   g_type_class_add_private (klass, sizeof (GstGhostPadPrivate));
511
512   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
513 }
514
515 /* see gstghostpad design docs */
516 static gboolean
517 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
518 {
519   gboolean ret;
520   GstPad *other;
521
522   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
523       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
524
525   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
526    * will be activated later (or already in case of a ghost sinkpad). */
527   other = GST_PROXY_PAD_INTERNAL (pad);
528   ret = gst_pad_activate_push (other, active);
529
530   return ret;
531 }
532
533 static gboolean
534 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
535 {
536   gboolean ret;
537   GstPad *other;
538
539   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
540       GST_DEBUG_PAD_NAME (pad));
541
542   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
543     /* we are activated in pull mode by our peer element, which is a sinkpad
544      * that wants to operate in pull mode. This activation has to propagate
545      * upstream throught the pipeline. We call the internal activation function,
546      * which will trigger gst_ghost_pad_do_activate_pull, which propagates even
547      * further upstream */
548     GST_LOG_OBJECT (pad, "pad is src, activate internal");
549     other = GST_PROXY_PAD_INTERNAL (pad);
550     ret = gst_pad_activate_pull (other, active);
551   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
552     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
553      * since we hold a pointer to the upstream peer. */
554     GST_LOG_OBJECT (pad, "activating peer");
555     ret = gst_pad_activate_pull (other, active);
556     gst_object_unref (other);
557   } else {
558     /* this is failure, we can't activate pull if there is no peer */
559     GST_LOG_OBJECT (pad, "not src and no peer, failing");
560     ret = FALSE;
561   }
562
563   return ret;
564 }
565
566 static gboolean
567 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
568 {
569   gboolean ret;
570   GstPad *other;
571
572   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
573       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
574
575   /* just activate the internal pad */
576   other = GST_PROXY_PAD_INTERNAL (pad);
577   ret = gst_pad_activate_push (other, active);
578
579   return ret;
580 }
581
582 static gboolean
583 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
584 {
585   gboolean ret;
586   GstPad *other;
587
588   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
589       GST_DEBUG_PAD_NAME (pad));
590
591   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
592     /* the ghostpad is SRC and activated in pull mode by its peer, call the
593      * activation function of the internal pad to propagate the activation
594      * upstream */
595     GST_LOG_OBJECT (pad, "pad is src, activate internal");
596     other = GST_PROXY_PAD_INTERNAL (pad);
597     ret = gst_pad_activate_pull (other, active);
598   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
599     /* We are SINK and activated by the internal pad, propagate activation
600      * upstream because we hold a ref to the upstream peer */
601     GST_LOG_OBJECT (pad, "activating peer");
602     ret = gst_pad_activate_pull (other, active);
603     gst_object_unref (other);
604   } else {
605     /* no peer, we fail */
606     GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
607     ret = FALSE;
608   }
609
610   return ret;
611 }
612
613 static GstPadLinkReturn
614 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
615 {
616   GstPadLinkReturn ret;
617   GstPad *internal;
618
619   GST_DEBUG_OBJECT (pad, "linking ghostpad");
620
621   internal = GST_PROXY_PAD_INTERNAL (pad);
622   if (!gst_proxy_pad_set_target (internal, peer))
623     goto target_failed;
624
625   ret = GST_PAD_LINK_OK;
626   /* if we are a source pad, we should call the peer link function
627    * if the peer has one, see design docs. */
628   if (GST_PAD_IS_SRC (pad)) {
629     if (GST_PAD_LINKFUNC (peer)) {
630       ret = GST_PAD_LINKFUNC (peer) (peer, pad);
631       if (ret != GST_PAD_LINK_OK)
632         goto link_failed;
633     }
634   }
635   return ret;
636
637   /* ERRORS */
638 target_failed:
639   {
640     GST_DEBUG_OBJECT (pad, "setting target failed");
641     return GST_PAD_LINK_REFUSED;
642   }
643 link_failed:
644   {
645     GST_DEBUG_OBJECT (pad, "linking failed");
646     /* clear target again */
647     gst_proxy_pad_set_target (internal, NULL);
648     return ret;
649   }
650 }
651
652 static void
653 gst_ghost_pad_do_unlink (GstPad * pad)
654 {
655   GstPad *internal;
656
657   internal = GST_PROXY_PAD_INTERNAL (pad);
658
659   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
660
661   /* The target of the internal pad is no longer valid */
662   gst_proxy_pad_set_target (internal, NULL);
663 }
664
665 static void
666 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
667 {
668   GstCaps *caps;
669
670   g_object_get (internal, "caps", &caps, NULL);
671
672   GST_OBJECT_LOCK (pad);
673   gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
674   GST_OBJECT_UNLOCK (pad);
675
676   g_object_notify (G_OBJECT (pad), "caps");
677   if (caps)
678     gst_caps_unref (caps);
679 }
680
681 static void
682 on_src_target_notify (GstPad * target, GParamSpec * unused, GstGhostPad * pad)
683 {
684   GstCaps *caps;
685
686   g_object_get (target, "caps", &caps, NULL);
687
688   GST_OBJECT_LOCK (pad);
689   gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
690   GST_OBJECT_UNLOCK (pad);
691
692   g_object_notify (G_OBJECT (pad), "caps");
693   if (caps)
694     gst_caps_unref (caps);
695
696 }
697
698 static gboolean
699 gst_ghost_pad_do_setcaps (GstPad * pad, GstCaps * caps)
700 {
701   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
702     return TRUE;
703
704   return gst_proxy_pad_do_setcaps (pad, caps);
705 }
706
707 static void
708 gst_ghost_pad_init (GstGhostPad * pad)
709 {
710   GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
711       GST_TYPE_GHOST_PAD, GstGhostPadPrivate);
712
713   gst_pad_set_setcaps_function (GST_PAD_CAST (pad),
714       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_setcaps));
715   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
716       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
717   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
718       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
719 }
720
721 static void
722 gst_ghost_pad_dispose (GObject * object)
723 {
724   GstPad *pad;
725   GstPad *internal;
726   GstPad *peer;
727
728   pad = GST_PAD (object);
729
730   GST_DEBUG_OBJECT (pad, "dispose");
731
732   gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
733
734   /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
735    * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */
736   peer = gst_pad_get_peer (pad);
737   if (peer) {
738     if (GST_PAD_IS_SRC (pad))
739       gst_pad_unlink (pad, peer);
740     else
741       gst_pad_unlink (peer, pad);
742
743     gst_object_unref (peer);
744   }
745
746   GST_PROXY_LOCK (pad);
747   internal = GST_PROXY_PAD_INTERNAL (pad);
748
749   gst_pad_set_activatepull_function (internal, NULL);
750   gst_pad_set_activatepush_function (internal, NULL);
751
752   g_signal_handler_disconnect (internal,
753       GST_GHOST_PAD_PRIVATE (pad)->notify_id);
754
755   /* disposes of the internal pad, since the ghostpad is the only possible object
756    * that has a refcount on the internal pad. */
757   gst_object_unparent (GST_OBJECT_CAST (internal));
758   GST_PROXY_PAD_INTERNAL (pad) = NULL;
759
760   GST_PROXY_UNLOCK (pad);
761
762   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
763 }
764
765 /**
766  * gst_ghost_pad_construct:
767  * @gpad: the newly allocated ghost pad
768  *
769  * Finish initialization of a newly allocated ghost pad.
770  *
771  * This function is most useful in language bindings and when subclassing
772  * #GstGhostPad; plugin and application developers normally will not call this
773  * function. Call this function directly after a call to g_object_new
774  * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
775  *
776  * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
777  *
778  * Since: 0.10.22
779  */
780 gboolean
781 gst_ghost_pad_construct (GstGhostPad * gpad)
782 {
783   GstPadDirection dir, otherdir;
784   GstPadTemplate *templ;
785   GstPad *pad, *internal;
786
787   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
788   g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
789       FALSE);
790
791   g_object_get (gpad, "direction", &dir, "template", &templ, NULL);
792
793   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);
794
795   pad = GST_PAD (gpad);
796
797   /* Set directional padfunctions for ghostpad */
798   if (dir == GST_PAD_SINK) {
799     gst_pad_set_bufferalloc_function (pad,
800         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
801     gst_pad_set_chain_function (pad,
802         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
803   } else {
804     gst_pad_set_getrange_function (pad,
805         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
806     gst_pad_set_checkgetrange_function (pad,
807         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
808   }
809
810   /* link/unlink functions */
811   gst_pad_set_link_function (pad, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
812   gst_pad_set_unlink_function (pad,
813       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
814
815   /* INTERNAL PAD, it always exists and is child of the ghostpad */
816   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
817   if (templ) {
818     internal =
819         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
820         "direction", otherdir, "template", templ, NULL);
821     /* release ref obtained via g_object_get */
822     gst_object_unref (templ);
823   } else {
824     internal =
825         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
826         "direction", otherdir, NULL);
827   }
828   GST_PAD_UNSET_FLUSHING (internal);
829
830   /* Set directional padfunctions for internal pad */
831   if (dir == GST_PAD_SRC) {
832     gst_pad_set_bufferalloc_function (internal,
833         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
834     gst_pad_set_chain_function (internal,
835         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
836   } else {
837     gst_pad_set_getrange_function (internal,
838         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
839     gst_pad_set_checkgetrange_function (internal,
840         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
841   }
842
843   GST_PROXY_LOCK (pad);
844
845   /* now make the ghostpad a parent of the internal pad */
846   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
847           GST_OBJECT_CAST (pad)))
848     goto parent_failed;
849
850   /* The ghostpad is the parent of the internal pad and is the only object that
851    * can have a refcount on the internal pad.
852    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
853    * a refcount of 1.
854    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
855    * it's refcount on the internal pad in the dispose method by un-parenting it.
856    * This is why we don't take extra refcounts in the assignments below
857    */
858   GST_PROXY_PAD_INTERNAL (pad) = internal;
859   GST_PROXY_PAD_INTERNAL (internal) = pad;
860
861   /* could be more general here, iterating over all writable properties...
862    * taking the short road for now tho */
863   GST_GHOST_PAD_PRIVATE (pad)->notify_id =
864       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
865       pad);
866
867   /* call function to init values of the pad caps */
868   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (pad));
869
870   /* special activation functions for the internal pad */
871   gst_pad_set_activatepull_function (internal,
872       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
873   gst_pad_set_activatepush_function (internal,
874       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
875
876   GST_PROXY_UNLOCK (pad);
877
878   GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
879   return TRUE;
880
881   /* ERRORS */
882 parent_failed:
883   {
884     GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
885         GST_DEBUG_PAD_NAME (internal));
886     g_critical ("Could not set internal pad %s:%s",
887         GST_DEBUG_PAD_NAME (internal));
888     GST_PROXY_UNLOCK (pad);
889     gst_object_unref (internal);
890     return FALSE;
891   }
892 }
893
894 static GstPad *
895 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
896     GstPadTemplate * templ)
897 {
898   GstGhostPad *ret;
899
900   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
901
902   /* OBJECT CREATION */
903   if (templ) {
904     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
905         "direction", dir, "template", templ, NULL);
906   } else {
907     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
908         "direction", dir, NULL);
909   }
910
911   if (!gst_ghost_pad_construct (ret))
912     goto construct_failed;
913
914   return GST_PAD (ret);
915
916 construct_failed:
917   /* already logged */
918   gst_object_unref (ret);
919   return NULL;
920 }
921
922 /**
923  * gst_ghost_pad_new_no_target:
924  * @name: the name of the new pad, or NULL to assign a default name.
925  * @dir: the direction of the ghostpad
926  *
927  * Create a new ghostpad without a target with the given direction.
928  * A target can be set on the ghostpad later with the
929  * gst_ghost_pad_set_target() function.
930  *
931  * The created ghostpad will not have a padtemplate.
932  *
933  * Returns: a new #GstPad, or NULL in case of an error.
934  */
935 GstPad *
936 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
937 {
938   GstPad *ret;
939
940   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
941
942   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
943
944   ret = gst_ghost_pad_new_full (name, dir, NULL);
945
946   return ret;
947 }
948
949 /**
950  * gst_ghost_pad_new:
951  * @name: the name of the new pad, or NULL to assign a default name.
952  * @target: the pad to ghost.
953  *
954  * Create a new ghostpad with @target as the target. The direction will be taken
955  * from the target pad. @target must be unlinked.
956  *
957  * Will ref the target.
958  *
959  * Returns: a new #GstPad, or NULL in case of an error.
960  */
961 GstPad *
962 gst_ghost_pad_new (const gchar * name, GstPad * target)
963 {
964   GstPad *ret;
965
966   g_return_val_if_fail (GST_IS_PAD (target), NULL);
967   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
968
969   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
970       GST_DEBUG_PAD_NAME (target));
971
972   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
973     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
974       goto set_target_failed;
975
976   return ret;
977
978   /* ERRORS */
979 set_target_failed:
980   {
981     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
982         GST_DEBUG_PAD_NAME (target));
983     gst_object_unref (ret);
984     return NULL;
985   }
986 }
987
988 /**
989  * gst_ghost_pad_new_from_template:
990  * @name: the name of the new pad, or NULL to assign a default name.
991  * @target: the pad to ghost.
992  * @templ: the #GstPadTemplate to use on the ghostpad.
993  *
994  * Create a new ghostpad with @target as the target. The direction will be taken
995  * from the target pad. The template used on the ghostpad will be @template.
996  *
997  * Will ref the target.
998  *
999  * Returns: a new #GstPad, or NULL in case of an error.
1000  *
1001  * Since: 0.10.10
1002  */
1003
1004 GstPad *
1005 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
1006     GstPadTemplate * templ)
1007 {
1008   GstPad *ret;
1009
1010   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1011   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1012   g_return_val_if_fail (templ != NULL, NULL);
1013   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
1014       GST_PAD_DIRECTION (target), NULL);
1015
1016   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
1017       GST_DEBUG_PAD_NAME (target), templ);
1018
1019   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
1020     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1021       goto set_target_failed;
1022
1023   return ret;
1024
1025   /* ERRORS */
1026 set_target_failed:
1027   {
1028     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1029         GST_DEBUG_PAD_NAME (target));
1030     gst_object_unref (ret);
1031     return NULL;
1032   }
1033 }
1034
1035 /**
1036  * gst_ghost_pad_new_no_target_from_template:
1037  * @name: the name of the new pad, or NULL to assign a default name.
1038  * @templ: the #GstPadTemplate to create the ghostpad from.
1039  *
1040  * Create a new ghostpad based on @templ, without setting a target. The
1041  * direction will be taken from the @templ.
1042  *
1043  * Returns: a new #GstPad, or NULL in case of an error.
1044  *
1045  * Since: 0.10.10
1046  */
1047 GstPad *
1048 gst_ghost_pad_new_no_target_from_template (const gchar * name,
1049     GstPadTemplate * templ)
1050 {
1051   GstPad *ret;
1052
1053   g_return_val_if_fail (templ != NULL, NULL);
1054
1055   ret =
1056       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
1057
1058   return ret;
1059 }
1060
1061 /**
1062  * gst_ghost_pad_get_target:
1063  * @gpad: the #GstGhostpad
1064  *
1065  * Get the target pad of #gpad. Unref target pad after usage.
1066  *
1067  * Returns: the target #GstPad, can be NULL if the ghostpad
1068  * has no target set. Unref target pad after usage.
1069  */
1070 GstPad *
1071 gst_ghost_pad_get_target (GstGhostPad * gpad)
1072 {
1073   GstPad *ret;
1074
1075   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
1076
1077   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
1078
1079   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
1080
1081   return ret;
1082 }
1083
1084 /**
1085  * gst_ghost_pad_set_target:
1086  * @gpad: the #GstGhostpad
1087  * @newtarget: the new pad target
1088  *
1089  * Set the new target of the ghostpad @gpad. Any existing target
1090  * is unlinked and links to the new target are established. if @newtarget is
1091  * NULL the target will be cleared.
1092  *
1093  * Returns: TRUE if the new target could be set. This function can return FALSE
1094  * when the internal pads could not be linked.
1095  */
1096 gboolean
1097 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1098 {
1099   GstPad *internal;
1100   GstPad *oldtarget;
1101   gboolean result;
1102   GstPadLinkReturn lret;
1103
1104   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1105
1106   GST_PROXY_LOCK (gpad);
1107   internal = GST_PROXY_PAD_INTERNAL (gpad);
1108
1109   if (newtarget)
1110     GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1111   else
1112     GST_DEBUG_OBJECT (gpad, "clearing target");
1113
1114   /* clear old target */
1115   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1116     if (GST_PAD_IS_SRC (oldtarget)) {
1117       g_signal_handlers_disconnect_by_func (oldtarget,
1118           on_src_target_notify, gpad);
1119     }
1120
1121     /* if we have an internal pad, unlink */
1122     if (internal) {
1123       if (GST_PAD_IS_SRC (internal))
1124         gst_pad_unlink (internal, oldtarget);
1125       else
1126         gst_pad_unlink (oldtarget, internal);
1127     }
1128   }
1129
1130   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1131
1132   if (result && newtarget) {
1133     if (GST_PAD_IS_SRC (newtarget)) {
1134       g_signal_connect (newtarget, "notify::caps",
1135           G_CALLBACK (on_src_target_notify), gpad);
1136     }
1137
1138     /* and link to internal pad */
1139     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
1140
1141     if (GST_PAD_IS_SRC (internal))
1142       lret = gst_pad_link (internal, newtarget);
1143     else
1144       lret = gst_pad_link (newtarget, internal);
1145
1146     if (lret != GST_PAD_LINK_OK)
1147       goto link_failed;
1148   }
1149   GST_PROXY_UNLOCK (gpad);
1150
1151   return result;
1152
1153   /* ERRORS */
1154 link_failed:
1155   {
1156     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
1157         lret);
1158     /* and unset target again */
1159     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
1160     GST_PROXY_UNLOCK (gpad);
1161     return FALSE;
1162   }
1163 }