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