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