ghostpad: API: Expose gst_proxy_pad_get_internal()
[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 any
33  * other #GstElement. This is where GhostPads come into play. A GhostPad acts as
34  * a proxy for another pad. Thus the bin can have sink and source ghost-pads
35  * that 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_PAD_RETARGET(pad)     (GST_PROXY_PAD_PRIVATE (pad)->retarget)
60 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_PRIVATE (pad)->proxy_lock)
61 #define GST_PROXY_LOCK(pad)     (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
62 #define GST_PROXY_UNLOCK(pad)   (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
63
64 struct _GstProxyPadPrivate
65 {
66   /* with PROXY_LOCK */
67   GMutex *proxy_lock;
68   GstPad *target;
69   GstPad *internal;
70   gboolean retarget;
71 };
72
73 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
74
75 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
76
77 static void gst_proxy_pad_dispose (GObject * object);
78 static void gst_proxy_pad_finalize (GObject * object);
79
80 #if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
81 #ifdef GST_DISABLE_DEPRECATED
82 #include <libxml/parser.h>
83 #endif
84 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
85     xmlNodePtr parent);
86 #endif
87
88 static void on_src_target_notify (GstPad * target,
89     GParamSpec * unused, gpointer user_data);
90
91 static GParamSpec *pspec_caps = NULL;
92
93 static const GstQueryType *
94 gst_proxy_pad_do_query_type (GstPad * pad)
95 {
96   GstPad *target = gst_proxy_pad_get_target (pad);
97   const GstQueryType *res = NULL;
98
99   if (target) {
100     res = gst_pad_get_query_types (target);
101     gst_object_unref (target);
102   }
103   return res;
104 }
105
106 static gboolean
107 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
108 {
109   gboolean res = FALSE;
110   GstPad *internal =
111       GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad)));
112
113   if (internal) {
114     res = gst_pad_push_event (internal, event);
115     gst_object_unref (internal);
116   }
117
118   return res;
119 }
120
121 static gboolean
122 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
123 {
124   gboolean res = FALSE;
125   GstPad *target = gst_proxy_pad_get_target (pad);
126
127   if (target) {
128     res = gst_pad_query (target, query);
129     gst_object_unref (target);
130   }
131
132   return res;
133 }
134
135 static GstIterator *
136 gst_proxy_pad_do_iterate_internal_links (GstPad * pad)
137 {
138   GstIterator *res = NULL;
139   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
140
141   if (internal) {
142     res =
143         gst_iterator_new_single (GST_TYPE_PAD, internal,
144         (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
145   }
146
147   return res;
148 }
149
150 static GstFlowReturn
151 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
152     GstCaps * caps, GstBuffer ** buf)
153 {
154   GstFlowReturn result = GST_FLOW_WRONG_STATE;
155   GstPad *internal =
156       GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad)));
157
158   if (internal) {
159     result = gst_pad_alloc_buffer (internal, offset, size, caps, buf);
160     gst_object_unref (internal);
161   }
162
163   return result;
164 }
165
166 static GstFlowReturn
167 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
168 {
169   GstFlowReturn res;
170   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
171
172   res = gst_pad_push (internal, buffer);
173
174   return res;
175 }
176
177 static GstFlowReturn
178 gst_proxy_pad_do_chain_list (GstPad * pad, GstBufferList * list)
179 {
180   GstFlowReturn res;
181   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
182
183   res = gst_pad_push_list (internal, list);
184
185   return res;
186 }
187
188 static GstFlowReturn
189 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
190     GstBuffer ** buffer)
191 {
192   GstFlowReturn res;
193   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
194
195   res = gst_pad_pull_range (internal, offset, size, buffer);
196
197   return res;
198 }
199
200 static gboolean
201 gst_proxy_pad_do_checkgetrange (GstPad * pad)
202 {
203   gboolean result;
204   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
205
206   result = gst_pad_check_pull_range (internal);
207
208   return result;
209 }
210
211 static GstCaps *
212 gst_proxy_pad_do_getcaps (GstPad * pad)
213 {
214   GstPad *target = gst_proxy_pad_get_target (pad);
215   GstCaps *res;
216   GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
217
218   if (target) {
219     /* if we have a real target, proxy the call */
220     res = gst_pad_get_caps_reffed (target);
221
222     GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
223         GST_DEBUG_PAD_NAME (target), res);
224
225     gst_object_unref (target);
226
227     /* filter against the template */
228     if (templ && res) {
229       GstCaps *filt, *tmp;
230
231       filt = GST_PAD_TEMPLATE_CAPS (templ);
232       if (filt) {
233         tmp = gst_caps_intersect (filt, res);
234         gst_caps_unref (res);
235         res = tmp;
236         GST_DEBUG_OBJECT (pad,
237             "filtered against template gives %" GST_PTR_FORMAT, res);
238       }
239     }
240   } else {
241     /* else, if we have a template, use its caps. */
242     if (templ) {
243       res = GST_PAD_TEMPLATE_CAPS (templ);
244       GST_DEBUG_OBJECT (pad,
245           "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
246           res);
247       res = gst_caps_ref (res);
248       goto done;
249     }
250
251     /* last resort, any caps */
252     GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
253     res = gst_caps_new_any ();
254   }
255
256 done:
257   return res;
258 }
259
260 static gboolean
261 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
262 {
263   GstPad *target = gst_proxy_pad_get_target (pad);
264   gboolean res;
265
266   if (target) {
267     res = gst_pad_accept_caps (target, caps);
268     gst_object_unref (target);
269   } else {
270     /* We don't have a target, we return TRUE and we assume that any future
271      * target will be able to deal with any configured caps. */
272     res = TRUE;
273   }
274
275   return res;
276 }
277
278 static void
279 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
280 {
281   GstPad *target = gst_proxy_pad_get_target (pad);
282
283   if (target) {
284     gst_pad_fixate_caps (target, caps);
285     gst_object_unref (target);
286   }
287 }
288
289 static gboolean
290 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
291 {
292   GstPad *target = gst_proxy_pad_get_target (pad);
293   gboolean res;
294
295   if (target) {
296     res = gst_pad_set_caps (target, caps);
297     gst_object_unref (target);
298   } else {
299     /* We don't have any target, but we shouldn't return FALSE since this
300      * would stop the actual push of a buffer (which might trigger a pad block
301      * or probe, or properly return GST_FLOW_NOT_LINKED.
302      */
303     res = TRUE;
304   }
305   return res;
306 }
307
308 static gboolean
309 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
310 {
311   GstPad *oldtarget;
312
313   if (target) {
314     GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
315
316     if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
317       goto wrong_direction;
318   } else
319     GST_LOG_OBJECT (pad, "clearing target");
320
321   /* clear old target */
322   if ((oldtarget = GST_PROXY_PAD_TARGET (pad)))
323     gst_object_unref (oldtarget);
324
325   /* set and ref new target if any */
326   if (target)
327     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
328   else
329     GST_PROXY_PAD_TARGET (pad) = NULL;
330
331   return TRUE;
332
333   /* ERRORS */
334 wrong_direction:
335   {
336     GST_ERROR_OBJECT (pad,
337         "target pad doesn't have the same direction as ourself");
338     return FALSE;
339   }
340 }
341
342 static gboolean
343 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
344 {
345   gboolean result;
346
347   GST_PROXY_LOCK (pad);
348   result = gst_proxy_pad_set_target_unlocked (pad, target);
349   GST_PROXY_UNLOCK (pad);
350
351   return result;
352 }
353
354 static GstPad *
355 gst_proxy_pad_get_target (GstPad * pad)
356 {
357   GstPad *target;
358
359   GST_PROXY_LOCK (pad);
360   target = GST_PROXY_PAD_TARGET (pad);
361   if (target)
362     gst_object_ref (target);
363   GST_PROXY_UNLOCK (pad);
364
365   return target;
366 }
367
368 /**
369  * gst_proxy_pad_get_internal:
370  * @pad: the #GstProxyPad
371  *
372  * Get the internal pad of @pad. Unref target pad after usage.
373  *
374  * The internal pad of a #GstGhostPad is the internally used
375  * pad of opposite direction, which is used to link to the target.
376  *
377  * Returns: (transfer full): the target #GstProxyPad, can be NULL.
378  * Unref target pad after usage.
379  */
380 GstProxyPad *
381 gst_proxy_pad_get_internal (GstProxyPad * pad)
382 {
383   GstPad *internal;
384
385   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);
386
387   GST_PROXY_LOCK (pad);
388   internal = GST_PROXY_PAD_INTERNAL (pad);
389   if (internal)
390     gst_object_ref (internal);
391   GST_PROXY_UNLOCK (pad);
392
393   return GST_PROXY_PAD_CAST (internal);
394 }
395
396 static void
397 gst_proxy_pad_do_unlink (GstPad * pad)
398 {
399   GstPad *internal;
400
401   /* don't do anything if this unlink resulted from retargeting the pad
402    * controlled by the ghostpad. We only want to invalidate the target pad when
403    * the element suddently unlinked with our internal pad. */
404   if (GST_PROXY_PAD_RETARGET (pad))
405     return;
406
407   internal = GST_PROXY_PAD_INTERNAL (pad);
408
409   GST_DEBUG_OBJECT (pad, "pad is unlinked");
410
411   gst_proxy_pad_set_target (internal, NULL);
412 }
413
414 static void
415 gst_proxy_pad_class_init (GstProxyPadClass * klass)
416 {
417   GObjectClass *gobject_class = (GObjectClass *) klass;
418
419   g_type_class_add_private (klass, sizeof (GstProxyPadPrivate));
420
421   gobject_class->dispose = gst_proxy_pad_dispose;
422   gobject_class->finalize = gst_proxy_pad_finalize;
423
424 #if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
425   {
426     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
427
428     gstobject_class->save_thyself =
429         ((gpointer (*)(GstObject * object,
430                 gpointer self)) *
431         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself));
432   }
433 #endif
434   /* Register common function pointer descriptions */
435   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_query_type);
436   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_event);
437   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_query);
438   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_iterate_internal_links);
439   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_getcaps);
440   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_acceptcaps);
441   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_fixatecaps);
442   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_setcaps);
443   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_unlink);
444   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_bufferalloc);
445   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain);
446   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_chain_list);
447   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_getrange);
448   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_do_checkgetrange);
449 }
450
451 static void
452 gst_proxy_pad_dispose (GObject * object)
453 {
454   GstPad *pad = GST_PAD (object);
455   GstPad **target_p;
456
457   GST_PROXY_LOCK (pad);
458   /* remove and unref the target */
459   target_p = &GST_PROXY_PAD_TARGET (pad);
460   gst_object_replace ((GstObject **) target_p, NULL);
461   /* The internal is only cleared by GstGhostPad::dispose, since it is the 
462    * parent of non-ghost GstProxyPad and owns the refcount on the internal.
463    */
464   GST_PROXY_UNLOCK (pad);
465
466   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
467 }
468
469 static void
470 gst_proxy_pad_finalize (GObject * object)
471 {
472   GstProxyPad *pad = GST_PROXY_PAD (object);
473
474   g_mutex_free (GST_PROXY_GET_LOCK (pad));
475   GST_PROXY_GET_LOCK (pad) = NULL;
476
477   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
478 }
479
480 static void
481 gst_proxy_pad_init (GstProxyPad * ppad)
482 {
483   GstPad *pad = (GstPad *) ppad;
484
485   GST_PROXY_PAD_PRIVATE (ppad) = G_TYPE_INSTANCE_GET_PRIVATE (ppad,
486       GST_TYPE_PROXY_PAD, GstProxyPadPrivate);
487   GST_PROXY_GET_LOCK (pad) = g_mutex_new ();
488
489   gst_pad_set_query_type_function (pad, gst_proxy_pad_do_query_type);
490   gst_pad_set_event_function (pad, gst_proxy_pad_do_event);
491   gst_pad_set_query_function (pad, gst_proxy_pad_do_query);
492   gst_pad_set_iterate_internal_links_function (pad,
493       gst_proxy_pad_do_iterate_internal_links);
494
495   gst_pad_set_getcaps_function (pad, gst_proxy_pad_do_getcaps);
496   gst_pad_set_acceptcaps_function (pad, gst_proxy_pad_do_acceptcaps);
497   gst_pad_set_fixatecaps_function (pad, gst_proxy_pad_do_fixatecaps);
498   gst_pad_set_setcaps_function (pad, gst_proxy_pad_do_setcaps);
499   gst_pad_set_unlink_function (pad, gst_proxy_pad_do_unlink);
500 }
501
502 #if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
503 /**
504  * gst_proxy_pad_save_thyself:
505  * @pad: a ghost #GstPad to save.
506  * @parent: the parent #xmlNodePtr to save the description in.
507  *
508  * Saves the ghost pad into an xml representation.
509  *
510  * Returns: the #xmlNodePtr representation of the pad.
511  */
512 static xmlNodePtr
513 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
514 {
515   xmlNodePtr self;
516   GstProxyPad *proxypad;
517   GstPad *pad;
518   GstPad *peer;
519
520   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
521
522   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
523   xmlNewChild (self, NULL, (xmlChar *) "name",
524       (xmlChar *) GST_OBJECT_NAME (object));
525   xmlNewChild (self, NULL, (xmlChar *) "parent",
526       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
527
528   proxypad = GST_PROXY_PAD_CAST (object);
529   pad = GST_PAD_CAST (proxypad);
530   peer = GST_PAD_CAST (pad->peer);
531
532   if (GST_IS_PAD (pad)) {
533     if (GST_PAD_IS_SRC (pad))
534       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source");
535     else if (GST_PAD_IS_SINK (pad))
536       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink");
537     else
538       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
539   } else {
540     xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
541   }
542   if (GST_IS_PAD (peer)) {
543     gchar *content = g_strdup_printf ("%s.%s",
544         GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
545
546     xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content);
547     g_free (content);
548   } else {
549     xmlNewChild (self, NULL, (xmlChar *) "peer", NULL);
550   }
551
552   return self;
553 }
554 #endif /* GST_DISABLE_LOADSAVE */
555
556
557 /***********************************************************************
558  * Ghost pads, implemented as a pair of proxy pads (sort of)
559  */
560
561
562 #define GST_GHOST_PAD_PRIVATE(obj)      (GST_GHOST_PAD_CAST (obj)->priv)
563
564 struct _GstGhostPadPrivate
565 {
566   /* with PROXY_LOCK */
567   gulong notify_id;
568
569   gboolean constructed;
570 };
571
572 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
573
574 static void gst_ghost_pad_dispose (GObject * object);
575
576 /* see gstghostpad design docs */
577 static gboolean
578 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
579 {
580   gboolean ret;
581   GstPad *other;
582
583   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
584       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
585
586   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
587    * will be activated later (or already in case of a ghost sinkpad). */
588   other = GST_PROXY_PAD_INTERNAL (pad);
589   ret = gst_pad_activate_push (other, active);
590
591   return ret;
592 }
593
594 static gboolean
595 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
596 {
597   gboolean ret;
598   GstPad *other;
599
600   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
601       GST_DEBUG_PAD_NAME (pad));
602
603   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
604     /* we are activated in pull mode by our peer element, which is a sinkpad
605      * that wants to operate in pull mode. This activation has to propagate
606      * upstream throught the pipeline. We call the internal activation function,
607      * which will trigger gst_ghost_pad_do_activate_pull, which propagates even
608      * further upstream */
609     GST_LOG_OBJECT (pad, "pad is src, activate internal");
610     other = GST_PROXY_PAD_INTERNAL (pad);
611     ret = gst_pad_activate_pull (other, active);
612   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
613     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
614      * since we hold a pointer to the upstream peer. */
615     GST_LOG_OBJECT (pad, "activating peer");
616     ret = gst_pad_activate_pull (other, active);
617     gst_object_unref (other);
618   } else {
619     /* this is failure, we can't activate pull if there is no peer */
620     GST_LOG_OBJECT (pad, "not src and no peer, failing");
621     ret = FALSE;
622   }
623
624   return ret;
625 }
626
627 static gboolean
628 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
629 {
630   gboolean ret;
631   GstPad *other;
632
633   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
634       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
635
636   /* just activate the internal pad */
637   other = GST_PROXY_PAD_INTERNAL (pad);
638   ret = gst_pad_activate_push (other, active);
639
640   return ret;
641 }
642
643 static gboolean
644 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
645 {
646   gboolean ret;
647   GstPad *other;
648
649   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
650       GST_DEBUG_PAD_NAME (pad));
651
652   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
653     /* the ghostpad is SRC and activated in pull mode by its peer, call the
654      * activation function of the internal pad to propagate the activation
655      * upstream */
656     GST_LOG_OBJECT (pad, "pad is src, activate internal");
657     other = GST_PROXY_PAD_INTERNAL (pad);
658     ret = gst_pad_activate_pull (other, active);
659   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
660     /* We are SINK and activated by the internal pad, propagate activation
661      * upstream because we hold a ref to the upstream peer */
662     GST_LOG_OBJECT (pad, "activating peer");
663     ret = gst_pad_activate_pull (other, active);
664     gst_object_unref (other);
665   } else {
666     /* no peer, we fail */
667     GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
668     ret = FALSE;
669   }
670
671   return ret;
672 }
673
674 static GstPadLinkReturn
675 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
676 {
677   GstPadLinkReturn ret;
678   GstPad *internal;
679
680   GST_DEBUG_OBJECT (pad, "linking ghostpad");
681
682   internal = GST_PROXY_PAD_INTERNAL (pad);
683   if (!gst_proxy_pad_set_target (internal, peer))
684     goto target_failed;
685
686   ret = GST_PAD_LINK_OK;
687   /* if we are a source pad, we should call the peer link function
688    * if the peer has one, see design docs. */
689   if (GST_PAD_IS_SRC (pad)) {
690     if (GST_PAD_LINKFUNC (peer)) {
691       ret = GST_PAD_LINKFUNC (peer) (peer, pad);
692       if (ret != GST_PAD_LINK_OK)
693         goto link_failed;
694     }
695   }
696   return ret;
697
698   /* ERRORS */
699 target_failed:
700   {
701     GST_DEBUG_OBJECT (pad, "setting target failed");
702     return GST_PAD_LINK_REFUSED;
703   }
704 link_failed:
705   {
706     GST_DEBUG_OBJECT (pad, "linking failed");
707     /* clear target again */
708     gst_proxy_pad_set_target (internal, NULL);
709     return ret;
710   }
711 }
712
713 static void
714 gst_ghost_pad_do_unlink (GstPad * pad)
715 {
716   GstPad *internal;
717
718   internal = GST_PROXY_PAD_INTERNAL (pad);
719
720   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
721
722   /* The target of the internal pad is no longer valid */
723   gst_proxy_pad_set_target (internal, NULL);
724 }
725
726 static void
727 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
728 {
729   GstCaps *caps;
730   gboolean changed;
731
732   g_object_get (internal, "caps", &caps, NULL);
733
734   GST_DEBUG_OBJECT (pad, "notified %p %" GST_PTR_FORMAT, caps, caps);
735
736   GST_OBJECT_LOCK (pad);
737   changed = (GST_PAD_CAPS (pad) != caps);
738   if (changed)
739     gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
740   GST_OBJECT_UNLOCK (pad);
741
742   if (changed) {
743 #if GLIB_CHECK_VERSION(2,26,0)
744     g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
745 #else
746     g_object_notify ((GObject *) pad, "caps");
747 #endif
748   }
749
750   if (caps)
751     gst_caps_unref (caps);
752 }
753
754 static void
755 on_src_target_notify (GstPad * target, GParamSpec * unused, gpointer user_data)
756 {
757   GstProxyPad *proxypad;
758   GstGhostPad *gpad;
759   GstCaps *caps;
760   gboolean changed;
761
762   g_object_get (target, "caps", &caps, NULL);
763
764   GST_OBJECT_LOCK (target);
765   /* First check if the peer is still available and our proxy pad */
766   if (!GST_PAD_PEER (target) || !GST_IS_PROXY_PAD (GST_PAD_PEER (target))) {
767     GST_OBJECT_UNLOCK (target);
768     goto done;
769   }
770
771   proxypad = GST_PROXY_PAD (GST_PAD_PEER (target));
772   GST_PROXY_LOCK (proxypad);
773   /* Now check if the proxypad's internal pad is still there and
774    * a ghostpad */
775   if (!GST_PROXY_PAD_INTERNAL (proxypad) ||
776       !GST_IS_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad))) {
777     GST_OBJECT_UNLOCK (target);
778     GST_PROXY_UNLOCK (proxypad);
779     goto done;
780   }
781   gpad = GST_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad));
782   g_object_ref (gpad);
783   GST_PROXY_UNLOCK (proxypad);
784   GST_OBJECT_UNLOCK (target);
785
786   GST_OBJECT_LOCK (gpad);
787
788   GST_DEBUG_OBJECT (gpad, "notified %p %" GST_PTR_FORMAT, caps, caps);
789
790   changed = (GST_PAD_CAPS (gpad) != caps);
791   if (changed)
792     gst_caps_replace (&(GST_PAD_CAPS (gpad)), caps);
793   GST_OBJECT_UNLOCK (gpad);
794
795   if (changed) {
796 #if GLIB_CHECK_VERSION(2,26,0)
797     g_object_notify_by_pspec ((GObject *) gpad, pspec_caps);
798 #else
799     g_object_notify ((GObject *) gpad, "caps");
800 #endif
801   }
802
803   g_object_unref (gpad);
804
805 done:
806   if (caps)
807     gst_caps_unref (caps);
808 }
809
810 static gboolean
811 gst_ghost_pad_do_setcaps (GstPad * pad, GstCaps * caps)
812 {
813   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
814     return TRUE;
815
816   return gst_proxy_pad_do_setcaps (pad, caps);
817 }
818
819 static GstIterator *
820 gst_ghost_pad_do_iterate_internal_links (GstPad * pad)
821 {
822   GstIterator *res = NULL;
823   GstPad *internal = GST_PROXY_PAD_INTERNAL (GST_GHOST_PAD_CAST (pad));
824
825   if (internal) {
826     res =
827         gst_iterator_new_single (GST_TYPE_PAD, internal,
828         (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
829   }
830
831   return res;
832 }
833
834 static void
835 gst_ghost_pad_class_init (GstGhostPadClass * klass)
836 {
837   GObjectClass *gobject_class = (GObjectClass *) klass;
838
839   g_type_class_add_private (klass, sizeof (GstGhostPadPrivate));
840
841   pspec_caps = g_object_class_find_property (gobject_class, "caps");
842
843   gobject_class->dispose = gst_ghost_pad_dispose;
844
845   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_setcaps);
846   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_activate_pull);
847   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_activate_push);
848   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_do_link);
849 }
850
851 static void
852 gst_ghost_pad_init (GstGhostPad * pad)
853 {
854   GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
855       GST_TYPE_GHOST_PAD, GstGhostPadPrivate);
856
857   gst_pad_set_setcaps_function (GST_PAD_CAST (pad), gst_ghost_pad_do_setcaps);
858   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
859       gst_ghost_pad_do_activate_pull);
860   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
861       gst_ghost_pad_do_activate_push);
862   gst_pad_set_iterate_internal_links_function (GST_PAD_CAST (pad),
863       gst_ghost_pad_do_iterate_internal_links);
864 }
865
866 static void
867 gst_ghost_pad_dispose (GObject * object)
868 {
869   GstPad *pad;
870   GstPad *internal;
871   GstPad *peer;
872
873   pad = GST_PAD (object);
874
875   GST_DEBUG_OBJECT (pad, "dispose");
876
877   gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
878
879   /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
880    * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */
881   peer = gst_pad_get_peer (pad);
882   if (peer) {
883     if (GST_PAD_IS_SRC (pad))
884       gst_pad_unlink (pad, peer);
885     else
886       gst_pad_unlink (peer, pad);
887
888     gst_object_unref (peer);
889   }
890
891   GST_PROXY_LOCK (pad);
892   internal = GST_PROXY_PAD_INTERNAL (pad);
893
894   gst_pad_set_activatepull_function (internal, NULL);
895   gst_pad_set_activatepush_function (internal, NULL);
896
897   g_signal_handler_disconnect (internal,
898       GST_GHOST_PAD_PRIVATE (pad)->notify_id);
899
900   /* disposes of the internal pad, since the ghostpad is the only possible object
901    * that has a refcount on the internal pad. */
902   gst_object_unparent (GST_OBJECT_CAST (internal));
903   GST_PROXY_PAD_INTERNAL (pad) = NULL;
904
905   GST_PROXY_UNLOCK (pad);
906
907   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
908 }
909
910 /**
911  * gst_ghost_pad_construct:
912  * @gpad: the newly allocated ghost pad
913  *
914  * Finish initialization of a newly allocated ghost pad.
915  *
916  * This function is most useful in language bindings and when subclassing
917  * #GstGhostPad; plugin and application developers normally will not call this
918  * function. Call this function directly after a call to g_object_new
919  * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
920  *
921  * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
922  *
923  * Since: 0.10.22
924  */
925 gboolean
926 gst_ghost_pad_construct (GstGhostPad * gpad)
927 {
928   GstPadDirection dir, otherdir;
929   GstPadTemplate *templ;
930   GstPad *pad, *internal;
931
932   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
933   g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
934       FALSE);
935
936   g_object_get (gpad, "direction", &dir, "template", &templ, NULL);
937
938   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);
939
940   pad = GST_PAD (gpad);
941
942   /* Set directional padfunctions for ghostpad */
943   if (dir == GST_PAD_SINK) {
944     gst_pad_set_bufferalloc_function (pad, gst_proxy_pad_do_bufferalloc);
945     gst_pad_set_chain_function (pad, gst_proxy_pad_do_chain);
946     gst_pad_set_chain_list_function (pad, gst_proxy_pad_do_chain_list);
947   } else {
948     gst_pad_set_getrange_function (pad, gst_proxy_pad_do_getrange);
949     gst_pad_set_checkgetrange_function (pad, gst_proxy_pad_do_checkgetrange);
950   }
951
952   /* link/unlink functions */
953   gst_pad_set_link_function (pad, gst_ghost_pad_do_link);
954   gst_pad_set_unlink_function (pad, gst_ghost_pad_do_unlink);
955
956   /* INTERNAL PAD, it always exists and is child of the ghostpad */
957   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
958   if (templ) {
959     internal =
960         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
961         "direction", otherdir, "template", templ, NULL);
962     /* release ref obtained via g_object_get */
963     gst_object_unref (templ);
964   } else {
965     internal =
966         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
967         "direction", otherdir, NULL);
968   }
969   GST_PAD_UNSET_FLUSHING (internal);
970
971   /* Set directional padfunctions for internal pad */
972   if (dir == GST_PAD_SRC) {
973     gst_pad_set_bufferalloc_function (internal, gst_proxy_pad_do_bufferalloc);
974     gst_pad_set_chain_function (internal, gst_proxy_pad_do_chain);
975     gst_pad_set_chain_list_function (internal, gst_proxy_pad_do_chain_list);
976   } else {
977     gst_pad_set_getrange_function (internal, gst_proxy_pad_do_getrange);
978     gst_pad_set_checkgetrange_function (internal,
979         gst_proxy_pad_do_checkgetrange);
980   }
981
982   GST_PROXY_LOCK (pad);
983
984   /* now make the ghostpad a parent of the internal pad */
985   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
986           GST_OBJECT_CAST (pad)))
987     goto parent_failed;
988
989   /* The ghostpad is the parent of the internal pad and is the only object that
990    * can have a refcount on the internal pad.
991    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
992    * a refcount of 1.
993    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
994    * its refcount on the internal pad in the dispose method by un-parenting it.
995    * This is why we don't take extra refcounts in the assignments below
996    */
997   GST_PROXY_PAD_INTERNAL (pad) = internal;
998   GST_PROXY_PAD_INTERNAL (internal) = pad;
999
1000   /* could be more general here, iterating over all writable properties...
1001    * taking the short road for now tho */
1002   GST_GHOST_PAD_PRIVATE (pad)->notify_id =
1003       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
1004       pad);
1005
1006   /* call function to init values of the pad caps */
1007   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (pad));
1008
1009   /* special activation functions for the internal pad */
1010   gst_pad_set_activatepull_function (internal,
1011       gst_ghost_pad_internal_do_activate_pull);
1012   gst_pad_set_activatepush_function (internal,
1013       gst_ghost_pad_internal_do_activate_push);
1014
1015   GST_PROXY_UNLOCK (pad);
1016
1017   GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
1018   return TRUE;
1019
1020   /* ERRORS */
1021 parent_failed:
1022   {
1023     GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
1024         GST_DEBUG_PAD_NAME (internal));
1025     g_critical ("Could not set internal pad %s:%s",
1026         GST_DEBUG_PAD_NAME (internal));
1027     GST_PROXY_UNLOCK (pad);
1028     gst_object_unref (internal);
1029     return FALSE;
1030   }
1031 }
1032
1033 static GstPad *
1034 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
1035     GstPadTemplate * templ)
1036 {
1037   GstGhostPad *ret;
1038
1039   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
1040
1041   /* OBJECT CREATION */
1042   if (templ) {
1043     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
1044         "direction", dir, "template", templ, NULL);
1045   } else {
1046     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
1047         "direction", dir, NULL);
1048   }
1049
1050   if (!gst_ghost_pad_construct (ret))
1051     goto construct_failed;
1052
1053   return GST_PAD_CAST (ret);
1054
1055 construct_failed:
1056   /* already logged */
1057   gst_object_unref (ret);
1058   return NULL;
1059 }
1060
1061 /**
1062  * gst_ghost_pad_new_no_target:
1063  * @name: (allow-none): the name of the new pad, or NULL to assign a default name.
1064  * @dir: the direction of the ghostpad
1065  *
1066  * Create a new ghostpad without a target with the given direction.
1067  * A target can be set on the ghostpad later with the
1068  * gst_ghost_pad_set_target() function.
1069  *
1070  * The created ghostpad will not have a padtemplate.
1071  *
1072  * Returns: (transfer full): a new #GstPad, or NULL in case of an error.
1073  */
1074 GstPad *
1075 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
1076 {
1077   GstPad *ret;
1078
1079   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
1080
1081   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
1082
1083   ret = gst_ghost_pad_new_full (name, dir, NULL);
1084
1085   return ret;
1086 }
1087
1088 /**
1089  * gst_ghost_pad_new:
1090  * @name: (allow-none): the name of the new pad, or NULL to assign a default name
1091  * @target: (transfer none): the pad to ghost.
1092  *
1093  * Create a new ghostpad with @target as the target. The direction will be taken
1094  * from the target pad. @target must be unlinked.
1095  *
1096  * Will ref the target.
1097  *
1098  * Returns: (transfer full): a new #GstPad, or NULL in case of an error.
1099  */
1100 GstPad *
1101 gst_ghost_pad_new (const gchar * name, GstPad * target)
1102 {
1103   GstPad *ret;
1104
1105   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1106   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1107
1108   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
1109       GST_DEBUG_PAD_NAME (target));
1110
1111   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
1112     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1113       goto set_target_failed;
1114
1115   return ret;
1116
1117   /* ERRORS */
1118 set_target_failed:
1119   {
1120     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1121         GST_DEBUG_PAD_NAME (target));
1122     gst_object_unref (ret);
1123     return NULL;
1124   }
1125 }
1126
1127 /**
1128  * gst_ghost_pad_new_from_template:
1129  * @name: (allow-none): the name of the new pad, or NULL to assign a default name.
1130  * @target: (transfer none): the pad to ghost.
1131  * @templ: (transfer none): the #GstPadTemplate to use on the ghostpad.
1132  *
1133  * Create a new ghostpad with @target as the target. The direction will be taken
1134  * from the target pad. The template used on the ghostpad will be @template.
1135  *
1136  * Will ref the target.
1137  *
1138  * Returns: (transfer full): a new #GstPad, or NULL in case of an error.
1139  *
1140  * Since: 0.10.10
1141  */
1142
1143 GstPad *
1144 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
1145     GstPadTemplate * templ)
1146 {
1147   GstPad *ret;
1148
1149   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1150   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1151   g_return_val_if_fail (templ != NULL, NULL);
1152   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
1153       GST_PAD_DIRECTION (target), NULL);
1154
1155   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
1156       GST_DEBUG_PAD_NAME (target), templ);
1157
1158   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
1159     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1160       goto set_target_failed;
1161
1162   return ret;
1163
1164   /* ERRORS */
1165 set_target_failed:
1166   {
1167     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1168         GST_DEBUG_PAD_NAME (target));
1169     gst_object_unref (ret);
1170     return NULL;
1171   }
1172 }
1173
1174 /**
1175  * gst_ghost_pad_new_no_target_from_template:
1176  * @name: (allow-none): the name of the new pad, or NULL to assign a default name
1177  * @templ: (transfer none): the #GstPadTemplate to create the ghostpad from.
1178  *
1179  * Create a new ghostpad based on @templ, without setting a target. The
1180  * direction will be taken from the @templ.
1181  *
1182  * Returns: (transfer full): a new #GstPad, or NULL in case of an error.
1183  *
1184  * Since: 0.10.10
1185  */
1186 GstPad *
1187 gst_ghost_pad_new_no_target_from_template (const gchar * name,
1188     GstPadTemplate * templ)
1189 {
1190   GstPad *ret;
1191
1192   g_return_val_if_fail (templ != NULL, NULL);
1193
1194   ret =
1195       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
1196
1197   return ret;
1198 }
1199
1200 /**
1201  * gst_ghost_pad_get_target:
1202  * @gpad: the #GstGhostPad
1203  *
1204  * Get the target pad of @gpad. Unref target pad after usage.
1205  *
1206  * Returns: (transfer full): the target #GstPad, can be NULL if the ghostpad
1207  * has no target set. Unref target pad after usage.
1208  */
1209 GstPad *
1210 gst_ghost_pad_get_target (GstGhostPad * gpad)
1211 {
1212   GstPad *ret;
1213
1214   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
1215
1216   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
1217
1218   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
1219
1220   return ret;
1221 }
1222
1223 /**
1224  * gst_ghost_pad_set_target:
1225  * @gpad: the #GstGhostPad
1226  * @newtarget: (transfer none) (allow-none): the new pad target
1227  *
1228  * Set the new target of the ghostpad @gpad. Any existing target
1229  * is unlinked and links to the new target are established. if @newtarget is
1230  * NULL the target will be cleared.
1231  *
1232  * Returns: (transfer full): TRUE if the new target could be set. This function
1233  *     can return FALSE when the internal pads could not be linked.
1234  */
1235 gboolean
1236 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1237 {
1238   GstPad *internal;
1239   GstPad *oldtarget;
1240   gboolean result;
1241   GstPadLinkReturn lret;
1242
1243   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1244   g_return_val_if_fail (GST_PAD_CAST (gpad) != newtarget, FALSE);
1245   g_return_val_if_fail (newtarget != GST_PROXY_PAD_INTERNAL (gpad), FALSE);
1246
1247   /* no need for locking, the internal pad's lifecycle is directly linked to the
1248    * ghostpad's */
1249   internal = GST_PROXY_PAD_INTERNAL (gpad);
1250
1251   if (newtarget)
1252     GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1253   else
1254     GST_DEBUG_OBJECT (gpad, "clearing target");
1255
1256   /* clear old target */
1257   GST_PROXY_LOCK (gpad);
1258   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1259     if (GST_PAD_IS_SRC (oldtarget)) {
1260       g_signal_handlers_disconnect_by_func (oldtarget,
1261           (gpointer) on_src_target_notify, NULL);
1262     }
1263
1264     GST_PROXY_PAD_RETARGET (internal) = TRUE;
1265
1266     /* unlink internal pad */
1267     if (GST_PAD_IS_SRC (internal))
1268       gst_pad_unlink (internal, oldtarget);
1269     else
1270       gst_pad_unlink (oldtarget, internal);
1271
1272     GST_PROXY_PAD_RETARGET (internal) = FALSE;
1273   }
1274
1275   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1276   GST_PROXY_UNLOCK (gpad);
1277
1278   if (result && newtarget) {
1279     if (GST_PAD_IS_SRC (newtarget)) {
1280       g_signal_connect (newtarget, "notify::caps",
1281           G_CALLBACK (on_src_target_notify), NULL);
1282     }
1283
1284     /* and link to internal pad without any checks */
1285     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
1286
1287     if (GST_PAD_IS_SRC (internal))
1288       lret =
1289           gst_pad_link_full (internal, newtarget, GST_PAD_LINK_CHECK_NOTHING);
1290     else
1291       lret =
1292           gst_pad_link_full (newtarget, internal, GST_PAD_LINK_CHECK_NOTHING);
1293
1294     if (lret != GST_PAD_LINK_OK)
1295       goto link_failed;
1296   }
1297
1298   return result;
1299
1300   /* ERRORS */
1301 link_failed:
1302   {
1303     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
1304         lret);
1305     /* and unset target again */
1306     GST_PROXY_LOCK (gpad);
1307     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
1308     GST_PROXY_UNLOCK (gpad);
1309     return FALSE;
1310   }
1311 }