gstreamer_core/gst/gstghostpad.c
changeset 2 5505e8908944
parent 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
1:4c282e7dd6d3 2:5505e8908944
       
     1 /* GStreamer
       
     2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       
     3  *                    2000 Wim Taymans <wtay@chello.be>
       
     4  *                    2005 Andy Wingo <wingo@pobox.com>
       
     5  *		      2006 Edward Hervey <bilboed@bilboed.com>
       
     6  *
       
     7  * gstghostpad.c: Proxy pads
       
     8  *
       
     9  * This library is free software; you can redistribute it and/or
       
    10  * modify it under the terms of the GNU Library General Public
       
    11  * License as published by the Free Software Foundation; either
       
    12  * version 2 of the License, or (at your option) any later version.
       
    13  *
       
    14  * This library is distributed in the hope that it will be useful,
       
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    17  * Library General Public License for more details.
       
    18  *
       
    19  * You should have received a copy of the GNU Library General Public
       
    20  * License along with this library; if not, write to the
       
    21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    22  * Boston, MA 02111-1307, USA.
       
    23  */
       
    24 
       
    25 /**
       
    26  * SECTION:gstghostpad
       
    27  * @short_description: Pseudo link pads
       
    28  * @see_also: #GstPad
       
    29  *
       
    30  * GhostPads are useful when organizing pipelines with #GstBin like elements.
       
    31  * The idea here is to create hierarchical element graphs. The bin element
       
    32  * contains a sub-graph. Now one would like to treat the bin-element like other
       
    33  * #GstElements. This is where GhostPads come into play. A GhostPad acts as a
       
    34  * proxy for another pad. Thus the bin can have sink and source ghost-pads that
       
    35  * are associated with sink and source pads of the child elements.
       
    36  *
       
    37  * If the target pad is known at creation time, gst_ghost_pad_new() is the
       
    38  * function to use to get a ghost-pad. Otherwise one can use gst_ghost_pad_new_no_target()
       
    39  * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
       
    40  * association later on.
       
    41  *
       
    42  * Note that GhostPads add overhead to the data processing of a pipeline.
       
    43  *
       
    44  * Last reviewed on 2005-11-18 (0.9.5)
       
    45  */
       
    46 
       
    47 #include "gst_private.h"
       
    48 #include "gstinfo.h"
       
    49 
       
    50 #include "gstghostpad.h"
       
    51 #include "gst.h"
       
    52 
       
    53 #ifdef __SYMBIAN32__
       
    54 #include <glib_global.h>
       
    55 #endif
       
    56 
       
    57 #define GST_CAT_DEFAULT GST_CAT_PADS
       
    58 
       
    59 #define GST_TYPE_PROXY_PAD              (gst_proxy_pad_get_type ())
       
    60 #define GST_IS_PROXY_PAD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD))
       
    61 #define GST_IS_PROXY_PAD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
       
    62 #define GST_PROXY_PAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
       
    63 #define GST_PROXY_PAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
       
    64 #define GST_PROXY_PAD_CAST(obj)         ((GstProxyPad *)obj)
       
    65 
       
    66 #define GST_PROXY_PAD_TARGET(pad)       (GST_PROXY_PAD_CAST (pad)->target)
       
    67 #define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD_CAST (pad)->internal)
       
    68 
       
    69 typedef struct _GstProxyPad GstProxyPad;
       
    70 typedef struct _GstProxyPadClass GstProxyPadClass;
       
    71 
       
    72 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD_CAST (pad)->proxy_lock)
       
    73 #define GST_PROXY_LOCK(pad)     (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
       
    74 #define GST_PROXY_UNLOCK(pad)   (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
       
    75 
       
    76 struct _GstProxyPad
       
    77 {
       
    78   GstPad pad;
       
    79 
       
    80   /* with PROXY_LOCK */
       
    81   GMutex *proxy_lock;
       
    82   GstPad *target;
       
    83   GstPad *internal;
       
    84 };
       
    85 
       
    86 struct _GstProxyPadClass
       
    87 {
       
    88   GstPadClass parent_class;
       
    89 
       
    90   /*< private > */
       
    91   gpointer _gst_reserved[1];
       
    92 };
       
    93 
       
    94 static GType gst_proxy_pad_get_type (void);
       
    95 
       
    96 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
       
    97 
       
    98 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
       
    99 
       
   100 static void gst_proxy_pad_dispose (GObject * object);
       
   101 static void gst_proxy_pad_finalize (GObject * object);
       
   102 
       
   103 #ifndef GST_DISABLE_LOADSAVE
       
   104 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
       
   105     xmlNodePtr parent);
       
   106 #endif
       
   107 
       
   108 
       
   109 static void
       
   110 gst_proxy_pad_class_init (GstProxyPadClass * klass)
       
   111 {
       
   112   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   113 
       
   114   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
       
   115   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
       
   116 
       
   117 #ifndef GST_DISABLE_LOADSAVE
       
   118   {
       
   119     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
       
   120 
       
   121     gstobject_class->save_thyself =
       
   122         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
       
   123   }
       
   124 #endif
       
   125 }
       
   126 
       
   127 static const GstQueryType *
       
   128 gst_proxy_pad_do_query_type (GstPad * pad)
       
   129 {
       
   130   GstPad *target = gst_proxy_pad_get_target (pad);
       
   131   const GstQueryType *res = NULL;
       
   132 
       
   133   if (target) {
       
   134     res = gst_pad_get_query_types (target);
       
   135     gst_object_unref (target);
       
   136   }
       
   137   return res;
       
   138 }
       
   139 
       
   140 static gboolean
       
   141 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
       
   142 {
       
   143   gboolean res = FALSE;
       
   144   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
       
   145 
       
   146   res = gst_pad_push_event (internal, event);
       
   147 
       
   148   return res;
       
   149 }
       
   150 
       
   151 static gboolean
       
   152 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
       
   153 {
       
   154   gboolean res = FALSE;
       
   155   GstPad *target = gst_proxy_pad_get_target (pad);
       
   156 
       
   157   if (target) {
       
   158     res = gst_pad_query (target, query);
       
   159     gst_object_unref (target);
       
   160   }
       
   161 
       
   162   return res;
       
   163 }
       
   164 
       
   165 static GList *
       
   166 gst_proxy_pad_do_internal_link (GstPad * pad)
       
   167 {
       
   168   GList *res = NULL;
       
   169   GstPad *target = gst_proxy_pad_get_target (pad);
       
   170 
       
   171   if (target) {
       
   172     res = gst_pad_get_internal_links (target);
       
   173     gst_object_unref (target);
       
   174   }
       
   175 
       
   176   return res;
       
   177 }
       
   178 
       
   179 static GstFlowReturn
       
   180 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
       
   181     GstCaps * caps, GstBuffer ** buf)
       
   182 {
       
   183   GstFlowReturn result;
       
   184   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
       
   185 
       
   186   result = gst_pad_alloc_buffer (internal, offset, size, caps, buf);
       
   187 
       
   188   return result;
       
   189 }
       
   190 
       
   191 static GstFlowReturn
       
   192 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
       
   193 {
       
   194   GstFlowReturn res;
       
   195   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
       
   196 
       
   197   res = gst_pad_push (internal, buffer);
       
   198 
       
   199   return res;
       
   200 }
       
   201 
       
   202 static GstFlowReturn
       
   203 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
       
   204     GstBuffer ** buffer)
       
   205 {
       
   206   GstFlowReturn res;
       
   207   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
       
   208 
       
   209   res = gst_pad_pull_range (internal, offset, size, buffer);
       
   210 
       
   211   return res;
       
   212 }
       
   213 
       
   214 static gboolean
       
   215 gst_proxy_pad_do_checkgetrange (GstPad * pad)
       
   216 {
       
   217   gboolean result;
       
   218   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
       
   219 
       
   220   result = gst_pad_check_pull_range (internal);
       
   221 
       
   222   return result;
       
   223 }
       
   224 
       
   225 static GstCaps *
       
   226 gst_proxy_pad_do_getcaps (GstPad * pad)
       
   227 {
       
   228   GstPad *target = gst_proxy_pad_get_target (pad);
       
   229   GstCaps *res;
       
   230   GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
       
   231 
       
   232   if (target) {
       
   233     /* if we have a real target, proxy the call */
       
   234     res = gst_pad_get_caps (target);
       
   235     gst_object_unref (target);
       
   236 
       
   237     GST_DEBUG_OBJECT (pad, "get caps of target: %" GST_PTR_FORMAT, res);
       
   238 
       
   239     /* filter against the template */
       
   240     if (templ && res) {
       
   241       GstCaps *filt, *tmp;
       
   242 
       
   243       filt = GST_PAD_TEMPLATE_CAPS (templ);
       
   244       if (filt) {
       
   245         tmp = gst_caps_intersect (filt, res);
       
   246         gst_caps_unref (res);
       
   247         res = tmp;
       
   248         GST_DEBUG_OBJECT (pad,
       
   249             "filtered against template gives %" GST_PTR_FORMAT, res);
       
   250       }
       
   251     }
       
   252   } else {
       
   253     /* else, if we have a template, use its caps. */
       
   254     if (templ) {
       
   255       res = GST_PAD_TEMPLATE_CAPS (templ);
       
   256       GST_DEBUG_OBJECT (pad,
       
   257           "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
       
   258           res);
       
   259       res = gst_caps_ref (res);
       
   260       goto done;
       
   261     }
       
   262 
       
   263     /* last resort, any caps */
       
   264     GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
       
   265     res = gst_caps_new_any ();
       
   266   }
       
   267 
       
   268 done:
       
   269   return res;
       
   270 }
       
   271 
       
   272 static gboolean
       
   273 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
       
   274 {
       
   275   GstPad *target = gst_proxy_pad_get_target (pad);
       
   276   gboolean res;
       
   277 
       
   278   if (target) {
       
   279     res = gst_pad_accept_caps (target, caps);
       
   280     gst_object_unref (target);
       
   281   } else {
       
   282     /* We don't have a target, we return TRUE and we assume that any future
       
   283      * target will be able to deal with any configured caps. */
       
   284     res = TRUE;
       
   285   }
       
   286 
       
   287   return res;
       
   288 }
       
   289 
       
   290 static void
       
   291 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
       
   292 {
       
   293   GstPad *target = gst_proxy_pad_get_target (pad);
       
   294 
       
   295   if (target) {
       
   296     gst_pad_fixate_caps (target, caps);
       
   297     gst_object_unref (target);
       
   298   }
       
   299 }
       
   300 
       
   301 static gboolean
       
   302 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
       
   303 {
       
   304   GstPad *target = gst_proxy_pad_get_target (pad);
       
   305   gboolean res;
       
   306 
       
   307   if (target) {
       
   308     res = gst_pad_set_caps (target, caps);
       
   309     gst_object_unref (target);
       
   310   } else {
       
   311     /* We don't have any target, but we shouldn't return FALSE since this
       
   312      * would stop the actual push of a buffer (which might trigger a pad block
       
   313      * or probe, or properly return GST_FLOW_NOT_LINKED.
       
   314      */
       
   315     res = TRUE;
       
   316   }
       
   317   return res;
       
   318 }
       
   319 
       
   320 static gboolean
       
   321 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
       
   322 {
       
   323   GstPad *oldtarget;
       
   324 
       
   325   if (target) {
       
   326     GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
       
   327 
       
   328     if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
       
   329       goto wrong_direction;
       
   330   } else
       
   331     GST_LOG_OBJECT (pad, "clearing target");
       
   332 
       
   333   /* clear old target */
       
   334   if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
       
   335     gst_object_unref (oldtarget);
       
   336   }
       
   337   /* set and ref new target if any */
       
   338   if (target)
       
   339     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
       
   340   else
       
   341     GST_PROXY_PAD_TARGET (pad) = NULL;
       
   342 
       
   343   return TRUE;
       
   344 
       
   345   /* ERRORS */
       
   346 wrong_direction:
       
   347   {
       
   348     GST_ERROR_OBJECT (pad,
       
   349         "target pad doesn't have the same direction as ourself");
       
   350     return FALSE;
       
   351   }
       
   352 }
       
   353 
       
   354 static gboolean
       
   355 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
       
   356 {
       
   357   gboolean result;
       
   358 
       
   359   GST_PROXY_LOCK (pad);
       
   360   result = gst_proxy_pad_set_target_unlocked (pad, target);
       
   361   GST_PROXY_UNLOCK (pad);
       
   362 
       
   363   return result;
       
   364 }
       
   365 
       
   366 static GstPad *
       
   367 gst_proxy_pad_get_target (GstPad * pad)
       
   368 {
       
   369   GstPad *target;
       
   370 
       
   371   GST_PROXY_LOCK (pad);
       
   372   target = GST_PROXY_PAD_TARGET (pad);
       
   373   if (target)
       
   374     gst_object_ref (target);
       
   375   GST_PROXY_UNLOCK (pad);
       
   376 
       
   377   return target;
       
   378 }
       
   379 
       
   380 static void
       
   381 gst_proxy_pad_dispose (GObject * object)
       
   382 {
       
   383   GstPad *pad = GST_PAD (object);
       
   384   GstPad **target_p;
       
   385 
       
   386   GST_PROXY_LOCK (pad);
       
   387   /* remove and unref the target */
       
   388   target_p = &GST_PROXY_PAD_TARGET (pad);
       
   389   gst_object_replace ((GstObject **) target_p, NULL);
       
   390   /* The internal is only cleared by GstGhostPad::dispose, since it is the 
       
   391    * parent of non-ghost GstProxyPad and owns the refcount on the internal.
       
   392    */
       
   393   GST_PROXY_UNLOCK (pad);
       
   394 
       
   395   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
       
   396 }
       
   397 
       
   398 static void
       
   399 gst_proxy_pad_finalize (GObject * object)
       
   400 {
       
   401   GstProxyPad *pad = GST_PROXY_PAD (object);
       
   402 
       
   403   g_mutex_free (pad->proxy_lock);
       
   404   pad->proxy_lock = NULL;
       
   405 
       
   406   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
       
   407 }
       
   408 
       
   409 static void
       
   410 gst_proxy_pad_init (GstProxyPad * ppad)
       
   411 {
       
   412   GstPad *pad = (GstPad *) ppad;
       
   413 
       
   414   ppad->proxy_lock = g_mutex_new ();
       
   415 
       
   416   gst_pad_set_query_type_function (pad,
       
   417       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
       
   418   gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
       
   419   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
       
   420   gst_pad_set_internal_link_function (pad,
       
   421       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
       
   422 
       
   423   gst_pad_set_getcaps_function (pad,
       
   424       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
       
   425   gst_pad_set_acceptcaps_function (pad,
       
   426       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
       
   427   gst_pad_set_fixatecaps_function (pad,
       
   428       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
       
   429   gst_pad_set_setcaps_function (pad,
       
   430       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
       
   431 }
       
   432 
       
   433 #ifndef GST_DISABLE_LOADSAVE
       
   434 /**
       
   435  * gst_proxy_pad_save_thyself:
       
   436  * @pad: a ghost #GstPad to save.
       
   437  * @parent: the parent #xmlNodePtr to save the description in.
       
   438  *
       
   439  * Saves the ghost pad into an xml representation.
       
   440  *
       
   441  * Returns: the #xmlNodePtr representation of the pad.
       
   442  */
       
   443 static xmlNodePtr
       
   444 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
       
   445 {
       
   446   xmlNodePtr self;
       
   447   GstProxyPad *proxypad;
       
   448   GstPad *pad;
       
   449   GstPad *peer;
       
   450 
       
   451   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
       
   452 
       
   453   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
       
   454   xmlNewChild (self, NULL, (xmlChar *) "name",
       
   455       (xmlChar *) GST_OBJECT_NAME (object));
       
   456   xmlNewChild (self, NULL, (xmlChar *) "parent",
       
   457       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
       
   458 
       
   459   proxypad = GST_PROXY_PAD_CAST (object);
       
   460   pad = GST_PAD_CAST (proxypad);
       
   461   peer = GST_PAD_CAST (pad->peer);
       
   462 
       
   463   if (GST_IS_PAD (pad)) {
       
   464     if (GST_PAD_IS_SRC (pad))
       
   465       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source");
       
   466     else if (GST_PAD_IS_SINK (pad))
       
   467       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink");
       
   468     else
       
   469       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
       
   470   } else {
       
   471     xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
       
   472   }
       
   473   if (GST_IS_PAD (peer)) {
       
   474     gchar *content = g_strdup_printf ("%s.%s",
       
   475         GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
       
   476 
       
   477     xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content);
       
   478     g_free (content);
       
   479   } else {
       
   480     xmlNewChild (self, NULL, (xmlChar *) "peer", NULL);
       
   481   }
       
   482 
       
   483   return self;
       
   484 }
       
   485 #endif /* GST_DISABLE_LOADSAVE */
       
   486 
       
   487 
       
   488 /***********************************************************************
       
   489  * Ghost pads, implemented as a pair of proxy pads (sort of)
       
   490  */
       
   491 
       
   492 
       
   493 struct _GstGhostPad
       
   494 {
       
   495   GstProxyPad pad;
       
   496 
       
   497   /* with PROXY_LOCK */
       
   498   gulong notify_id;
       
   499 
       
   500   /*< private > */
       
   501   gpointer _gst_reserved[GST_PADDING];
       
   502 };
       
   503 
       
   504 struct _GstGhostPadClass
       
   505 {
       
   506   GstProxyPadClass parent_class;
       
   507 
       
   508   /*< private > */
       
   509   gpointer _gst_reserved[GST_PADDING];
       
   510 };
       
   511 
       
   512 
       
   513 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
       
   514 
       
   515 static void gst_ghost_pad_dispose (GObject * object);
       
   516 
       
   517 static void
       
   518 gst_ghost_pad_class_init (GstGhostPadClass * klass)
       
   519 {
       
   520   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   521 
       
   522   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
       
   523 }
       
   524 
       
   525 /* see gstghostpad design docs */
       
   526 static gboolean
       
   527 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
       
   528 {
       
   529   gboolean ret;
       
   530   GstPad *other;
       
   531 
       
   532   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
       
   533       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
       
   534 
       
   535   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
       
   536    * will be activated later (or already in case of a ghost sinkpad). */
       
   537   other = GST_PROXY_PAD_INTERNAL (pad);
       
   538   ret = gst_pad_activate_push (other, active);
       
   539 
       
   540   return ret;
       
   541 }
       
   542 
       
   543 static gboolean
       
   544 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
       
   545 {
       
   546   gboolean ret;
       
   547   GstPad *other;
       
   548 
       
   549   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
       
   550       GST_DEBUG_PAD_NAME (pad));
       
   551 
       
   552   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
       
   553     /* we are activated in pull mode by our peer element, which is a sinkpad
       
   554      * that wants to operate in pull mode. This activation has to propagate
       
   555      * upstream throught the pipeline. We call the internal activation function,
       
   556      * which will trigger gst_ghost_pad_do_activate_pull, which propagates even
       
   557      * further upstream */
       
   558     GST_LOG_OBJECT (pad, "pad is src, activate internal");
       
   559     other = GST_PROXY_PAD_INTERNAL (pad);
       
   560     ret = gst_pad_activate_pull (other, active);
       
   561   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
       
   562     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
       
   563      * since we hold a pointer to the upstream peer. */
       
   564     GST_LOG_OBJECT (pad, "activating peer");
       
   565     ret = gst_pad_activate_pull (other, active);
       
   566     gst_object_unref (other);
       
   567   } else {
       
   568     /* this is failure, we can't activate pull if there is no peer */
       
   569     GST_LOG_OBJECT (pad, "not src and no peer, failing");
       
   570     ret = FALSE;
       
   571   }
       
   572 
       
   573   return ret;
       
   574 }
       
   575 
       
   576 static gboolean
       
   577 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
       
   578 {
       
   579   gboolean ret;
       
   580   GstPad *other;
       
   581 
       
   582   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
       
   583       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
       
   584 
       
   585   /* just activate the internal pad */
       
   586   other = GST_PROXY_PAD_INTERNAL (pad);
       
   587   ret = gst_pad_activate_push (other, active);
       
   588 
       
   589   return ret;
       
   590 }
       
   591 
       
   592 static gboolean
       
   593 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
       
   594 {
       
   595   gboolean ret;
       
   596   GstPad *other;
       
   597 
       
   598   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
       
   599       GST_DEBUG_PAD_NAME (pad));
       
   600 
       
   601   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
       
   602     /* the ghostpad is SRC and activated in pull mode by its peer, call the
       
   603      * activation function of the internal pad to propagate the activation
       
   604      * upstream */
       
   605     GST_LOG_OBJECT (pad, "pad is src, activate internal");
       
   606     other = GST_PROXY_PAD_INTERNAL (pad);
       
   607     ret = gst_pad_activate_pull (other, active);
       
   608   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
       
   609     /* We are SINK and activated by the internal pad, propagate activation
       
   610      * upstream because we hold a ref to the upstream peer */
       
   611     GST_LOG_OBJECT (pad, "activating peer");
       
   612     ret = gst_pad_activate_pull (other, active);
       
   613     gst_object_unref (other);
       
   614   } else {
       
   615     /* no peer, we fail */
       
   616     GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
       
   617     ret = FALSE;
       
   618   }
       
   619 
       
   620   return ret;
       
   621 }
       
   622 
       
   623 static GstPadLinkReturn
       
   624 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
       
   625 {
       
   626   GstPadLinkReturn ret;
       
   627   GstPad *internal;
       
   628 
       
   629   GST_DEBUG_OBJECT (pad, "linking ghostpad");
       
   630 
       
   631   internal = GST_PROXY_PAD_INTERNAL (pad);
       
   632   if (!gst_proxy_pad_set_target (internal, peer))
       
   633     goto target_failed;
       
   634 
       
   635   ret = GST_PAD_LINK_OK;
       
   636   /* if we are a source pad, we should call the peer link function
       
   637    * if the peer has one, see design docs. */
       
   638   if (GST_PAD_IS_SRC (pad)) {
       
   639     if (GST_PAD_LINKFUNC (peer)) {
       
   640       ret = GST_PAD_LINKFUNC (peer) (peer, pad);
       
   641       if (ret != GST_PAD_LINK_OK)
       
   642         goto link_failed;
       
   643     }
       
   644   }
       
   645   return ret;
       
   646 
       
   647   /* ERRORS */
       
   648 target_failed:
       
   649   {
       
   650     GST_DEBUG_OBJECT (pad, "setting target failed");
       
   651     return GST_PAD_LINK_REFUSED;
       
   652   }
       
   653 link_failed:
       
   654   {
       
   655     GST_DEBUG_OBJECT (pad, "linking failed");
       
   656     /* clear target again */
       
   657     gst_proxy_pad_set_target (internal, NULL);
       
   658     return ret;
       
   659   }
       
   660 }
       
   661 
       
   662 static void
       
   663 gst_ghost_pad_do_unlink (GstPad * pad)
       
   664 {
       
   665   GstPad *target;
       
   666   GstPad *internal;
       
   667 
       
   668   target = gst_proxy_pad_get_target (pad);
       
   669   internal = GST_PROXY_PAD_INTERNAL (pad);
       
   670 
       
   671   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
       
   672 
       
   673   /* The target of the internal pad is no longer valid */
       
   674   gst_proxy_pad_set_target (internal, NULL);
       
   675 
       
   676   if (target) {
       
   677     if (GST_PAD_UNLINKFUNC (target))
       
   678       GST_PAD_UNLINKFUNC (target) (target);
       
   679 
       
   680     gst_object_unref (target);
       
   681   }
       
   682 }
       
   683 
       
   684 static void
       
   685 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
       
   686 {
       
   687   GstCaps *caps;
       
   688 
       
   689   g_object_get (internal, "caps", &caps, NULL);
       
   690 
       
   691   GST_OBJECT_LOCK (pad);
       
   692   gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
       
   693   GST_OBJECT_UNLOCK (pad);
       
   694 
       
   695   g_object_notify (G_OBJECT (pad), "caps");
       
   696   if (caps)
       
   697     gst_caps_unref (caps);
       
   698 }
       
   699 
       
   700 static void
       
   701 gst_ghost_pad_init (GstGhostPad * pad)
       
   702 {
       
   703   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
       
   704       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
       
   705   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
       
   706       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
       
   707 }
       
   708 
       
   709 static void
       
   710 gst_ghost_pad_dispose (GObject * object)
       
   711 {
       
   712   GstPad *pad;
       
   713   GstPad *internal;
       
   714   GstPad *intpeer;
       
   715 
       
   716   pad = GST_PAD (object);
       
   717 
       
   718   GST_DEBUG_OBJECT (pad, "dispose");
       
   719 
       
   720   GST_PROXY_LOCK (pad);
       
   721   internal = GST_PROXY_PAD_INTERNAL (pad);
       
   722 
       
   723   gst_pad_set_activatepull_function (internal, NULL);
       
   724   gst_pad_set_activatepush_function (internal, NULL);
       
   725 
       
   726   g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id);
       
   727 
       
   728   intpeer = gst_pad_get_peer (internal);
       
   729   if (intpeer) {
       
   730     if (GST_PAD_IS_SRC (internal))
       
   731       gst_pad_unlink (internal, intpeer);
       
   732     else
       
   733       gst_pad_unlink (intpeer, internal);
       
   734 
       
   735     gst_object_unref (intpeer);
       
   736   }
       
   737 
       
   738   GST_PROXY_PAD_INTERNAL (internal) = NULL;
       
   739 
       
   740   /* disposes of the internal pad, since the ghostpad is the only possible object
       
   741    * that has a refcount on the internal pad. */
       
   742   gst_object_unparent (GST_OBJECT_CAST (internal));
       
   743 
       
   744   GST_PROXY_UNLOCK (pad);
       
   745 
       
   746   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
       
   747 }
       
   748 
       
   749 static GstPad *
       
   750 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
       
   751     GstPadTemplate * templ)
       
   752 {
       
   753   GstPad *ret;
       
   754   GstPad *internal;
       
   755   GstPadDirection otherdir;
       
   756 
       
   757   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
       
   758 
       
   759   /* OBJECT CREATION */
       
   760   if (templ) {
       
   761     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
       
   762         "direction", dir, "template", templ, NULL);
       
   763   } else {
       
   764     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
       
   765         "direction", dir, NULL);
       
   766   }
       
   767 
       
   768   /* Set directional padfunctions for ghostpad */
       
   769   if (dir == GST_PAD_SINK) {
       
   770     gst_pad_set_bufferalloc_function (ret,
       
   771         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
       
   772     gst_pad_set_chain_function (ret,
       
   773         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
       
   774   } else {
       
   775     gst_pad_set_getrange_function (ret,
       
   776         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
       
   777     gst_pad_set_checkgetrange_function (ret,
       
   778         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
       
   779   }
       
   780 
       
   781   /* link/unlink functions */
       
   782   gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
       
   783   gst_pad_set_unlink_function (ret,
       
   784       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
       
   785 
       
   786 
       
   787   /* INTERNAL PAD, it always exists and is child of the ghostpad */
       
   788   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
       
   789   if (templ) {
       
   790     internal =
       
   791         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
       
   792         "direction", otherdir, "template", templ, NULL);
       
   793   } else {
       
   794     internal =
       
   795         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
       
   796         "direction", otherdir, NULL);
       
   797   }
       
   798   GST_PAD_UNSET_FLUSHING (internal);
       
   799 
       
   800   /* Set directional padfunctions for internal pad */
       
   801   if (dir == GST_PAD_SRC) {
       
   802     gst_pad_set_bufferalloc_function (internal,
       
   803         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
       
   804     gst_pad_set_chain_function (internal,
       
   805         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
       
   806   } else {
       
   807     gst_pad_set_getrange_function (internal,
       
   808         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
       
   809     gst_pad_set_checkgetrange_function (internal,
       
   810         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
       
   811   }
       
   812 
       
   813   GST_PROXY_LOCK (ret);
       
   814 
       
   815   /* now make the ghostpad a parent of the internal pad */
       
   816   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
       
   817           GST_OBJECT_CAST (ret)))
       
   818     goto parent_failed;
       
   819 
       
   820   /* The ghostpad is the parent of the internal pad and is the only object that
       
   821    * can have a refcount on the internal pad.
       
   822    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
       
   823    * a refcount of 1.
       
   824    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
       
   825    * it's refcount on the internal pad in the dispose method by un-parenting it.
       
   826    * This is why we don't take extra refcounts in the assignments below
       
   827    */
       
   828   GST_PROXY_PAD_INTERNAL (ret) = internal;
       
   829   GST_PROXY_PAD_INTERNAL (internal) = ret;
       
   830 
       
   831   /* could be more general here, iterating over all writable properties...
       
   832    * taking the short road for now tho */
       
   833   GST_GHOST_PAD_CAST (ret)->notify_id =
       
   834       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
       
   835       ret);
       
   836 
       
   837   /* call function to init values of the pad caps */
       
   838   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (ret));
       
   839 
       
   840   /* special activation functions for the internal pad */
       
   841   gst_pad_set_activatepull_function (internal,
       
   842       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
       
   843   gst_pad_set_activatepush_function (internal,
       
   844       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
       
   845 
       
   846   GST_PROXY_UNLOCK (ret);
       
   847 
       
   848   return ret;
       
   849 
       
   850   /* ERRORS */
       
   851 parent_failed:
       
   852   {
       
   853     GST_WARNING_OBJECT (ret, "Could not set internal pad %s:%s",
       
   854         GST_DEBUG_PAD_NAME (internal));
       
   855     g_critical ("Could not set internal pad %s:%s",
       
   856         GST_DEBUG_PAD_NAME (internal));
       
   857     GST_PROXY_UNLOCK (ret);
       
   858     gst_object_unref (ret);
       
   859     gst_object_unref (internal);
       
   860     return NULL;
       
   861   }
       
   862 }
       
   863 
       
   864 /**
       
   865  * gst_ghost_pad_new_no_target:
       
   866  * @name: the name of the new pad, or NULL to assign a default name.
       
   867  * @dir: the direction of the ghostpad
       
   868  *
       
   869  * Create a new ghostpad without a target with the given direction.
       
   870  * A target can be set on the ghostpad later with the
       
   871  * gst_ghost_pad_set_target() function.
       
   872  *
       
   873  * The created ghostpad will not have a padtemplate.
       
   874  *
       
   875  * Returns: a new #GstPad, or NULL in case of an error.
       
   876  */
       
   877 #ifdef __SYMBIAN32__
       
   878 EXPORT_C
       
   879 #endif
       
   880 
       
   881 GstPad *
       
   882 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
       
   883 {
       
   884   GstPad *ret;
       
   885 
       
   886   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
       
   887 
       
   888   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
       
   889 
       
   890   ret = gst_ghost_pad_new_full (name, dir, NULL);
       
   891 
       
   892   return ret;
       
   893 }
       
   894 
       
   895 /**
       
   896  * gst_ghost_pad_new:
       
   897  * @name: the name of the new pad, or NULL to assign a default name.
       
   898  * @target: the pad to ghost.
       
   899  *
       
   900  * Create a new ghostpad with @target as the target. The direction will be taken
       
   901  * from the target pad. @target must be unlinked.
       
   902  *
       
   903  * Will ref the target.
       
   904  *
       
   905  * Returns: a new #GstPad, or NULL in case of an error.
       
   906  */
       
   907 #ifdef __SYMBIAN32__
       
   908 EXPORT_C
       
   909 #endif
       
   910 
       
   911 GstPad *
       
   912 gst_ghost_pad_new (const gchar * name, GstPad * target)
       
   913 {
       
   914   GstPad *ret;
       
   915 
       
   916   g_return_val_if_fail (GST_IS_PAD (target), NULL);
       
   917   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
       
   918 
       
   919   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
       
   920       GST_DEBUG_PAD_NAME (target));
       
   921 
       
   922   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
       
   923     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
       
   924       goto set_target_failed;
       
   925 
       
   926   return ret;
       
   927 
       
   928   /* ERRORS */
       
   929 set_target_failed:
       
   930   {
       
   931     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
       
   932         GST_DEBUG_PAD_NAME (target));
       
   933     gst_object_unref (ret);
       
   934     return NULL;
       
   935   }
       
   936 }
       
   937 
       
   938 /**
       
   939  * gst_ghost_pad_new_from_template:
       
   940  * @name: the name of the new pad, or NULL to assign a default name.
       
   941  * @target: the pad to ghost.
       
   942  * @templ: the #GstPadTemplate to use on the ghostpad.
       
   943  *
       
   944  * Create a new ghostpad with @target as the target. The direction will be taken
       
   945  * from the target pad. The template used on the ghostpad will be @template.
       
   946  *
       
   947  * Will ref the target.
       
   948  *
       
   949  * Returns: a new #GstPad, or NULL in case of an error.
       
   950  *
       
   951  * Since: 0.10.10
       
   952  */
       
   953 #ifdef __SYMBIAN32__
       
   954 EXPORT_C
       
   955 #endif
       
   956 
       
   957 
       
   958 GstPad *
       
   959 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
       
   960     GstPadTemplate * templ)
       
   961 {
       
   962   GstPad *ret;
       
   963 
       
   964   g_return_val_if_fail (GST_IS_PAD (target), NULL);
       
   965   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
       
   966   g_return_val_if_fail (templ != NULL, NULL);
       
   967   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
       
   968       GST_PAD_DIRECTION (target), NULL);
       
   969 
       
   970   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
       
   971       GST_DEBUG_PAD_NAME (target), templ);
       
   972 
       
   973   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
       
   974     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
       
   975       goto set_target_failed;
       
   976 
       
   977   return ret;
       
   978 
       
   979   /* ERRORS */
       
   980 set_target_failed:
       
   981   {
       
   982     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
       
   983         GST_DEBUG_PAD_NAME (target));
       
   984     gst_object_unref (ret);
       
   985     return NULL;
       
   986   }
       
   987 }
       
   988 
       
   989 /**
       
   990  * gst_ghost_pad_new_no_target_from_template:
       
   991  * @name: the name of the new pad, or NULL to assign a default name.
       
   992  * @templ: the #GstPadTemplate to create the ghostpad from.
       
   993  *
       
   994  * Create a new ghostpad based on @templ, without setting a target. The
       
   995  * direction will be taken from the @templ.
       
   996  *
       
   997  * Returns: a new #GstPad, or NULL in case of an error.
       
   998  *
       
   999  * Since: 0.10.10
       
  1000  */
       
  1001 #ifdef __SYMBIAN32__
       
  1002 EXPORT_C
       
  1003 #endif
       
  1004 
       
  1005 GstPad *
       
  1006 gst_ghost_pad_new_no_target_from_template (const gchar * name,
       
  1007     GstPadTemplate * templ)
       
  1008 {
       
  1009   GstPad *ret;
       
  1010 
       
  1011   g_return_val_if_fail (templ != NULL, NULL);
       
  1012 
       
  1013   ret =
       
  1014       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
       
  1015 
       
  1016   return ret;
       
  1017 }
       
  1018 
       
  1019 /**
       
  1020  * gst_ghost_pad_get_target:
       
  1021  * @gpad: the #GstGhostpad
       
  1022  *
       
  1023  * Get the target pad of #gpad. Unref target pad after usage.
       
  1024  *
       
  1025  * Returns: the target #GstPad, can be NULL if the ghostpad
       
  1026  * has no target set. Unref target pad after usage.
       
  1027  */
       
  1028 #ifdef __SYMBIAN32__
       
  1029 EXPORT_C
       
  1030 #endif
       
  1031 
       
  1032 GstPad *
       
  1033 gst_ghost_pad_get_target (GstGhostPad * gpad)
       
  1034 {
       
  1035   GstPad *ret;
       
  1036 
       
  1037   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
       
  1038 
       
  1039   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
       
  1040 
       
  1041   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
       
  1042 
       
  1043   return ret;
       
  1044 }
       
  1045 
       
  1046 /**
       
  1047  * gst_ghost_pad_set_target:
       
  1048  * @gpad: the #GstGhostpad
       
  1049  * @newtarget: the new pad target
       
  1050  *
       
  1051  * Set the new target of the ghostpad @gpad. Any existing target
       
  1052  * is unlinked and links to the new target are established.
       
  1053  *
       
  1054  * Returns: TRUE if the new target could be set. This function can return FALSE
       
  1055  * when the internal pads could not be linked.
       
  1056  */
       
  1057 #ifdef __SYMBIAN32__
       
  1058 EXPORT_C
       
  1059 #endif
       
  1060 
       
  1061 gboolean
       
  1062 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
       
  1063 {
       
  1064   GstPad *internal;
       
  1065   GstPad *oldtarget;
       
  1066   gboolean result;
       
  1067   GstPadLinkReturn lret;
       
  1068 
       
  1069   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
       
  1070 
       
  1071   GST_PROXY_LOCK (gpad);
       
  1072   internal = GST_PROXY_PAD_INTERNAL (gpad);
       
  1073 
       
  1074   GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
       
  1075 
       
  1076   /* clear old target */
       
  1077   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
       
  1078     /* if we have an internal pad, unlink */
       
  1079     if (internal) {
       
  1080       if (GST_PAD_IS_SRC (internal))
       
  1081         gst_pad_unlink (internal, oldtarget);
       
  1082       else
       
  1083         gst_pad_unlink (oldtarget, internal);
       
  1084     }
       
  1085   }
       
  1086 
       
  1087   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
       
  1088 
       
  1089   if (result && newtarget) {
       
  1090     /* and link to internal pad */
       
  1091     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
       
  1092 
       
  1093     if (GST_PAD_IS_SRC (internal))
       
  1094       lret = gst_pad_link (internal, newtarget);
       
  1095     else
       
  1096       lret = gst_pad_link (newtarget, internal);
       
  1097 
       
  1098     if (lret != GST_PAD_LINK_OK)
       
  1099       goto link_failed;
       
  1100   }
       
  1101   GST_PROXY_UNLOCK (gpad);
       
  1102 
       
  1103   return result;
       
  1104 
       
  1105   /* ERRORS */
       
  1106 link_failed:
       
  1107   {
       
  1108     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
       
  1109         lret);
       
  1110     /* and unset target again */
       
  1111     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
       
  1112     GST_PROXY_UNLOCK (gpad);
       
  1113     return FALSE;
       
  1114   }
       
  1115 }