gst/gstghostpad.c: add push activation of sink ghost pads.
[platform/upstream/gstreamer.git] / gst / gstghostpad.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Andy Wingo <wingo@pobox.com>
5  *
6  * gstghostpad.c: Proxy pads
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23 /**
24  * SECTION:gstghostpad
25  * @short_description: Pseudo link pads
26  * @see_also: #GstPad
27  *
28  */
29
30 #include "gst_private.h"
31
32 #include "gstghostpad.h"
33
34 #define GST_TYPE_PROXY_PAD              (gst_proxy_pad_get_type ())
35 #define GST_IS_PROXY_PAD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PROXY_PAD))
36 #define GST_IS_PROXY_PAD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_PROXY_PAD))
37 #define GST_PROXY_PAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
38 #define GST_PROXY_PAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
39 #define GST_PROXY_PAD_TARGET(pad)       (GST_PROXY_PAD (pad)->target)
40
41
42 typedef struct _GstProxyPad GstProxyPad;
43 typedef struct _GstProxyPadClass GstProxyPadClass;
44
45 #define GST_PROXY_GET_LOCK(pad) (GST_PROXY_PAD (pad)->proxy_lock)
46 #define GST_PROXY_LOCK(pad)     (g_mutex_lock (GST_PROXY_GET_LOCK (pad)))
47 #define GST_PROXY_UNLOCK(pad)   (g_mutex_unlock (GST_PROXY_GET_LOCK (pad)))
48
49 struct _GstProxyPad
50 {
51   GstPad pad;
52
53   /* with PROXY_LOCK */
54   GMutex *proxy_lock;
55   GstPad *target;
56
57   /*< private > */
58   gpointer _gst_reserved[1];
59 };
60
61 struct _GstProxyPadClass
62 {
63   GstPadClass parent_class;
64
65   /*< private > */
66   gpointer _gst_reserved[1];
67 };
68
69
70 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
71
72 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
73
74 static void gst_proxy_pad_dispose (GObject * object);
75 static void gst_proxy_pad_finalize (GObject * object);
76
77 #ifndef GST_DISABLE_LOADSAVE
78 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
79     xmlNodePtr parent);
80 #endif
81
82
83 static void
84 gst_proxy_pad_class_init (GstProxyPadClass * klass)
85 {
86   GObjectClass *gobject_class = (GObjectClass *) klass;
87
88   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
89   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_proxy_pad_finalize);
90
91 #ifndef GST_DISABLE_LOADSAVE
92   {
93     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
94
95     gstobject_class->save_thyself =
96         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
97   }
98 #endif
99 }
100
101 const GstQueryType *
102 gst_proxy_pad_do_query_type (GstPad * pad)
103 {
104   GstPad *target = gst_proxy_pad_get_target (pad);
105   const GstQueryType *res;
106
107   g_return_val_if_fail (target != NULL, NULL);
108
109   res = gst_pad_get_query_types (target);
110   gst_object_unref (target);
111
112   return res;
113 }
114
115 static gboolean
116 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
117 {
118   gboolean res;
119   GstPad *target = gst_proxy_pad_get_target (pad);
120
121   g_return_val_if_fail (target != NULL, FALSE);
122
123   res = gst_pad_send_event (target, event);
124   gst_object_unref (target);
125
126   return res;
127 }
128
129 static gboolean
130 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
131 {
132   gboolean res;
133   GstPad *target = gst_proxy_pad_get_target (pad);
134
135   g_return_val_if_fail (target != NULL, FALSE);
136
137   res = gst_pad_query (target, query);
138   gst_object_unref (target);
139
140   return res;
141 }
142
143 static GList *
144 gst_proxy_pad_do_internal_link (GstPad * pad)
145 {
146   GstPad *target = gst_proxy_pad_get_target (pad);
147   GList *res;
148
149   g_return_val_if_fail (target != NULL, NULL);
150
151   res = gst_pad_get_internal_links (target);
152   gst_object_unref (target);
153
154   return res;
155 }
156
157 static GstFlowReturn
158 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
159     GstCaps * caps, GstBuffer ** buf)
160 {
161   GstFlowReturn result;
162   GstPad *target = gst_proxy_pad_get_target (pad);
163   GstPad *peer;
164
165   g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
166
167   peer = gst_pad_get_peer (target);
168   if (peer) {
169     GST_DEBUG ("buffer alloc on %s:%s", GST_DEBUG_PAD_NAME (target));
170
171     result = gst_pad_alloc_buffer (peer, offset, size, caps, buf);
172
173     gst_object_unref (peer);
174   } else {
175     result = GST_FLOW_NOT_LINKED;
176   }
177
178   gst_object_unref (target);
179
180   return result;
181 }
182
183 static GstFlowReturn
184 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
185 {
186   GstPad *target = gst_proxy_pad_get_target (pad);
187   GstFlowReturn res;
188
189   g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
190
191   res = gst_pad_chain (target, buffer);
192   gst_object_unref (target);
193
194   return res;
195 }
196
197 static GstFlowReturn
198 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
199     GstBuffer ** buffer)
200 {
201   GstPad *target = gst_proxy_pad_get_target (pad);
202   GstFlowReturn res;
203
204   g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
205
206   res = gst_pad_get_range (target, offset, size, buffer);
207   gst_object_unref (target);
208
209   return res;
210 }
211
212 static gboolean
213 gst_proxy_pad_do_checkgetrange (GstPad * pad)
214 {
215   gboolean result;
216   GstPad *target = gst_proxy_pad_get_target (pad);
217   GstPad *peer;
218
219   g_return_val_if_fail (target != NULL, FALSE);
220
221   peer = gst_pad_get_peer (target);
222   if (peer) {
223     result = gst_pad_check_pull_range (peer);
224     gst_object_unref (peer);
225   } else {
226     result = FALSE;
227   }
228   gst_object_unref (target);
229
230   return result;
231 }
232
233 static GstCaps *
234 gst_proxy_pad_do_getcaps (GstPad * pad)
235 {
236   GstPad *target = gst_proxy_pad_get_target (pad);
237   GstCaps *res;
238
239   g_return_val_if_fail (target != NULL, NULL);
240
241   res = gst_pad_get_caps (target);
242   gst_object_unref (target);
243
244   return res;
245 }
246
247 static gboolean
248 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
249 {
250   GstPad *target = gst_proxy_pad_get_target (pad);
251   gboolean res;
252
253   g_return_val_if_fail (target != NULL, FALSE);
254
255   res = gst_pad_accept_caps (target, caps);
256   gst_object_unref (target);
257
258   return res;
259 }
260
261 static void
262 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
263 {
264   GstPad *target = gst_proxy_pad_get_target (pad);
265
266   g_return_if_fail (target != NULL);
267
268   gst_pad_fixate_caps (target, caps);
269   gst_object_unref (target);
270 }
271
272 static gboolean
273 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
274 {
275   GstPad *target = gst_proxy_pad_get_target (pad);
276   gboolean res;
277
278   g_return_val_if_fail (target != NULL, FALSE);
279
280   res = gst_pad_set_caps (target, caps);
281   gst_object_unref (target);
282
283   return res;
284 }
285
286 #define SETFUNC(member, kind) \
287   if (target->member) \
288     gst_pad_set_##kind##_function (pad, gst_proxy_pad_do_##kind)
289
290 static gboolean
291 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
292 {
293   GstPad *oldtarget;
294
295   GST_DEBUG ("set target %s:%s on %s:%s",
296       GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (pad));
297
298   /* clear old target */
299   if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
300     gst_object_unref (oldtarget);
301     GST_PROXY_PAD_TARGET (pad) = NULL;
302   }
303
304   if (target) {
305     /* set and ref new target if any */
306     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
307
308     /* really, all these should have default implementations so I can set them
309      * in the _init() instead of here */
310     SETFUNC (querytypefunc, query_type);
311     SETFUNC (eventfunc, event);
312     SETFUNC (queryfunc, query);
313     SETFUNC (intlinkfunc, internal_link);
314     SETFUNC (getcapsfunc, getcaps);
315     SETFUNC (acceptcapsfunc, acceptcaps);
316     SETFUNC (fixatecapsfunc, fixatecaps);
317     SETFUNC (setcapsfunc, setcaps);
318
319     if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
320       SETFUNC (bufferallocfunc, bufferalloc);
321       SETFUNC (chainfunc, chain);
322     } else {
323       SETFUNC (getrangefunc, getrange);
324       SETFUNC (checkgetrangefunc, checkgetrange);
325     }
326   }
327   return TRUE;
328 }
329
330 static gboolean
331 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
332 {
333   gboolean result;
334
335   GST_PROXY_LOCK (pad);
336   result = gst_proxy_pad_set_target_unlocked (pad, target);
337   GST_PROXY_UNLOCK (pad);
338
339   return result;
340 }
341
342 static GstPad *
343 gst_proxy_pad_get_target (GstPad * pad)
344 {
345   GstPad *target;
346
347   GST_PROXY_LOCK (pad);
348   target = GST_PROXY_PAD_TARGET (pad);
349   gst_object_ref (target);
350   GST_PROXY_UNLOCK (pad);
351
352   return target;
353 }
354
355 static void
356 gst_proxy_pad_init (GstProxyPad * pad)
357 {
358   pad->proxy_lock = g_mutex_new ();
359 }
360
361 static void
362 gst_proxy_pad_dispose (GObject * object)
363 {
364   GstPad *pad = GST_PAD (object);
365
366   GST_PROXY_LOCK (pad);
367   gst_object_replace ((GstObject **) & GST_PROXY_PAD_TARGET (pad), NULL);
368   GST_PROXY_UNLOCK (pad);
369
370   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
371 }
372
373 static void
374 gst_proxy_pad_finalize (GObject * object)
375 {
376   GstProxyPad *pad = GST_PROXY_PAD (object);
377
378   g_mutex_free (pad->proxy_lock);
379   pad->proxy_lock = NULL;
380
381   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
382 }
383
384 #ifndef GST_DISABLE_LOADSAVE
385 /**
386  * gst_proxy_pad_save_thyself:
387  * @pad: a ghost #GstPad to save.
388  * @parent: the parent #xmlNodePtr to save the description in.
389  *
390  * Saves the ghost pad into an xml representation.
391  *
392  * Returns: the #xmlNodePtr representation of the pad.
393  */
394 static xmlNodePtr
395 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
396 {
397   xmlNodePtr self;
398
399   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
400
401   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
402   xmlNewChild (self, NULL, (xmlChar *) "name",
403       (xmlChar *) GST_OBJECT_NAME (object));
404   xmlNewChild (self, NULL, (xmlChar *) "parent",
405       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
406
407   /* FIXME FIXME FIXME! */
408
409   return self;
410 }
411 #endif /* GST_DISABLE_LOADSAVE */
412
413
414 /***********************************************************************
415  * Ghost pads, implemented as a pair of proxy pads (sort of)
416  */
417
418
419 struct _GstGhostPad
420 {
421   GstProxyPad pad;
422
423   /* with PROXY_LOCK */
424   GstPad *internal;
425   gulong notify_id;
426
427   /*< private > */
428   gpointer _gst_reserved[GST_PADDING];
429 };
430
431 struct _GstGhostPadClass
432 {
433   GstProxyPadClass parent_class;
434
435   /*< private > */
436   gpointer _gst_reserved[GST_PADDING];
437 };
438
439
440 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
441
442 static gboolean gst_ghost_pad_set_internal (GstGhostPad * pad,
443     GstPad * internal);
444
445 static void gst_ghost_pad_dispose (GObject * object);
446
447 /* Work around g_logv's use of G_GNUC_PRINTF because gcc chokes on %P, which we
448  * use for GST_PTR_FORMAT. */
449 static void
450 gst_critical (const gchar * format, ...)
451 {
452   va_list args;
453
454   va_start (args, format);
455   g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, format, args);
456   va_end (args);
457 }
458
459 static GstPad *
460 gst_ghost_pad_get_internal (GstPad * pad)
461 {
462   GstPad *internal;
463
464   GST_PROXY_LOCK (pad);
465   internal = GST_GHOST_PAD (pad)->internal;
466   gst_object_ref (internal);
467   GST_PROXY_UNLOCK (pad);
468
469   return internal;
470 }
471
472 static void
473 gst_ghost_pad_class_init (GstGhostPadClass * klass)
474 {
475   GObjectClass *gobject_class = (GObjectClass *) klass;
476
477   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
478 }
479
480 /* see gstghostpad design docs */
481 static gboolean
482 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
483 {
484   gboolean ret;
485
486   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
487     GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
488
489     if (parent) {
490       g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
491
492       ret = gst_pad_activate_push (parent, active);
493
494       gst_object_unref (parent);
495     } else {
496       ret = FALSE;
497     }
498   } else {
499     GstPad *peer = gst_pad_get_peer (pad);
500
501     if (peer) {
502       ret = gst_pad_activate_push (peer, active);
503       gst_object_unref (peer);
504     } else {
505       ret = FALSE;
506     }
507   }
508
509   return ret;
510 }
511
512 static gboolean
513 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
514 {
515   gboolean ret;
516
517   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
518     GstPad *peer = gst_pad_get_peer (pad);
519
520     if (peer) {
521       ret = gst_pad_activate_pull (peer, active);
522       gst_object_unref (peer);
523     } else {
524       ret = FALSE;
525     }
526   } else {
527     GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
528
529     if (parent) {
530       g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
531
532       ret = gst_pad_activate_pull (parent, active);
533
534       gst_object_unref (parent);
535     } else {
536       ret = FALSE;
537     }
538   }
539
540   return ret;
541 }
542
543 static gboolean
544 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
545 {
546   gboolean ret;
547
548   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
549     GstPad *internal = gst_ghost_pad_get_internal (pad);
550
551     if (internal) {
552       ret = gst_pad_activate_push (internal, active);
553       gst_object_unref (internal);
554     } else {
555       ret = FALSE;
556     }
557   } else {
558     ret = TRUE;
559   }
560
561   return ret;
562 }
563
564 static gboolean
565 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
566 {
567   gboolean ret;
568
569   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
570     GstPad *peer = gst_pad_get_peer (pad);
571
572     if (peer) {
573       ret = gst_pad_activate_pull (peer, active);
574       gst_object_unref (peer);
575     } else {
576       ret = FALSE;
577     }
578   } else {
579     GstPad *internal = gst_ghost_pad_get_internal (pad);
580
581     if (internal) {
582       ret = gst_pad_activate_pull (internal, active);
583       gst_object_unref (internal);
584     } else {
585       ret = FALSE;
586     }
587   }
588
589   return ret;
590 }
591
592 static GstPadLinkReturn
593 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
594 {
595   GstPad *internal, *target;
596   GstPadLinkReturn ret;
597
598   target = gst_proxy_pad_get_target (pad);
599
600   g_return_val_if_fail (target != NULL, GST_PAD_LINK_NOSCHED);
601
602   /* proxy the peer into the bin */
603   internal = g_object_new (GST_TYPE_PROXY_PAD,
604       "name", NULL,
605       "direction", GST_PAD_DIRECTION (peer),
606       "template", GST_PAD_PAD_TEMPLATE (peer), NULL);
607
608   gst_proxy_pad_set_target (internal, peer);
609   gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), internal);
610
611   if (GST_PAD_IS_SRC (internal))
612     ret = gst_pad_link (internal, target);
613   else
614     ret = gst_pad_link (target, internal);
615
616   gst_object_unref (target);
617
618   if (ret == GST_PAD_LINK_OK)
619     gst_pad_set_active (internal, GST_PAD_ACTIVATE_MODE (pad));
620   else
621     gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL);
622
623   return ret;
624 }
625
626 static void
627 gst_ghost_pad_do_unlink (GstPad * pad)
628 {
629   GstPad *target = gst_proxy_pad_get_target (pad);
630
631   g_return_if_fail (target != NULL);
632
633   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
634
635   if (target->unlinkfunc)
636     target->unlinkfunc (target);
637
638   gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL);
639
640   gst_object_unref (target);
641 }
642
643 static void
644 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
645 {
646   GstCaps *caps;
647
648   g_object_get (internal, "caps", &caps, NULL);
649
650   GST_LOCK (pad);
651   gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
652   GST_UNLOCK (pad);
653
654   g_object_notify (G_OBJECT (pad), "caps");
655   if (caps)
656     gst_caps_unref (caps);
657 }
658
659 static gboolean
660 gst_ghost_pad_set_internal (GstGhostPad * pad, GstPad * internal)
661 {
662   GST_PROXY_LOCK (pad);
663   /* first remove old internal pad */
664   if (pad->internal) {
665     GstPad *intpeer;
666
667     gst_pad_set_activatepull_function (pad->internal, NULL);
668     gst_pad_set_activatepush_function (pad->internal, NULL);
669
670     g_signal_handler_disconnect (pad->internal, pad->notify_id);
671
672     intpeer = gst_pad_get_peer (pad->internal);
673     if (intpeer) {
674       if (GST_PAD_IS_SRC (pad->internal))
675         gst_pad_unlink (pad->internal, intpeer);
676       else
677         gst_pad_unlink (intpeer, pad->internal);
678       gst_object_unref (intpeer);
679     }
680     /* should dispose it */
681     gst_object_unparent (GST_OBJECT_CAST (pad->internal));
682   }
683
684   /* then set new internal pad */
685   if (internal) {
686     if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
687             GST_OBJECT_CAST (pad)))
688       goto could_not_set;
689
690     /* could be more general here, iterating over all writable properties...
691      * taking the short road for now tho */
692     pad->notify_id = g_signal_connect (internal, "notify::caps",
693         G_CALLBACK (on_int_notify), pad);
694     on_int_notify (internal, NULL, pad);
695     gst_pad_set_activatepull_function (GST_PAD (internal),
696         gst_ghost_pad_internal_do_activate_pull);
697     gst_pad_set_activatepush_function (GST_PAD (internal),
698         gst_ghost_pad_internal_do_activate_push);
699     /* a ref was taken by set_parent */
700   }
701   pad->internal = internal;
702
703   GST_PROXY_UNLOCK (pad);
704
705   return TRUE;
706
707   /* ERRORS */
708 could_not_set:
709   {
710     gst_critical ("Could not set internal pad %" GST_PTR_FORMAT, internal);
711     GST_PROXY_UNLOCK (pad);
712     return FALSE;
713   }
714 }
715
716 static void
717 gst_ghost_pad_init (GstGhostPad * pad)
718 {
719   gst_pad_set_activatepull_function (GST_PAD (pad),
720       gst_ghost_pad_do_activate_pull);
721   gst_pad_set_activatepush_function (GST_PAD (pad),
722       gst_ghost_pad_do_activate_push);
723 }
724
725 static void
726 gst_ghost_pad_dispose (GObject * object)
727 {
728   gst_ghost_pad_set_internal (GST_GHOST_PAD (object), NULL);
729
730   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
731 }
732
733 /**
734  * gst_ghost_pad_new_notarget:
735  * @name: the name of the new pad, or NULL to assign a default name.
736  * @dir: the direction of the ghostpad
737  *
738  * Create a new ghostpad without a target with the given direction.
739  * A target can be set on the ghostpad later with the 
740  * #gst_ghost_pad_set_target() function.
741  *
742  * The created ghostpad will not have a padtemplate.
743  *
744  * Returns: a new #GstPad, or NULL in case of an error.
745  */
746 GstPad *
747 gst_ghost_pad_new_notarget (const gchar * name, GstPadDirection dir)
748 {
749   GstPad *ret;
750
751   ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "direction", dir, NULL);
752
753   gst_pad_set_activatepush_function (ret, gst_ghost_pad_do_activate_push);
754   gst_pad_set_link_function (ret, gst_ghost_pad_do_link);
755   gst_pad_set_unlink_function (ret, gst_ghost_pad_do_unlink);
756
757   return ret;
758 }
759
760 /**
761  * gst_ghost_pad_new:
762  * @name: the name of the new pad, or NULL to assign a default name.
763  * @target: the pad to ghost.
764  *
765  * Create a new ghostpad with @target as the target. The direction and
766  * padtemplate will be taken from the target pad.
767  *
768  * Will ref the target.
769  *
770  * Returns: a new #GstPad, or NULL in case of an error.
771  */
772 GstPad *
773 gst_ghost_pad_new (const gchar * name, GstPad * target)
774 {
775   GstPad *ret;
776
777   g_return_val_if_fail (GST_IS_PAD (target), NULL);
778   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
779
780   if ((ret = gst_ghost_pad_new_notarget (name, GST_PAD_DIRECTION (target)))) {
781     g_object_set (G_OBJECT (ret),
782         "template", GST_PAD_PAD_TEMPLATE (target), NULL);
783     gst_ghost_pad_set_target (GST_GHOST_PAD (ret), target);
784   }
785   return ret;
786 }
787
788 /**
789  * gst_ghost_pad_get_target:
790  * @gpad: the #GstGhostpad
791  *
792  * Get the target pad of #gpad. Unref after usage.
793  *
794  * Returns: the target #GstPad, can be NULL if the ghostpad
795  * has no target set. Unref after usage.
796  */
797 GstPad *
798 gst_ghost_pad_get_target (GstGhostPad * gpad)
799 {
800   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
801
802   return gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
803 }
804
805 /**
806  * gst_ghost_pad_set_target:
807  * @gpad: the #GstGhostpad
808  * @newtarget: the new pad target
809  *
810  * Set the new target of the ghostpad @gpad. Any existing target
811  * is unlinked.
812  *
813  * Returns: TRUE if the new target could be set, FALSE otherwise.
814  */
815 gboolean
816 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
817 {
818   GstPad *internal;
819   GstPad *oldtarget;
820   gboolean result;
821
822   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
823
824   GST_PROXY_LOCK (gpad);
825   internal = gpad->internal;
826
827   GST_DEBUG ("set target %s:%s on %s:%s",
828       GST_DEBUG_PAD_NAME (newtarget), GST_DEBUG_PAD_NAME (gpad));
829
830   /* clear old target */
831   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
832     /* if we have an internal pad, unlink */
833     if (internal) {
834       if (GST_PAD_IS_SRC (internal))
835         gst_pad_unlink (internal, oldtarget);
836       else
837         gst_pad_unlink (oldtarget, internal);
838     }
839   }
840
841   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
842
843   if (result && newtarget) {
844     /* and link to internal pad if we have one */
845     if (internal) {
846       if (GST_PAD_IS_SRC (internal))
847         result = gst_pad_link (internal, newtarget);
848       else
849         result = gst_pad_link (newtarget, internal);
850     }
851   }
852   GST_PROXY_UNLOCK (gpad);
853
854   return result;
855 }