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>
6 * gstghostpad.c: Proxy pads
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 * @short_description: Pseudo link pads
29 * GhostPads are useful when organizing pipelines with #GstBin like elements.
30 * The idea here is to create hierarchical element graphs. The bin element
31 * contains a sub-graph. Now one would like to treat the bin-element like other
32 * #GstElements. This is where GhostPads come into play. A GhostPad acts as a
33 * proxy for another pad. Thus the bin can have sink and source ghost-pads that
34 * are associated with sink and source pads of the child elements.
36 * If the target pad is known at creation time, gst_ghost_pad_new() is the
37 * function to use to get a ghost-pad. Otherwise one can use gst_ghost_pad_new_no_target()
38 * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
39 * association later on.
41 * Last reviewed on 2005-11-18 (0.9.5)
44 #include "gst_private.h"
46 #include "gstghostpad.h"
48 #define GST_TYPE_PROXY_PAD (gst_proxy_pad_get_type ())
49 #define GST_IS_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD))
50 #define GST_IS_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
51 #define GST_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
52 #define GST_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
53 #define GST_PROXY_PAD_TARGET(pad) (GST_PROXY_PAD (pad)->target)
56 typedef struct _GstProxyPad GstProxyPad;
57 typedef struct _GstProxyPadClass GstProxyPadClass;
59 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD (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)))
72 gpointer _gst_reserved[1];
75 struct _GstProxyPadClass
77 GstPadClass parent_class;
80 gpointer _gst_reserved[1];
84 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
86 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
88 static void gst_proxy_pad_dispose (GObject * object);
89 static void gst_proxy_pad_finalize (GObject * object);
91 #ifndef GST_DISABLE_LOADSAVE
92 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
98 gst_proxy_pad_class_init (GstProxyPadClass * klass)
100 GObjectClass *gobject_class = (GObjectClass *) klass;
102 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
103 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
105 #ifndef GST_DISABLE_LOADSAVE
107 GstObjectClass *gstobject_class = (GstObjectClass *) klass;
109 gstobject_class->save_thyself =
110 GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
116 gst_proxy_pad_do_query_type (GstPad * pad)
118 GstPad *target = gst_proxy_pad_get_target (pad);
119 const GstQueryType *res;
121 g_return_val_if_fail (target != NULL, NULL);
123 res = gst_pad_get_query_types (target);
124 gst_object_unref (target);
130 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
133 GstPad *target = gst_proxy_pad_get_target (pad);
135 g_return_val_if_fail (target != NULL, FALSE);
137 res = gst_pad_send_event (target, event);
138 gst_object_unref (target);
144 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
147 GstPad *target = gst_proxy_pad_get_target (pad);
149 g_return_val_if_fail (target != NULL, FALSE);
151 res = gst_pad_query (target, query);
152 gst_object_unref (target);
158 gst_proxy_pad_do_internal_link (GstPad * pad)
160 GstPad *target = gst_proxy_pad_get_target (pad);
163 g_return_val_if_fail (target != NULL, NULL);
165 res = gst_pad_get_internal_links (target);
166 gst_object_unref (target);
172 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
173 GstCaps * caps, GstBuffer ** buf)
175 GstFlowReturn result;
176 GstPad *target = gst_proxy_pad_get_target (pad);
179 g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
181 peer = gst_pad_get_peer (target);
183 GST_DEBUG ("buffer alloc on %s:%s", GST_DEBUG_PAD_NAME (target));
185 result = gst_pad_alloc_buffer (peer, offset, size, caps, buf);
187 gst_object_unref (peer);
189 result = GST_FLOW_NOT_LINKED;
192 gst_object_unref (target);
198 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
200 GstPad *target = gst_proxy_pad_get_target (pad);
203 g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
205 res = gst_pad_chain (target, buffer);
206 gst_object_unref (target);
212 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
215 GstPad *target = gst_proxy_pad_get_target (pad);
218 g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
220 res = gst_pad_get_range (target, offset, size, buffer);
221 gst_object_unref (target);
227 gst_proxy_pad_do_checkgetrange (GstPad * pad)
230 GstPad *target = gst_proxy_pad_get_target (pad);
233 g_return_val_if_fail (target != NULL, FALSE);
235 peer = gst_pad_get_peer (target);
237 result = gst_pad_check_pull_range (peer);
238 gst_object_unref (peer);
242 gst_object_unref (target);
248 gst_proxy_pad_do_getcaps (GstPad * pad)
250 GstPad *target = gst_proxy_pad_get_target (pad);
253 g_return_val_if_fail (target != NULL, NULL);
255 res = gst_pad_get_caps (target);
256 gst_object_unref (target);
262 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
264 GstPad *target = gst_proxy_pad_get_target (pad);
267 g_return_val_if_fail (target != NULL, FALSE);
269 res = gst_pad_accept_caps (target, caps);
270 gst_object_unref (target);
276 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
278 GstPad *target = gst_proxy_pad_get_target (pad);
280 g_return_if_fail (target != NULL);
282 gst_pad_fixate_caps (target, caps);
283 gst_object_unref (target);
287 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
289 GstPad *target = gst_proxy_pad_get_target (pad);
292 g_return_val_if_fail (target != NULL, FALSE);
294 res = gst_pad_set_caps (target, caps);
295 gst_object_unref (target);
301 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
305 GST_DEBUG ("set target %s:%s on %s:%s",
306 GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (pad));
308 /* clear old target */
309 if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
310 gst_object_unref (oldtarget);
311 GST_PROXY_PAD_TARGET (pad) = NULL;
315 /* set and ref new target if any */
316 GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
318 gst_pad_set_query_type_function (pad,
319 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
320 gst_pad_set_event_function (pad,
321 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
322 gst_pad_set_query_function (pad,
323 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
324 gst_pad_set_internal_link_function (pad,
325 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
326 gst_pad_set_getcaps_function (pad,
327 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
328 gst_pad_set_acceptcaps_function (pad,
329 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
330 gst_pad_set_fixatecaps_function (pad,
331 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
332 gst_pad_set_setcaps_function (pad,
333 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
335 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
336 gst_pad_set_bufferalloc_function (pad,
337 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
338 gst_pad_set_chain_function (pad,
339 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
341 gst_pad_set_getrange_function (pad,
342 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
343 gst_pad_set_checkgetrange_function (pad,
344 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
351 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
355 GST_PROXY_LOCK (pad);
356 result = gst_proxy_pad_set_target_unlocked (pad, target);
357 GST_PROXY_UNLOCK (pad);
363 gst_proxy_pad_get_target (GstPad * pad)
367 GST_PROXY_LOCK (pad);
368 target = GST_PROXY_PAD_TARGET (pad);
370 gst_object_ref (target);
371 GST_PROXY_UNLOCK (pad);
377 gst_proxy_pad_init (GstProxyPad * pad)
379 pad->proxy_lock = g_mutex_new ();
383 gst_proxy_pad_dispose (GObject * object)
385 GstPad *pad = GST_PAD (object);
388 GST_PROXY_LOCK (pad);
389 target_p = &GST_PROXY_PAD_TARGET (pad);
390 gst_object_replace ((GstObject **) target_p, NULL);
391 GST_PROXY_UNLOCK (pad);
393 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
397 gst_proxy_pad_finalize (GObject * object)
399 GstProxyPad *pad = GST_PROXY_PAD (object);
401 g_mutex_free (pad->proxy_lock);
402 pad->proxy_lock = NULL;
404 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
407 #ifndef GST_DISABLE_LOADSAVE
409 * gst_proxy_pad_save_thyself:
410 * @pad: a ghost #GstPad to save.
411 * @parent: the parent #xmlNodePtr to save the description in.
413 * Saves the ghost pad into an xml representation.
415 * Returns: the #xmlNodePtr representation of the pad.
418 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
422 g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
424 self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
425 xmlNewChild (self, NULL, (xmlChar *) "name",
426 (xmlChar *) GST_OBJECT_NAME (object));
427 xmlNewChild (self, NULL, (xmlChar *) "parent",
428 (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
430 /* FIXME FIXME FIXME! */
434 #endif /* GST_DISABLE_LOADSAVE */
437 /***********************************************************************
438 * Ghost pads, implemented as a pair of proxy pads (sort of)
446 /* with PROXY_LOCK */
451 gpointer _gst_reserved[GST_PADDING];
454 struct _GstGhostPadClass
456 GstProxyPadClass parent_class;
459 gpointer _gst_reserved[GST_PADDING];
463 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
465 static gboolean gst_ghost_pad_set_internal (GstGhostPad * pad,
468 static void gst_ghost_pad_dispose (GObject * object);
470 /* Work around g_logv's use of G_GNUC_PRINTF because gcc chokes on %P, which we
471 * use for GST_PTR_FORMAT. */
473 gst_critical (const gchar * format, ...)
477 va_start (args, format);
478 g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
483 gst_ghost_pad_get_internal (GstPad * pad)
487 GST_PROXY_LOCK (pad);
488 internal = GST_GHOST_PAD (pad)->internal;
490 gst_object_ref (internal);
491 GST_PROXY_UNLOCK (pad);
497 gst_ghost_pad_class_init (GstGhostPadClass * klass)
499 GObjectClass *gobject_class = (GObjectClass *) klass;
501 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
504 /* see gstghostpad design docs */
506 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
510 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
511 GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
514 g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
516 ret = gst_pad_activate_push (parent, active);
518 gst_object_unref (parent);
523 GstPad *peer = gst_pad_get_peer (pad);
526 ret = gst_pad_activate_push (peer, active);
527 gst_object_unref (peer);
537 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
541 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
542 GstPad *peer = gst_pad_get_peer (pad);
545 ret = gst_pad_activate_pull (peer, active);
546 gst_object_unref (peer);
551 GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
554 g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
556 ret = gst_pad_activate_pull (parent, active);
558 gst_object_unref (parent);
568 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
572 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
573 GstPad *internal = gst_ghost_pad_get_internal (pad);
576 ret = gst_pad_activate_push (internal, active);
577 gst_object_unref (internal);
589 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
593 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
594 GstPad *peer = gst_pad_get_peer (pad);
597 ret = gst_pad_activate_pull (peer, active);
598 gst_object_unref (peer);
603 GstPad *internal = gst_ghost_pad_get_internal (pad);
606 ret = gst_pad_activate_pull (internal, active);
607 gst_object_unref (internal);
616 static GstPadLinkReturn
617 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
619 GstPad *internal, *target;
620 GstPadLinkReturn ret;
622 target = gst_proxy_pad_get_target (pad);
624 g_return_val_if_fail (target != NULL, GST_PAD_LINK_NOSCHED);
626 /* proxy the peer into the bin */
627 internal = g_object_new (GST_TYPE_PROXY_PAD,
629 "direction", GST_PAD_DIRECTION (peer),
630 "template", GST_PAD_PAD_TEMPLATE (peer), NULL);
632 gst_proxy_pad_set_target (internal, peer);
633 gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), internal);
635 if (GST_PAD_IS_SRC (internal))
636 ret = gst_pad_link (internal, target);
638 ret = gst_pad_link (target, internal);
640 /* if we are a source pad, we should call the peer link function
641 * if the peer has one */
642 if (GST_PAD_IS_SRC (pad)) {
643 if (GST_PAD_LINKFUNC (peer) && ret == GST_PAD_LINK_OK)
644 ret = GST_PAD_LINKFUNC (peer) (peer, pad);
647 gst_object_unref (target);
649 if (ret == GST_PAD_LINK_OK)
650 gst_pad_set_active (internal, GST_PAD_ACTIVATE_MODE (pad));
652 gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL);
658 gst_ghost_pad_do_unlink (GstPad * pad)
660 GstPad *target = gst_proxy_pad_get_target (pad);
662 g_return_if_fail (target != NULL);
664 GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
666 if (target->unlinkfunc)
667 target->unlinkfunc (target);
669 gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL);
671 gst_object_unref (target);
675 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
679 g_object_get (internal, "caps", &caps, NULL);
681 GST_OBJECT_LOCK (pad);
682 gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
683 GST_OBJECT_UNLOCK (pad);
685 g_object_notify (G_OBJECT (pad), "caps");
687 gst_caps_unref (caps);
691 gst_ghost_pad_set_internal (GstGhostPad * pad, GstPad * internal)
693 GST_PROXY_LOCK (pad);
694 /* first remove old internal pad */
698 gst_pad_set_activatepull_function (pad->internal, NULL);
699 gst_pad_set_activatepush_function (pad->internal, NULL);
701 g_signal_handler_disconnect (pad->internal, pad->notify_id);
703 intpeer = gst_pad_get_peer (pad->internal);
705 if (GST_PAD_IS_SRC (pad->internal))
706 gst_pad_unlink (pad->internal, intpeer);
708 gst_pad_unlink (intpeer, pad->internal);
709 gst_object_unref (intpeer);
711 /* should dispose it */
712 gst_object_unparent (GST_OBJECT_CAST (pad->internal));
715 /* then set new internal pad */
717 if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
718 GST_OBJECT_CAST (pad)))
721 /* could be more general here, iterating over all writable properties...
722 * taking the short road for now tho */
723 pad->notify_id = g_signal_connect (internal, "notify::caps",
724 G_CALLBACK (on_int_notify), pad);
725 on_int_notify (internal, NULL, pad);
726 gst_pad_set_activatepull_function (GST_PAD (internal),
727 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
728 gst_pad_set_activatepush_function (GST_PAD (internal),
729 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
730 /* a ref was taken by set_parent */
732 pad->internal = internal;
734 GST_PROXY_UNLOCK (pad);
741 gst_critical ("Could not set internal pad %" GST_PTR_FORMAT, internal);
742 GST_PROXY_UNLOCK (pad);
748 gst_ghost_pad_init (GstGhostPad * pad)
750 gst_pad_set_activatepull_function (GST_PAD (pad),
751 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
752 gst_pad_set_activatepush_function (GST_PAD (pad),
753 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
757 gst_ghost_pad_dispose (GObject * object)
759 gst_ghost_pad_set_internal (GST_GHOST_PAD (object), NULL);
761 G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
765 * gst_ghost_pad_new_no_target:
766 * @name: the name of the new pad, or NULL to assign a default name.
767 * @dir: the direction of the ghostpad
769 * Create a new ghostpad without a target with the given direction.
770 * A target can be set on the ghostpad later with the
771 * gst_ghost_pad_set_target() function.
773 * The created ghostpad will not have a padtemplate.
775 * Returns: a new #GstPad, or NULL in case of an error.
778 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
782 ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "direction", dir, NULL);
784 gst_pad_set_activatepush_function (ret,
785 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
786 gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
787 gst_pad_set_unlink_function (ret,
788 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
795 * @name: the name of the new pad, or NULL to assign a default name.
796 * @target: the pad to ghost.
798 * Create a new ghostpad with @target as the target. The direction and
799 * padtemplate will be taken from the target pad.
801 * Will ref the target.
803 * Returns: a new #GstPad, or NULL in case of an error.
806 gst_ghost_pad_new (const gchar * name, GstPad * target)
810 g_return_val_if_fail (GST_IS_PAD (target), NULL);
811 g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
813 if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target)))) {
814 g_object_set (G_OBJECT (ret),
815 "template", GST_PAD_PAD_TEMPLATE (target), NULL);
816 gst_ghost_pad_set_target (GST_GHOST_PAD (ret), target);
822 * gst_ghost_pad_get_target:
823 * @gpad: the #GstGhostpad
825 * Get the target pad of #gpad. Unref target pad after usage.
827 * Returns: the target #GstPad, can be NULL if the ghostpad
828 * has no target set. Unref target pad after usage.
831 gst_ghost_pad_get_target (GstGhostPad * gpad)
833 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
835 return gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
839 * gst_ghost_pad_set_target:
840 * @gpad: the #GstGhostpad
841 * @newtarget: the new pad target
843 * Set the new target of the ghostpad @gpad. Any existing target
844 * is unlinked and links to the new target are established.
846 * Returns: TRUE if the new target could be set, FALSE otherwise.
849 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
855 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
857 GST_PROXY_LOCK (gpad);
858 internal = gpad->internal;
860 GST_DEBUG ("set target %s:%s on %s:%s",
861 GST_DEBUG_PAD_NAME (newtarget), GST_DEBUG_PAD_NAME (gpad));
863 /* clear old target */
864 if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
865 /* if we have an internal pad, unlink */
867 if (GST_PAD_IS_SRC (internal))
868 gst_pad_unlink (internal, oldtarget);
870 gst_pad_unlink (oldtarget, internal);
874 result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
876 if (result && newtarget) {
877 /* and link to internal pad if we have one */
879 if (GST_PAD_IS_SRC (internal))
880 result = gst_pad_link (internal, newtarget);
882 result = gst_pad_link (newtarget, internal);
885 GST_PROXY_UNLOCK (gpad);