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