gstbasetransform.c 75.3 KB
Newer Older
Wim Taymans's avatar
Wim Taymans committed
1 2 3
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2005 Wim Taymans <wim@fluendo.com>
4 5
 *                    2005 Andy Wingo <wingo@fluendo.com>
 *                    2005 Thomas Vander Stichele <thomas at apestaart dot org>
6
 *                    2008 Wim Taymans <wim.taymans@gmail.com>
Wim Taymans's avatar
Wim Taymans committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * 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.
 */

24 25
/**
 * SECTION:gstbasetransform
26
 * @short_description: Base class for simple transform filters
27 28 29 30
 * @see_also: #GstBaseSrc, #GstBaseSink
 *
 * This base class is for filter elements that process data.
 *
31
 * It provides for:
32 33 34
 * <itemizedlist>
 *   <listitem><para>one sinkpad and one srcpad</para></listitem>
 *   <listitem><para>
35
 *      Possible formats on sink and source pad implemented
36 37 38
 *      with custom transform_caps function. By default uses
 *      same format on sink and source.
 *   </para></listitem>
39 40 41
 *   <listitem><para>Handles state changes</para></listitem>
 *   <listitem><para>Does flushing</para></listitem>
 *   <listitem><para>Push mode</para></listitem>
42
 *   <listitem><para>
43
 *       Pull mode if the sub-class transform can operate on arbitrary data
44 45
 *    </para></listitem>
 * </itemizedlist>
46
 *
47 48 49
 * <refsect2>
 * <title>Use Cases</title>
 * <para>
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
 * <orderedlist>
 * <listitem>
 *   <itemizedlist><title>Passthrough mode</title>
 *   <listitem><para>
 *     Element has no interest in modifying the buffer. It may want to inspect it,
 *     in which case the element should have a transform_ip function. If there
 *     is no transform_ip function in passthrough mode, the buffer is pushed
 *     intact.
 *   </para></listitem>
 *   <listitem><para>
 *     On the GstBaseTransformClass is the passthrough_on_same_caps variable
 *     which will automatically set/unset passthrough based on whether the
 *     element negotiates the same caps on both pads.
 *   </para></listitem>
 *   <listitem><para>
65 66 67
 *     passthrough_on_same_caps on an element that doesn't implement a
 *     transform_caps function is useful for elements that only inspect data
 *     (such as level)
68 69 70 71 72
 *   </para></listitem>
 *   </itemizedlist>
 *   <itemizedlist>
 *   <title>Example elements</title>
 *     <listitem>Level</listitem>
73 74
 *     <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
 *     certain modes.</listitem>
75 76 77
 *   </itemizedlist>
 * </listitem>
 * <listitem>
78 79 80
 *   <itemizedlist>
 *     <title>Modifications in-place - input buffer and output buffer are the
 *     same thing.</title>
81 82 83 84 85 86 87
 *   <listitem><para>
 *     The element must implement a transform_ip function.
 *   </para></listitem>
 *   <listitem><para>
 *     Output buffer size must <= input buffer size
 *   </para></listitem>
 *   <listitem><para>
88 89 90
 *     If the always_in_place flag is set, non-writable buffers will be copied
 *     and passed to the transform_ip function, otherwise a new buffer will be
 *     created and the transform function called.
91 92
 *   </para></listitem>
 *   <listitem><para>
93 94
 *     Incoming writable buffers will be passed to the transform_ip function
 *     immediately.  </para></listitem>
95
 *   <listitem><para>
96 97
 *     only implementing transform_ip and not transform implies always_in_place
 *     = TRUE
98 99 100 101 102
 *   </para></listitem>
 *   </itemizedlist>
 *   <itemizedlist>
 *   <title>Example elements</title>
 *     <listitem>Volume</listitem>
103 104 105 106
 *     <listitem>Audioconvert in certain modes (signed/unsigned
 *     conversion)</listitem>
 *     <listitem>ffmpegcolorspace in certain modes (endianness
 *     swapping)</listitem>
107 108 109
 *   </itemizedlist>
 *  </listitem>
 * <listitem>
110 111
 *   <itemizedlist>
 *   <title>Modifications only to the caps/metadata of a buffer</title>
112
 *   <listitem><para>
113 114
 *     The element does not require writable data, but non-writable buffers
 *     should be subbuffered so that the meta-information can be replaced.
115 116 117
 *   </para></listitem>
 *   <listitem><para>
 *     Elements wishing to operate in this mode should replace the
118 119
 *     prepare_output_buffer method to create subbuffers of the input buffer
 *     and set always_in_place to TRUE
120 121 122 123
 *   </para></listitem>
 *   </itemizedlist>
 *   <itemizedlist>
 *   <title>Example elements</title>
124 125 126 127
 *     <listitem>Capsfilter when setting caps on outgoing buffers that have
 *     none.</listitem>
 *     <listitem>identity when it is going to re-timestamp buffers by
 *     datarate.</listitem>
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
 *   </itemizedlist>
 * </listitem>
 * <listitem>
 *   <itemizedlist><title>Normal mode</title>
 *   <listitem><para>
 *     always_in_place flag is not set, or there is no transform_ip function
 *   </para></listitem>
 *   <listitem><para>
 *     Element will receive an input buffer and output buffer to operate on.
 *   </para></listitem>
 *   <listitem><para>
 *     Output buffer is allocated by calling the prepare_output_buffer function.
 *   </para></listitem>
 *   </itemizedlist>
 *   <itemizedlist>
 *   <title>Example elements</title>
144 145
 *     <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
 *     scaling/conversions</listitem>
146 147 148 149 150
 *   </itemizedlist>
 * </listitem>
 * <listitem>
 *   <itemizedlist><title>Special output buffer allocations</title>
 *   <listitem><para>
151 152
 *     Elements which need to do special allocation of their output buffers
 *     other than what gst_buffer_pad_alloc allows should implement a
153 154 155 156 157 158 159 160 161 162
 *     prepare_output_buffer method, which calls the parent implementation and
 *     passes the newly allocated buffer.
 *   </para></listitem>
 *   </itemizedlist>
 *   <itemizedlist>
 *   <title>Example elements</title>
 *     <listitem>efence</listitem>
 *   </itemizedlist>
 * </listitem>
 * </orderedlist>
163 164 165 166 167 168
 * </para>
 * </refsect2>
 * <refsect2>
 * <title>Sub-class settable flags on GstBaseTransform</title>
 * <para>
 * <itemizedlist>
169 170 171 172 173 174 175
 * <listitem><para>
 *   <itemizedlist><title>passthrough</title>
 *     <listitem><para>
 *       Implies that in the current configuration, the sub-class is not
 *       interested in modifying the buffers.
 *     </para></listitem>
 *     <listitem><para>
176 177
 *       Elements which are always in passthrough mode whenever the same caps
 *       has been negotiated on both pads can set the class variable
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
 *       passthrough_on_same_caps to have this behaviour automatically.
 *     </para></listitem>
 *   </itemizedlist>
 * </para></listitem>
 * <listitem><para>
 *   <itemizedlist><title>always_in_place</title>
 *     <listitem><para>
 *       Determines whether a non-writable buffer will be copied before passing
 *       to the transform_ip function.
 *     </para></listitem>
 *     <listitem><para>
 *       Implied TRUE if no transform function is implemented.
 *     </para></listitem>
 *     <listitem><para>
 *       Implied FALSE if ONLY transform function is implemented.
 *     </para></listitem>
 *   </itemizedlist>
 * </para></listitem>
 * </itemizedlist>
197 198 199
 * </para>
 * </refsect2>
 */
Wim Taymans's avatar
Wim Taymans committed
200 201 202 203 204

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

205 206 207
#include <stdlib.h>
#include <string.h>

208 209 210
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
 * with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
211
#include "../../../gst/gst_private.h"
212
#include "../../../gst/gst-i18n-lib.h"
213
#include "../../../gst/glib-compat-private.h"
Wim Taymans's avatar
Wim Taymans committed
214 215 216 217 218 219 220 221 222 223 224 225 226
#include "gstbasetransform.h"
#include <gst/gstmarshal.h>

GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
#define GST_CAT_DEFAULT gst_base_transform_debug

/* BaseTransform signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

227 228
#define DEFAULT_PROP_QOS	FALSE

Wim Taymans's avatar
Wim Taymans committed
229 230 231
enum
{
  PROP_0,
232 233 234 235 236 237 238 239 240 241 242 243
  PROP_QOS
};

#define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))

struct _GstBaseTransformPrivate
{
  /* QoS *//* with LOCK */
  gboolean qos_enabled;
  gdouble proportion;
  GstClockTime earliest_time;
244 245
  /* previous buffer had a discont */
  gboolean discont;
246

Wim Taymans's avatar
Wim Taymans committed
247
  GstPadMode pad_mode;
248 249

  gboolean gap_aware;
250

251
  gboolean reconfigure;
252 253 254 255

  /* QoS stats */
  guint64 processed;
  guint64 dropped;
256

Wim Taymans's avatar
Wim Taymans committed
257
  GstClockTime position_out;
258

259
  GstBufferPool *pool;
260
  const GstAllocator *allocator;
261 262
  guint prefix;
  guint alignment;
Wim Taymans's avatar
Wim Taymans committed
263 264
};

265

Wim Taymans's avatar
Wim Taymans committed
266 267 268 269
static GstElementClass *parent_class = NULL;

static void gst_base_transform_class_init (GstBaseTransformClass * klass);
static void gst_base_transform_init (GstBaseTransform * trans,
270
    GstBaseTransformClass * klass);
Wim Taymans's avatar
Wim Taymans committed
271

272 273
/* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
 * method to get to the padtemplates */
Wim Taymans's avatar
Wim Taymans committed
274 275 276
GType
gst_base_transform_get_type (void)
{
277
  static volatile gsize base_transform_type = 0;
Wim Taymans's avatar
Wim Taymans committed
278

279 280
  if (g_once_init_enter (&base_transform_type)) {
    GType _type;
Wim Taymans's avatar
Wim Taymans committed
281 282
    static const GTypeInfo base_transform_info = {
      sizeof (GstBaseTransformClass),
283
      NULL,
Wim Taymans's avatar
Wim Taymans committed
284 285 286 287 288 289 290 291 292
      NULL,
      (GClassInitFunc) gst_base_transform_class_init,
      NULL,
      NULL,
      sizeof (GstBaseTransform),
      0,
      (GInstanceInitFunc) gst_base_transform_init,
    };

293
    _type = g_type_register_static (GST_TYPE_ELEMENT,
Wim Taymans's avatar
Wim Taymans committed
294
        "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
295
    g_once_init_leave (&base_transform_type, _type);
Wim Taymans's avatar
Wim Taymans committed
296 297 298 299 300 301 302 303 304
  }
  return base_transform_type;
}

static void gst_base_transform_finalize (GObject * object);
static void gst_base_transform_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_base_transform_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);
305 306 307 308
static gboolean gst_base_transform_src_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
static gboolean gst_base_transform_sink_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
309 310
static gboolean gst_base_transform_activate (GstBaseTransform * trans,
    gboolean active);
311
static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
312
    GstCaps * caps, gsize * size);
313

314 315
static gboolean gst_base_transform_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event);
316 317
static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
    GstEvent * event);
318 319
static gboolean gst_base_transform_sink_event (GstPad * pad, GstObject * parent,
    GstEvent * event);
320
static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
321
    GstEvent * event);
322 323 324
static GstFlowReturn gst_base_transform_getrange (GstPad * pad,
    GstObject * parent, guint64 offset, guint length, GstBuffer ** buffer);
static GstFlowReturn gst_base_transform_chain (GstPad * pad, GstObject * parent,
Wim Taymans's avatar
Wim Taymans committed
325
    GstBuffer * buffer);
Wim Taymans's avatar
Wim Taymans committed
326 327
static GstCaps *gst_base_transform_default_transform_caps (GstBaseTransform *
    trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
328 329
static void gst_base_transform_default_fixate (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
330 331
static GstCaps *gst_base_transform_query_caps (GstBaseTransform * trans,
    GstPad * pad, GstCaps * filter);
332 333
static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps);
334
static gboolean gst_base_transform_setcaps (GstBaseTransform * trans,
335
    GstPad * pad, GstCaps * caps);
336 337
static gboolean gst_base_transform_query (GstPad * pad, GstObject * parent,
    GstQuery * query);
338
static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
339
    GstPadDirection direction, GstQuery * query);
Wim Taymans's avatar
Wim Taymans committed
340 341 342
static gboolean gst_base_transform_default_transform_size (GstBaseTransform *
    trans, GstPadDirection direction, GstCaps * caps, gsize size,
    GstCaps * othercaps, gsize * othersize);
Wim Taymans's avatar
Wim Taymans committed
343

344
static GstFlowReturn default_prepare_output_buffer (GstBaseTransform * trans,
345
    GstBuffer * inbuf, GstBuffer ** outbuf);
346 347
static gboolean default_copy_metadata (GstBaseTransform * trans,
    GstBuffer * inbuf, GstBuffer * outbuf);
348

Wim Taymans's avatar
Wim Taymans committed
349 350
/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */

351

Wim Taymans's avatar
Wim Taymans committed
352 353 354
static void
gst_base_transform_finalize (GObject * object)
{
355 356 357 358 359 360
  GstBaseTransform *trans;

  trans = GST_BASE_TRANSFORM (object);

  g_mutex_free (trans->transform_lock);

Wim Taymans's avatar
Wim Taymans committed
361 362 363 364 365 366 367 368 369 370
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gst_base_transform_class_init (GstBaseTransformClass * klass)
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);

371 372 373
  GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
      "basetransform element");

374 375
  GST_DEBUG ("gst_base_transform_class_init");

376 377
  g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));

378
  parent_class = g_type_class_peek_parent (klass);
Wim Taymans's avatar
Wim Taymans committed
379

380 381
  gobject_class->set_property = gst_base_transform_set_property;
  gobject_class->get_property = gst_base_transform_get_property;
Wim Taymans's avatar
Wim Taymans committed
382

383
  g_object_class_install_property (gobject_class, PROP_QOS,
384
      g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
385
          DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
386

387
  gobject_class->finalize = gst_base_transform_finalize;
Wim Taymans's avatar
Wim Taymans committed
388

389
  klass->passthrough_on_same_caps = FALSE;
Wim Taymans's avatar
Wim Taymans committed
390 391 392 393

  klass->transform_caps =
      GST_DEBUG_FUNCPTR (gst_base_transform_default_transform_caps);
  klass->fixate_caps = GST_DEBUG_FUNCPTR (gst_base_transform_default_fixate);
394 395
  klass->accept_caps =
      GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
Wim Taymans's avatar
Wim Taymans committed
396 397 398 399 400 401
  klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
  klass->transform_size =
      GST_DEBUG_FUNCPTR (gst_base_transform_default_transform_size);

  klass->sink_event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
  klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
402 403
  klass->prepare_output_buffer =
      GST_DEBUG_FUNCPTR (default_prepare_output_buffer);
404
  klass->copy_metadata = GST_DEBUG_FUNCPTR (default_copy_metadata);
Wim Taymans's avatar
Wim Taymans committed
405 406 407
}

static void
408 409
gst_base_transform_init (GstBaseTransform * trans,
    GstBaseTransformClass * bclass)
Wim Taymans's avatar
Wim Taymans committed
410 411 412 413 414
{
  GstPadTemplate *pad_template;

  GST_DEBUG ("gst_base_transform_init");

415 416
  trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);

Wim Taymans's avatar
Wim Taymans committed
417
  pad_template =
418
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
Wim Taymans's avatar
Wim Taymans committed
419 420 421
  g_return_if_fail (pad_template != NULL);
  trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
  gst_pad_set_event_function (trans->sinkpad,
422
      GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
Wim Taymans's avatar
Wim Taymans committed
423 424
  gst_pad_set_chain_function (trans->sinkpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_chain));
425 426
  gst_pad_set_activatemode_function (trans->sinkpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_mode));
427 428
  gst_pad_set_query_function (trans->sinkpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_query));
Wim Taymans's avatar
Wim Taymans committed
429 430 431
  gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);

  pad_template =
432
      gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
Wim Taymans's avatar
Wim Taymans committed
433 434
  g_return_if_fail (pad_template != NULL);
  trans->srcpad = gst_pad_new_from_template (pad_template, "src");
435 436
  gst_pad_set_event_function (trans->srcpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
Wim Taymans's avatar
Wim Taymans committed
437 438
  gst_pad_set_getrange_function (trans->srcpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
439 440
  gst_pad_set_activatemode_function (trans->srcpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_mode));
441 442
  gst_pad_set_query_function (trans->srcpad,
      GST_DEBUG_FUNCPTR (gst_base_transform_query));
Wim Taymans's avatar
Wim Taymans committed
443
  gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
444

445
  trans->transform_lock = g_mutex_new ();
446
  trans->priv->qos_enabled = DEFAULT_PROP_QOS;
447 448
  trans->cache_caps1 = NULL;
  trans->cache_caps2 = NULL;
Wim Taymans's avatar
Wim Taymans committed
449
  trans->priv->pad_mode = GST_PAD_MODE_NONE;
450
  trans->priv->gap_aware = FALSE;
451 452 453 454 455 456 457

  trans->passthrough = FALSE;
  if (bclass->transform == NULL) {
    /* If no transform function, always_in_place is TRUE */
    GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
    trans->always_in_place = TRUE;

458 459
    if (bclass->transform_ip == NULL) {
      GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
460
      trans->passthrough = TRUE;
461
    }
462
  }
463 464 465

  trans->priv->processed = 0;
  trans->priv->dropped = 0;
Wim Taymans's avatar
Wim Taymans committed
466 467
}

Wim Taymans's avatar
Wim Taymans committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
static GstCaps *
gst_base_transform_default_transform_caps (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
  GstCaps *ret;

  GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
  /* no transform function, use the identity transform */
  if (filter) {
    ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
  } else {
    ret = gst_caps_ref (caps);
  }
  return ret;
}

484 485 486 487 488
/* given @caps on the src or sink pad (given by @direction)
 * calculate the possible caps on the other pad.
 *
 * Returns new caps, unref after usage.
 */
Wim Taymans's avatar
Wim Taymans committed
489
static GstCaps *
490
gst_base_transform_transform_caps (GstBaseTransform * trans,
491
    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
492
{
Wim Taymans's avatar
Wim Taymans committed
493
  GstCaps *ret = NULL;
494 495
  GstBaseTransformClass *klass;

496 497 498
  if (caps == NULL)
    return NULL;

499 500
  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);

501 502
  /* if there is a custom transform function, use this */
  if (klass->transform_caps) {
503
    GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
504

505 506 507
    GST_LOG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
    ret = klass->transform_caps (trans, direction, caps, filter);
    GST_LOG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, ret);
508 509 510 511

#ifndef G_DISABLE_ASSERT
    if (filter) {
      if (!gst_caps_is_subset (ret, filter)) {
512 513
        GstCaps *intersection;

514 515 516 517 518 519 520
        GST_ERROR_OBJECT (trans,
            "transform_caps returned caps %" GST_PTR_FORMAT
            " which are not a real subset of the filter caps %"
            GST_PTR_FORMAT, ret, filter);
        g_warning ("%s: transform_caps returned caps which are not a real "
            "subset of the filter caps", GST_ELEMENT_NAME (trans));

521 522
        intersection =
            gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
523
        gst_caps_unref (ret);
524
        ret = intersection;
525 526 527
      }
    }
#endif
528
  }
529

Wim Taymans's avatar
Wim Taymans committed
530
  GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
531 532

  return ret;
533 534
}

535
static gboolean
Wim Taymans's avatar
Wim Taymans committed
536 537 538
gst_base_transform_default_transform_size (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps, gsize size,
    GstCaps * othercaps, gsize * othersize)
539
{
540
  gsize inunitsize, outunitsize, units;
541 542 543 544
  GstBaseTransformClass *klass;

  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);

Wim Taymans's avatar
Wim Taymans committed
545
  if (klass->get_unit_size == NULL) {
546 547 548
    /* if there is no transform_size and no unit_size, it means the
     * element does not modify the size of a buffer */
    *othersize = size;
549
  } else {
550 551 552
    /* there is no transform_size function, we have to use the unit_size
     * functions. This method assumes there is a fixed unit_size associated with
     * each caps. We provide the same amount of units on both sides. */
553 554
    if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
      goto no_in_size;
555

Josep Torra's avatar
Josep Torra committed
556 557 558
    GST_DEBUG_OBJECT (trans,
        "input size %" G_GSIZE_FORMAT ", input unit size %" G_GSIZE_FORMAT,
        size, inunitsize);
559

560
    /* input size must be a multiple of the unit_size of the input caps */
561 562
    if (inunitsize == 0 || (size % inunitsize != 0))
      goto no_multiple;
563

564
    /* get the amount of units */
565
    units = size / inunitsize;
566 567

    /* now get the unit size of the output */
568 569
    if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
      goto no_out_size;
570

571 572
    /* the output size is the unit_size times the amount of units on the
     * input */
573
    *othersize = units * outunitsize;
Josep Torra's avatar
Josep Torra committed
574 575
    GST_DEBUG_OBJECT (trans, "transformed size to %" G_GSIZE_FORMAT,
        *othersize);
576
  }
Wim Taymans's avatar
Wim Taymans committed
577
  return TRUE;
578 579 580 581 582

  /* ERRORS */
no_in_size:
  {
    GST_DEBUG_OBJECT (trans, "could not get in_size");
583
    g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
584 585 586 587
    return FALSE;
  }
no_multiple:
  {
Josep Torra's avatar
Josep Torra committed
588 589
    GST_DEBUG_OBJECT (trans, "Size %" G_GSIZE_FORMAT " is not a multiple of"
        "unit size %" G_GSIZE_FORMAT, size, inunitsize);
590 591
    g_warning ("%s: size %" G_GSIZE_FORMAT " is not a multiple of unit size %"
        G_GSIZE_FORMAT, GST_ELEMENT_NAME (trans), size, inunitsize);
592 593 594 595 596
    return FALSE;
  }
no_out_size:
  {
    GST_DEBUG_OBJECT (trans, "could not get out_size");
597
    g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
598 599
    return FALSE;
  }
600 601
}

Wim Taymans's avatar
Wim Taymans committed
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
/* transform a buffer of @size with @caps on the pad with @direction to
 * the size of a buffer with @othercaps and store the result in @othersize
 *
 * We have two ways of doing this:
 *  1) use a custom transform size function, this is for complicated custom
 *     cases with no fixed unit_size.
 *  2) use the unit_size functions where there is a relationship between the
 *     caps and the size of a buffer.
 */
static gboolean
gst_base_transform_transform_size (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps,
    gsize size, GstCaps * othercaps, gsize * othersize)
{
  GstBaseTransformClass *klass;
  gboolean ret = FALSE;

  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);

  GST_DEBUG_OBJECT (trans,
      "asked to transform size %" G_GSIZE_FORMAT " for caps %"
      GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
      size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");

  if (klass->transform_size) {
    /* if there is a custom transform function, use this */
    ret = klass->transform_size (trans, direction, caps, size, othercaps,
        othersize);
  }
  return ret;
}

Thijs Vermeir's avatar
Thijs Vermeir committed
634
/* get the caps that can be handled by @pad. We perform:
635 636 637 638 639 640 641 642
 *
 *  - take the caps of peer of otherpad,
 *  - filter against the padtemplate of otherpad, 
 *  - calculate all transforms of remaining caps
 *  - filter against template of @pad
 *
 * If there is no peer, we simply return the caps of the padtemplate of pad.
 */
643
static GstCaps *
644 645
gst_base_transform_query_caps (GstBaseTransform * trans, GstPad * pad,
    GstCaps * filter)
Wim Taymans's avatar
Wim Taymans committed
646
{
647
  GstPad *otherpad;
648 649
  GstCaps *peercaps, *caps, *temp, *peerfilter = NULL;
  GstCaps *templ;
650

651
  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
Wim Taymans's avatar
Wim Taymans committed
652

653
  /* we can do what the peer can */
654 655 656 657 658 659 660 661 662
  if (filter) {

    GST_DEBUG_OBJECT (pad, "filter caps  %" GST_PTR_FORMAT, filter);

    /* filtered against our padtemplate on the other side */
    templ = gst_pad_get_pad_template_caps (pad);
    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
    temp = gst_caps_intersect_full (filter, templ, GST_CAPS_INTERSECT_FIRST);
    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
663
    gst_caps_unref (templ);
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678

    /* then see what we can transform this to */
    peerfilter = gst_base_transform_transform_caps (trans,
        GST_PAD_DIRECTION (pad), temp, NULL);
    GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, peerfilter);
    gst_caps_unref (temp);

    /* and filter against the template of this pad */
    templ = gst_pad_get_pad_template_caps (otherpad);
    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
    /* We keep the caps sorted like the returned caps */
    temp =
        gst_caps_intersect_full (peerfilter, templ, GST_CAPS_INTERSECT_FIRST);
    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
    gst_caps_unref (peerfilter);
679
    gst_caps_unref (templ);
680 681 682
    peerfilter = temp;
  }

683
  peercaps = gst_pad_peer_query_caps (otherpad, peerfilter);
684 685 686 687

  if (peerfilter)
    gst_caps_unref (peerfilter);

Wim Taymans's avatar
Wim Taymans committed
688
  if (peercaps) {
689
    GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
690

691
    /* filtered against our padtemplate on the other side */
692
    templ = gst_pad_get_pad_template_caps (otherpad);
693
    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
694
    temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
695
    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
696
    gst_caps_unref (templ);
697 698 699
  } else {
    temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
  }
700

701 702
  /* then see what we can transform this to */
  caps = gst_base_transform_transform_caps (trans,
703
      GST_PAD_DIRECTION (otherpad), temp, filter);
704 705 706 707
  GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
  gst_caps_unref (temp);
  if (caps == NULL)
    goto done;
708

709
  if (peercaps) {
710 711 712 713 714 715 716 717 718 719
    /* and filter against the template of this pad */
    templ = gst_pad_get_pad_template_caps (pad);
    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
    /* We keep the caps sorted like the returned caps */
    temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
    gst_caps_unref (caps);
    gst_caps_unref (templ);
    caps = temp;

720 721 722 723 724 725 726 727
    /* Now try if we can put the untransformed downstream caps first */
    temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
    if (!gst_caps_is_empty (temp)) {
      gst_caps_merge (temp, caps);
      caps = temp;
    } else {
      gst_caps_unref (temp);
    }
728
  } else {
729
    gst_caps_unref (caps);
730
    /* no peer or the peer can do anything, our padtemplate is enough then */
731
    caps = gst_pad_get_pad_template_caps (pad);
732 733 734 735 736 737 738 739

    if (filter) {
      GstCaps *temp;

      temp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
      gst_caps_unref (caps);
      caps = temp;
    }
740
  }
741

742
done:
743
  GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
744

745 746 747
  if (peercaps)
    gst_caps_unref (peercaps);

748
  return caps;
Wim Taymans's avatar
Wim Taymans committed
749 750
}

751
static gboolean
752
gst_base_transform_set_allocation (GstBaseTransform * trans,
753
    GstBufferPool * pool, const GstAllocator * allocator, guint prefix,
754 755 756 757 758
    guint alignment)
{
  GstBufferPool *oldpool;
  GstBaseTransformPrivate *priv = trans->priv;

759 760
  /* activate */
  if (pool) {
Wim Taymans's avatar
Wim Taymans committed
761
    GST_DEBUG_OBJECT (trans, "setting pool %p active", pool);
762 763 764 765
    if (!gst_buffer_pool_set_active (pool, TRUE))
      goto activate_failed;
  }

766 767 768 769 770 771 772 773 774
  GST_OBJECT_LOCK (trans);
  oldpool = priv->pool;
  priv->pool = pool;
  priv->allocator = allocator;
  priv->prefix = prefix;
  priv->alignment = alignment;
  GST_OBJECT_UNLOCK (trans);

  if (oldpool) {
Wim Taymans's avatar
Wim Taymans committed
775
    GST_DEBUG_OBJECT (trans, "deactivating old pool %p", oldpool);
776 777 778
    gst_buffer_pool_set_active (oldpool, FALSE);
    gst_object_unref (oldpool);
  }
Wim Taymans's avatar
Wim Taymans committed
779
  return TRUE;
780 781 782 783 784 785 786

  /* ERRORS */
activate_failed:
  {
    GST_ERROR_OBJECT (trans, "failed to activate bufferpool.");
    return FALSE;
  }
787 788
}

789 790 791 792
static gboolean
gst_base_transform_do_bufferpool (GstBaseTransform * trans, GstCaps * outcaps)
{
  GstQuery *query;
793
  gboolean result = TRUE;
794 795
  GstBufferPool *pool = NULL, *oldpool;
  guint size, min, max, prefix, alignment;
796
  GstBaseTransformClass *klass;
797
  const GstAllocator *allocator = NULL;
798 799 800

  /* there are these possibilities:
   *
Wim Taymans's avatar
Wim Taymans committed
801 802 803
   * 1) we negotiated passthrough, we can proxy the bufferpool directly and we
   *    will do that whenever some upstream does an allocation query.
   * 2) we need to do a transform, we need to get a bufferpool from downstream
804
   *    and configure it. When upstream does the ALLOCATION query, the
Wim Taymans's avatar
Wim Taymans committed
805 806
   *    propose_allocation vmethod will be called and we will configure the
   *    upstream allocator with our porposed values then.
807 808 809
   */

  /* clear old pool */
810
  oldpool = trans->priv->pool;
811
  if (oldpool) {
Wim Taymans's avatar
Wim Taymans committed
812
    GST_DEBUG_OBJECT (trans, "unreffing old pool");
813 814
    gst_buffer_pool_set_active (oldpool, FALSE);
    gst_object_unref (oldpool);
815
    trans->priv->pool = oldpool = NULL;
816 817
  }

818
  if (trans->passthrough || trans->always_in_place) {
819 820 821 822 823 824 825 826 827 828
    /* we are in passthrough, the input buffer is never copied and always passed
     * along. We never allocate an output buffer on the srcpad. What we do is
     * let the upstream element decide if it wants to use a bufferpool and
     * then we will proxy the downstream pool */
    GST_DEBUG_OBJECT (trans, "we're passthough, delay bufferpool");
    return TRUE;
  }

  /* not passthrough, we need to allocate */
  /* find a pool for the negotiated caps now */
Wim Taymans's avatar
Wim Taymans committed
829
  GST_DEBUG_OBJECT (trans, "doing allocation query");
830
  query = gst_query_new_allocation (outcaps, TRUE);
831 832 833 834 835 836
  if (!gst_pad_peer_query (trans->srcpad, query)) {
    /* not a problem, just debug a little */
    GST_DEBUG_OBJECT (trans, "peer ALLOCATION query failed");
  }

  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
837

Wim Taymans's avatar
Wim Taymans committed
838 839 840
  GST_DEBUG_OBJECT (trans, "calling decide_allocation");
  if (G_LIKELY (klass->decide_allocation))
    result = klass->decide_allocation (trans, query);
841 842 843 844 845

  /* we got configuration from our peer, parse them */
  gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
      &alignment, &pool);

846 847 848 849 850 851 852
  if (size == 0) {
    const gchar *mem = NULL;

    /* no size, we have variable size buffers */
    if (gst_query_get_n_allocation_memories (query) > 0) {
      mem = gst_query_parse_nth_allocation_memory (query, 0);
    }
853
    allocator = gst_allocator_find (mem);
Wim Taymans's avatar
Wim Taymans committed
854
    GST_DEBUG_OBJECT (trans, "no size, using allocator %s", GST_STR_NULL (mem));
855
  } else if (pool == NULL) {
856 857 858 859 860
    GstStructure *config;

    /* we did not get a pool, make one ourselves then */
    pool = gst_buffer_pool_new ();

Wim Taymans's avatar
Wim Taymans committed
861
    GST_DEBUG_OBJECT (trans, "no pool, making one");
862
    config = gst_buffer_pool_get_config (pool);
863
    gst_buffer_pool_config_set (config, outcaps, size, min, max, prefix,
864 865
        alignment);
    gst_buffer_pool_set_config (pool, config);
866
  }
867

868 869
  gst_query_unref (query);

870
  /* and store */
871 872 873
  result =
      gst_base_transform_set_allocation (trans, pool, allocator, prefix,
      alignment);
874

875
  return result;
876 877
}

878 879
/* function triggered when the in and out caps are negotiated and need
 * to be configured in the subclass. */
880 881 882 883 884 885 886 887 888
static gboolean
gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
    GstCaps * out)
{
  gboolean ret = TRUE;
  GstBaseTransformClass *klass;

  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);

889 890 891
  GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
  GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);

892 893 894 895
  /* clear the cache */
  gst_caps_replace (&trans->cache_caps1, NULL);
  gst_caps_replace (&trans->cache_caps2, NULL);

896 897 898 899
  /* figure out same caps state */
  trans->have_same_caps = gst_caps_is_equal (in, out);
  GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);

900 901 902 903 904 905 906 907 908 909 910
  /* If we've a transform_ip method and same input/output caps, set in_place
   * by default. If for some reason the sub-class prefers using a transform
   * function, it can clear the in place flag in the set_caps */
  gst_base_transform_set_in_place (trans,
      klass->transform_ip && trans->have_same_caps);

  /* Set the passthrough if the class wants passthrough_on_same_caps
   * and we have the same caps on each pad */
  if (klass->passthrough_on_same_caps)
    gst_base_transform_set_passthrough (trans, trans->have_same_caps);

911
  /* now configure the element with the caps */
912
  if (klass->set_caps) {
913
    GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
914 915 916
    ret = klass->set_caps (trans, in, out);
  }

917 918
  trans->negotiated = ret;

919 920 921
  return ret;
}

922 923 924 925 926 927 928 929
static void
gst_base_transform_default_fixate (GstBaseTransform * trans,
    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
{
  GST_DEBUG_OBJECT (trans, "using default caps fixate function");
  gst_caps_fixate (othercaps);
}

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
/* given a fixed @caps on @pad, create the best possible caps for the
 * other pad.
 * @caps must be fixed when calling this function.
 *
 * This function calls the transform caps vmethod of the basetransform to figure
 * out the possible target formats. It then tries to select the best format from
 * this list by:
 *
 * - attempt passthrough if the target caps is a superset of the input caps
 * - fixating by using peer caps
 * - fixating with transform fixate function
 * - fixating with pad fixate functions.
 *
 * this function returns a caps that can be transformed into and is accepted by
 * the peer element.
 */
static GstCaps *
gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
948
    GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
949
{
950 951
  GstBaseTransformClass *klass;
  GstPad *otherpad, *otherpeer;
952
  GstCaps *othercaps;
953
  gboolean is_fixed;
954

955 956 957
  /* caps must be fixed here, this is a programming error if it's not */
  g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);

958 959 960 961 962
  klass = GST_BASE_TRANSFORM_GET_CLASS (trans);

  otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
  otherpeer = gst_pad_get_peer (otherpad);

963 964 965
  /* see how we can transform the input caps. We need to do this even for
   * passthrough because it might be possible that this element cannot support
   * passthrough at all. */
Thomas Vander Stichele's avatar