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