docs: it's its
[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_DEBUG_FUNCPTR (gst_proxy_pad_dispose);
97   gobject_class->finalize = GST_DEBUG_FUNCPTR (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 (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_DEBUG_FUNCPTR (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     gst_caps_unref (caps);
722     return;
723   }
724
725   proxypad = GST_PROXY_PAD (GST_PAD_PEER (target));
726   GST_PROXY_LOCK (proxypad);
727   /* Now check if the proxypad's internal pad is still there and
728    * a ghostpad */
729   if (!GST_PROXY_PAD_INTERNAL (proxypad) ||
730       !GST_IS_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad))) {
731     GST_OBJECT_UNLOCK (target);
732     GST_PROXY_UNLOCK (proxypad);
733     gst_caps_unref (caps);
734     return;
735   }
736   gpad = GST_GHOST_PAD (GST_PROXY_PAD_INTERNAL (proxypad));
737   g_object_ref (gpad);
738   GST_PROXY_UNLOCK (proxypad);
739   GST_OBJECT_UNLOCK (target);
740
741   GST_OBJECT_LOCK (gpad);
742
743   GST_DEBUG_OBJECT (gpad, "notified %p %" GST_PTR_FORMAT, caps, caps);
744
745   changed = (GST_PAD_CAPS (gpad) != caps);
746   if (changed)
747     gst_caps_replace (&(GST_PAD_CAPS (gpad)), caps);
748   GST_OBJECT_UNLOCK (gpad);
749   if (changed)
750     g_object_notify (G_OBJECT (gpad), "caps");
751
752   g_object_unref (gpad);
753
754   if (caps)
755     gst_caps_unref (caps);
756 }
757
758 static gboolean
759 gst_ghost_pad_do_setcaps (GstPad * pad, GstCaps * caps)
760 {
761   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
762     return TRUE;
763
764   return gst_proxy_pad_do_setcaps (pad, caps);
765 }
766
767 static void
768 gst_ghost_pad_init (GstGhostPad * pad)
769 {
770   GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
771       GST_TYPE_GHOST_PAD, GstGhostPadPrivate);
772
773   gst_pad_set_setcaps_function (GST_PAD_CAST (pad),
774       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_setcaps));
775   gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
776       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_pull));
777   gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
778       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
779 }
780
781 static void
782 gst_ghost_pad_dispose (GObject * object)
783 {
784   GstPad *pad;
785   GstPad *internal;
786   GstPad *peer;
787
788   pad = GST_PAD (object);
789
790   GST_DEBUG_OBJECT (pad, "dispose");
791
792   gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
793
794   /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
795    * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */
796   peer = gst_pad_get_peer (pad);
797   if (peer) {
798     if (GST_PAD_IS_SRC (pad))
799       gst_pad_unlink (pad, peer);
800     else
801       gst_pad_unlink (peer, pad);
802
803     gst_object_unref (peer);
804   }
805
806   GST_PROXY_LOCK (pad);
807   internal = GST_PROXY_PAD_INTERNAL (pad);
808
809   gst_pad_set_activatepull_function (internal, NULL);
810   gst_pad_set_activatepush_function (internal, NULL);
811
812   g_signal_handler_disconnect (internal,
813       GST_GHOST_PAD_PRIVATE (pad)->notify_id);
814
815   /* disposes of the internal pad, since the ghostpad is the only possible object
816    * that has a refcount on the internal pad. */
817   gst_object_unparent (GST_OBJECT_CAST (internal));
818   GST_PROXY_PAD_INTERNAL (pad) = NULL;
819
820   GST_PROXY_UNLOCK (pad);
821
822   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
823 }
824
825 /**
826  * gst_ghost_pad_construct:
827  * @gpad: the newly allocated ghost pad
828  *
829  * Finish initialization of a newly allocated ghost pad.
830  *
831  * This function is most useful in language bindings and when subclassing
832  * #GstGhostPad; plugin and application developers normally will not call this
833  * function. Call this function directly after a call to g_object_new
834  * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
835  *
836  * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
837  *
838  * Since: 0.10.22
839  */
840 gboolean
841 gst_ghost_pad_construct (GstGhostPad * gpad)
842 {
843   GstPadDirection dir, otherdir;
844   GstPadTemplate *templ;
845   GstPad *pad, *internal;
846
847   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
848   g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
849       FALSE);
850
851   g_object_get (gpad, "direction", &dir, "template", &templ, NULL);
852
853   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);
854
855   pad = GST_PAD (gpad);
856
857   /* Set directional padfunctions for ghostpad */
858   if (dir == GST_PAD_SINK) {
859     gst_pad_set_bufferalloc_function (pad,
860         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
861     gst_pad_set_chain_function (pad,
862         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
863     gst_pad_set_chain_list_function (pad,
864         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain_list));
865   } else {
866     gst_pad_set_getrange_function (pad,
867         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
868     gst_pad_set_checkgetrange_function (pad,
869         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
870   }
871
872   /* link/unlink functions */
873   gst_pad_set_link_function (pad, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
874   gst_pad_set_unlink_function (pad,
875       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
876
877   /* INTERNAL PAD, it always exists and is child of the ghostpad */
878   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
879   if (templ) {
880     internal =
881         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
882         "direction", otherdir, "template", templ, NULL);
883     /* release ref obtained via g_object_get */
884     gst_object_unref (templ);
885   } else {
886     internal =
887         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
888         "direction", otherdir, NULL);
889   }
890   GST_PAD_UNSET_FLUSHING (internal);
891
892   /* Set directional padfunctions for internal pad */
893   if (dir == GST_PAD_SRC) {
894     gst_pad_set_bufferalloc_function (internal,
895         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
896     gst_pad_set_chain_function (internal,
897         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
898     gst_pad_set_chain_list_function (internal,
899         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain_list));
900   } else {
901     gst_pad_set_getrange_function (internal,
902         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
903     gst_pad_set_checkgetrange_function (internal,
904         GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
905   }
906
907   GST_PROXY_LOCK (pad);
908
909   /* now make the ghostpad a parent of the internal pad */
910   if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
911           GST_OBJECT_CAST (pad)))
912     goto parent_failed;
913
914   /* The ghostpad is the parent of the internal pad and is the only object that
915    * can have a refcount on the internal pad.
916    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
917    * a refcount of 1.
918    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
919    * its refcount on the internal pad in the dispose method by un-parenting it.
920    * This is why we don't take extra refcounts in the assignments below
921    */
922   GST_PROXY_PAD_INTERNAL (pad) = internal;
923   GST_PROXY_PAD_INTERNAL (internal) = pad;
924
925   /* could be more general here, iterating over all writable properties...
926    * taking the short road for now tho */
927   GST_GHOST_PAD_PRIVATE (pad)->notify_id =
928       g_signal_connect (internal, "notify::caps", G_CALLBACK (on_int_notify),
929       pad);
930
931   /* call function to init values of the pad caps */
932   on_int_notify (internal, NULL, GST_GHOST_PAD_CAST (pad));
933
934   /* special activation functions for the internal pad */
935   gst_pad_set_activatepull_function (internal,
936       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_pull));
937   gst_pad_set_activatepush_function (internal,
938       GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
939
940   GST_PROXY_UNLOCK (pad);
941
942   GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
943   return TRUE;
944
945   /* ERRORS */
946 parent_failed:
947   {
948     GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
949         GST_DEBUG_PAD_NAME (internal));
950     g_critical ("Could not set internal pad %s:%s",
951         GST_DEBUG_PAD_NAME (internal));
952     GST_PROXY_UNLOCK (pad);
953     gst_object_unref (internal);
954     return FALSE;
955   }
956 }
957
958 static GstPad *
959 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
960     GstPadTemplate * templ)
961 {
962   GstGhostPad *ret;
963
964   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
965
966   /* OBJECT CREATION */
967   if (templ) {
968     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
969         "direction", dir, "template", templ, NULL);
970   } else {
971     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
972         "direction", dir, NULL);
973   }
974
975   if (!gst_ghost_pad_construct (ret))
976     goto construct_failed;
977
978   return GST_PAD (ret);
979
980 construct_failed:
981   /* already logged */
982   gst_object_unref (ret);
983   return NULL;
984 }
985
986 /**
987  * gst_ghost_pad_new_no_target:
988  * @name: the name of the new pad, or NULL to assign a default name.
989  * @dir: the direction of the ghostpad
990  *
991  * Create a new ghostpad without a target with the given direction.
992  * A target can be set on the ghostpad later with the
993  * gst_ghost_pad_set_target() function.
994  *
995  * The created ghostpad will not have a padtemplate.
996  *
997  * Returns: a new #GstPad, or NULL in case of an error.
998  */
999 GstPad *
1000 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
1001 {
1002   GstPad *ret;
1003
1004   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
1005
1006   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
1007
1008   ret = gst_ghost_pad_new_full (name, dir, NULL);
1009
1010   return ret;
1011 }
1012
1013 /**
1014  * gst_ghost_pad_new:
1015  * @name: the name of the new pad, or NULL to assign a default name.
1016  * @target: the pad to ghost.
1017  *
1018  * Create a new ghostpad with @target as the target. The direction will be taken
1019  * from the target pad. @target must be unlinked.
1020  *
1021  * Will ref the target.
1022  *
1023  * Returns: a new #GstPad, or NULL in case of an error.
1024  */
1025 GstPad *
1026 gst_ghost_pad_new (const gchar * name, GstPad * target)
1027 {
1028   GstPad *ret;
1029
1030   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1031   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1032
1033   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
1034       GST_DEBUG_PAD_NAME (target));
1035
1036   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
1037     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1038       goto set_target_failed;
1039
1040   return ret;
1041
1042   /* ERRORS */
1043 set_target_failed:
1044   {
1045     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1046         GST_DEBUG_PAD_NAME (target));
1047     gst_object_unref (ret);
1048     return NULL;
1049   }
1050 }
1051
1052 /**
1053  * gst_ghost_pad_new_from_template:
1054  * @name: the name of the new pad, or NULL to assign a default name.
1055  * @target: the pad to ghost.
1056  * @templ: the #GstPadTemplate to use on the ghostpad.
1057  *
1058  * Create a new ghostpad with @target as the target. The direction will be taken
1059  * from the target pad. The template used on the ghostpad will be @template.
1060  *
1061  * Will ref the target.
1062  *
1063  * Returns: a new #GstPad, or NULL in case of an error.
1064  *
1065  * Since: 0.10.10
1066  */
1067
1068 GstPad *
1069 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
1070     GstPadTemplate * templ)
1071 {
1072   GstPad *ret;
1073
1074   g_return_val_if_fail (GST_IS_PAD (target), NULL);
1075   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
1076   g_return_val_if_fail (templ != NULL, NULL);
1077   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
1078       GST_PAD_DIRECTION (target), NULL);
1079
1080   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
1081       GST_DEBUG_PAD_NAME (target), templ);
1082
1083   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
1084     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
1085       goto set_target_failed;
1086
1087   return ret;
1088
1089   /* ERRORS */
1090 set_target_failed:
1091   {
1092     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
1093         GST_DEBUG_PAD_NAME (target));
1094     gst_object_unref (ret);
1095     return NULL;
1096   }
1097 }
1098
1099 /**
1100  * gst_ghost_pad_new_no_target_from_template:
1101  * @name: the name of the new pad, or NULL to assign a default name.
1102  * @templ: the #GstPadTemplate to create the ghostpad from.
1103  *
1104  * Create a new ghostpad based on @templ, without setting a target. The
1105  * direction will be taken from the @templ.
1106  *
1107  * Returns: a new #GstPad, or NULL in case of an error.
1108  *
1109  * Since: 0.10.10
1110  */
1111 GstPad *
1112 gst_ghost_pad_new_no_target_from_template (const gchar * name,
1113     GstPadTemplate * templ)
1114 {
1115   GstPad *ret;
1116
1117   g_return_val_if_fail (templ != NULL, NULL);
1118
1119   ret =
1120       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
1121
1122   return ret;
1123 }
1124
1125 /**
1126  * gst_ghost_pad_get_target:
1127  * @gpad: the #GstGhostpad
1128  *
1129  * Get the target pad of #gpad. Unref target pad after usage.
1130  *
1131  * Returns: the target #GstPad, can be NULL if the ghostpad
1132  * has no target set. Unref target pad after usage.
1133  */
1134 GstPad *
1135 gst_ghost_pad_get_target (GstGhostPad * gpad)
1136 {
1137   GstPad *ret;
1138
1139   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
1140
1141   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
1142
1143   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
1144
1145   return ret;
1146 }
1147
1148 /**
1149  * gst_ghost_pad_set_target:
1150  * @gpad: the #GstGhostpad
1151  * @newtarget: the new pad target
1152  *
1153  * Set the new target of the ghostpad @gpad. Any existing target
1154  * is unlinked and links to the new target are established. if @newtarget is
1155  * NULL the target will be cleared.
1156  *
1157  * Returns: TRUE if the new target could be set. This function can return FALSE
1158  * when the internal pads could not be linked.
1159  */
1160 gboolean
1161 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
1162 {
1163   GstPad *internal;
1164   GstPad *oldtarget;
1165   gboolean result;
1166   GstPadLinkReturn lret;
1167
1168   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
1169
1170   GST_PROXY_LOCK (gpad);
1171   internal = GST_PROXY_PAD_INTERNAL (gpad);
1172   g_assert (internal);
1173
1174   if (newtarget)
1175     GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
1176   else
1177     GST_DEBUG_OBJECT (gpad, "clearing target");
1178
1179   /* clear old target */
1180   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
1181     if (GST_PAD_IS_SRC (oldtarget)) {
1182       g_signal_handlers_disconnect_by_func (oldtarget,
1183           (gpointer) on_src_target_notify, NULL);
1184     }
1185
1186     GST_PROXY_PAD_RETARGET (internal) = TRUE;
1187
1188     /* unlink internal pad */
1189     if (GST_PAD_IS_SRC (internal))
1190       gst_pad_unlink (internal, oldtarget);
1191     else
1192       gst_pad_unlink (oldtarget, internal);
1193
1194     GST_PROXY_PAD_RETARGET (internal) = FALSE;
1195   }
1196
1197   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
1198
1199   if (result && newtarget) {
1200     if (GST_PAD_IS_SRC (newtarget)) {
1201       g_signal_connect (newtarget, "notify::caps",
1202           G_CALLBACK (on_src_target_notify), NULL);
1203     }
1204
1205     /* and link to internal pad */
1206     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target");
1207
1208     if (GST_PAD_IS_SRC (internal))
1209       lret = gst_pad_link (internal, newtarget);
1210     else
1211       lret = gst_pad_link (newtarget, internal);
1212
1213     if (lret != GST_PAD_LINK_OK)
1214       goto link_failed;
1215   }
1216   GST_PROXY_UNLOCK (gpad);
1217
1218   return result;
1219
1220   /* ERRORS */
1221 link_failed:
1222   {
1223     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%d",
1224         lret);
1225     /* and unset target again */
1226     gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), NULL);
1227     GST_PROXY_UNLOCK (gpad);
1228     return FALSE;
1229   }
1230 }