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>
7 * gstghostpad.c: Proxy pads
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.
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.
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.
27 * @short_description: Pseudo link pads
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.
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.
42 * Note that GhostPads add overhead to the data processing of a pipeline.
44 * Last reviewed on 2005-11-18 (0.9.5)
47 #include "gst_private.h"
49 #include "gstghostpad.h"
51 #define GST_TYPE_PROXY_PAD (gst_proxy_pad_get_type ())
52 #define GST_IS_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD))
53 #define GST_IS_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
54 #define GST_PROXY_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
55 #define GST_PROXY_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
56 #define GST_PROXY_PAD_CAST(obj) ((GstProxyPad *)obj)
58 #define GST_PROXY_PAD_TARGET(pad) (GST_PROXY_PAD (pad)->target)
59 #define GST_PROXY_PAD_INTERNAL(pad) (GST_PROXY_PAD (pad)->internal)
62 typedef struct _GstProxyPad GstProxyPad;
63 typedef struct _GstProxyPadClass GstProxyPadClass;
65 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD (pad)->proxy_lock)
66 #define GST_PROXY_LOCK(pad) (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
67 #define GST_PROXY_UNLOCK(pad) (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
79 struct _GstProxyPadClass
81 GstPadClass parent_class;
84 gpointer _gst_reserved[1];
88 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
90 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
91 static GstPad *gst_proxy_pad_get_internal (GstPad * pad);
93 static void gst_proxy_pad_dispose (GObject * object);
94 static void gst_proxy_pad_finalize (GObject * object);
96 #ifndef GST_DISABLE_LOADSAVE
97 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
103 gst_proxy_pad_class_init (GstProxyPadClass * klass)
105 GObjectClass *gobject_class = (GObjectClass *) klass;
107 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
108 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
110 #ifndef GST_DISABLE_LOADSAVE
112 GstObjectClass *gstobject_class = (GstObjectClass *) klass;
114 gstobject_class->save_thyself =
115 GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
121 gst_proxy_pad_do_query_type (GstPad * pad)
123 GstPad *target = gst_proxy_pad_get_target (pad);
124 const GstQueryType *res = NULL;
127 res = gst_pad_get_query_types (target);
128 gst_object_unref (target);
134 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
136 gboolean res = FALSE;
137 GstPad *internal = gst_proxy_pad_get_internal (pad);
139 g_return_val_if_fail (internal != NULL, FALSE);
141 res = gst_pad_push_event (internal, event);
142 gst_object_unref (internal);
148 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
150 gboolean res = FALSE;
151 GstPad *target = gst_proxy_pad_get_target (pad);
154 res = gst_pad_query (target, query);
155 gst_object_unref (target);
162 gst_proxy_pad_do_internal_link (GstPad * pad)
164 GstPad *target = gst_proxy_pad_get_target (pad);
168 res = gst_pad_get_internal_links (target);
169 gst_object_unref (target);
176 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
177 GstCaps * caps, GstBuffer ** buf)
179 GstFlowReturn result;
180 GstPad *internal = gst_proxy_pad_get_internal (pad);
182 g_return_val_if_fail (internal != NULL, GST_FLOW_NOT_LINKED);
184 result = gst_pad_alloc_buffer (internal, offset, size, caps, buf);
185 gst_object_unref (internal);
191 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
193 GstPad *internal = gst_proxy_pad_get_internal (pad);
196 g_return_val_if_fail (internal != NULL, GST_FLOW_NOT_LINKED);
198 res = gst_pad_push (internal, buffer);
199 gst_object_unref (internal);
205 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
208 GstPad *internal = gst_proxy_pad_get_internal (pad);
211 g_return_val_if_fail (internal != NULL, GST_FLOW_NOT_LINKED);
213 res = gst_pad_pull_range (internal, offset, size, buffer);
214 gst_object_unref (internal);
220 gst_proxy_pad_do_checkgetrange (GstPad * pad)
223 GstPad *internal = gst_proxy_pad_get_internal (pad);
225 g_return_val_if_fail (internal != NULL, FALSE);
227 result = gst_pad_check_pull_range (internal);
228 gst_object_unref (internal);
234 gst_proxy_pad_do_getcaps (GstPad * pad)
236 GstPad *target = gst_proxy_pad_get_target (pad);
240 /* if we have a real target, proxy the call */
241 GST_DEBUG_OBJECT (pad, "get caps of target");
242 res = gst_pad_get_caps (target);
243 gst_object_unref (target);
245 GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
247 /* else, if we have a template, use that */
249 res = GST_PAD_TEMPLATE_CAPS (templ);
250 GST_DEBUG_OBJECT (pad,
251 "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
253 res = gst_caps_ref (res);
257 /* last resort, any caps */
258 GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
259 res = gst_caps_new_any ();
267 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
269 GstPad *target = gst_proxy_pad_get_target (pad);
270 gboolean res = FALSE;
273 res = gst_pad_accept_caps (target, caps);
274 gst_object_unref (target);
281 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
283 GstPad *target = gst_proxy_pad_get_target (pad);
286 gst_pad_fixate_caps (target, caps);
287 gst_object_unref (target);
292 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
294 GstPad *target = gst_proxy_pad_get_target (pad);
298 res = gst_pad_set_caps (target, caps);
299 gst_object_unref (target);
301 /* We don't have any target, but we shouldn't return FALSE since this
302 * would stop the actual push of a buffer (which might trigger a pad block
303 * or probe, or properly return GST_FLOW_NOT_LINKED.
311 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
316 GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
318 if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
319 goto wrong_direction;
321 GST_LOG_OBJECT (pad, "clearing target");
323 /* clear old target */
324 if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
325 GST_PROXY_PAD_TARGET (pad) = NULL;
326 gst_object_unref (oldtarget);
329 /* set and ref new target if any */
331 GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
337 GST_ERROR_OBJECT (pad,
338 "target pad doesn't have the same direction as ourself");
344 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
348 GST_PROXY_LOCK (pad);
349 result = gst_proxy_pad_set_target_unlocked (pad, target);
350 GST_PROXY_UNLOCK (pad);
356 gst_proxy_pad_get_target (GstPad * pad)
360 GST_PROXY_LOCK (pad);
361 target = GST_PROXY_PAD_TARGET (pad);
363 gst_object_ref (target);
364 GST_PROXY_UNLOCK (pad);
370 gst_proxy_pad_get_internal (GstPad * pad)
374 GST_PROXY_LOCK (pad);
375 internal = GST_PROXY_PAD_INTERNAL (pad);
377 gst_object_ref (internal);
378 GST_PROXY_UNLOCK (pad);
384 gst_proxy_pad_dispose (GObject * object)
386 GstPad *pad = GST_PAD (object);
389 GST_PROXY_LOCK (pad);
390 /* remove and unref the target */
391 target_p = &GST_PROXY_PAD_TARGET (pad);
392 gst_object_replace ((GstObject **) target_p, NULL);
393 /* The internal is only cleared by GstGhostPad::dispose, since it is the
394 * parent of non-ghost GstProxyPad and owns the refcount on the internal.
396 GST_PROXY_UNLOCK (pad);
398 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
402 gst_proxy_pad_finalize (GObject * object)
404 GstProxyPad *pad = GST_PROXY_PAD (object);
406 g_mutex_free (pad->proxy_lock);
407 pad->proxy_lock = NULL;
409 G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
413 gst_proxy_pad_init (GstProxyPad * ppad)
415 GstPad *pad = (GstPad *) ppad;
417 ppad->proxy_lock = g_mutex_new ();
419 gst_pad_set_query_type_function (pad,
420 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
421 gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
422 gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
423 gst_pad_set_internal_link_function (pad,
424 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
425 gst_pad_set_getcaps_function (pad,
426 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
427 gst_pad_set_acceptcaps_function (pad,
428 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
429 gst_pad_set_fixatecaps_function (pad,
430 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
431 gst_pad_set_setcaps_function (pad,
432 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
436 #ifndef GST_DISABLE_LOADSAVE
438 * gst_proxy_pad_save_thyself:
439 * @pad: a ghost #GstPad to save.
440 * @parent: the parent #xmlNodePtr to save the description in.
442 * Saves the ghost pad into an xml representation.
444 * Returns: the #xmlNodePtr representation of the pad.
447 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
451 g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
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)));
459 /* FIXME FIXME FIXME! */
463 #endif /* GST_DISABLE_LOADSAVE */
466 /***********************************************************************
467 * Ghost pads, implemented as a pair of proxy pads (sort of)
475 /* with PROXY_LOCK */
479 gpointer _gst_reserved[GST_PADDING];
482 struct _GstGhostPadClass
484 GstProxyPadClass parent_class;
487 gpointer _gst_reserved[GST_PADDING];
491 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
493 static void gst_ghost_pad_dispose (GObject * object);
495 /* Work around g_logv's use of G_GNUC_PRINTF because gcc chokes on %P, which we
496 * use for GST_PTR_FORMAT. */
498 gst_critical (const gchar * format, ...)
502 va_start (args, format);
503 g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
508 * The parent_set and parent_unset are used to make sure that:
509 * _ the internal and target are only linked when the GhostPad has a parent,
510 * _ the internal and target are unlinked as soon as the GhostPad is removed
515 gst_ghost_pad_parent_set (GstObject * object, GstObject * parent)
517 GstPad *gpad = GST_PAD (object);
518 GstPad *target = gst_proxy_pad_get_target (gpad);
519 GstPad *internal = gst_proxy_pad_get_internal (gpad);
522 if (GST_PAD_IS_SRC (internal))
523 gst_pad_link (internal, target);
525 gst_pad_link (target, internal);
526 gst_object_unref (target);
528 gst_object_unref (internal);
530 if (GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_set)
531 GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_set (object, parent);
535 gst_ghost_pad_parent_unset (GstObject * object, GstObject * parent)
537 GstPad *gpad = GST_PAD (object);
538 GstPad *target = gst_proxy_pad_get_target (gpad);
539 GstPad *internal = gst_proxy_pad_get_internal (gpad);
542 if (GST_PAD_IS_SRC (internal))
543 gst_pad_unlink (internal, target);
545 gst_pad_unlink (target, internal);
546 gst_object_unref (target);
548 gst_object_unref (internal);
550 if (GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_unset)
551 GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_unset (object,
557 gst_ghost_pad_class_init (GstGhostPadClass * klass)
559 GObjectClass *gobject_class = (GObjectClass *) klass;
560 GstObjectClass *gstobject_class = (GstObjectClass *) klass;
562 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
563 gstobject_class->parent_set = GST_DEBUG_FUNCPTR (gst_ghost_pad_parent_set);
564 gstobject_class->parent_unset =
565 GST_DEBUG_FUNCPTR (gst_ghost_pad_parent_unset);
568 /* see gstghostpad design docs */
570 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
574 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
575 GstPad *parent = gst_proxy_pad_get_internal (pad);
578 g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
580 ret = gst_pad_activate_push (parent, active);
582 gst_object_unref (parent);
587 GstPad *peer = gst_pad_get_peer (pad);
590 ret = gst_pad_activate_push (peer, active);
591 gst_object_unref (peer);
601 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
605 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
606 GstPad *peer = gst_pad_get_peer (pad);
609 ret = gst_pad_activate_pull (peer, active);
610 gst_object_unref (peer);
615 GstPad *parent = gst_proxy_pad_get_internal (pad);
618 g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
620 ret = gst_pad_activate_pull (parent, active);
622 gst_object_unref (parent);
632 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
636 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
637 GstPad *internal = gst_proxy_pad_get_internal (pad);
640 ret = gst_pad_activate_push (internal, active);
641 gst_object_unref (internal);
653 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
657 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
658 GstPad *peer = gst_pad_get_peer (pad);
661 ret = gst_pad_activate_pull (peer, active);
662 gst_object_unref (peer);
667 GstPad *internal = gst_proxy_pad_get_internal (pad);
670 ret = gst_pad_activate_pull (internal, active);
671 gst_object_unref (internal);
680 static GstPadLinkReturn
681 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
683 GstPad *internal, *target;
684 GstPadLinkReturn ret = GST_PAD_LINK_OK;
686 target = gst_proxy_pad_get_target (pad);
687 g_return_val_if_fail (target != NULL, GST_PAD_LINK_NOSCHED);
689 internal = gst_proxy_pad_get_internal (pad);
690 gst_proxy_pad_set_target (internal, peer);
692 /* if we are a source pad, we should call the peer link function
693 * if the peer has one */
694 if (GST_PAD_IS_SRC (pad)) {
695 if (GST_PAD_LINKFUNC (peer) && ret == GST_PAD_LINK_OK)
696 ret = GST_PAD_LINKFUNC (peer) (peer, pad);
699 gst_object_unref (target);
700 gst_object_unref (internal);
706 gst_ghost_pad_do_unlink (GstPad * pad)
708 GstPad *target = gst_proxy_pad_get_target (pad);
709 GstPad *internal = gst_proxy_pad_get_internal (pad);
711 GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
713 /* The target of the internal pad is no longer valid */
714 gst_proxy_pad_set_target (internal, NULL);
716 if (target && target->unlinkfunc)
717 target->unlinkfunc (target);
720 gst_object_unref (target);
721 gst_object_unref (internal);
725 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
729 g_object_get (internal, "caps", &caps, NULL);
731 GST_OBJECT_LOCK (pad);
732 gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
733 GST_OBJECT_UNLOCK (pad);
735 g_object_notify (G_OBJECT (pad), "caps");
737 gst_caps_unref (caps);
741 gst_ghost_pad_init (GstGhostPad * pad)
743 gst_pad_set_activatepull_function (GST_PAD (pad),
744 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
745 gst_pad_set_activatepush_function (GST_PAD (pad),
746 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
750 gst_ghost_pad_dispose (GObject * object)
752 GstPad *pad = GST_PAD (object);
756 GST_PROXY_LOCK (pad);
757 internal = GST_PROXY_PAD_INTERNAL (pad);
759 gst_pad_set_activatepull_function (internal, NULL);
760 gst_pad_set_activatepush_function (internal, NULL);
762 g_signal_handler_disconnect (internal, GST_GHOST_PAD (pad)->notify_id);
764 intpeer = gst_pad_get_peer (internal);
766 if (GST_PAD_IS_SRC (internal))
767 gst_pad_unlink (internal, intpeer);
769 gst_pad_unlink (intpeer, internal);
770 gst_object_unref (intpeer);
773 GST_PROXY_PAD_INTERNAL (internal) = NULL;
775 disposes of the internal pad, since the ghostpad is the only possible object
776 that has a refcount on the internal pad.
778 gst_object_unparent (GST_OBJECT_CAST (internal));
780 GST_PROXY_UNLOCK (pad);
782 G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
786 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
787 GstPadTemplate * templ)
792 g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
794 /* OBJECT CREATION */
796 ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
797 "direction", dir, "template", templ, NULL);
799 ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
800 "direction", dir, NULL);
803 /* Set directional padfunctions for ghostpad */
804 if (dir == GST_PAD_SINK) {
805 gst_pad_set_bufferalloc_function (ret,
806 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
807 gst_pad_set_chain_function (ret,
808 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
810 gst_pad_set_getrange_function (ret,
811 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
812 gst_pad_set_checkgetrange_function (ret,
813 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
816 gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
817 gst_pad_set_unlink_function (ret,
818 GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
824 g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
825 "direction", (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC, NULL);
827 /* Set directional padfunctions for internal pad */
828 if (dir == GST_PAD_SRC) {
829 gst_pad_set_bufferalloc_function (internal,
830 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
831 gst_pad_set_chain_function (internal,
832 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
834 gst_pad_set_getrange_function (internal,
835 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
836 gst_pad_set_checkgetrange_function (internal,
837 GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
840 GST_PROXY_LOCK (ret);
842 if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
843 GST_OBJECT_CAST (ret))) {
844 gst_critical ("Could not set internal pad%" GST_PTR_FORMAT, internal);
849 The ghostpad is the parent of the internal pad and is the only object that
850 can have a refcount on the internal pad.
851 At this point, the GstGhostPad has a refcount of 1, and the internal pad has
853 When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
854 it's refcount on the internal pad in the dispose method by un-parenting it.
855 This is why we don't take extra refcounts in the assignments below
857 GST_PROXY_PAD_INTERNAL (ret) = internal;
858 GST_PROXY_PAD_INTERNAL (internal) = GST_PAD (ret);
860 /* could be more general here, iterating over all writable properties...
861 * taking the short road for now tho */
862 GST_GHOST_PAD (ret)->notify_id = g_signal_connect (internal, "notify::caps",
863 G_CALLBACK (on_int_notify), ret);
864 on_int_notify (internal, NULL, GST_GHOST_PAD (ret));
865 gst_pad_set_activatepull_function (GST_PAD (internal),
866 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
867 gst_pad_set_activatepush_function (GST_PAD (internal),
868 GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
871 GST_PROXY_UNLOCK (ret);
877 * gst_ghost_pad_new_no_target:
878 * @name: the name of the new pad, or NULL to assign a default name.
879 * @dir: the direction of the ghostpad
881 * Create a new ghostpad without a target with the given direction.
882 * A target can be set on the ghostpad later with the
883 * gst_ghost_pad_set_target() function.
885 * The created ghostpad will not have a padtemplate.
887 * Returns: a new #GstPad, or NULL in case of an error.
890 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
892 g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
894 GST_LOG ("name:%s, direction:%d", name, dir);
896 return gst_ghost_pad_new_full (name, dir, NULL);
901 * @name: the name of the new pad, or NULL to assign a default name.
902 * @target: the pad to ghost.
904 * Create a new ghostpad with @target as the target. The direction will be taken
905 * from the target pad.
907 * Will ref the target.
909 * Returns: a new #GstPad, or NULL in case of an error.
912 gst_ghost_pad_new (const gchar * name, GstPad * target)
916 GST_LOG ("name:%s, target:%s:%s", name, GST_DEBUG_PAD_NAME (target));
918 g_return_val_if_fail (GST_IS_PAD (target), NULL);
919 g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
921 if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
922 if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
923 goto set_target_failed;
930 gst_object_unref (ret);
936 * gst_ghost_pad_new_from_template:
937 * @name: the name of the new pad, or NULL to assign a default name.
938 * @target: the pad to ghost.
939 * @templ: the #GstPadTemplate to use on the ghostpad.
941 * Create a new ghostpad with @target as the target. The direction will be taken
942 * from the target pad. The template used on the ghostpad will be @template.
944 * Will ref the target.
946 * Returns: a new #GstPad, or NULL in case of an error.
952 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
953 GstPadTemplate * templ)
957 g_return_val_if_fail (GST_IS_PAD (target), NULL);
958 g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
959 g_return_val_if_fail (templ != NULL, NULL);
960 g_return_val_if_fail (templ->direction == GST_PAD_DIRECTION (target), NULL);
962 if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
963 if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
964 goto set_target_failed;
971 gst_object_unref (ret);
977 * gst_ghost_pad_new_no_target_from_template:
978 * @name: the name of the new pad, or NULL to assign a default name.
979 * @templ: the #GstPadTemplate to create the ghostpad from.
981 * Create a new ghostpad based on @templ, without setting a target. The
982 * direction will be taken from @templ.
984 * Returns: a new #GstPad, or NULL in case of an error.
990 gst_ghost_pad_new_no_target_from_template (const gchar * name,
991 GstPadTemplate * templ)
995 g_return_val_if_fail (templ != NULL, NULL);
998 gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
1004 * gst_ghost_pad_get_target:
1005 * @gpad: the #GstGhostpad
1007 * Get the target pad of #gpad. Unref target pad after usage.
1009 * Returns: the target #GstPad, can be NULL if the ghostpad
1010 * has no target set. Unref target pad after usage.
1013 gst_ghost_pad_get_target (GstGhostPad * gpad)
1015 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
1017 return gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
1021 * gst_ghost_pad_set_target:
1022 * @gpad: the #GstGhostpad
1023 * @newtarget: the new pad target
1025 * Set the new target of the ghostpad @gpad. Any existing target
1026 * is unlinked and links to the new target are established.
1028 * Returns: TRUE if the new target could be set, FALSE otherwise.
1031 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1038 g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1040 GST_PROXY_LOCK (gpad);
1041 internal = GST_PROXY_PAD_INTERNAL (GST_PAD (gpad));
1043 GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1045 /* clear old target */
1046 if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1047 /* if we have an internal pad, unlink */
1049 if (GST_PAD_IS_SRC (internal))
1050 gst_pad_unlink (internal, oldtarget);
1052 gst_pad_unlink (oldtarget, internal);
1056 result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1058 if (result && newtarget) {
1059 /* and link to internal pad if we are not unparent-ed */
1060 if ((parent = gst_object_get_parent (GST_OBJECT (gpad)))) {
1061 if (GST_PAD_IS_SRC (internal))
1062 result = gst_pad_link (internal, newtarget);
1064 result = gst_pad_link (newtarget, internal);
1065 gst_object_unref (parent);
1067 /* we need to connect the internal pad once we have a parent */
1068 GST_DEBUG_OBJECT (gpad,
1069 "GhostPad doesn't have a parent, will connect internal pad later");
1072 GST_PROXY_UNLOCK (gpad);