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