• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 /**
26  * SECTION:gstghostpad
27  * @title: GstGhostPad
28  * @short_description: Pseudo link pads
29  * @see_also: #GstPad
30  *
31  * GhostPads are useful when organizing pipelines with #GstBin like elements.
32  * The idea here is to create hierarchical element graphs. The bin element
33  * contains a sub-graph. Now one would like to treat the bin-element like any
34  * other #GstElement. This is where GhostPads come into play. A GhostPad acts as
35  * a proxy for another pad. Thus the bin can have sink and source ghost-pads
36  * that are associated with sink and source pads of the child elements.
37  *
38  * If the target pad is known at creation time, gst_ghost_pad_new() is the
39  * function to use to get a ghost-pad. Otherwise one can use gst_ghost_pad_new_no_target()
40  * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
41  * association later on.
42  *
43  * Note that GhostPads add overhead to the data processing of a pipeline.
44  */
45 
46 #include "gst_private.h"
47 #include "gstinfo.h"
48 
49 #include "gstghostpad.h"
50 #include "gst.h"
51 
52 #define GST_CAT_DEFAULT GST_CAT_PADS
53 
54 #define GST_PROXY_PAD_CAST(obj)         ((GstProxyPad *)obj)
55 #define GST_PROXY_PAD_PRIVATE(obj)      (GST_PROXY_PAD_CAST (obj)->priv)
56 #define GST_PROXY_PAD_TARGET(pad)       (GST_PAD_PEER (GST_PROXY_PAD_INTERNAL (pad)))
57 #define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD_PRIVATE (pad)->internal)
58 
59 #define GST_PROXY_PAD_ACQUIRE_INTERNAL(pad, internal, retval)           \
60   internal =                                                            \
61       GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD_CAST (pad))); \
62   if (internal == NULL)                                                 \
63     return retval;
64 
65 #define GST_PROXY_PAD_RELEASE_INTERNAL(internal) gst_object_unref (internal);
66 
67 struct _GstProxyPadPrivate
68 {
69   GstPad *internal;
70 };
71 
72 G_DEFINE_TYPE_WITH_PRIVATE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
73 
74 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
75 
76 /**
77  * gst_proxy_pad_iterate_internal_links_default:
78  * @pad: the #GstPad to get the internal links of.
79  * @parent: (allow-none): the parent of @pad or %NULL
80  *
81  * Invoke the default iterate internal links function of the proxy pad.
82  *
83  * Returns: (nullable): a #GstIterator of #GstPad, or %NULL if @pad
84  * has no parent. Unref each returned pad with gst_object_unref().
85  */
86 GstIterator *
gst_proxy_pad_iterate_internal_links_default(GstPad * pad,GstObject * parent)87 gst_proxy_pad_iterate_internal_links_default (GstPad * pad, GstObject * parent)
88 {
89   GstIterator *res = NULL;
90   GstPad *internal;
91   GValue v = { 0, };
92 
93   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);
94 
95   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, internal, NULL);
96 
97   g_value_init (&v, GST_TYPE_PAD);
98   g_value_take_object (&v, internal);
99   res = gst_iterator_new_single (GST_TYPE_PAD, &v);
100   g_value_unset (&v);
101 
102   return res;
103 }
104 
105 /**
106  * gst_proxy_pad_chain_default:
107  * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
108  * @parent: (allow-none): the parent of @pad or %NULL
109  * @buffer: (transfer full): the #GstBuffer to send, return GST_FLOW_ERROR
110  *     if not.
111  *
112  * Invoke the default chain function of the proxy pad.
113  *
114  * Returns: a #GstFlowReturn from the pad.
115  */
116 GstFlowReturn
gst_proxy_pad_chain_default(GstPad * pad,GstObject * parent,GstBuffer * buffer)117 gst_proxy_pad_chain_default (GstPad * pad, GstObject * parent,
118     GstBuffer * buffer)
119 {
120   GstFlowReturn res;
121   GstPad *internal;
122 
123   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
124   g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
125 
126   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, internal, GST_FLOW_NOT_LINKED);
127   res = gst_pad_push (internal, buffer);
128   GST_PROXY_PAD_RELEASE_INTERNAL (internal);
129 
130   return res;
131 }
132 
133 /**
134  * gst_proxy_pad_chain_list_default:
135  * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
136  * @parent: (allow-none): the parent of @pad or %NULL
137  * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR
138  *     if not.
139  *
140  * Invoke the default chain list function of the proxy pad.
141  *
142  * Returns: a #GstFlowReturn from the pad.
143  */
144 GstFlowReturn
gst_proxy_pad_chain_list_default(GstPad * pad,GstObject * parent,GstBufferList * list)145 gst_proxy_pad_chain_list_default (GstPad * pad, GstObject * parent,
146     GstBufferList * list)
147 {
148   GstFlowReturn res;
149   GstPad *internal;
150 
151   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
152   g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
153 
154   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, internal, GST_FLOW_NOT_LINKED);
155   res = gst_pad_push_list (internal, list);
156   GST_PROXY_PAD_RELEASE_INTERNAL (internal);
157 
158   return res;
159 }
160 
161 /**
162  * gst_proxy_pad_getrange_default:
163  * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not.
164  * @parent: the parent of @pad
165  * @offset: The start offset of the buffer
166  * @size: The length of the buffer
167  * @buffer: (out callee-allocates): a pointer to hold the #GstBuffer,
168  *     returns #GST_FLOW_ERROR if %NULL.
169  *
170  * Invoke the default getrange function of the proxy pad.
171  *
172  * Returns: a #GstFlowReturn from the pad.
173  */
174 GstFlowReturn
gst_proxy_pad_getrange_default(GstPad * pad,GstObject * parent,guint64 offset,guint size,GstBuffer ** buffer)175 gst_proxy_pad_getrange_default (GstPad * pad, GstObject * parent,
176     guint64 offset, guint size, GstBuffer ** buffer)
177 {
178   GstFlowReturn res;
179   GstPad *internal;
180 
181   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
182   g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
183 
184   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, internal, GST_FLOW_NOT_LINKED);
185   res = gst_pad_pull_range (internal, offset, size, buffer);
186   GST_PROXY_PAD_RELEASE_INTERNAL (internal);
187 
188   return res;
189 }
190 
191 static GstPad *
gst_proxy_pad_get_target(GstPad * pad)192 gst_proxy_pad_get_target (GstPad * pad)
193 {
194   GstPad *target;
195 
196   GST_OBJECT_LOCK (pad);
197   target = gst_pad_get_peer (GST_PROXY_PAD_INTERNAL (pad));
198   GST_OBJECT_UNLOCK (pad);
199 
200   return target;
201 }
202 
203 /**
204  * gst_proxy_pad_get_internal:
205  * @pad: the #GstProxyPad
206  *
207  * Get the internal pad of @pad. Unref target pad after usage.
208  *
209  * The internal pad of a #GstGhostPad is the internally used
210  * pad of opposite direction, which is used to link to the target.
211  *
212  * Returns: (transfer full) (nullable): the target #GstProxyPad, can
213  * be %NULL.  Unref target pad after usage.
214  */
215 GstProxyPad *
gst_proxy_pad_get_internal(GstProxyPad * pad)216 gst_proxy_pad_get_internal (GstProxyPad * pad)
217 {
218   GstPad *internal;
219 
220   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);
221 
222   GST_OBJECT_LOCK (pad);
223   internal = GST_PROXY_PAD_INTERNAL (pad);
224   if (internal)
225     gst_object_ref (internal);
226   GST_OBJECT_UNLOCK (pad);
227 
228   return GST_PROXY_PAD_CAST (internal);
229 }
230 
231 static void
gst_proxy_pad_class_init(GstProxyPadClass * klass)232 gst_proxy_pad_class_init (GstProxyPadClass * klass)
233 {
234   /* Register common function pointer descriptions */
235   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_iterate_internal_links_default);
236   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_default);
237   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_list_default);
238   GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getrange_default);
239 }
240 
241 static void
gst_proxy_pad_init(GstProxyPad * ppad)242 gst_proxy_pad_init (GstProxyPad * ppad)
243 {
244   GstPad *pad = (GstPad *) ppad;
245 
246   GST_PROXY_PAD_PRIVATE (ppad) = gst_proxy_pad_get_instance_private (ppad);
247 
248   gst_pad_set_iterate_internal_links_function (pad,
249       gst_proxy_pad_iterate_internal_links_default);
250 
251   GST_PAD_SET_PROXY_CAPS (pad);
252   GST_PAD_SET_PROXY_SCHEDULING (pad);
253   GST_PAD_SET_PROXY_ALLOCATION (pad);
254 }
255 
256 
257 /***********************************************************************
258  * Ghost pads, implemented as a pair of proxy pads (sort of)
259  */
260 G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);
261 
262 static void gst_ghost_pad_dispose (GObject * object);
263 static void gst_ghost_pad_constructed (GObject * object);
264 
265 static gboolean
gst_ghost_pad_internal_activate_push_default(GstPad * pad,GstObject * parent,gboolean active)266 gst_ghost_pad_internal_activate_push_default (GstPad * pad, GstObject * parent,
267     gboolean active)
268 {
269   gboolean ret;
270   GstPad *other;
271 
272   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
273       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
274 
275   /* in both cases (SRC and SINK) we activate just the internal pad. The targets
276    * will be activated later (or already in case of a ghost sinkpad). */
277   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE);
278   ret = gst_pad_activate_mode (other, GST_PAD_MODE_PUSH, active);
279   GST_PROXY_PAD_RELEASE_INTERNAL (other);
280 
281   return ret;
282 }
283 
284 static gboolean
gst_ghost_pad_internal_activate_pull_default(GstPad * pad,GstObject * parent,gboolean active)285 gst_ghost_pad_internal_activate_pull_default (GstPad * pad, GstObject * parent,
286     gboolean active)
287 {
288   gboolean ret;
289   GstPad *other;
290 
291   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
292       GST_DEBUG_PAD_NAME (pad));
293 
294   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
295     /* we are activated in pull mode by our peer element, which is a sinkpad
296      * that wants to operate in pull mode. This activation has to propagate
297      * upstream through the pipeline. We call the internal activation function,
298      * which will trigger gst_ghost_pad_activate_pull_default, which propagates even
299      * further upstream */
300     GST_LOG_OBJECT (pad, "pad is src, activate internal");
301     GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE);
302     ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
303     GST_PROXY_PAD_RELEASE_INTERNAL (other);
304   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
305     /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
306      * since we hold a pointer to the upstream peer. */
307     GST_LOG_OBJECT (pad, "activating peer");
308     ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
309     gst_object_unref (other);
310   } else if (active) {
311     /* this is failure, we can't activate pull if there is no peer */
312     GST_LOG_OBJECT (pad, "not src and no peer, failing");
313     ret = FALSE;
314   } else {
315     GST_LOG_OBJECT (pad, "deactivating pull, with no peer - allowing");
316     ret = TRUE;
317   }
318 
319   return ret;
320 }
321 
322 /**
323  * gst_ghost_pad_internal_activate_mode_default:
324  * @pad: the #GstPad to activate or deactivate.
325  * @parent: (allow-none): the parent of @pad or %NULL
326  * @mode: the requested activation mode
327  * @active: whether the pad should be active or not.
328  *
329  * Invoke the default activate mode function of a proxy pad that is
330  * owned by a ghost pad.
331  *
332  * Returns: %TRUE if the operation was successful.
333  */
334 gboolean
gst_ghost_pad_internal_activate_mode_default(GstPad * pad,GstObject * parent,GstPadMode mode,gboolean active)335 gst_ghost_pad_internal_activate_mode_default (GstPad * pad, GstObject * parent,
336     GstPadMode mode, gboolean active)
337 {
338   gboolean res;
339 
340   g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
341 
342   switch (mode) {
343     case GST_PAD_MODE_PULL:
344       res = gst_ghost_pad_internal_activate_pull_default (pad, parent, active);
345       break;
346     case GST_PAD_MODE_PUSH:
347       res = gst_ghost_pad_internal_activate_push_default (pad, parent, active);
348       break;
349     default:
350       GST_LOG_OBJECT (pad, "unknown activation mode %d", mode);
351       res = FALSE;
352       break;
353   }
354   return res;
355 }
356 
357 static gboolean
gst_ghost_pad_activate_push_default(GstPad * pad,GstObject * parent,gboolean active)358 gst_ghost_pad_activate_push_default (GstPad * pad, GstObject * parent,
359     gboolean active)
360 {
361   gboolean ret;
362   GstPad *other;
363 
364   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);
365 
366   GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
367       (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
368 
369   /* just activate the internal pad */
370   GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE);
371   ret = gst_pad_activate_mode (other, GST_PAD_MODE_PUSH, active);
372   GST_PROXY_PAD_RELEASE_INTERNAL (other);
373 
374   return ret;
375 }
376 
377 static gboolean
gst_ghost_pad_activate_pull_default(GstPad * pad,GstObject * parent,gboolean active)378 gst_ghost_pad_activate_pull_default (GstPad * pad, GstObject * parent,
379     gboolean active)
380 {
381   gboolean ret;
382   GstPad *other;
383 
384   GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
385       GST_DEBUG_PAD_NAME (pad));
386 
387   if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
388     /* the ghostpad is SRC and activated in pull mode by its peer, call the
389      * activation function of the internal pad to propagate the activation
390      * upstream */
391     GST_LOG_OBJECT (pad, "pad is src, activate internal");
392     GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE);
393     ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
394     GST_PROXY_PAD_RELEASE_INTERNAL (other);
395   } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
396     /* We are SINK and activated by the internal pad, propagate activation
397      * upstream because we hold a ref to the upstream peer */
398     GST_LOG_OBJECT (pad, "activating peer");
399     ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active);
400     gst_object_unref (other);
401   } else if (active) {
402     /* this is failure, we can't activate pull if there is no peer */
403     GST_LOG_OBJECT (pad, "not src and no peer, failing");
404     ret = FALSE;
405   } else {
406     GST_LOG_OBJECT (pad, "deactivating pull, with no peer - allowing");
407     ret = TRUE;
408   }
409 
410   return ret;
411 }
412 
413 /**
414  * gst_ghost_pad_activate_mode_default:
415  * @pad: the #GstPad to activate or deactivate.
416  * @parent: (allow-none): the parent of @pad or %NULL
417  * @mode: the requested activation mode
418  * @active: whether the pad should be active or not.
419  *
420  * Invoke the default activate mode function of a ghost pad.
421  *
422  * Returns: %TRUE if the operation was successful.
423  */
424 gboolean
gst_ghost_pad_activate_mode_default(GstPad * pad,GstObject * parent,GstPadMode mode,gboolean active)425 gst_ghost_pad_activate_mode_default (GstPad * pad, GstObject * parent,
426     GstPadMode mode, gboolean active)
427 {
428   gboolean res;
429 
430   g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);
431 
432   switch (mode) {
433     case GST_PAD_MODE_PULL:
434       res = gst_ghost_pad_activate_pull_default (pad, parent, active);
435       break;
436     case GST_PAD_MODE_PUSH:
437       res = gst_ghost_pad_activate_push_default (pad, parent, active);
438       break;
439     default:
440       GST_LOG_OBJECT (pad, "unknown activation mode %d", mode);
441       res = FALSE;
442       break;
443   }
444   return res;
445 }
446 
447 static void
gst_ghost_pad_class_init(GstGhostPadClass * klass)448 gst_ghost_pad_class_init (GstGhostPadClass * klass)
449 {
450   GObjectClass *gobject_class = (GObjectClass *) klass;
451 
452   gobject_class->dispose = gst_ghost_pad_dispose;
453   gobject_class->constructed = gst_ghost_pad_constructed;
454 
455   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_pull_default);
456   GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_push_default);
457 }
458 
459 static void
gst_ghost_pad_init(GstGhostPad * pad)460 gst_ghost_pad_init (GstGhostPad * pad)
461 {
462   gst_pad_set_activatemode_function (GST_PAD_CAST (pad),
463       gst_ghost_pad_activate_mode_default);
464 }
465 
466 static void
gst_ghost_pad_dispose(GObject * object)467 gst_ghost_pad_dispose (GObject * object)
468 {
469   GstPad *pad;
470   GstPad *internal;
471   GstPad *peer;
472 
473   pad = GST_PAD (object);
474 
475   GST_DEBUG_OBJECT (pad, "dispose");
476 
477   gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);
478 
479   /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
480    * gst_ghost_pad_unlink_default when the ghost pad is in an inconsistent state */
481   peer = gst_pad_get_peer (pad);
482   if (peer) {
483     if (GST_PAD_IS_SRC (pad))
484       gst_pad_unlink (pad, peer);
485     else
486       gst_pad_unlink (peer, pad);
487 
488     gst_object_unref (peer);
489   }
490 
491   GST_OBJECT_LOCK (pad);
492   internal = GST_PROXY_PAD_INTERNAL (pad);
493   if (internal) {
494     gst_pad_set_activatemode_function (internal, NULL);
495 
496     GST_PROXY_PAD_INTERNAL (pad) = NULL;
497     GST_PROXY_PAD_INTERNAL (internal) = NULL;
498 
499     /* disposes of the internal pad, since the ghostpad is the only possible object
500      * that has a refcount on the internal pad. */
501     gst_object_unparent (GST_OBJECT_CAST (internal));
502   }
503 
504   GST_OBJECT_UNLOCK (pad);
505 
506   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
507 }
508 
509 static void
gst_ghost_pad_constructed(GObject * object)510 gst_ghost_pad_constructed (GObject * object)
511 {
512   GstGhostPad *gpad = GST_GHOST_PAD (object);
513   GstPadDirection dir, otherdir;
514   GstPadTemplate *templ;
515   GstPad *pad, *internal;
516 
517   G_OBJECT_CLASS (gst_ghost_pad_parent_class)->constructed (object);
518 
519   g_object_get (gpad, "direction", &dir, "template", &templ, NULL);
520 
521   g_return_if_fail (dir != GST_PAD_UNKNOWN);
522 
523   pad = GST_PAD (gpad);
524 
525   /* Set directional padfunctions for ghostpad */
526   if (dir == GST_PAD_SINK) {
527     gst_pad_set_chain_function (pad, gst_proxy_pad_chain_default);
528     gst_pad_set_chain_list_function (pad, gst_proxy_pad_chain_list_default);
529   } else {
530     gst_pad_set_getrange_function (pad, gst_proxy_pad_getrange_default);
531   }
532 
533   /* INTERNAL PAD, it always exists and is child of the ghostpad */
534   otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
535   if (templ) {
536     internal =
537         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
538         "direction", otherdir, "template", templ, NULL);
539     /* release ref obtained via g_object_get */
540     gst_object_unref (templ);
541   } else {
542     internal =
543         g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
544         "direction", otherdir, NULL);
545   }
546   GST_PAD_UNSET_FLUSHING (internal);
547 
548   /* Set directional padfunctions for internal pad */
549   if (dir == GST_PAD_SRC) {
550     gst_pad_set_chain_function (internal, gst_proxy_pad_chain_default);
551     gst_pad_set_chain_list_function (internal,
552         gst_proxy_pad_chain_list_default);
553   } else {
554     gst_pad_set_getrange_function (internal, gst_proxy_pad_getrange_default);
555   }
556 
557   /* now make the ghostpad a parent of the internal pad */
558   gst_object_set_parent (GST_OBJECT_CAST (internal), GST_OBJECT_CAST (pad));
559 
560   /* The ghostpad is the parent of the internal pad and is the only object that
561    * can have a refcount on the internal pad.
562    * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
563    * a refcount of 1.
564    * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
565    * its refcount on the internal pad in the dispose method by un-parenting it.
566    * This is why we don't take extra refcounts in the assignments below
567    */
568   GST_PROXY_PAD_INTERNAL (pad) = internal;
569   GST_PROXY_PAD_INTERNAL (internal) = pad;
570 
571   /* special activation functions for the internal pad */
572   gst_pad_set_activatemode_function (internal,
573       gst_ghost_pad_internal_activate_mode_default);
574 }
575 
576 #ifndef GST_REMOVE_DEPRECATED
577 /**
578  * gst_ghost_pad_construct:
579  * @gpad: the newly allocated ghost pad
580  *
581  * Finish initialization of a newly allocated ghost pad.
582  *
583  * This function is most useful in language bindings and when subclassing
584  * #GstGhostPad; plugin and application developers normally will not call this
585  * function. Call this function directly after a call to g_object_new
586  * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
587  *
588  * Deprecated: This function is deprecated since 1.18 and does nothing
589  * anymore.
590  *
591  * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
592  */
593 gboolean
gst_ghost_pad_construct(GstGhostPad * gpad)594 gst_ghost_pad_construct (GstGhostPad * gpad)
595 {
596   return TRUE;
597 }
598 #endif
599 
600 static GstPad *
gst_ghost_pad_new_full(const gchar * name,GstPadDirection dir,GstPadTemplate * templ)601 gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
602     GstPadTemplate * templ)
603 {
604   GstGhostPad *ret;
605   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
606 
607   /* OBJECT CREATION */
608   if (templ) {
609     GType pad_type =
610         GST_PAD_TEMPLATE_GTYPE (templ) ==
611         G_TYPE_NONE ? GST_TYPE_GHOST_PAD : GST_PAD_TEMPLATE_GTYPE (templ);
612 
613     g_return_val_if_fail (g_type_is_a (pad_type, GST_TYPE_GHOST_PAD), NULL);
614 
615     ret = g_object_new (pad_type, "name", name,
616         "direction", dir, "template", templ, NULL);
617   } else {
618     ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
619         "direction", dir, NULL);
620   }
621 
622   return GST_PAD_CAST (ret);
623 }
624 
625 /**
626  * gst_ghost_pad_new_no_target:
627  * @name: (allow-none): the name of the new pad, or %NULL to assign a default name.
628  * @dir: the direction of the ghostpad
629  *
630  * Create a new ghostpad without a target with the given direction.
631  * A target can be set on the ghostpad later with the
632  * gst_ghost_pad_set_target() function.
633  *
634  * The created ghostpad will not have a padtemplate.
635  *
636  * Returns: (transfer floating) (nullable): a new #GstPad, or %NULL in
637  * case of an error.
638  */
639 GstPad *
gst_ghost_pad_new_no_target(const gchar * name,GstPadDirection dir)640 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
641 {
642   GstPad *ret;
643 
644   g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);
645 
646   GST_LOG ("name:%s, direction:%d", GST_STR_NULL (name), dir);
647 
648   ret = gst_ghost_pad_new_full (name, dir, NULL);
649 
650   return ret;
651 }
652 
653 /**
654  * gst_ghost_pad_new:
655  * @name: (allow-none): the name of the new pad, or %NULL to assign a default name
656  * @target: (transfer none): the pad to ghost.
657  *
658  * Create a new ghostpad with @target as the target. The direction will be taken
659  * from the target pad. @target must be unlinked.
660  *
661  * Will ref the target.
662  *
663  * Returns: (transfer floating) (nullable): a new #GstPad, or %NULL in
664  * case of an error.
665  */
666 GstPad *
gst_ghost_pad_new(const gchar * name,GstPad * target)667 gst_ghost_pad_new (const gchar * name, GstPad * target)
668 {
669   GstPad *ret;
670 
671   g_return_val_if_fail (GST_IS_PAD (target), NULL);
672   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
673 
674   GST_LOG ("name:%s, target:%s:%s", GST_STR_NULL (name),
675       GST_DEBUG_PAD_NAME (target));
676 
677   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target))))
678     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
679       goto set_target_failed;
680 
681   return ret;
682 
683   /* ERRORS */
684 set_target_failed:
685   {
686     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
687         GST_DEBUG_PAD_NAME (target));
688     gst_object_unref (ret);
689     return NULL;
690   }
691 }
692 
693 /**
694  * gst_ghost_pad_new_from_template:
695  * @name: (allow-none): the name of the new pad, or %NULL to assign a default name.
696  * @target: (transfer none): the pad to ghost.
697  * @templ: (transfer none): the #GstPadTemplate to use on the ghostpad.
698  *
699  * Create a new ghostpad with @target as the target. The direction will be taken
700  * from the target pad. The template used on the ghostpad will be @template.
701  *
702  * Will ref the target.
703  *
704  * Returns: (transfer floating) (nullable): a new #GstPad, or %NULL in
705  * case of an error.
706  */
707 
708 GstPad *
gst_ghost_pad_new_from_template(const gchar * name,GstPad * target,GstPadTemplate * templ)709 gst_ghost_pad_new_from_template (const gchar * name, GstPad * target,
710     GstPadTemplate * templ)
711 {
712   GstPad *ret;
713 
714   g_return_val_if_fail (GST_IS_PAD (target), NULL);
715   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
716   g_return_val_if_fail (templ != NULL, NULL);
717   g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) ==
718       GST_PAD_DIRECTION (target), NULL);
719 
720   GST_LOG ("name:%s, target:%s:%s, templ:%p", GST_STR_NULL (name),
721       GST_DEBUG_PAD_NAME (target), templ);
722 
723   if ((ret = gst_ghost_pad_new_full (name, GST_PAD_DIRECTION (target), templ)))
724     if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ret), target))
725       goto set_target_failed;
726 
727   return ret;
728 
729   /* ERRORS */
730 set_target_failed:
731   {
732     GST_WARNING_OBJECT (ret, "failed to set target %s:%s",
733         GST_DEBUG_PAD_NAME (target));
734     gst_object_unref (ret);
735     return NULL;
736   }
737 }
738 
739 /**
740  * gst_ghost_pad_new_no_target_from_template:
741  * @name: (allow-none): the name of the new pad, or %NULL to assign a default name
742  * @templ: (transfer none): the #GstPadTemplate to create the ghostpad from.
743  *
744  * Create a new ghostpad based on @templ, without setting a target. The
745  * direction will be taken from the @templ.
746  *
747  * Returns: (transfer floating) (nullable): a new #GstPad, or %NULL in
748  * case of an error.
749  */
750 GstPad *
gst_ghost_pad_new_no_target_from_template(const gchar * name,GstPadTemplate * templ)751 gst_ghost_pad_new_no_target_from_template (const gchar * name,
752     GstPadTemplate * templ)
753 {
754   GstPad *ret;
755 
756   g_return_val_if_fail (templ != NULL, NULL);
757 
758   ret =
759       gst_ghost_pad_new_full (name, GST_PAD_TEMPLATE_DIRECTION (templ), templ);
760 
761   return ret;
762 }
763 
764 /**
765  * gst_ghost_pad_get_target:
766  * @gpad: the #GstGhostPad
767  *
768  * Get the target pad of @gpad. Unref target pad after usage.
769  *
770  * Returns: (transfer full) (nullable): the target #GstPad, can be
771  * %NULL if the ghostpad has no target set. Unref target pad after
772  * usage.
773  */
774 GstPad *
gst_ghost_pad_get_target(GstGhostPad * gpad)775 gst_ghost_pad_get_target (GstGhostPad * gpad)
776 {
777   GstPad *ret;
778 
779   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), NULL);
780 
781   ret = gst_proxy_pad_get_target (GST_PAD_CAST (gpad));
782 
783   GST_DEBUG_OBJECT (gpad, "get target %s:%s", GST_DEBUG_PAD_NAME (ret));
784 
785   return ret;
786 }
787 
788 /**
789  * gst_ghost_pad_set_target:
790  * @gpad: the #GstGhostPad
791  * @newtarget: (transfer none) (allow-none): the new pad target
792  *
793  * Set the new target of the ghostpad @gpad. Any existing target
794  * is unlinked and links to the new target are established. if @newtarget is
795  * %NULL the target will be cleared.
796  *
797  * Returns: %TRUE if the new target could be set. This function
798  *     can return %FALSE when the internal pads could not be linked.
799  */
800 gboolean
gst_ghost_pad_set_target(GstGhostPad * gpad,GstPad * newtarget)801 gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget)
802 {
803   GstPad *internal;
804   GstPad *oldtarget;
805   GstPadLinkReturn lret;
806 
807   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
808   g_return_val_if_fail (GST_PAD_CAST (gpad) != newtarget, FALSE);
809 
810   GST_OBJECT_LOCK (gpad);
811   internal = GST_PROXY_PAD_INTERNAL (gpad);
812 
813   if (newtarget == internal) {
814     GST_OBJECT_UNLOCK (gpad);
815     GST_WARNING_OBJECT (gpad, "Target has already been set to %s:%s",
816         GST_DEBUG_PAD_NAME (newtarget));
817     return TRUE;
818   }
819 
820   if (newtarget)
821     GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget));
822   else
823     GST_DEBUG_OBJECT (gpad, "clearing target");
824 
825   /* clear old target */
826   if ((oldtarget = gst_pad_get_peer (internal))) {
827     GST_OBJECT_UNLOCK (gpad);
828 
829     /* unlink internal pad */
830     if (GST_PAD_IS_SRC (internal))
831       gst_pad_unlink (internal, oldtarget);
832     else
833       gst_pad_unlink (oldtarget, internal);
834 
835     gst_object_unref (oldtarget);
836   } else {
837     GST_OBJECT_UNLOCK (gpad);
838   }
839 
840   if (newtarget) {
841     /* and link to internal pad without any checks */
842     GST_DEBUG_OBJECT (gpad, "connecting internal pad to target %"
843         GST_PTR_FORMAT, newtarget);
844 
845     if (GST_PAD_IS_SRC (internal))
846       lret =
847           gst_pad_link_full (internal, newtarget, GST_PAD_LINK_CHECK_NOTHING);
848     else
849       lret =
850           gst_pad_link_full (newtarget, internal, GST_PAD_LINK_CHECK_NOTHING);
851 
852     if (lret != GST_PAD_LINK_OK)
853       goto link_failed;
854   }
855 
856   return TRUE;
857 
858   /* ERRORS */
859 link_failed:
860   {
861     GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%s",
862         gst_pad_link_get_name (lret));
863     return FALSE;
864   }
865 }
866