ghostpad: fix locking
[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  *                    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 #define GST_CAT_DEFAULT GST_CAT_PADS
54
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)))
63
64 struct _GstProxyPadPrivate
65 {
66   /* with PROXY_LOCK */
67   GMutex *proxy_lock;
68   GstPad *target;
69   GstPad *internal;
70   gboolean retarget;
71 };
72
73 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
74
75 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
76
77 static void gst_proxy_pad_dispose (GObject * object);
78 static void gst_proxy_pad_finalize (GObject * object);
79
80 #ifndef GST_DISABLE_LOADSAVE
81 static xmlNodePtr gst_proxy_pad_save_thyself (GstObject * object,
82     xmlNodePtr parent);
83 #endif
84
85 static void on_src_target_notify (GstPad * target,
86     GParamSpec * unused, gpointer user_data);
87
88
89 static void
90 gst_proxy_pad_class_init (GstProxyPadClass * klass)
91 {
92   GObjectClass *gobject_class = (GObjectClass *) klass;
93
94   g_type_class_add_private (klass, sizeof (GstProxyPadPrivate));
95
96   gobject_class->dispose = gst_proxy_pad_dispose;
97   gobject_class->finalize = gst_proxy_pad_finalize;
98
99 #ifndef GST_DISABLE_LOADSAVE
100   {
101     GstObjectClass *gstobject_class = (GstObjectClass *) klass;
102
103     gstobject_class->save_thyself =
104         GST_DEBUG_FUNCPTR (gst_proxy_pad_save_thyself);
105   }
106 #endif
107 }
108
109 static const GstQueryType *
110 gst_proxy_pad_do_query_type (GstPad * pad)
111 {
112   GstPad *target = gst_proxy_pad_get_target (pad);
113   const GstQueryType *res = NULL;
114
115   if (target) {
116     res = gst_pad_get_query_types (target);
117     gst_object_unref (target);
118   }
119   return res;
120 }
121
122 static gboolean
123 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
124 {
125   gboolean res = FALSE;
126   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
127
128   res = gst_pad_push_event (internal, event);
129
130   return res;
131 }
132
133 static gboolean
134 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
135 {
136   gboolean res = FALSE;
137   GstPad *target = gst_proxy_pad_get_target (pad);
138
139   if (target) {
140     res = gst_pad_query (target, query);
141     gst_object_unref (target);
142   }
143
144   return res;
145 }
146
147 static GstIterator *
148 gst_proxy_pad_do_iterate_internal_links (GstPad * pad)
149 {
150   GstIterator *res = NULL;
151   GstPad *target = gst_proxy_pad_get_target (pad);
152
153   if (target) {
154     res = gst_pad_iterate_internal_links (target);
155     gst_object_unref (target);
156   }
157
158   return res;
159 }
160
161 static GstFlowReturn
162 gst_proxy_pad_do_bufferalloc (GstPad * pad, guint64 offset, guint size,
163     GstCaps * caps, GstBuffer ** buf)
164 {
165   GstFlowReturn result;
166   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
167
168   result = gst_pad_alloc_buffer (internal, offset, size, caps, buf);
169
170   return result;
171 }
172
173 static GstFlowReturn
174 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
175 {
176   GstFlowReturn res;
177   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
178
179   res = gst_pad_push (internal, buffer);
180
181   return res;
182 }
183
184 static GstFlowReturn
185 gst_proxy_pad_do_chain_list (GstPad * pad, GstBufferList * list)
186 {
187   GstFlowReturn res;
188   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
189
190   res = gst_pad_push_list (internal, list);
191
192   return res;
193 }
194
195 static GstFlowReturn
196 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
197     GstBuffer ** buffer)
198 {
199   GstFlowReturn res;
200   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
201
202   res = gst_pad_pull_range (internal, offset, size, buffer);
203
204   return res;
205 }
206
207 static gboolean
208 gst_proxy_pad_do_checkgetrange (GstPad * pad)
209 {
210   gboolean result;
211   GstPad *internal = GST_PROXY_PAD_INTERNAL (pad);
212
213   result = gst_pad_check_pull_range (internal);
214
215   return result;
216 }
217
218 static GstCaps *
219 gst_proxy_pad_do_getcaps (GstPad * pad)
220 {
221   GstPad *target = gst_proxy_pad_get_target (pad);
222   GstCaps *res;
223   GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
224
225   if (target) {
226     /* if we have a real target, proxy the call */
227     res = gst_pad_get_caps_reffed (target);
228
229     GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
230         GST_DEBUG_PAD_NAME (target), res);
231
232     gst_object_unref (target);
233
234     /* filter against the template */
235     if (templ && res) {
236       GstCaps *filt, *tmp;
237
238       filt = GST_PAD_TEMPLATE_CAPS (templ);
239       if (filt) {
240         tmp = gst_caps_intersect (filt, res);
241         gst_caps_unref (res);
242         res = tmp;
243         GST_DEBUG_OBJECT (pad,
244             "filtered against template gives %" GST_PTR_FORMAT, res);
245       }
246     }
247   } else {
248     /* else, if we have a template, use its caps. */
249     if (templ) {
250       res = GST_PAD_TEMPLATE_CAPS (templ);
251       GST_DEBUG_OBJECT (pad,
252           "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
253           res);
254       res = gst_caps_ref (res);
255       goto done;
256     }
257
258     /* last resort, any caps */
259     GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
260     res = gst_caps_new_any ();
261   }
262
263 done:
264   return res;
265 }
266
267 static gboolean
268 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
269 {
270   GstPad *target = gst_proxy_pad_get_target (pad);
271   gboolean res;
272
273   if (target) {
274     res = gst_pad_accept_caps (target, caps);
275     gst_object_unref (target);
276   } else {
277     /* We don't have a target, we return TRUE and we assume that any future
278      * target will be able to deal with any configured caps. */
279     res = TRUE;
280   }
281
282   return res;
283 }
284
285 static void
286 gst_proxy_pad_do_fixatecaps (GstPad * pad, GstCaps * caps)
287 {
288   GstPad *target = gst_proxy_pad_get_target (pad);
289
290   if (target) {
291     gst_pad_fixate_caps (target, caps);
292     gst_object_unref (target);
293   }
294 }
295
296 static gboolean
297 gst_proxy_pad_do_setcaps (GstPad * pad, GstCaps * caps)
298 {
299   GstPad *target = gst_proxy_pad_get_target (pad);
300   gboolean res;
301
302   if (target) {
303     res = gst_pad_set_caps (target, caps);
304     gst_object_unref (target);
305   } else {
306     /* We don't have any target, but we shouldn't return FALSE since this
307      * would stop the actual push of a buffer (which might trigger a pad block
308      * or probe, or properly return GST_FLOW_NOT_LINKED.
309      */
310     res = TRUE;
311   }
312   return res;
313 }
314
315 static gboolean
316 gst_proxy_pad_set_target_unlocked (GstPad * pad, GstPad * target)
317 {
318   GstPad *oldtarget;
319
320   if (target) {
321     GST_LOG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
322
323     if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target)))
324       goto wrong_direction;
325   } else
326     GST_LOG_OBJECT (pad, "clearing target");
327
328   /* clear old target */
329   if ((oldtarget = GST_PROXY_PAD_TARGET (pad)))
330     gst_object_unref (oldtarget);
331
332   /* set and ref new target if any */
333   if (target)
334     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
335   else
336     GST_PROXY_PAD_TARGET (pad) = NULL;
337
338   return TRUE;
339
340   /* ERRORS */
341 wrong_direction:
342   {
343     GST_ERROR_OBJECT (pad,
344         "target pad doesn't have the same direction as ourself");
345     return FALSE;
346   }
347 }
348
349 static gboolean
350 gst_proxy_pad_set_target (GstPad * pad, GstPad * target)
351 {
352   gboolean result;
353
354   GST_PROXY_LOCK (pad);
355   result = gst_proxy_pad_set_target_unlocked (pad, target);
356   GST_PROXY_UNLOCK (pad);
357
358   return result;
359 }
360
361 static GstPad *
362 gst_proxy_pad_get_target (GstPad * pad)
363 {
364   GstPad *target;
365
366   GST_PROXY_LOCK (pad);
367   target = GST_PROXY_PAD_TARGET (pad);
368   if (target)
369     gst_object_ref (target);
370   GST_PROXY_UNLOCK (pad);
371
372   return target;
373 }
374
375 static void
376 gst_proxy_pad_do_unlink (GstPad * pad)
377 {
378   GstPad *internal;
379
380   /* don't do anything if this unlink resulted from retargeting the pad
381    * controlled by the ghostpad. We only want to invalidate the target pad when
382    * the element suddently unlinked with our internal pad. */
383   if (GST_PROXY_PAD_RETARGET (pad))
384     return;
385
386   internal = GST_PROXY_PAD_INTERNAL (pad);
387
388   GST_DEBUG_OBJECT (pad, "pad is unlinked");
389
390   gst_proxy_pad_set_target (internal, NULL);
391 }
392
393 static void
394 gst_proxy_pad_dispose (GObject * object)
395 {
396   GstPad *pad = GST_PAD (object);
397   GstPad **target_p;
398
399   GST_PROXY_LOCK (pad);
400   /* remove and unref the target */
401   target_p = &GST_PROXY_PAD_TARGET (pad);
402   gst_object_replace ((GstObject **) target_p, NULL);
403   /* The internal is only cleared by GstGhostPad::dispose, since it is the 
404    * parent of non-ghost GstProxyPad and owns the refcount on the internal.
405    */
406   GST_PROXY_UNLOCK (pad);
407
408   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->dispose (object);
409 }
410
411 static void
412 gst_proxy_pad_finalize (GObject * object)
413 {
414   GstProxyPad *pad = GST_PROXY_PAD (object);
415
416   g_mutex_free (GST_PROXY_GET_LOCK (pad));
417   GST_PROXY_GET_LOCK (pad) = NULL;
418
419   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
420 }
421
422 static void
423 gst_proxy_pad_init (GstProxyPad * ppad)
424 {
425   GstPad *pad = (GstPad *) ppad;
426
427   GST_PROXY_PAD_PRIVATE (ppad) = G_TYPE_INSTANCE_GET_PRIVATE (ppad,
428       GST_TYPE_PROXY_PAD, GstProxyPadPrivate);
429   GST_PROXY_GET_LOCK (pad) = g_mutex_new ();
430
431   gst_pad_set_query_type_function (pad,
432       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
433   gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
434   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
435   gst_pad_set_iterate_internal_links_function (pad,
436       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_iterate_internal_links));
437
438   gst_pad_set_getcaps_function (pad,
439       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
440   gst_pad_set_acceptcaps_function (pad,
441       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
442   gst_pad_set_fixatecaps_function (pad,
443       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
444   gst_pad_set_setcaps_function (pad,
445       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
446   gst_pad_set_unlink_function (pad,
447       GST_DEBUG_FUNCPTR (gst_proxy_pad_do_unlink));
448 }
449
450 #ifndef GST_DISABLE_LOADSAVE
451 /**
452  * gst_proxy_pad_save_thyself:
453  * @pad: a ghost #GstPad to save.
454  * @parent: the parent #xmlNodePtr to save the description in.
455  *
456  * Saves the ghost pad into an xml representation.
457  *
458  * Returns: the #xmlNodePtr representation of the pad.
459  */
460 static xmlNodePtr
461 gst_proxy_pad_save_thyself (GstObject * object, xmlNodePtr parent)
462 {
463   xmlNodePtr self;
464   GstProxyPad *proxypad;
465   GstPad *pad;
466   GstPad *peer;
467
468   g_return_val_if_fail (GST_IS_PROXY_PAD (object), NULL);
469
470   self = xmlNewChild (parent, NULL, (xmlChar *) "ghostpad", NULL);
471   xmlNewChild (self, NULL, (xmlChar *) "name",
472       (xmlChar *) GST_OBJECT_NAME (object));
473   xmlNewChild (self, NULL, (xmlChar *) "parent",
474       (xmlChar *) GST_OBJECT_NAME (GST_OBJECT_PARENT (object)));
475
476   proxypad = GST_PROXY_PAD_CAST (object);
477   pad = GST_PAD_CAST (proxypad);
478   peer = GST_PAD_CAST (pad->peer);
479
480   if (GST_IS_PAD (pad)) {
481     if (GST_PAD_IS_SRC (pad))
482       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "source");
483     else if (GST_PAD_IS_SINK (pad))
484       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "sink");
485     else
486       xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
487   } else {
488     xmlNewChild (self, NULL, (xmlChar *) "direction", (xmlChar *) "unknown");
489   }
490   if (GST_IS_PAD (peer)) {
491     gchar *content = g_strdup_printf ("%s.%s",
492         GST_OBJECT_NAME (GST_PAD_PARENT (peer)), GST_PAD_NAME (peer));
493
494     xmlNewChild (self, NULL, (xmlChar *) "peer", (xmlChar *) content);
495     g_free (content);
496   } else {
497     xmlNewChild (self, NULL, (xmlChar *) "peer", NULL);
498   }
499
500   return self;
501 }
502 #endif /* GST_DISABLE_LOADSAVE */
503
504
505 /***********************************************************************
506  * Ghost pads, implemented as a pair of proxy pads (sort of)
507  */
508
509
510 #define GST_GHOST_PAD_PRIVATE(obj)      (GST_GHOST_PAD_CAST (obj)->priv)
511
512 struct _GstGhostPadPrivate
513 {
514   /* with PROXY_LOCK */
515   gulong notify_id;
516
517   gboolean constructed;
518 };
519
520 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
521
522 static void gst_ghost_pad_dispose (GObject * object);
523
524 static void
525 gst_ghost_pad_class_init (GstGhostPadClass * klass)
526 {
527   GObjectClass *gobject_class = (GObjectClass *) klass;
528
529   g_type_class_add_private (klass, sizeof (GstGhostPadPrivate));
530
531   gobject_class->dispose = gst_ghost_pad_dispose;
532 }
533
534 /* see gstghostpad design docs */
535 static gboolean
536 gst_ghost_pad_internal_do_activate_push (GstPad * pad, gboolean active)
537 {
538   gboolean ret;
539   GstPad *other;
540
541   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
542       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
543
544   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
545    * will be activated later (or already in case of a ghost sinkpad). */
546   other = GST_PROXY_PAD_INTERNAL (pad);
547   ret = gst_pad_activate_push (other, active);
548
549   return ret;
550 }
551
552 static gboolean
553 gst_ghost_pad_internal_do_activate_pull (GstPad * pad, gboolean active)
554 {
555   gboolean ret;
556   GstPad *other;
557
558   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
559       GST_DEBUG_PAD_NAME (pad));
560
561   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
562     /* we are activated in pull mode by our peer element, which is a sinkpad
563      * that wants to operate in pull mode. This activation has to propagate
564      * upstream throught the pipeline. We call the internal activation function,
565      * which will trigger gst_ghost_pad_do_activate_pull, which propagates even
566      * further upstream */
567     GST_LOG_OBJECT (pad, "pad is src, activate internal");
568     other = GST_PROXY_PAD_INTERNAL (pad);
569     ret = gst_pad_activate_pull (other, active);
570   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
571     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
572      * since we hold a pointer to the upstream peer. */
573     GST_LOG_OBJECT (pad, "activating peer");
574     ret = gst_pad_activate_pull (other, active);
575     gst_object_unref (other);
576   } else {
577     /* this is failure, we can't activate pull if there is no peer */
578     GST_LOG_OBJECT (pad, "not src and no peer, failing");
579     ret = FALSE;
580   }
581
582   return ret;
583 }
584
585 static gboolean
586 gst_ghost_pad_do_activate_push (GstPad * pad, gboolean active)
587 {
588   gboolean ret;
589   GstPad *other;
590
591   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
592       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
593
594   /* just activate the internal pad */
595   other = GST_PROXY_PAD_INTERNAL (pad);
596   ret = gst_pad_activate_push (other, active);
597
598   return ret;
599 }
600
601 static gboolean
602 gst_ghost_pad_do_activate_pull (GstPad * pad, gboolean active)
603 {
604   gboolean ret;
605   GstPad *other;
606
607   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
608       GST_DEBUG_PAD_NAME (pad));
609
610   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
611     /* the ghostpad is SRC and activated in pull mode by its peer, call the
612      * activation function of the internal pad to propagate the activation
613      * upstream */
614     GST_LOG_OBJECT (pad, "pad is src, activate internal");
615     other = GST_PROXY_PAD_INTERNAL (pad);
616     ret = gst_pad_activate_pull (other, active);
617   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
618     /* We are SINK and activated by the internal pad, propagate activation
619      * upstream because we hold a ref to the upstream peer */
620     GST_LOG_OBJECT (pad, "activating peer");
621     ret = gst_pad_activate_pull (other, active);
622     gst_object_unref (other);
623   } else {
624     /* no peer, we fail */
625     GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
626     ret = FALSE;
627   }
628
629   return ret;
630 }
631
632 static GstPadLinkReturn
633 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
634 {
635   GstPadLinkReturn ret;
636   GstPad *internal;
637
638   GST_DEBUG_OBJECT (pad, "linking ghostpad");
639
640   internal = GST_PROXY_PAD_INTERNAL (pad);
641   if (!gst_proxy_pad_set_target (internal, peer))
642     goto target_failed;
643
644   ret = GST_PAD_LINK_OK;
645   /* if we are a source pad, we should call the peer link function
646    * if the peer has one, see design docs. */
647   if (GST_PAD_IS_SRC (pad)) {
648     if (GST_PAD_LINKFUNC (peer)) {
649       ret = GST_PAD_LINKFUNC (peer) (peer, pad);
650       if (ret != GST_PAD_LINK_OK)
651         goto link_failed;
652     }
653   }
654   return ret;
655
656   /* ERRORS */
657 target_failed:
658   {
659     GST_DEBUG_OBJECT (pad, "setting target failed");
660     return GST_PAD_LINK_REFUSED;
661   }
662 link_failed:
663   {
664     GST_DEBUG_OBJECT (pad, "linking failed");
665     /* clear target again */
666     gst_proxy_pad_set_target (internal, NULL);
667     return ret;
668   }
669 }
670
671 static void
672 gst_ghost_pad_do_unlink (GstPad * pad)
673 {
674   GstPad *internal;
675
676   internal = GST_PROXY_PAD_INTERNAL (pad);
677
678   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
679
680   /* The target of the internal pad is no longer valid */
681   gst_proxy_pad_set_target (internal, NULL);
682 }
683
684 static void
685 on_int_notify (GstPad * internal, GParamSpec * unused, GstGhostPad * pad)
686 {
687   GstCaps *caps;
688   gboolean changed;
689
690   g_object_get (internal, "caps", &caps, NULL);
691
692   GST_DEBUG_OBJECT (pad, "notified %p %" GST_PTR_FORMAT, caps, caps);
693
694   GST_OBJECT_LOCK (pad);
695   changed = (GST_PAD_CAPS (pad) != caps);
696   if (changed)
697     gst_caps_replace (&(GST_PAD_CAPS (pad)), caps);
698   GST_OBJECT_UNLOCK (pad);
699
700   if (changed)
701     g_object_notify (G_OBJECT (pad), "caps");
702
703   if (caps)
704     gst_caps_unref (caps);
705 }
706
707 static void
708 on_src_target_notify (GstPad * target, GParamSpec * unused, gpointer user_data)
709 {
710   GstProxyPad *proxypad;
711   GstGhostPad *gpad;
712   GstCaps *caps;
713   gboolean changed;
714
715   g_object_get (target, "caps", &caps, NULL);
716
717   GST_OBJECT_LOCK (target);
718   /* First check if the peer is still available and our proxy pad */
719   if (!GST_PAD_PEER (target) || !GST_IS_PROXY_PAD (GST_PAD_PEER (target))) {
720     GST_OBJECT_UNLOCK (target);
721     goto done;
722   }
723
724   proxypad = GST_PROXY_PAD (GST_PAD_PEER (target));
725   GST_PROXY_LOCK (proxypad);
726   /* Now check if the proxypad's internal pad is still there and
727    * a ghostpad */
728   if (!GST_PROXY_PAD_INTERNAL (proxypad) ||
729       !GST_IS_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad))) {
730     GST_OBJECT_UNLOCK (target);
731     GST_PROXY_UNLOCK (proxypad);
732     goto done;
733   }
734   gpad = GST_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad));
735   g_object_ref (gpad);
736   GST_PROXY_UNLOCK (proxypad);
737   GST_OBJECT_UNLOCK (target);
738
739   GST_OBJECT_LOCK (gpad);
740
741   GST_DEBUG_OBJECT (gpad, "notified %p %" GST_PTR_FORMAT, caps, caps);
742
743   changed = (GST_PAD_CAPS (gpad) != caps);
744   if (changed)
745     gst_caps_replace (&(GST_PAD_CAPS (gpad)), caps);
746   GST_OBJECT_UNLOCK (gpad);
747   if (changed)
748     g_object_notify (G_OBJECT (gpad), "caps");
749
750   g_object_unref (gpad);
751
752 done:
753   if (caps)
754     gst_caps_unref (caps);
755 }
756
757 static gboolean
758 gst_ghost_pad_do_setcaps (GstPad * pad, GstCaps * caps)
759 {
760   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
761     return TRUE;
762
763   return gst_proxy_pad_do_setcaps (pad, caps);
764 }
765
766 static GstIterator *
767 gst_ghost_pad_do_iterate_internal_links (GstPad * pad)
768 {
769   GstIterator *res = NULL;
770   GstPad *internal = GST_PROXY_PAD_INTERNAL (GST_GHOST_PAD_CAST (pad));
771
772   if (internal) {
773     res =
774         gst_iterator_new_single (GST_TYPE_PAD, internal,
775         (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
776   }
777
778   return res;
779 }
780
781 static void
782 gst_ghost_pad_init (GstGhostPad * pad)
783 {
784   GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
785       GST_TYPE_GHOST_PAD, GstGhostPadPrivate);
786
787   gst_pad_set_setcaps_function (GST_PAD_CAST (pad),
788       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_setcaps));
789   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
790       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
791   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
792       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
793   gst_pad_set_iterate_internal_links_function (GST_PAD_CAST (pad),
794       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_iterate_internal_links));
795 }
796
797 static void
798 gst_ghost_pad_dispose (GObject * object)
799 {
800   GstPad *pad;
801   GstPad *internal;
802   GstPad *peer;
803
804   pad = GST_PAD (object);
805
806   GST_DEBUG_OBJECT (pad, "dispose");
807
808   gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
809
810   /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
811    * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */
812   peer = gst_pad_get_peer (pad);
813   if (peer) {
814     if (GST_PAD_IS_SRC (pad))
815       gst_pad_unlink (pad, peer);
816     else
817       gst_pad_unlink (peer, pad);
818
819     gst_object_unref (peer);
820   }
821
822   GST_PROXY_LOCK (pad);
823   internal = GST_PROXY_PAD_INTERNAL (pad);
824
825   gst_pad_set_activatepull_function (internal, NULL);
826   gst_pad_set_activatepush_function (internal, NULL);
827
828   g_signal_handler_disconnect (internal,
829       GST_GHOST_PAD_PRIVATE (pad)->notify_id);
830
831   /* disposes of the internal pad, since the ghostpad is the only possible object
832    * that has a refcount on the internal pad. */
833   gst_object_unparent (GST_OBJECT_CAST (internal));
834   GST_PROXY_PAD_INTERNAL (pad) = NULL;
835
836   GST_PROXY_UNLOCK (pad);
837
838   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
839 }
840
841 /**
842  * gst_ghost_pad_construct:
843  * @gpad: the newly allocated ghost pad
844  *
845  * Finish initialization of a newly allocated ghost pad.
846  *
847  * This function is most useful in language bindings and when subclassing
848  * #GstGhostPad; plugin and application developers normally will not call this
849  * function. Call this function directly after a call to g_object_new
850  * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
851  *
852  * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
853  *
854  * Since: 0.10.22
855  */
856 gboolean
857 gst_ghost_pad_construct (GstGhostPad * gpad)
858 {
859   GstPadDirection dir, otherdir;
860   GstPadTemplate *templ;
861   GstPad *pad, *internal;
862
863   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
864   g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
865       FALSE);
866
867   g_object_get (gpad, "direction", &dir, "template", &templ, NULL);
868
869   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);
870
871   pad = GST_PAD (gpad);
872
873   /* Set directional padfunctions for ghostpad */
874   if (dir == GST_PAD_SINK) {
875     gst_pad_set_bufferalloc_function (pad,
876         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
877     gst_pad_set_chain_function (pad,
878         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
879     gst_pad_set_chain_list_function (pad,
880         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain_list));
881   } else {
882     gst_pad_set_getrange_function (pad,
883         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
884     gst_pad_set_checkgetrange_function (pad,
885         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
886   }
887
888   /* link/unlink functions */
889   gst_pad_set_link_function (pad, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
890   gst_pad_set_unlink_function (pad,
891       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
892
893   /* INTERNAL PAD, it always exists and is child of the ghostpad */
894   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
895   if (templ) {
896     internal =
897         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
898         "direction", otherdir, "template", templ, NULL);
899     /* release ref obtained via g_object_get */
900     gst_object_unref (templ);
901   } else {
902     internal =
903         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
904         "direction", otherdir, NULL);
905   }
906   GST_PAD_UNSET_FLUSHING (internal);
907
908   /* Set directional padfunctions for internal pad */
909   if (dir == GST_PAD_SRC) {
910     gst_pad_set_bufferalloc_function (internal,
911         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
912     gst_pad_set_chain_function (internal,
913         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
914     gst_pad_set_chain_list_function (internal,
915         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain_list));
916   } else {
917     gst_pad_set_getrange_function (internal,
918         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
919     gst_pad_set_checkgetrange_function (internal,
920         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
921   }
922
923   GST_PROXY_LOCK (pad);
924
925   /* now make the ghostpad a parent of the internal pad */
926   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
927           GST_OBJECT_CAST (pad)))
928     goto parent_failed;
929
930   /* The ghostpad is the parent of the internal pad and is the only object that
931    * can have a refcount on the internal pad.
932    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
933    * a refcount of 1.
934    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
935    * its refcount on the internal pad in the dispose method by un-parenting it.
936    * This is why we don't take extra refcounts in the assignments below
937    */
938   GST_PROXY_PAD_INTERNAL (pad) = internal;
939   GST_PROXY_PAD_INTERNAL (internal) = pad;
940
941   /* could be more general here, iterating over all writable properties...
942    * taking the short road for now tho */
943   GST_GHOST_PAD_PRIVATE (pad)->notify_id =
944       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
945       pad);
946
947   /* call function to init values of the pad caps */
948   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (pad));
949
950   /* special activation functions for the internal pad */
951   gst_pad_set_activatepull_function (internal,
952       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
953   gst_pad_set_activatepush_function (internal,
954       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
955
956   GST_PROXY_UNLOCK (pad);
957
958   GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
959   return TRUE;
960
961   /* ERRORS */
962 parent_failed:
963   {
964     GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
965         GST_DEBUG_PAD_NAME (internal));
966     g_critical ("Could not set internal pad %s:%s",
967         GST_DEBUG_PAD_NAME (internal));
968     GST_PROXY_UNLOCK (pad);
969     gst_object_unref (internal);
970     return FALSE;
971   }
972 }
973
974 static GstPad *
975 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
976     GstPadTemplate * templ)
977 {
978   GstGhostPad *ret;
979
980   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
981
982   /* OBJECT CREATION */
983   if (templ) {
984     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
985         "direction", dir, "template", templ, NULL);
986   } else {
987     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
988         "direction", dir, NULL);
989   }
990
991   if (!gst_ghost_pad_construct (ret))
992     goto construct_failed;
993
994   return GST_PAD_CAST (ret);
995
996 construct_failed:
997   /* already logged */
998   gst_object_unref (ret);
999   return NULL;
1000 }
1001
1002 /**
1003  * gst_ghost_pad_new_no_target:
1004  * @name: the name of the new pad, or NULL to assign a default name.
1005  * @dir: the direction of the ghostpad
1006  *
1007  * Create a new ghostpad without a target with the given direction.
1008  * A target can be set on the ghostpad later with the
1009  * gst_ghost_pad_set_target() function.
1010  *
1011  * The created ghostpad will not have a padtemplate.
1012  *
1013  * Returns: a new #GstPad, or NULL in case of an error.
1014  */
1015 GstPad *
1016 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
1017 {
1018   GstPad *ret;
1019
1020   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
1021
1022   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
1023
1024   ret = gst_ghost_pad_new_full (name, dir, NULL);
1025
1026   return ret;
1027 }
1028
1029 /**
1030  * gst_ghost_pad_new:
1031  * @name: the name of the new pad, or NULL to assign a default name.
1032  * @target: the pad to ghost.
1033  *
1034  * Create a new ghostpad with @target as the target. The direction will be taken
1035  * from the target pad. @target must be unlinked.
1036  *
1037  * Will ref the target.
1038  *
1039  * Returns: a new #GstPad, or NULL in case of an error.
1040  */
1041 GstPad *
1042 gst_ghost_pad_new (const gchar * name, GstPad * target)
1043 {
1044   GstPad *ret;
1045
1046   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1047   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1048
1049   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
1050       GST_DEBUG_PAD_NAME (target));
1051
1052   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
1053     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1054       goto set_target_failed;
1055
1056   return ret;
1057
1058   /* ERRORS */
1059 set_target_failed:
1060   {
1061     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1062         GST_DEBUG_PAD_NAME (target));
1063     gst_object_unref (ret);
1064     return NULL;
1065   }
1066 }
1067
1068 /**
1069  * gst_ghost_pad_new_from_template:
1070  * @name: the name of the new pad, or NULL to assign a default name.
1071  * @target: the pad to ghost.
1072  * @templ: the #GstPadTemplate to use on the ghostpad.
1073  *
1074  * Create a new ghostpad with @target as the target. The direction will be taken
1075  * from the target pad. The template used on the ghostpad will be @template.
1076  *
1077  * Will ref the target.
1078  *
1079  * Returns: a new #GstPad, or NULL in case of an error.
1080  *
1081  * Since: 0.10.10
1082  */
1083
1084 GstPad *
1085 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
1086     GstPadTemplate * templ)
1087 {
1088   GstPad *ret;
1089
1090   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1091   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1092   g_return_val_if_fail (templ != NULL, NULL);
1093   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
1094       GST_PAD_DIRECTION (target), NULL);
1095
1096   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
1097       GST_DEBUG_PAD_NAME (target), templ);
1098
1099   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
1100     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1101       goto set_target_failed;
1102
1103   return ret;
1104
1105   /* ERRORS */
1106 set_target_failed:
1107   {
1108     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1109         GST_DEBUG_PAD_NAME (target));
1110     gst_object_unref (ret);
1111     return NULL;
1112   }
1113 }
1114
1115 /**
1116  * gst_ghost_pad_new_no_target_from_template:
1117  * @name: the name of the new pad, or NULL to assign a default name.
1118  * @templ: the #GstPadTemplate to create the ghostpad from.
1119  *
1120  * Create a new ghostpad based on @templ, without setting a target. The
1121  * direction will be taken from the @templ.
1122  *
1123  * Returns: a new #GstPad, or NULL in case of an error.
1124  *
1125  * Since: 0.10.10
1126  */
1127 GstPad *
1128 gst_ghost_pad_new_no_target_from_template (const gchar * name,
1129     GstPadTemplate * templ)
1130 {
1131   GstPad *ret;
1132
1133   g_return_val_if_fail (templ != NULL, NULL);
1134
1135   ret =
1136       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
1137
1138   return ret;
1139 }
1140
1141 /**
1142  * gst_ghost_pad_get_target:
1143  * @gpad: the #GstGhostpad
1144  *
1145  * Get the target pad of #gpad. Unref target pad after usage.
1146  *
1147  * Returns: the target #GstPad, can be NULL if the ghostpad
1148  * has no target set. Unref target pad after usage.
1149  */
1150 GstPad *
1151 gst_ghost_pad_get_target (GstGhostPad * gpad)
1152 {
1153   GstPad *ret;
1154
1155   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
1156
1157   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
1158
1159   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
1160
1161   return ret;
1162 }
1163
1164 /**
1165  * gst_ghost_pad_set_target:
1166  * @gpad: the #GstGhostpad
1167  * @newtarget: the new pad target
1168  *
1169  * Set the new target of the ghostpad @gpad. Any existing target
1170  * is unlinked and links to the new target are established. if @newtarget is
1171  * NULL the target will be cleared.
1172  *
1173  * Returns: TRUE if the new target could be set. This function can return FALSE
1174  * when the internal pads could not be linked.
1175  */
1176 gboolean
1177 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1178 {
1179   GstPad *internal;
1180   GstPad *oldtarget;
1181   gboolean result;
1182   GstPadLinkReturn lret;
1183
1184   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1185   g_return_val_if_fail (GST_PAD_CAST (gpad) != newtarget, FALSE);
1186   g_return_val_if_fail (newtarget != GST_PROXY_PAD_INTERNAL (gpad), FALSE);
1187
1188   /* no need for locking, the internal pad's lifecycle is directly linked to the
1189    * ghostpad's */
1190   internal = GST_PROXY_PAD_INTERNAL (gpad);
1191
1192   if (newtarget)
1193     GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1194   else
1195     GST_DEBUG_OBJECT (gpad, "clearing target");
1196
1197   /* clear old target */
1198   GST_PROXY_LOCK (gpad);
1199   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1200     if (GST_PAD_IS_SRC (oldtarget)) {
1201       g_signal_handlers_disconnect_by_func (oldtarget,
1202           (gpointer) on_src_target_notify, NULL);
1203     }
1204
1205     GST_PROXY_PAD_RETARGET (internal) = TRUE;
1206
1207     /* unlink internal pad */
1208     if (GST_PAD_IS_SRC (internal))
1209       gst_pad_unlink (internal, oldtarget);
1210     else
1211       gst_pad_unlink (oldtarget, internal);
1212
1213     GST_PROXY_PAD_RETARGET (internal) = FALSE;
1214   }
1215
1216   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1217   GST_PROXY_UNLOCK (gpad);
1218
1219   if (result && newtarget) {
1220     if (GST_PAD_IS_SRC (newtarget)) {
1221       g_signal_connect (newtarget, "notify::caps",
1222           G_CALLBACK (on_src_target_notify), NULL);
1223     }
1224
1225     /* and link to internal pad */
1226     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
1227
1228     if (GST_PAD_IS_SRC (internal))
1229       lret = gst_pad_link (internal, newtarget);
1230     else
1231       lret = gst_pad_link (newtarget, internal);
1232
1233     if (lret != GST_PAD_LINK_OK)
1234       goto link_failed;
1235   }
1236
1237   return result;
1238
1239   /* ERRORS */
1240 link_failed:
1241   {
1242     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
1243         lret);
1244     /* and unset target again */
1245     GST_PROXY_LOCK (gpad);
1246     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
1247     GST_PROXY_UNLOCK (gpad);
1248     return FALSE;
1249   }
1250 }