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