gstghostpad.c 30.9 KB
Newer Older
1 2 3 4
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *                    2005 Andy Wingo <wingo@pobox.com>
5
 *		      2006 Edward Hervey <bilboed@bilboed.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * gstghostpad.c: Proxy pads
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
24

Stefan Kost's avatar
Stefan Kost committed
25 26 27 28 29
/**
 * SECTION:gstghostpad
 * @short_description: Pseudo link pads
 * @see_also: #GstPad
 *
Stefan Kost's avatar
Stefan Kost committed
30 31
 * GhostPads are useful when organizing pipelines with #GstBin like elements.
 * The idea here is to create hierarchical element graphs. The bin element
Stefan Kost's avatar
Stefan Kost committed
32 33 34 35
 * contains a sub-graph. Now one would like to treat the bin-element like any
 * other #GstElement. This is where GhostPads come into play. A GhostPad acts as
 * a proxy for another pad. Thus the bin can have sink and source ghost-pads
 * that are associated with sink and source pads of the child elements.
Stefan Kost's avatar
Stefan Kost committed
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()
Stefan Kost's avatar
Stefan Kost committed
39
 * to create the ghost-pad and use gst_ghost_pad_set_target() to establish the
40
 * association later on.
Stefan Kost's avatar
Stefan Kost committed
41
 *
Edward Hervey's avatar
Edward Hervey committed
42 43
 * Note that GhostPads add overhead to the data processing of a pipeline.
 *
Stefan Kost's avatar
Stefan Kost committed
44
 * Last reviewed on 2005-11-18 (0.9.5)
Stefan Kost's avatar
Stefan Kost committed
45
 */
46 47

#include "gst_private.h"
48
#include "gstinfo.h"
49 50

#include "gstghostpad.h"
51
#include "gst.h"
52

53 54
#define GST_CAT_DEFAULT GST_CAT_PADS

Edward Hervey's avatar
Edward Hervey committed
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_PAD_PEER (GST_PROXY_PAD_INTERNAL (pad)))
58
#define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD_PRIVATE (pad)->internal)
59

60
struct _GstProxyPadPrivate
61
{
62
  GstPad *internal;
63 64 65 66
};

G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);

67
static GstPad *gst_proxy_pad_get_target (GstPad * pad);
68

69 70 71 72 73 74 75 76 77
/**
 * gst_proxy_pad_event_default:
 * @pad: a #GstPad to push the event to.
 * @event: (transfer full): the #GstEvent to send to the pad.
 *
 * Invoke the default event of the proxy pad.
 *
 * Returns: TRUE if the event was handled.
 *
78
 * Since: 0.10.36
79
 */
80
gboolean
81
gst_proxy_pad_event_default (GstPad * pad, GstEvent * event)
82
{
Wim Taymans's avatar
Wim Taymans committed
83
  gboolean res;
84
  GstPad *internal;
85

86 87 88
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
  g_return_val_if_fail (GST_IS_EVENT (event), FALSE);

Wim Taymans's avatar
Wim Taymans committed
89 90
  internal = GST_PROXY_PAD_INTERNAL (pad);
  res = gst_pad_push_event (internal, event);
91 92

  return res;
93 94
}

95 96 97 98 99 100 101 102 103
/**
 * gst_proxy_pad_query_default:
 * @pad: a #GstPad to invoke the default query on.
 * @query: (transfer none): the #GstQuery to perform.
 *
 * Invoke the default query function of the proxy pad.
 *
 * Returns: TRUE if the query could be performed.
 *
104
 * Since: 0.10.36
105
 */
106
gboolean
107
gst_proxy_pad_query_default (GstPad * pad, GstQuery * query)
108
{
Wim Taymans's avatar
Wim Taymans committed
109
  gboolean res;
Wim Taymans's avatar
Wim Taymans committed
110
  GstPad *target;
111 112

  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
113
  g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
114

Wim Taymans's avatar
Wim Taymans committed
115 116
  target = gst_proxy_pad_get_target (pad);

Wim Taymans's avatar
Wim Taymans committed
117
  switch (GST_QUERY_TYPE (query)) {
Wim Taymans's avatar
Wim Taymans committed
118 119 120 121 122 123 124 125 126 127 128 129 130
    case GST_QUERY_ACCEPT_CAPS:
    {
      if (target) {
        res = gst_pad_query (target, query);
        gst_object_unref (target);
      } else {
        GST_DEBUG_OBJECT (pad, "no target");
        /* We don't have a target, we return TRUE and we assume that any future
         * target will be able to deal with any configured caps. */
        res = TRUE;
      }
      break;
    }
Wim Taymans's avatar
Wim Taymans committed
131 132
    default:
    {
Wim Taymans's avatar
Wim Taymans committed
133 134 135 136 137 138 139
      if (target) {
        res = gst_pad_query (target, query);
        gst_object_unref (target);
      } else {
        GST_DEBUG_OBJECT (pad, "no target pad");
        res = FALSE;
      }
Wim Taymans's avatar
Wim Taymans committed
140 141 142
      break;
    }
  }
143
  return res;
144 145
}

146 147 148 149 150 151 152 153 154
/**
 * gst_proyx_pad_iterate_internal_links_default:
 * @pad: the #GstPad to get the internal links of.
 *
 * Invoke the default iterate internal links function of the proxy pad.
 *
 * Returns: a #GstIterator of #GstPad, or NULL if @pad has no parent. Unref each
 * returned pad with gst_object_unref().
 *
155
 * Since: 0.10.36
156
 */
157
GstIterator *
158
gst_proxy_pad_iterate_internal_links_default (GstPad * pad)
159 160
{
  GstIterator *res = NULL;
161
  GstPad *internal;
Wim Taymans's avatar
Wim Taymans committed
162
  GValue v = { 0, };
163

164 165
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);

Wim Taymans's avatar
Wim Taymans committed
166 167 168 169 170
  internal = GST_PROXY_PAD_INTERNAL (pad);
  g_value_init (&v, GST_TYPE_PAD);
  g_value_set_object (&v, internal);
  res = gst_iterator_new_single (GST_TYPE_PAD, &v);
  g_value_unset (&v);
171 172 173 174

  return res;
}

175 176 177 178 179 180 181 182 183 184
/**
 * gst_proxy_pad_chain_default:
 * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
 * @buffer: (transfer full): the #GstBuffer to send, return GST_FLOW_ERROR
 *     if not.
 *
 * Invoke the default chain function of the proxy pad.
 *
 * Returns: a #GstFlowReturn from the pad.
 *
185
 * Since: 0.10.36
186
 */
187
GstFlowReturn
188
gst_proxy_pad_chain_default (GstPad * pad, GstBuffer * buffer)
189
{
190
  GstFlowReturn res;
191 192 193 194
  GstPad *internal;

  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
195

196
  internal = GST_PROXY_PAD_INTERNAL (pad);
197
  res = gst_pad_push (internal, buffer);
198 199

  return res;
200 201
}

202 203 204 205 206 207 208 209 210 211
/**
 * gst_proxy_pad_chain_list_default:
 * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
 * @list: (transfer full): the #GstBufferList to send, return GST_FLOW_ERROR
 *     if not.
 *
 * Invoke the default chain list function of the proxy pad.
 *
 * Returns: a #GstFlowReturn from the pad.
 *
212
 * Since: 0.10.36
213
 */
214
GstFlowReturn
215
gst_proxy_pad_chain_list_default (GstPad * pad, GstBufferList * list)
216 217
{
  GstFlowReturn res;
218 219 220 221
  GstPad *internal;

  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
222

223
  internal = GST_PROXY_PAD_INTERNAL (pad);
224 225 226 227 228
  res = gst_pad_push_list (internal, list);

  return res;
}

229 230 231 232 233 234 235 236 237 238 239 240
/**
 * gst_proxy_pad_get_range_default:
 * @pad: a src #GstPad, returns #GST_FLOW_ERROR if not.
 * @offset: The start offset of the buffer
 * @size: The length of the buffer
 * @buffer: (out callee-allocates): a pointer to hold the #GstBuffer,
 *     returns #GST_FLOW_ERROR if %NULL.
 *
 * Invoke the default getrange function of the proxy pad.
 *
 * Returns: a #GstFlowReturn from the pad.
 *
241
 * Since: 0.10.36
242
 */
243
GstFlowReturn
244
gst_proxy_pad_getrange_default (GstPad * pad, guint64 offset, guint size,
245 246
    GstBuffer ** buffer)
{
247
  GstFlowReturn res;
248 249 250 251
  GstPad *internal;

  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), GST_FLOW_ERROR);
  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
252

253
  internal = GST_PROXY_PAD_INTERNAL (pad);
254
  res = gst_pad_pull_range (internal, offset, size, buffer);
255 256

  return res;
257 258
}

259 260
/**
 * gst_proxy_pad_getcaps_default:
261 262
 * @pad: a #GstPad to get the capabilities of.
 * @filter: a #GstCaps filter.
263 264 265 266 267
 *
 * Invoke the default getcaps function of the proxy pad.
 *
 * Returns: (transfer full): the caps of the pad with incremented ref-count
 *
268
 * Since: 0.10.36
269
 */
270
GstCaps *
271
gst_proxy_pad_getcaps_default (GstPad * pad, GstCaps * filter)
272
{
273
  GstPad *target;
274
  GstCaps *res;
275
  GstPadTemplate *templ;
276

277
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);
278

279 280
  templ = GST_PAD_PAD_TEMPLATE (pad);
  target = gst_proxy_pad_get_target (pad);
281
  if (target) {
Edward Hervey's avatar
Edward Hervey committed
282
    /* if we have a real target, proxy the call */
283
    res = gst_pad_get_caps (target, filter);
Edward Hervey's avatar
Edward Hervey committed
284

285 286
    GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
        GST_DEBUG_PAD_NAME (target), res);
287

Wim Taymans's avatar
Wim Taymans committed
288 289
    gst_object_unref (target);

290 291 292 293 294 295
    /* filter against the template */
    if (templ && res) {
      GstCaps *filt, *tmp;

      filt = GST_PAD_TEMPLATE_CAPS (templ);
      if (filt) {
296
        tmp = gst_caps_intersect_full (res, filt, GST_CAPS_INTERSECT_FIRST);
297 298 299 300 301 302 303 304
        gst_caps_unref (res);
        res = tmp;
        GST_DEBUG_OBJECT (pad,
            "filtered against template gives %" GST_PTR_FORMAT, res);
      }
    }
  } else {
    /* else, if we have a template, use its caps. */
Edward Hervey's avatar
Edward Hervey committed
305 306 307 308 309 310
    if (templ) {
      res = GST_PAD_TEMPLATE_CAPS (templ);
      GST_DEBUG_OBJECT (pad,
          "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
          res);
      res = gst_caps_ref (res);
311 312 313 314 315 316 317 318 319

      if (filter) {
        GstCaps *intersection =
            gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);

        gst_caps_unref (res);
        res = intersection;
      }

Edward Hervey's avatar
Edward Hervey committed
320 321 322
      goto done;
    }

323 324 325 326 327 328
    /* If there's a filter, return that */
    if (filter != NULL) {
      res = gst_caps_ref (filter);
      goto done;
    }

Edward Hervey's avatar
Edward Hervey committed
329 330
    /* last resort, any caps */
    GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
331 332
    res = gst_caps_new_any ();
  }
Edward Hervey's avatar
Edward Hervey committed
333 334

done:
335
  return res;
336 337
}

338 339 340 341 342 343 344 345 346
/**
 * gst_proxy_pad_acceptcaps_default:
 * @pad: a #GstPad to check
 * @caps: a #GstCaps to check on the pad
 *
 * Invoke the default acceptcaps function of the proxy pad.
 *
 * Returns: TRUE if the pad can accept the caps.
 *
347
 * Since: 0.10.36
348
 */
349
gboolean
350
gst_proxy_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
351
{
352
  GstPad *target;
353
  gboolean res;
354

355 356 357 358
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
  g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), FALSE);

  target = gst_proxy_pad_get_target (pad);
359 360 361
  if (target) {
    res = gst_pad_accept_caps (target, caps);
    gst_object_unref (target);
362
  } else {
Wim Taymans's avatar
Wim Taymans committed
363
    GST_DEBUG_OBJECT (pad, "no target");
364 365 366
    /* We don't have a target, we return TRUE and we assume that any future
     * target will be able to deal with any configured caps. */
    res = TRUE;
367
  }
368 369

  return res;
370 371
}

372 373 374 375 376
static GstPad *
gst_proxy_pad_get_target (GstPad * pad)
{
  GstPad *target;

377
  GST_OBJECT_LOCK (pad);
378
  target = GST_PROXY_PAD_TARGET (pad);
379 380
  if (target)
    gst_object_ref (target);
381
  GST_OBJECT_UNLOCK (pad);
382 383

  return target;
384 385
}

386 387 388 389 390 391 392 393 394 395 396
/**
 * gst_proxy_pad_get_internal:
 * @pad: the #GstProxyPad
 *
 * Get the internal pad of @pad. Unref target pad after usage.
 *
 * The internal pad of a #GstGhostPad is the internally used
 * pad of opposite direction, which is used to link to the target.
 *
 * Returns: (transfer full): the target #GstProxyPad, can be NULL.
 * Unref target pad after usage.
397
 *
398
 * Since: 0.10.36
399 400 401
 */
GstProxyPad *
gst_proxy_pad_get_internal (GstProxyPad * pad)
402 403 404
{
  GstPad *internal;

405 406
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);

407
  GST_OBJECT_LOCK (pad);
408 409 410
  internal = GST_PROXY_PAD_INTERNAL (pad);
  if (internal)
    gst_object_ref (internal);
411
  GST_OBJECT_UNLOCK (pad);
412

413
  return GST_PROXY_PAD_CAST (internal);
414 415
}

416 417 418 419 420 421
/**
 * gst_proxy_pad_unlink_default:
 * @pad: a #GstPad to unlink
 *
 * Invoke the default unlink function of the proxy pad.
 *
422
 * Since: 0.10.36
423 424
 */
void
425
gst_proxy_pad_unlink_default (GstPad * pad)
426
{
427
  /* nothing to do anymore */
428 429 430
  GST_DEBUG_OBJECT (pad, "pad is unlinked");
}

431 432 433 434 435 436
static void
gst_proxy_pad_class_init (GstProxyPadClass * klass)
{
  g_type_class_add_private (klass, sizeof (GstProxyPadPrivate));

  /* Register common function pointer descriptions */
437 438 439 440 441 442 443 444 445
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_event_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_query_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_iterate_internal_links_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getcaps_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_acceptcaps_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_unlink_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_list_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getrange_default);
446 447
}

448 449 450 451 452
static void
gst_proxy_pad_init (GstProxyPad * ppad)
{
  GstPad *pad = (GstPad *) ppad;

453 454
  GST_PROXY_PAD_PRIVATE (ppad) = G_TYPE_INSTANCE_GET_PRIVATE (ppad,
      GST_TYPE_PROXY_PAD, GstProxyPadPrivate);
455

456 457
  gst_pad_set_event_function (pad, gst_proxy_pad_event_default);
  gst_pad_set_query_function (pad, gst_proxy_pad_query_default);
458
  gst_pad_set_iterate_internal_links_function (pad,
459
      gst_proxy_pad_iterate_internal_links_default);
460

461 462
  gst_pad_set_getcaps_function (pad, gst_proxy_pad_getcaps_default);
  gst_pad_set_unlink_function (pad, gst_proxy_pad_unlink_default);
463 464
}

465 466 467 468 469 470

/***********************************************************************
 * Ghost pads, implemented as a pair of proxy pads (sort of)
 */


471
#define GST_GHOST_PAD_PRIVATE(obj)	(GST_GHOST_PAD_CAST (obj)->priv)
472

473 474
struct _GstGhostPadPrivate
{
475
  /* with PROXY_LOCK */
476
  gboolean constructed;
477 478 479 480 481 482
};

G_DEFINE_TYPE (GstGhostPad, gst_ghost_pad, GST_TYPE_PROXY_PAD);

static void gst_ghost_pad_dispose (GObject * object);

483 484 485 486 487 488 489 490 491 492
/**
 * gst_ghost_pad_internal_activate_push_default:
 * @pad: the #GstPad to activate or deactivate.
 * @active: whether the pad should be active or not.
 *
 * Invoke the default activate push function of a proxy pad that is
 * owned by a ghost pad.
 *
 * Returns: %TRUE if the operation was successful.
 *
493
 * Since: 0.10.36
494
 */
495 496
gboolean
gst_ghost_pad_internal_activate_push_default (GstPad * pad, gboolean active)
497
{
498
  gboolean ret;
499
  GstPad *other;
500

501 502
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);

503 504
  GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, we're ok",
      (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
505

506 507 508 509
  /* in both cases (SRC and SINK) we activate just the internal pad. The targets
   * will be activated later (or already in case of a ghost sinkpad). */
  other = GST_PROXY_PAD_INTERNAL (pad);
  ret = gst_pad_activate_push (other, active);
510

511 512
  return ret;
}
513

514 515 516 517 518 519 520 521 522 523
/**
 * gst_ghost_pad_internal_activate_pull_default:
 * @pad: the #GstPad to activate or deactivate.
 * @active: whether the pad should be active or not.
 *
 * Invoke the default activate pull function of a proxy pad that is
 * owned by a ghost pad.
 *
 * Returns: %TRUE if the operation was successful.
 *
524
 * Since: 0.10.36
525
 */
526 527
gboolean
gst_ghost_pad_internal_activate_pull_default (GstPad * pad, gboolean active)
528 529
{
  gboolean ret;
530
  GstPad *other;
531

532 533
  g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);

534 535
  GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
      GST_DEBUG_PAD_NAME (pad));
536

537
  if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
538 539
    /* we are activated in pull mode by our peer element, which is a sinkpad
     * that wants to operate in pull mode. This activation has to propagate
Piotr Fusik's avatar
Piotr Fusik committed
540
     * upstream through the pipeline. We call the internal activation function,
541
     * which will trigger gst_ghost_pad_activate_pull_default, which propagates even
542 543
     * further upstream */
    GST_LOG_OBJECT (pad, "pad is src, activate internal");
544 545 546
    other = GST_PROXY_PAD_INTERNAL (pad);
    ret = gst_pad_activate_pull (other, active);
  } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
547 548 549
    /* We are SINK, the ghostpad is SRC, we propagate the activation upstream
     * since we hold a pointer to the upstream peer. */
    GST_LOG_OBJECT (pad, "activating peer");
550 551
    ret = gst_pad_activate_pull (other, active);
    gst_object_unref (other);
552 553 554
  } else {
    /* this is failure, we can't activate pull if there is no peer */
    GST_LOG_OBJECT (pad, "not src and no peer, failing");
555
    ret = FALSE;
556
  }
557 558 559 560

  return ret;
}

561 562 563 564 565 566 567 568 569
/**
 * gst_ghost_pad_activate_push_default:
 * @pad: the #GstPad to activate or deactivate.
 * @active: whether the pad should be active or not.
 *
 * Invoke the default activate push function of a ghost pad.
 *
 * Returns: %TRUE if the operation was successful.
 *
570
 * Since: 0.10.36
571
 */
572
gboolean
573
gst_ghost_pad_activate_push_default (GstPad * pad, gboolean active)
574 575
{
  gboolean ret;
576
  GstPad *other;
577

578 579
  g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);

580 581
  GST_LOG_OBJECT (pad, "%sactivate push on %s:%s, proxy internal",
      (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad));
582

583 584 585
  /* just activate the internal pad */
  other = GST_PROXY_PAD_INTERNAL (pad);
  ret = gst_pad_activate_push (other, active);
586

587 588 589
  return ret;
}

590 591 592 593 594 595 596 597 598
/**
 * gst_ghost_pad_activate_pull_default:
 * @pad: the #GstPad to activate or deactivate.
 * @active: whether the pad should be active or not.
 *
 * Invoke the default activate pull function of a ghost pad.
 *
 * Returns: %TRUE if the operation was successful.
 *
599
 * Since: 0.10.36
600
 */
601
gboolean
602
gst_ghost_pad_activate_pull_default (GstPad * pad, gboolean active)
603 604
{
  gboolean ret;
605
  GstPad *other;
606

607 608
  g_return_val_if_fail (GST_IS_GHOST_PAD (pad), FALSE);

609 610
  GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"),
      GST_DEBUG_PAD_NAME (pad));
611

612
  if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
613 614 615 616
    /* the ghostpad is SRC and activated in pull mode by its peer, call the
     * activation function of the internal pad to propagate the activation
     * upstream */
    GST_LOG_OBJECT (pad, "pad is src, activate internal");
617 618 619
    other = GST_PROXY_PAD_INTERNAL (pad);
    ret = gst_pad_activate_pull (other, active);
  } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) {
620 621 622
    /* We are SINK and activated by the internal pad, propagate activation
     * upstream because we hold a ref to the upstream peer */
    GST_LOG_OBJECT (pad, "activating peer");
623 624
    ret = gst_pad_activate_pull (other, active);
    gst_object_unref (other);
625 626 627
  } else {
    /* no peer, we fail */
    GST_LOG_OBJECT (pad, "pad not src and no peer, failing");
628
    ret = FALSE;
629
  }
630 631 632 633

  return ret;
}

634 635 636 637 638 639 640 641 642
/**
 * gst_ghost_pad_link_default:
 * @pad: the #GstPad to link.
 * @peer: the #GstPad peer
 *
 * Invoke the default link function of a ghost pad.
 *
 * Returns: #GstPadLinkReturn of the operation
 *
643
 * Since: 0.10.36
644
 */
645
GstPadLinkReturn
646
gst_ghost_pad_link_default (GstPad * pad, GstPad * peer)
647
{
648
  GstPadLinkReturn ret;
649

650 651 652
  g_return_val_if_fail (GST_IS_GHOST_PAD (pad), GST_PAD_LINK_REFUSED);
  g_return_val_if_fail (GST_IS_PAD (peer), GST_PAD_LINK_REFUSED);

653
  GST_DEBUG_OBJECT (pad, "linking ghostpad");
654

655
  ret = GST_PAD_LINK_OK;
656
  /* if we are a source pad, we should call the peer link function
657
   * if the peer has one, see design docs. */
658
  if (GST_PAD_IS_SRC (pad)) {
659
    if (GST_PAD_LINKFUNC (peer)) {
660
      ret = GST_PAD_LINKFUNC (peer) (peer, pad);
661
      if (ret != GST_PAD_LINK_OK)
662
        GST_DEBUG_OBJECT (pad, "linking failed");
663
    }
664
  }
665
  return ret;
666 667
}

668 669 670 671 672 673
/**
 * gst_ghost_pad_unlink_default:
 * @pad: the #GstPad to link.
 *
 * Invoke the default unlink function of a ghost pad.
 *
674
 * Since: 0.10.36
675
 */
676
void
677
gst_ghost_pad_unlink_default (GstPad * pad)
678
{
679 680
  g_return_if_fail (GST_IS_GHOST_PAD (pad));

681
  GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
682 683
}

684 685 686 687 688 689 690 691 692
static void
gst_ghost_pad_class_init (GstGhostPadClass * klass)
{
  GObjectClass *gobject_class = (GObjectClass *) klass;

  g_type_class_add_private (klass, sizeof (GstGhostPadPrivate));

  gobject_class->dispose = gst_ghost_pad_dispose;

693 694 695
  GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_pull_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_activate_push_default);
  GST_DEBUG_REGISTER_FUNCPTR (gst_ghost_pad_link_default);
696 697
}

698 699 700
static void
gst_ghost_pad_init (GstGhostPad * pad)
{
701 702 703
  GST_GHOST_PAD_PRIVATE (pad) = G_TYPE_INSTANCE_GET_PRIVATE (pad,
      GST_TYPE_GHOST_PAD, GstGhostPadPrivate);

704
  gst_pad_set_activatepull_function (GST_PAD_CAST (pad),
705
      gst_ghost_pad_activate_pull_default);
706
  gst_pad_set_activatepush_function (GST_PAD_CAST (pad),
707
      gst_ghost_pad_activate_push_default);
708 709 710 711 712
}

static void
gst_ghost_pad_dispose (GObject * object)
{
713
  GstPad *pad;
714
  GstPad *internal;
715
  GstPad *peer;
716

717 718 719 720
  pad = GST_PAD (object);

  GST_DEBUG_OBJECT (pad, "dispose");

721 722 723
  gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL);

  /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to
724
   * gst_ghost_pad_unlink_default when the ghost pad is in an inconsistent state */
725 726 727 728 729 730 731 732 733 734
  peer = gst_pad_get_peer (pad);
  if (peer) {
    if (GST_PAD_IS_SRC (pad))
      gst_pad_unlink (pad, peer);
    else
      gst_pad_unlink (peer, pad);

    gst_object_unref (peer);
  }

735
  GST_OBJECT_LOCK (pad);
736 737 738 739 740
  internal = GST_PROXY_PAD_INTERNAL (pad);

  gst_pad_set_activatepull_function (internal, NULL);
  gst_pad_set_activatepush_function (internal, NULL);

741
  /* disposes of the internal pad, since the ghostpad is the only possible object
742 743
   * that has a refcount on the internal pad. */
  gst_object_unparent (GST_OBJECT_CAST (internal));
744
  GST_PROXY_PAD_INTERNAL (pad) = NULL;
745

746
  GST_OBJECT_UNLOCK (pad);
747 748 749 750

  G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object);
}

751 752 753 754 755 756 757 758 759 760 761 762
/**
 * gst_ghost_pad_construct:
 * @gpad: the newly allocated ghost pad
 *
 * Finish initialization of a newly allocated ghost pad.
 *
 * This function is most useful in language bindings and when subclassing
 * #GstGhostPad; plugin and application developers normally will not call this
 * function. Call this function directly after a call to g_object_new
 * (GST_TYPE_GHOST_PAD, "direction", @dir, ..., NULL).
 *
 * Returns: %TRUE if the construction succeeds, %FALSE otherwise.
763 764
 *
 * Since: 0.10.22
765 766 767
 */
gboolean
gst_ghost_pad_construct (GstGhostPad * gpad)
768
{
769 770 771
  GstPadDirection dir, otherdir;
  GstPadTemplate *templ;
  GstPad *pad, *internal;
772

773
  g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
774 775
  g_return_val_if_fail (GST_GHOST_PAD_PRIVATE (gpad)->constructed == FALSE,
      FALSE);
776

777 778 779 780 781
  g_object_get (gpad, "direction", &dir, "template", &templ, NULL);

  g_return_val_if_fail (dir != GST_PAD_UNKNOWN, FALSE);

  pad = GST_PAD (gpad);
782

783 784
  /* Set directional padfunctions for ghostpad */
  if (dir == GST_PAD_SINK) {
785 786
    gst_pad_set_chain_function (pad, gst_proxy_pad_chain_default);
    gst_pad_set_chain_list_function (pad, gst_proxy_pad_chain_list_default);
787
  } else {
788
    gst_pad_set_getrange_function (pad, gst_proxy_pad_getrange_default);
789 790
  }

791
  /* link/unlink functions */
792 793
  gst_pad_set_link_function (pad, gst_ghost_pad_link_default);
  gst_pad_set_unlink_function (pad, gst_ghost_pad_unlink_default);
794

795
  /* INTERNAL PAD, it always exists and is child of the ghostpad */
796 797 798 799 800
  otherdir = (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC;
  if (templ) {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, "template", templ, NULL);
801 802
    /* release ref obtained via g_object_get */
    gst_object_unref (templ);
803 804 805 806 807
  } else {
    internal =
        g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
        "direction", otherdir, NULL);
  }
808
  GST_PAD_UNSET_FLUSHING (internal);
809 810 811

  /* Set directional padfunctions for internal pad */
  if (dir == GST_PAD_SRC) {
812 813 814
    gst_pad_set_chain_function (internal, gst_proxy_pad_chain_default);
    gst_pad_set_chain_list_function (internal,
        gst_proxy_pad_chain_list_default);
815
  } else {
816
    gst_pad_set_getrange_function (internal, gst_proxy_pad_getrange_default);
817 818
  }

819
  GST_OBJECT_LOCK (pad);
820

821 822
  /* now make the ghostpad a parent of the internal pad */
  if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
823
          GST_OBJECT_CAST (pad)))
824
    goto parent_failed;
825

826
  /* The ghostpad is the parent of the internal pad and is the only object that
827 828 829 830
   * can have a refcount on the internal pad.
   * At this point, the GstGhostPad has a refcount of 1, and the internal pad has
   * a refcount of 1.
   * When the refcount of the GstGhostPad drops to 0, the ghostpad will dispose
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
831
   * its refcount on the internal pad in the dispose method by un-parenting it.
832
   * This is why we don't take extra refcounts in the assignments below
833
   */
834 835
  GST_PROXY_PAD_INTERNAL (pad) = internal;
  GST_PROXY_PAD_INTERNAL (internal) = pad;
836

837 838
  /* special activation functions for the internal pad */
  gst_pad_set_activatepull_function (internal,
839
      gst_ghost_pad_internal_activate_pull_default);
840
  gst_pad_set_activatepush_function (internal,
841
      gst_ghost_pad_internal_activate_push_default);
842

843
  GST_OBJECT_UNLOCK (pad);
844

845
  GST_GHOST_PAD_PRIVATE (gpad)->constructed = TRUE;
846
  return TRUE;
847 848 849 850

  /* ERRORS */
parent_failed:
  {
851
    GST_WARNING_OBJECT (gpad, "Could not set internal pad %s:%s",
852 853 854
        GST_DEBUG_PAD_NAME (internal));
    g_critical ("Could not set internal pad %s:%s",
        GST_DEBUG_PAD_NAME (internal));
855
    GST_OBJECT_UNLOCK (pad);
856
    gst_object_unref (internal);
857
    return FALSE;
858
  }
859
}
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880

static GstPad *
gst_ghost_pad_new_full (const gchar * name, GstPadDirection dir,
    GstPadTemplate * templ)
{
  GstGhostPad *ret;

  g_return_val_if_fail (dir != GST_PAD_UNKNOWN, NULL);

  /* OBJECT CREATION */
  if (templ) {
    ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
        "direction", dir, "template", templ, NULL);
  } else {
    ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name,
        "direction", dir, NULL);
  }

  if (!gst_ghost_pad_construct (ret))
    goto construct_failed;

881
  return GST_PAD_CAST (ret);