2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2005 Wim Taymans <wim@fluendo.com>
4 * 2005 Andy Wingo <wingo@fluendo.com>
5 * 2005 Thomas Vander Stichele <thomas at apestaart dot org>
6 * 2008 Wim Taymans <wim.taymans@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:gstbasetransform
26 * @short_description: Base class for simple transform filters
27 * @see_also: #GstBaseSrc, #GstBaseSink
29 * This base class is for filter elements that process data.
33 * <listitem><para>one sinkpad and one srcpad</para></listitem>
35 * Possible formats on sink and source pad implemented
36 * with custom transform_caps function. By default uses
37 * same format on sink and source.
39 * <listitem><para>Handles state changes</para></listitem>
40 * <listitem><para>Does flushing</para></listitem>
41 * <listitem><para>Push mode</para></listitem>
43 * Pull mode if the sub-class transform can operate on arbitrary data
48 * <title>Use Cases</title>
52 * <itemizedlist><title>Passthrough mode</title>
54 * Element has no interest in modifying the buffer. It may want to inspect it,
55 * in which case the element should have a transform_ip function. If there
56 * is no transform_ip function in passthrough mode, the buffer is pushed
60 * On the GstBaseTransformClass is the passthrough_on_same_caps variable
61 * which will automatically set/unset passthrough based on whether the
62 * element negotiates the same caps on both pads.
65 * passthrough_on_same_caps on an element that doesn't implement a
66 * transform_caps function is useful for elements that only inspect data
71 * <title>Example elements</title>
72 * <listitem>Level</listitem>
73 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
74 * certain modes.</listitem>
79 * <title>Modifications in-place - input buffer and output buffer are the
82 * The element must implement a transform_ip function.
85 * Output buffer size must <= input buffer size
88 * If the always_in_place flag is set, non-writable buffers will be copied
89 * and passed to the transform_ip function, otherwise a new buffer will be
90 * created and the transform function called.
93 * Incoming writable buffers will be passed to the transform_ip function
94 * immediately. </para></listitem>
96 * only implementing transform_ip and not transform implies always_in_place
101 * <title>Example elements</title>
102 * <listitem>Volume</listitem>
103 * <listitem>Audioconvert in certain modes (signed/unsigned
104 * conversion)</listitem>
105 * <listitem>ffmpegcolorspace in certain modes (endianness
106 * swapping)</listitem>
111 * <title>Modifications only to the caps/metadata of a buffer</title>
113 * The element does not require writable data, but non-writable buffers
114 * should be subbuffered so that the meta-information can be replaced.
117 * Elements wishing to operate in this mode should replace the
118 * prepare_output_buffer method to create subbuffers of the input buffer
119 * and set always_in_place to TRUE
123 * <title>Example elements</title>
124 * <listitem>Capsfilter when setting caps on outgoing buffers that have
126 * <listitem>identity when it is going to re-timestamp buffers by
127 * datarate.</listitem>
131 * <itemizedlist><title>Normal mode</title>
133 * always_in_place flag is not set, or there is no transform_ip function
136 * Element will receive an input buffer and output buffer to operate on.
139 * Output buffer is allocated by calling the prepare_output_buffer function.
143 * <title>Example elements</title>
144 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
145 * scaling/conversions</listitem>
149 * <itemizedlist><title>Special output buffer allocations</title>
151 * Elements which need to do special allocation of their output buffers
152 * other than what gst_buffer_pad_alloc allows should implement a
153 * prepare_output_buffer method, which calls the parent implementation and
154 * passes the newly allocated buffer.
158 * <title>Example elements</title>
159 * <listitem>efence</listitem>
166 * <title>Sub-class settable flags on GstBaseTransform</title>
170 * <itemizedlist><title>passthrough</title>
172 * Implies that in the current configuration, the sub-class is not
173 * interested in modifying the buffers.
176 * Elements which are always in passthrough mode whenever the same caps
177 * has been negotiated on both pads can set the class variable
178 * passthrough_on_same_caps to have this behaviour automatically.
183 * <itemizedlist><title>always_in_place</title>
185 * Determines whether a non-writable buffer will be copied before passing
186 * to the transform_ip function.
189 * Implied TRUE if no transform function is implemented.
192 * Implied FALSE if ONLY transform function is implemented.
208 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
209 * with newer GLib versions (>= 2.31.0) */
210 #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"
214 #include "gstbasetransform.h"
215 #include <gst/gstmarshal.h>
217 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
218 #define GST_CAT_DEFAULT gst_base_transform_debug
220 /* BaseTransform signals and args */
227 #define DEFAULT_PROP_QOS FALSE
235 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \
236 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
238 struct _GstBaseTransformPrivate
240 /* QoS *//* with LOCK */
241 gboolean qos_enabled;
243 GstClockTime earliest_time;
244 /* previous buffer had a discont */
247 GstActivateMode pad_mode;
251 /* caps used for allocating buffers */
252 gboolean proxy_alloc;
257 * This flag controls if basetransform should explicitly
258 * do a pad alloc when it receives a buffer even if it operates on
259 * passthrough, this is needed to check for downstream caps suggestions
260 * and this newly alloc'ed buffer is discarded.
262 * Without this flag basetransform would try a pad alloc whenever it
263 * gets a new buffer and pipelines like:
264 * "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
265 * Would have a 3 pad allocs for each buffer pushed downstream from the src.
267 * This flag is set to TRUE on start up, on setcaps and when a buffer is
268 * pushed downstream. It is set to FALSE after a pad alloc has been requested
270 * The rationale is that when a pad alloc flows through the pipeline, all
271 * basetransform elements on passthrough will avoid pad alloc'ing when they
274 gboolean force_alloc;
276 /* upstream caps and size suggestions */
277 GstCaps *sink_suggest;
279 gboolean suggest_pending;
281 gboolean reconfigure;
287 GstClockTime last_stop_out;
288 GList *delayed_events;
290 GstCaps *cached_peer_caps[2];
291 GstCaps *cached_transformed_caps[2];
294 static GstElementClass *parent_class = NULL;
296 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
297 static void gst_base_transform_init (GstBaseTransform * trans,
298 GstBaseTransformClass * klass);
299 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
300 * trans, GstBuffer * input, GstBuffer ** buf);
303 gst_base_transform_get_type (void)
305 static volatile gsize base_transform_type = 0;
307 if (g_once_init_enter (&base_transform_type)) {
309 static const GTypeInfo base_transform_info = {
310 sizeof (GstBaseTransformClass),
313 (GClassInitFunc) gst_base_transform_class_init,
316 sizeof (GstBaseTransform),
318 (GInstanceInitFunc) gst_base_transform_init,
321 _type = g_type_register_static (GST_TYPE_ELEMENT,
322 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
323 g_once_init_leave (&base_transform_type, _type);
325 return base_transform_type;
328 static void gst_base_transform_finalize (GObject * object);
329 static void gst_base_transform_set_property (GObject * object, guint prop_id,
330 const GValue * value, GParamSpec * pspec);
331 static void gst_base_transform_get_property (GObject * object, guint prop_id,
332 GValue * value, GParamSpec * pspec);
333 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
335 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
337 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
339 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
340 GstCaps * caps, guint * size);
342 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
343 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
345 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
346 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
348 static gboolean gst_base_transform_check_get_range (GstPad * pad);
349 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
350 guint length, GstBuffer ** buffer);
351 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
353 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
354 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
355 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
356 GstPadDirection direction, GstCaps * caps);
357 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
358 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
359 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
360 static gboolean gst_base_transform_query (GstPad * pad, GstQuery * query);
361 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
362 GstPadDirection direction, GstQuery * query);
363 static const GstQueryType *gst_base_transform_query_type (GstPad * pad);
365 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
368 gst_base_transform_drop_delayed_events (GstBaseTransform * trans)
370 GST_OBJECT_LOCK (trans);
371 if (trans->priv->delayed_events) {
372 g_list_foreach (trans->priv->delayed_events, (GFunc) gst_event_unref, NULL);
373 g_list_free (trans->priv->delayed_events);
374 trans->priv->delayed_events = NULL;
376 GST_OBJECT_UNLOCK (trans);
380 gst_base_transform_clear_transformed_caps_cache (GstBaseTransform * trans)
382 struct _GstBaseTransformPrivate *priv = trans->priv;
385 for (n = 0; n < 2; ++n) {
386 if (priv->cached_peer_caps[n]) {
387 gst_caps_unref (priv->cached_peer_caps[n]);
388 priv->cached_peer_caps[n] = NULL;
390 if (priv->cached_transformed_caps[n]) {
391 gst_caps_unref (priv->cached_transformed_caps[n]);
392 priv->cached_transformed_caps[n] = NULL;
398 gst_base_transform_finalize (GObject * object)
400 GstBaseTransform *trans;
402 trans = GST_BASE_TRANSFORM (object);
404 gst_base_transform_drop_delayed_events (trans);
405 gst_caps_replace (&trans->priv->sink_suggest, NULL);
406 g_mutex_free (trans->transform_lock);
408 gst_base_transform_clear_transformed_caps_cache (trans);
410 G_OBJECT_CLASS (parent_class)->finalize (object);
414 gst_base_transform_class_init (GstBaseTransformClass * klass)
416 GObjectClass *gobject_class;
418 gobject_class = G_OBJECT_CLASS (klass);
420 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
421 "basetransform element");
423 GST_DEBUG ("gst_base_transform_class_init");
425 g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
427 parent_class = g_type_class_peek_parent (klass);
429 gobject_class->set_property = gst_base_transform_set_property;
430 gobject_class->get_property = gst_base_transform_get_property;
432 g_object_class_install_property (gobject_class, PROP_QOS,
433 g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
434 DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
436 gobject_class->finalize = gst_base_transform_finalize;
438 klass->passthrough_on_same_caps = FALSE;
439 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
440 klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
442 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
443 klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
447 gst_base_transform_init (GstBaseTransform * trans,
448 GstBaseTransformClass * bclass)
450 GstPadTemplate *pad_template;
452 GST_DEBUG ("gst_base_transform_init");
454 trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
457 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
458 g_return_if_fail (pad_template != NULL);
459 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
460 gst_pad_set_getcaps_function (trans->sinkpad,
461 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
462 gst_pad_set_acceptcaps_function (trans->sinkpad,
463 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
464 gst_pad_set_setcaps_function (trans->sinkpad,
465 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
466 gst_pad_set_event_function (trans->sinkpad,
467 GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
468 gst_pad_set_chain_function (trans->sinkpad,
469 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
470 gst_pad_set_activatepush_function (trans->sinkpad,
471 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
472 gst_pad_set_bufferalloc_function (trans->sinkpad,
473 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
474 gst_pad_set_query_function (trans->sinkpad,
475 GST_DEBUG_FUNCPTR (gst_base_transform_query));
476 gst_pad_set_query_type_function (trans->sinkpad,
477 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
478 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
481 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
482 g_return_if_fail (pad_template != NULL);
483 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
484 gst_pad_set_getcaps_function (trans->srcpad,
485 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
486 gst_pad_set_acceptcaps_function (trans->srcpad,
487 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
488 gst_pad_set_event_function (trans->srcpad,
489 GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
490 gst_pad_set_checkgetrange_function (trans->srcpad,
491 GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
492 gst_pad_set_getrange_function (trans->srcpad,
493 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
494 gst_pad_set_activatepull_function (trans->srcpad,
495 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
496 gst_pad_set_query_function (trans->srcpad,
497 GST_DEBUG_FUNCPTR (gst_base_transform_query));
498 gst_pad_set_query_type_function (trans->srcpad,
499 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
500 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
502 trans->transform_lock = g_mutex_new ();
503 trans->pending_configure = FALSE;
504 trans->priv->qos_enabled = DEFAULT_PROP_QOS;
505 trans->cache_caps1 = NULL;
506 trans->cache_caps2 = NULL;
507 trans->priv->pad_mode = GST_ACTIVATE_NONE;
508 trans->priv->gap_aware = FALSE;
509 trans->priv->delayed_events = NULL;
511 trans->passthrough = FALSE;
512 if (bclass->transform == NULL) {
513 /* If no transform function, always_in_place is TRUE */
514 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
515 trans->always_in_place = TRUE;
517 if (bclass->transform_ip == NULL) {
518 GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
519 trans->passthrough = TRUE;
523 trans->priv->processed = 0;
524 trans->priv->dropped = 0;
525 trans->priv->force_alloc = TRUE;
528 /* given @caps on the src or sink pad (given by @direction)
529 * calculate the possible caps on the other pad.
531 * Returns new caps, unref after usage.
534 gst_base_transform_transform_caps (GstBaseTransform * trans,
535 GstPadDirection direction, GstCaps * caps)
538 GstBaseTransformClass *klass;
543 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
545 /* if there is a custom transform function, use this */
546 if (klass->transform_caps) {
550 /* start with empty caps */
551 ret = gst_caps_new_empty ();
552 GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
554 if (gst_caps_is_any (caps)) {
555 /* for any caps we still have to call the transform function */
556 GST_DEBUG_OBJECT (trans, "from: ANY");
557 temp = klass->transform_caps (trans, direction, caps);
558 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
560 temp = gst_caps_make_writable (temp);
561 gst_caps_append (ret, temp);
563 gint n = gst_caps_get_size (caps);
564 /* we send caps with just one structure to the transform
565 * function as this is easier for the element */
566 for (i = 0; i < n; i++) {
569 nth = gst_caps_copy_nth (caps, i);
570 GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
571 temp = klass->transform_caps (trans, direction, nth);
572 gst_caps_unref (nth);
573 GST_LOG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
575 temp = gst_caps_make_writable (temp);
577 /* here we need to only append those structures, that are not yet
578 * in there, we use the merge function for this */
579 gst_caps_merge (ret, temp);
581 GST_LOG_OBJECT (trans, " merged[%d]: %" GST_PTR_FORMAT, i, ret);
583 GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
584 /* FIXME: we can't do much simplification here because we don't really want to
585 * change the caps order
586 gst_caps_do_simplify (ret);
587 GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
591 GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
592 /* no transform function, use the identity transform */
593 ret = gst_caps_ref (caps);
596 GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
602 /* transform a buffer of @size with @caps on the pad with @direction to
603 * the size of a buffer with @othercaps and store the result in @othersize
605 * We have two ways of doing this:
606 * 1) use a custom transform size function, this is for complicated custom
607 * cases with no fixed unit_size.
608 * 2) use the unit_size functions where there is a relationship between the
609 * caps and the size of a buffer.
612 gst_base_transform_transform_size (GstBaseTransform * trans,
613 GstPadDirection direction, GstCaps * caps,
614 guint size, GstCaps * othercaps, guint * othersize)
616 guint inunitsize, outunitsize, units;
617 GstBaseTransformClass *klass;
620 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
622 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
623 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
624 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
626 if (klass->transform_size) {
627 /* if there is a custom transform function, use this */
628 ret = klass->transform_size (trans, direction, caps, size, othercaps,
630 } else if (klass->get_unit_size == NULL) {
631 /* if there is no transform_size and no unit_size, it means the
632 * element does not modify the size of a buffer */
636 /* there is no transform_size function, we have to use the unit_size
637 * functions. This method assumes there is a fixed unit_size associated with
638 * each caps. We provide the same amount of units on both sides. */
639 if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
642 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
645 /* input size must be a multiple of the unit_size of the input caps */
646 if (inunitsize == 0 || (size % inunitsize != 0))
649 /* get the amount of units */
650 units = size / inunitsize;
652 /* now get the unit size of the output */
653 if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
656 /* the output size is the unit_size times the amount of units on the
658 *othersize = units * outunitsize;
659 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
668 GST_DEBUG_OBJECT (trans, "could not get in_size");
669 g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
674 GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
676 g_warning ("%s: size %u is not a multiple of unit size %u",
677 GST_ELEMENT_NAME (trans), size, inunitsize);
682 GST_DEBUG_OBJECT (trans, "could not get out_size");
683 g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
688 /* get the caps that can be handled by @pad. We perform:
690 * - take the caps of peer of otherpad,
691 * - filter against the padtemplate of otherpad,
692 * - calculate all transforms of remaining caps
693 * - filter against template of @pad
695 * If there is no peer, we simply return the caps of the padtemplate of pad.
698 gst_base_transform_getcaps (GstPad * pad)
700 GstBaseTransform *trans;
702 const GstCaps *templ;
703 GstCaps *peercaps, *caps, *temp;
707 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
709 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
710 cache_index = (pad == trans->srcpad) ? 0 : 1;
712 /* we can do what the peer can */
713 peercaps = gst_pad_peer_get_caps_reffed (otherpad);
714 GST_OBJECT_LOCK (trans);
715 samecaps = (peercaps && trans->priv->cached_peer_caps[cache_index]
716 && gst_caps_is_strictly_equal (peercaps,
717 trans->priv->cached_peer_caps[cache_index]));
719 if (trans->priv->cached_peer_caps[cache_index]) {
720 gst_caps_unref (trans->priv->cached_peer_caps[cache_index]);
721 trans->priv->cached_peer_caps[cache_index] = NULL;
723 if (trans->priv->cached_transformed_caps[cache_index]) {
724 gst_caps_unref (trans->priv->cached_transformed_caps[cache_index]);
725 trans->priv->cached_transformed_caps[cache_index] = NULL;
728 GST_DEBUG_OBJECT (trans,
729 "Returning cached transformed caps (index = %d)", cache_index);
730 caps = gst_caps_ref (trans->priv->cached_transformed_caps[cache_index]);
733 GST_OBJECT_UNLOCK (trans);
736 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peercaps);
738 /* filtered against our padtemplate on the other side */
739 templ = gst_pad_get_pad_template_caps (otherpad);
740 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
741 temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
742 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
744 temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
745 GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
749 /* then see what we can transform this to */
750 caps = gst_base_transform_transform_caps (trans,
751 GST_PAD_DIRECTION (otherpad), temp);
752 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
753 gst_caps_unref (temp);
755 goto done_update_cache;
757 /* and filter against the template of this pad */
758 templ = gst_pad_get_pad_template_caps (pad);
759 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
760 /* We keep the caps sorted like the returned caps */
761 temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
762 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
763 gst_caps_unref (caps);
767 /* Now try if we can put the untransformed downstream caps first */
768 temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
769 if (!gst_caps_is_empty (temp)) {
770 gst_caps_merge (temp, caps);
773 gst_caps_unref (temp);
778 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
780 GST_OBJECT_LOCK (trans);
782 trans->priv->cached_peer_caps[cache_index] = gst_caps_ref (peercaps);
785 trans->priv->cached_transformed_caps[cache_index] = gst_caps_ref (caps);
789 GST_OBJECT_UNLOCK (trans);
792 gst_caps_unref (peercaps);
794 gst_object_unref (trans);
799 /* function triggered when the in and out caps are negotiated and need
800 * to be configured in the subclass. */
802 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
806 GstBaseTransformClass *klass;
808 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
810 GST_DEBUG_OBJECT (trans, "in caps: %" GST_PTR_FORMAT, in);
811 GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
813 /* clear the cache */
814 gst_caps_replace (&trans->cache_caps1, NULL);
815 gst_caps_replace (&trans->cache_caps2, NULL);
817 /* figure out same caps state */
818 trans->have_same_caps = gst_caps_is_equal (in, out);
819 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
821 /* If we've a transform_ip method and same input/output caps, set in_place
822 * by default. If for some reason the sub-class prefers using a transform
823 * function, it can clear the in place flag in the set_caps */
824 gst_base_transform_set_in_place (trans,
825 klass->transform_ip && trans->have_same_caps);
827 /* Set the passthrough if the class wants passthrough_on_same_caps
828 * and we have the same caps on each pad */
829 if (klass->passthrough_on_same_caps)
830 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
832 /* now configure the element with the caps */
833 if (klass->set_caps) {
834 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
835 ret = klass->set_caps (trans, in, out);
838 GST_OBJECT_LOCK (trans);
839 /* make sure we reevaluate how the buffer_alloc works wrt to proxy allocating
840 * the buffer. FIXME, this triggers some quite heavy codepaths that don't need
842 trans->priv->suggest_pending = TRUE;
843 GST_OBJECT_UNLOCK (trans);
844 trans->negotiated = ret;
849 /* check if caps @in on @pad can be transformed to @out on the other pad.
850 * We don't have a vmethod to test this yet so we have to do a somewhat less
851 * efficient check for this.
854 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
855 GstCaps * in, GstCaps * out)
859 /* convert the in caps to all possible out caps */
861 gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
863 /* check if transform is empty */
864 if (!othercaps || gst_caps_is_empty (othercaps))
867 /* check if the out caps is a subset of the othercaps */
868 if (!gst_caps_can_intersect (out, othercaps))
872 gst_caps_unref (othercaps);
874 GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
875 GST_DEBUG_OBJECT (trans, "to %" GST_PTR_FORMAT, out);
882 GST_DEBUG_OBJECT (trans,
883 "transform returned useless %" GST_PTR_FORMAT, othercaps);
885 gst_caps_unref (othercaps);
890 GST_DEBUG_OBJECT (trans, "no subset");
892 gst_caps_unref (othercaps);
897 /* given a fixed @caps on @pad, create the best possible caps for the
899 * @caps must be fixed when calling this function.
901 * This function calls the transform caps vmethod of the basetransform to figure
902 * out the possible target formats. It then tries to select the best format from
905 * - attempt passthrough if the target caps is a superset of the input caps
906 * - fixating by using peer caps
907 * - fixating with transform fixate function
908 * - fixating with pad fixate functions.
910 * this function returns a caps that can be transformed into and is accepted by
914 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
917 GstBaseTransformClass *klass;
918 GstPad *otherpad, *otherpeer;
920 gboolean peer_checked = FALSE;
923 /* caps must be fixed here, this is a programming error if it's not */
924 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
926 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
928 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
929 otherpeer = gst_pad_get_peer (otherpad);
931 /* see how we can transform the input caps. We need to do this even for
932 * passthrough because it might be possible that this element cannot support
933 * passthrough at all. */
934 othercaps = gst_base_transform_transform_caps (trans,
935 GST_PAD_DIRECTION (pad), caps);
937 /* The caps we can actually output is the intersection of the transformed
938 * caps with the pad template for the pad */
941 const GstCaps *templ_caps;
943 templ_caps = gst_pad_get_pad_template_caps (otherpad);
944 GST_DEBUG_OBJECT (trans,
945 "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
948 gst_caps_intersect_full (othercaps, templ_caps,
949 GST_CAPS_INTERSECT_FIRST);
951 gst_caps_unref (othercaps);
952 othercaps = intersect;
955 /* check if transform is empty */
956 if (!othercaps || gst_caps_is_empty (othercaps))
959 /* if the othercaps are not fixed, we need to fixate them, first attempt
960 * is by attempting passthrough if the othercaps are a superset of caps. */
961 /* FIXME. maybe the caps is not fixed because it has multiple structures of
963 is_fixed = gst_caps_is_fixed (othercaps);
965 GST_DEBUG_OBJECT (trans,
966 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
968 /* see if the target caps are a superset of the source caps, in this
969 * case we can try to perform passthrough */
970 if (gst_caps_can_intersect (othercaps, caps)) {
971 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
973 /* try passthrough. we know it's fixed, because caps is fixed */
974 if (gst_pad_accept_caps (otherpeer, caps)) {
975 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
976 /* peer accepted unmodified caps, we free the original non-fixed
977 * caps and work with the passthrough caps */
978 gst_caps_unref (othercaps);
979 othercaps = gst_caps_ref (caps);
981 /* mark that we checked othercaps with the peer, this
982 * makes sure we don't call accept_caps again with these same
986 GST_DEBUG_OBJECT (trans,
987 "peer did not accept %" GST_PTR_FORMAT, caps);
990 GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
991 gst_caps_unref (othercaps);
992 othercaps = gst_caps_ref (caps);
998 /* second attempt at fixation is done by intersecting with
1000 if (!is_fixed && otherpeer) {
1001 /* intersect against what the peer can do */
1005 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
1007 peercaps = gst_pad_get_caps_reffed (otherpeer);
1008 intersect = gst_caps_intersect (peercaps, othercaps);
1009 gst_caps_unref (peercaps);
1010 gst_caps_unref (othercaps);
1011 othercaps = intersect;
1012 peer_checked = FALSE;
1014 is_fixed = gst_caps_is_fixed (othercaps);
1016 GST_DEBUG_OBJECT (trans,
1017 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
1020 if (gst_caps_is_empty (othercaps))
1021 goto no_transform_possible;
1023 /* third attempt at fixation, call the fixate vmethod and
1024 * ultimately call the pad fixate function. */
1026 GST_DEBUG_OBJECT (trans,
1027 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
1028 othercaps, GST_DEBUG_PAD_NAME (otherpad));
1030 /* since we have no other way to fixate left, we might as well just take
1031 * the first of the caps list and fixate that */
1033 /* FIXME: when fixating using the vmethod, it might make sense to fixate
1034 * each of the caps; but Wim doesn't see a use case for that yet */
1035 gst_caps_truncate (othercaps);
1036 peer_checked = FALSE;
1038 if (klass->fixate_caps) {
1039 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1040 " using caps %" GST_PTR_FORMAT
1041 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1042 GST_DEBUG_PAD_NAME (otherpad));
1043 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1044 is_fixed = gst_caps_is_fixed (othercaps);
1046 /* if still not fixed, no other option but to let the default pad fixate
1047 * function do its job */
1049 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1050 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
1051 GST_DEBUG_PAD_NAME (otherpad));
1052 gst_pad_fixate_caps (otherpad, othercaps);
1053 is_fixed = gst_caps_is_fixed (othercaps);
1055 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
1057 GST_DEBUG ("caps are fixed");
1058 /* else caps are fixed but the subclass may want to add fields */
1059 if (klass->fixate_caps) {
1060 othercaps = gst_caps_make_writable (othercaps);
1062 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1063 " using caps %" GST_PTR_FORMAT
1064 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1065 GST_DEBUG_PAD_NAME (otherpad));
1067 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1068 is_fixed = gst_caps_is_fixed (othercaps);
1072 /* caps should be fixed now, if not we have to fail. */
1074 goto could_not_fixate;
1076 /* and peer should accept, don't check again if we already checked the
1077 * othercaps against the peer. */
1078 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
1079 goto peer_no_accept;
1081 GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1082 ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1085 gst_object_unref (otherpeer);
1092 GST_DEBUG_OBJECT (trans,
1093 "transform returned useless %" GST_PTR_FORMAT, othercaps);
1096 no_transform_possible:
1098 GST_DEBUG_OBJECT (trans,
1099 "transform could not transform %" GST_PTR_FORMAT
1100 " in anything we support", caps);
1105 GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1110 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1111 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1117 gst_object_unref (otherpeer);
1119 gst_caps_unref (othercaps);
1125 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1126 GstPadDirection direction, GstCaps * caps)
1130 GstCaps *othercaps = NULL;
1132 gboolean ret = TRUE;
1135 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1137 /* we need fixed caps for the check, fall back to the default implementation
1139 if (!gst_caps_is_fixed (caps))
1144 GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1146 /* get all the formats we can handle on this pad */
1147 if (direction == GST_PAD_SRC)
1148 allowed = gst_pad_get_caps_reffed (trans->srcpad);
1150 allowed = gst_pad_get_caps_reffed (trans->sinkpad);
1153 GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1154 goto no_transform_possible;
1157 GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1159 /* intersect with the requested format */
1160 ret = gst_caps_can_intersect (allowed, caps);
1161 gst_caps_unref (allowed);
1164 goto no_transform_possible;
1168 GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1170 /* find best possible caps for the other pad as a way to see if we can
1171 * transform this caps. */
1172 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1173 if (!othercaps || gst_caps_is_empty (othercaps))
1174 goto no_transform_possible;
1176 GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1182 /* We know it's always NULL since we never use it */
1184 gst_caps_unref (othercaps);
1190 no_transform_possible:
1192 GST_DEBUG_OBJECT (trans,
1193 "transform could not transform %" GST_PTR_FORMAT
1194 " in anything we support", caps);
1201 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1203 gboolean ret = TRUE;
1204 GstBaseTransform *trans;
1205 GstBaseTransformClass *bclass;
1207 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1208 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1210 if (bclass->accept_caps)
1211 ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1213 gst_object_unref (trans);
1218 /* called when new caps arrive on the sink or source pad,
1219 * We try to find the best caps for the other side using our _find_transform()
1220 * function. If there are caps, we configure the transform for this new
1223 * FIXME, this function is currently commutative but this should not really be
1224 * because we never set caps starting from the srcpad.
1227 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1229 GstBaseTransform *trans;
1230 GstPad *otherpad, *otherpeer;
1231 GstCaps *othercaps = NULL;
1232 gboolean ret = TRUE;
1233 GstCaps *incaps, *outcaps;
1235 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1237 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1238 otherpeer = gst_pad_get_peer (otherpad);
1240 /* if we get called recursively, we bail out now to avoid an
1242 if (GST_PAD_IS_IN_SETCAPS (otherpad))
1245 GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1247 /* find best possible caps for the other pad */
1248 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1249 if (!othercaps || gst_caps_is_empty (othercaps))
1250 goto no_transform_possible;
1252 /* configure the element now */
1253 /* make sure in and out caps are correct */
1254 if (pad == trans->sinkpad) {
1256 outcaps = othercaps;
1262 /* if we have the same caps, we can optimize and reuse the input caps */
1263 if (gst_caps_is_equal (incaps, outcaps)) {
1264 GST_INFO_OBJECT (trans, "reuse caps");
1265 gst_caps_unref (othercaps);
1266 outcaps = othercaps = gst_caps_ref (incaps);
1269 /* call configure now */
1270 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1271 goto failed_configure;
1273 /* we know this will work, we implement the setcaps */
1274 gst_pad_set_caps (otherpad, othercaps);
1276 if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1278 ret &= gst_pad_set_caps (otherpeer, othercaps);
1280 GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1286 /* new caps, force alloc on next buffer on the chain */
1287 trans->priv->force_alloc = TRUE;
1289 gst_object_unref (otherpeer);
1291 gst_caps_unref (othercaps);
1293 trans->negotiated = ret;
1295 gst_object_unref (trans);
1300 no_transform_possible:
1302 GST_WARNING_OBJECT (trans,
1303 "transform could not transform %" GST_PTR_FORMAT
1304 " in anything we support", caps);
1310 GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1311 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1318 gst_base_transform_default_query (GstBaseTransform * trans,
1319 GstPadDirection direction, GstQuery * query)
1321 gboolean ret = FALSE;
1324 otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1326 switch (GST_QUERY_TYPE (query)) {
1327 case GST_QUERY_POSITION:{
1330 gst_query_parse_position (query, &format, NULL);
1331 if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1335 if ((direction == GST_PAD_SINK)
1336 || (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
1338 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1339 trans->segment.last_stop);
1341 pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1342 trans->priv->last_stop_out);
1344 gst_query_set_position (query, format, pos);
1346 ret = gst_pad_peer_query (otherpad, query);
1351 ret = gst_pad_peer_query (otherpad, query);
1359 gst_base_transform_query (GstPad * pad, GstQuery * query)
1361 GstBaseTransform *trans;
1362 GstBaseTransformClass *bclass;
1365 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1366 if (G_UNLIKELY (trans == NULL))
1369 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1372 ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1374 ret = gst_pad_query_default (pad, query);
1376 gst_object_unref (trans);
1381 static const GstQueryType *
1382 gst_base_transform_query_type (GstPad * pad)
1384 static const GstQueryType types[] = {
1393 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1397 GstBaseTransformPrivate *priv = trans->priv;
1399 GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1401 /* we cannot convert the current buffer but we might be able to suggest a
1402 * new format upstream, try to find what the best format is. */
1403 othercaps = gst_base_transform_find_transform (trans, trans->srcpad, caps);
1406 GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1407 /* we received caps that we cannot transform. Upstream is behaving badly
1408 * because it should have checked if we could handle these caps. We can
1409 * simply ignore these caps and produce a buffer with our original caps. */
1413 GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1415 /* not a subset, we have a new upstream suggestion, remember it and
1416 * allocate a default buffer. First we try to convert the size */
1417 if (gst_base_transform_transform_size (trans,
1418 GST_PAD_SRC, caps, expsize, othercaps, &size_suggest)) {
1420 /* ok, remember the suggestions now */
1421 GST_DEBUG_OBJECT (trans,
1422 "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1423 size_suggest, othercaps);
1425 GST_OBJECT_LOCK (trans->sinkpad);
1426 if (priv->sink_suggest)
1427 gst_caps_unref (priv->sink_suggest);
1428 priv->sink_suggest = gst_caps_ref (othercaps);
1429 priv->size_suggest = size_suggest;
1430 trans->priv->suggest_pending = TRUE;
1431 GST_OBJECT_UNLOCK (trans->sinkpad);
1433 gst_caps_unref (othercaps);
1437 /* Allocate a buffer using gst_pad_alloc_buffer
1439 * This function can do renegotiation on the source pad
1441 * The output buffer is always writable. outbuf can be equal to
1442 * inbuf, the caller should be prepared for this and perform
1443 * appropriate refcounting.
1445 static GstFlowReturn
1446 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1447 GstBuffer * in_buf, GstBuffer ** out_buf)
1449 GstBaseTransformClass *bclass;
1450 GstBaseTransformPrivate *priv;
1451 GstFlowReturn ret = GST_FLOW_OK;
1452 guint outsize, newsize, expsize;
1453 gboolean discard, setcaps, copymeta;
1454 GstCaps *incaps, *oldcaps, *newcaps, *outcaps;
1456 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1462 /* figure out how to allocate a buffer based on the current configuration */
1463 if (trans->passthrough) {
1464 GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1465 /* passthrough, we don't really need to call pad alloc but we still need to
1466 * in order to get upstream negotiation. The output size is the same as the
1468 outsize = GST_BUFFER_SIZE (in_buf);
1469 /* we always alloc and discard here */
1472 gboolean want_in_place = (bclass->transform_ip != NULL)
1473 && trans->always_in_place;
1475 if (want_in_place) {
1476 GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1477 /* we alloc a buffer of the same size as the input */
1478 outsize = GST_BUFFER_SIZE (in_buf);
1479 /* only discard it when the input was not writable, otherwise, we reuse
1480 * the input buffer. */
1481 discard = gst_buffer_is_writable (in_buf);
1482 GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1484 GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1485 /* copy transform, figure out the output size */
1486 if (!gst_base_transform_transform_size (trans,
1487 GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1488 GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1492 /* never discard this buffer, we need it for storing the output */
1497 oldcaps = GST_PAD_CAPS (trans->srcpad);
1499 if (bclass->prepare_output_buffer) {
1500 GST_DEBUG_OBJECT (trans,
1501 "calling prepare buffer with caps %p %" GST_PTR_FORMAT, oldcaps,
1504 bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1507 /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1508 * update the pad caps if it wants */
1509 oldcaps = GST_PAD_CAPS (trans->srcpad);
1512 * decrease refcount again if vmethod returned refcounted in_buf. This
1513 * is because we need to make sure that the buffer is writable for the
1514 * in_place transform. The docs of the vmethod say that you should return
1515 * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1516 if (in_buf == *out_buf)
1517 gst_buffer_unref (in_buf);
1519 /* never discard the buffer from the prepare_buffer method */
1520 if (*out_buf != NULL)
1524 if (ret != GST_FLOW_OK)
1527 if (*out_buf == NULL) {
1528 if (trans->passthrough && !trans->priv->force_alloc) {
1529 GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
1530 *out_buf = gst_buffer_ref (in_buf);
1532 GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
1535 ret = gst_pad_alloc_buffer (trans->srcpad,
1536 GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1537 if (ret != GST_FLOW_OK)
1542 /* must always have a buffer by now */
1543 if (*out_buf == NULL)
1546 /* check if we got different caps on this new output buffer */
1547 newcaps = GST_BUFFER_CAPS (*out_buf);
1548 newsize = GST_BUFFER_SIZE (*out_buf);
1550 if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1552 gboolean can_convert;
1554 GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1556 incaps = GST_PAD_CAPS (trans->sinkpad);
1558 /* check if we can convert the current incaps to the new target caps */
1560 gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1564 GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1566 gst_base_transform_transform_size (trans,
1567 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1569 compute_upstream_suggestion (trans, expsize, newcaps);
1571 /* we got a suggested caps but we can't transform to it. See if there is
1572 * another downstream format that we can transform to */
1574 gst_base_transform_find_transform (trans, trans->sinkpad, incaps);
1576 if (othercaps && !gst_caps_is_empty (othercaps)) {
1577 GST_DEBUG_OBJECT (trans, "we found target caps %" GST_PTR_FORMAT,
1579 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1580 gst_buffer_set_caps (*out_buf, othercaps);
1581 gst_caps_unref (othercaps);
1582 newcaps = GST_BUFFER_CAPS (*out_buf);
1584 } else if (othercaps)
1585 gst_caps_unref (othercaps);
1588 /* it's possible that the buffer we got is of the wrong size, get the
1589 * expected size here, we will check the size if we are going to use the
1590 * buffer later on. */
1591 gst_base_transform_transform_size (trans,
1592 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1595 GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1597 /* subclass might want to add fields to the caps */
1598 if (bclass->fixate_caps != NULL) {
1599 newcaps = gst_caps_copy (newcaps);
1601 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1602 " using caps %" GST_PTR_FORMAT
1603 " on pad %s:%s using fixate_caps vmethod", newcaps, incaps,
1604 GST_DEBUG_PAD_NAME (trans->srcpad));
1605 bclass->fixate_caps (trans, GST_PAD_SINK, incaps, newcaps);
1607 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1608 gst_buffer_set_caps (*out_buf, newcaps);
1609 gst_caps_unref (newcaps);
1610 newcaps = GST_BUFFER_CAPS (*out_buf);
1613 /* caps not empty, try to renegotiate to the new format */
1614 if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1615 /* not sure we need to fail hard here, we can simply continue our
1616 * conversion with what we negotiated before */
1617 goto failed_configure;
1619 /* new format configure, and use the new output buffer */
1620 gst_pad_set_caps (trans->srcpad, newcaps);
1622 /* clear previous cached sink-pad caps, so buffer_alloc knows that
1623 * it needs to revisit the decision about whether to proxy or not: */
1624 gst_caps_replace (&priv->sink_alloc, NULL);
1625 /* if we got a buffer of the wrong size, discard it now and make sure we
1626 * allocate a properly sized buffer later. */
1627 if (newsize != expsize) {
1628 if (in_buf != *out_buf)
1629 gst_buffer_unref (*out_buf);
1634 compute_upstream_suggestion (trans, expsize, newcaps);
1636 if (in_buf != *out_buf)
1637 gst_buffer_unref (*out_buf);
1640 } else if (outsize != newsize) {
1641 GST_WARNING_OBJECT (trans, "Caps did not change but allocated size does "
1642 "not match expected size (%d != %d)", newsize, outsize);
1643 if (in_buf != *out_buf)
1644 gst_buffer_unref (*out_buf);
1648 /* these are the final output caps */
1649 outcaps = GST_PAD_CAPS (trans->srcpad);
1652 if (*out_buf == NULL) {
1654 GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1656 /* no valid buffer yet, make one, metadata is writable */
1657 *out_buf = gst_buffer_new_and_alloc (outsize);
1658 gst_buffer_copy_metadata (*out_buf, in_buf,
1659 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1661 GST_DEBUG_OBJECT (trans, "reuse input buffer");
1665 if (trans->passthrough && in_buf != *out_buf) {
1666 /* we are asked to perform a passthrough transform but the input and
1667 * output buffers are different. We have to discard the output buffer and
1668 * reuse the input buffer. */
1669 GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1673 GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1674 gst_buffer_unref (*out_buf);
1677 GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", in_buf,
1679 /* if we have different buffers, check if the metadata is ok */
1680 if (*out_buf != in_buf) {
1683 mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
1684 GST_BUFFER_FLAG_DELTA_UNIT | GST_BUFFER_FLAG_DISCONT |
1685 GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_MEDIA1 |
1686 GST_BUFFER_FLAG_MEDIA2 | GST_BUFFER_FLAG_MEDIA3;
1687 /* see if the flags and timestamps match */
1689 (GST_MINI_OBJECT_FLAGS (*out_buf) & mask) ==
1690 (GST_MINI_OBJECT_FLAGS (in_buf) & mask);
1692 GST_BUFFER_TIMESTAMP (*out_buf) != GST_BUFFER_TIMESTAMP (in_buf) ||
1693 GST_BUFFER_DURATION (*out_buf) != GST_BUFFER_DURATION (in_buf) ||
1694 GST_BUFFER_OFFSET (*out_buf) != GST_BUFFER_OFFSET (in_buf) ||
1695 GST_BUFFER_OFFSET_END (*out_buf) != GST_BUFFER_OFFSET_END (in_buf);
1700 /* check if we need to make things writable. We need this when we need to
1701 * update the caps or the metadata on the output buffer. */
1702 newcaps = GST_BUFFER_CAPS (*out_buf);
1703 /* we check the pointers as a quick check and then go to the more involved
1704 * check. This is needed when we receive different pointers on the sinkpad
1705 * that mean the same caps. What we then want to do is prefer those caps over
1706 * the ones on the srcpad and set the srcpad caps to the buffer caps */
1707 setcaps = !newcaps || ((newcaps != outcaps)
1708 && (!gst_caps_is_equal (newcaps, outcaps)));
1709 /* we need to modify the metadata when the element is not gap aware,
1710 * passthrough is not used and the gap flag is set */
1711 copymeta |= !trans->priv->gap_aware && !trans->passthrough
1712 && (GST_MINI_OBJECT_FLAGS (*out_buf) & GST_BUFFER_FLAG_GAP);
1714 if (setcaps || copymeta) {
1715 GST_DEBUG_OBJECT (trans, "setcaps %d, copymeta %d", setcaps, copymeta);
1716 if (!gst_buffer_is_metadata_writable (*out_buf)) {
1717 GST_DEBUG_OBJECT (trans, "buffer metadata %p not writable", *out_buf);
1718 if (in_buf == *out_buf)
1719 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
1721 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1723 /* when we get here, the metadata should be writable */
1725 gst_buffer_set_caps (*out_buf, outcaps);
1727 gst_buffer_copy_metadata (*out_buf, in_buf,
1728 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1729 /* clear the GAP flag when the subclass does not understand it */
1730 if (!trans->priv->gap_aware)
1731 GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1739 GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1744 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1745 ("Sub-class failed to provide an output buffer"), (NULL));
1746 return GST_FLOW_ERROR;
1750 GST_ERROR_OBJECT (trans, "unknown output size");
1751 return GST_FLOW_ERROR;
1755 GST_WARNING_OBJECT (trans, "failed to configure caps");
1756 return GST_FLOW_NOT_NEGOTIATED;
1760 /* Given @caps calcultate the size of one unit.
1762 * For video caps, this is the size of one frame (and thus one buffer).
1763 * For audio caps, this is the size of one sample.
1765 * These values are cached since they do not change and the calculation
1766 * potentially involves parsing caps and other expensive stuff.
1768 * We have two cache locations to store the size, one for the source caps
1769 * and one for the sink caps.
1771 * this function returns FALSE if no size could be calculated.
1774 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1777 gboolean res = FALSE;
1778 GstBaseTransformClass *bclass;
1780 /* see if we have the result cached */
1781 if (trans->cache_caps1 == caps) {
1782 *size = trans->cache_caps1_size;
1783 GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1786 if (trans->cache_caps2 == caps) {
1787 *size = trans->cache_caps2_size;
1788 GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1792 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1793 if (bclass->get_unit_size) {
1794 res = bclass->get_unit_size (trans, caps, size);
1795 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1796 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1799 /* and cache the values */
1800 if (trans->cache_caps1 == NULL) {
1801 gst_caps_replace (&trans->cache_caps1, caps);
1802 trans->cache_caps1_size = *size;
1803 GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1804 } else if (trans->cache_caps2 == NULL) {
1805 gst_caps_replace (&trans->cache_caps2, caps);
1806 trans->cache_caps2_size = *size;
1807 GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1809 GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1813 GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1818 /* your upstream peer wants to send you a buffer
1819 * that buffer has the given offset, size and caps
1820 * you're requested to allocate a buffer
1822 static GstFlowReturn
1823 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1824 GstCaps * caps, GstBuffer ** buf)
1826 GstBaseTransform *trans;
1827 GstBaseTransformPrivate *priv;
1829 gboolean alloced = FALSE;
1830 gboolean proxy, suggest, new_caps;
1831 GstCaps *sink_suggest = NULL;
1834 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1835 if (G_UNLIKELY (trans == NULL))
1836 return GST_FLOW_WRONG_STATE;
1839 GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1842 /* if the code below does not come up with a better buffer, we will return _OK
1843 * and an empty buffer. This will trigger the core to allocate a buffer with
1844 * given input size and caps. */
1848 /* we remember our previous alloc request to quickly see if we can proxy or
1849 * not. We skip this check if we have a pending suggestion. */
1850 GST_OBJECT_LOCK (pad);
1851 suggest = priv->suggest_pending;
1852 GST_OBJECT_UNLOCK (pad);
1855 /* we have no suggestion, see below if we need to proxy */
1856 gst_caps_replace (&sink_suggest, caps);
1857 size_suggest = size;
1859 new_caps = sink_suggest
1860 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1863 GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1865 GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1867 /* if we have a suggestion, pretend we got these as input */
1868 GST_OBJECT_LOCK (pad);
1869 if (priv->sink_suggest &&
1870 !gst_caps_can_intersect (caps, priv->sink_suggest)) {
1871 sink_suggest = gst_caps_ref (priv->sink_suggest);
1872 size_suggest = priv->size_suggest;
1873 GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1874 sink_suggest, sink_suggest, priv->size_suggest);
1876 GST_DEBUG_OBJECT (trans,
1877 "have suggestion equal to upstream caps %p %" GST_PTR_FORMAT, caps,
1879 gst_caps_replace (&sink_suggest, caps);
1880 size_suggest = size;
1883 priv->suggest_pending = FALSE;
1884 GST_OBJECT_UNLOCK (pad);
1886 /* check if we actually handle this format on the sinkpad */
1890 /* Always intersect with the peer caps to get correct
1891 * and complete caps. The suggested caps could be incomplete,
1892 * for example video/x-raw-yuv without any fields at all.
1895 gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1901 gst_caps_intersect_full (sink_suggest, peercaps,
1902 GST_CAPS_INTERSECT_FIRST);
1903 gst_caps_unref (peercaps);
1905 /* If intersected caps is empty then just keep them empty. The
1906 * code below will try to come up with possible caps if there
1908 gst_caps_unref (sink_suggest);
1909 sink_suggest = intersect;
1912 /* If the suggested caps are not empty and not fixed, try to fixate them */
1913 if (!gst_caps_is_fixed (sink_suggest)
1914 && !gst_caps_is_empty (sink_suggest)) {
1915 GST_DEBUG_OBJECT (trans,
1916 "Suggested caps is not fixed: %" GST_PTR_FORMAT, sink_suggest);
1918 /* try the alloc caps if it is still not fixed */
1919 if (!gst_caps_is_fixed (sink_suggest)) {
1922 GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1923 "with the non-fixed caps suggestion");
1925 gst_caps_intersect_full (sink_suggest, caps,
1926 GST_CAPS_INTERSECT_FIRST);
1927 if (!gst_caps_is_empty (intersect)) {
1928 GST_DEBUG_OBJECT (trans, "It is, using it");
1929 gst_caps_replace (&sink_suggest, caps);
1931 gst_caps_unref (intersect);
1934 /* be safe and call default fixate */
1935 sink_suggest = gst_caps_make_writable (sink_suggest);
1936 gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1938 if (!gst_caps_is_fixed (sink_suggest)) {
1939 GST_DEBUG_OBJECT (trans,
1940 "Impossible to fixate caps, using upstream caps");
1941 gst_caps_replace (&sink_suggest, caps);
1942 size_suggest = size;
1946 GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1951 new_caps = sink_suggest
1952 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1955 /* Check if the new caps are compatible with our
1956 * sinkpad template caps and if they're not
1957 * we try to come up with any supported caps
1960 const GstCaps *templ;
1962 templ = gst_pad_get_pad_template_caps (pad);
1964 /* Fall back to the upstream caps if the suggested caps
1965 * are not actually supported. Shouldn't really happen
1967 if (suggest && !gst_caps_can_intersect (sink_suggest, templ)) {
1968 GST_DEBUG_OBJECT (trans,
1969 "Suggested caps not supported by sinkpad, using upstream caps");
1970 gst_caps_replace (&sink_suggest, caps);
1971 size_suggest = size;
1973 new_caps = sink_suggest
1974 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1977 if (new_caps && (suggest || !gst_caps_can_intersect (sink_suggest, templ))) {
1978 GstCaps *allowed, *peercaps;
1980 GST_DEBUG_OBJECT (trans,
1981 "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1983 /* the requested pad alloc caps are not supported, so let's try
1984 * picking something allowed between the pads (they are linked,
1985 * there must be something) */
1986 allowed = gst_pad_get_allowed_caps (pad);
1987 if (allowed && !gst_caps_is_empty (allowed)) {
1988 GST_DEBUG_OBJECT (trans,
1989 "pads could agree on one of the following caps: " "%"
1990 GST_PTR_FORMAT, allowed);
1992 /* Check which caps would be possible with downstream */
1994 gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1996 GstCaps *tmp, *intersect;
1999 gst_base_transform_transform_caps (trans, GST_PAD_SRC, peercaps);
2000 gst_caps_unref (peercaps);
2001 intersect = gst_caps_intersect (allowed, tmp);
2002 gst_caps_unref (tmp);
2003 gst_caps_unref (allowed);
2005 if (gst_caps_is_empty (intersect)) {
2006 gst_caps_unref (intersect);
2010 allowed = intersect;
2013 allowed = gst_caps_make_writable (allowed);
2015 /* Fixate them to be safe if the subclass didn't do it */
2016 gst_caps_truncate (allowed);
2017 gst_pad_fixate_caps (pad, allowed);
2019 if (!gst_caps_is_fixed (allowed)) {
2020 GST_ERROR_OBJECT (trans, "Impossible to fixate any caps");
2021 gst_caps_unref (allowed);
2025 gst_caps_replace (&sink_suggest, allowed);
2026 gst_caps_unref (allowed);
2029 new_caps = !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
2031 GST_DEBUG_OBJECT (trans, "Calculated new suggestion caps %"
2032 GST_PTR_FORMAT, sink_suggest);
2035 gst_caps_unref (allowed);
2041 /* find the best format for the other side here we decide if we will proxy
2042 * the caps or not. */
2043 if (sink_suggest == NULL) {
2044 /* always proxy when the caps are NULL. When this is a new format, see if
2045 * we can proxy it downstream */
2046 GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
2047 priv->proxy_alloc = TRUE;
2048 } else if (new_caps) {
2051 /* we have a new format, see what we need to proxy to */
2052 othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
2053 if (!othercaps || gst_caps_is_empty (othercaps)) {
2054 /* no transform possible, we certainly can't proxy */
2055 GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
2056 priv->proxy_alloc = FALSE;
2058 /* we transformed into something */
2059 if (gst_caps_is_equal (sink_suggest, othercaps)) {
2060 GST_DEBUG_OBJECT (trans, "best caps same as input, marking for proxy");
2061 priv->proxy_alloc = TRUE;
2063 GST_DEBUG_OBJECT (trans,
2064 "best caps different from input, disable proxy");
2065 priv->proxy_alloc = FALSE;
2069 gst_caps_unref (othercaps);
2072 /* remember the new caps */
2073 GST_OBJECT_LOCK (pad);
2074 gst_caps_replace (&priv->sink_alloc, sink_suggest);
2075 GST_OBJECT_UNLOCK (pad);
2077 proxy = priv->proxy_alloc;
2078 GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
2081 /* we only want to proxy if we have no suggestion pending, FIXME */
2082 if (proxy && !suggest) {
2085 GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
2086 ", size %u", caps, caps, size);
2088 /* we always proxy the input caps, never the suggestion. The reason is that
2089 * We don't yet handle the caps of renegotiation in here. FIXME */
2090 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
2091 if (res != GST_FLOW_OK)
2095 /* check if the caps changed */
2096 newcaps = GST_BUFFER_CAPS (*buf);
2098 GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
2100 if (!gst_caps_is_equal (newcaps, caps)) {
2101 GST_DEBUG_OBJECT (trans, "caps are new");
2102 /* we have new caps, see if we can proxy downstream */
2103 if (gst_pad_peer_accept_caps (pad, newcaps)) {
2104 /* peer accepts the caps, return a buffer in this format */
2105 GST_DEBUG_OBJECT (trans, "peer accepted new caps");
2106 /* remember the format */
2107 GST_OBJECT_LOCK (pad);
2108 gst_caps_replace (&priv->sink_alloc, newcaps);
2109 GST_OBJECT_UNLOCK (pad);
2111 GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
2112 /* peer does not accept the caps, disable proxy_alloc, free the
2113 * buffer we received and create a buffer of the requested format
2114 * by the default handler. */
2115 GST_DEBUG_OBJECT (trans, "disabling proxy");
2116 priv->proxy_alloc = FALSE;
2117 gst_buffer_unref (*buf);
2121 GST_DEBUG_OBJECT (trans, "received required caps from peer");
2123 } else if (suggest) {
2124 /* there was a custom suggestion, create a buffer of this format and return
2125 * it. Note that this format */
2126 *buf = gst_buffer_new_and_alloc (size_suggest);
2127 GST_DEBUG_OBJECT (trans,
2128 "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2129 sink_suggest, sink_suggest);
2130 GST_BUFFER_CAPS (*buf) = sink_suggest;
2131 sink_suggest = NULL;
2133 /* fallback buffer allocation by gst_pad_alloc_buffer() with the
2134 * caps and size provided by the caller */
2138 gst_caps_unref (sink_suggest);
2140 if (res == GST_FLOW_OK && alloced) {
2141 /* just alloc'ed a buffer, so we only want to do this again if we
2142 * received a buffer */
2143 GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2144 trans->priv->force_alloc = FALSE;
2147 gst_object_unref (trans);
2153 GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2155 gst_caps_unref (sink_suggest);
2156 gst_object_unref (trans);
2161 GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2163 gst_caps_unref (sink_suggest);
2164 gst_object_unref (trans);
2165 return GST_FLOW_NOT_NEGOTIATED;
2170 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2174 GST_OBJECT_LOCK (trans);
2175 list = trans->priv->delayed_events;
2176 trans->priv->delayed_events = NULL;
2177 GST_OBJECT_UNLOCK (trans);
2181 for (tmp = list; tmp; tmp = tmp->next) {
2182 GstEvent *ev = tmp->data;
2184 GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2185 GST_EVENT_TYPE_NAME (ev));
2186 gst_pad_push_event (trans->srcpad, ev);
2192 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2194 GstBaseTransform *trans;
2195 GstBaseTransformClass *bclass;
2196 gboolean ret = TRUE;
2197 gboolean forward = TRUE;
2199 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2200 if (G_UNLIKELY (trans == NULL)) {
2201 gst_event_unref (event);
2204 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2207 forward = bclass->event (trans, event);
2209 /* FIXME, do this in the default event handler so the subclass can do
2210 * something different. */
2212 gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2214 /* src caps may not yet be set, so we delay any serialized events
2215 that we receive before (in particular newsegment events), except
2216 EOS and flush stops, since those'll obsolete previous events */
2217 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2218 gst_base_transform_drop_delayed_events (trans);
2221 delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2222 && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2224 /* do not stall sparse stream update newsegment events */
2225 if (delay && (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
2228 gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL,
2231 GST_DEBUG_OBJECT (trans, "update segment; triggering delayed events");
2239 GST_OBJECT_LOCK (trans);
2240 trans->priv->delayed_events =
2241 g_list_append (trans->priv->delayed_events, event);
2242 GST_OBJECT_UNLOCK (trans);
2244 if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2245 gst_base_transform_send_delayed_events (trans);
2246 ret = gst_pad_push_event (trans->srcpad, event);
2249 gst_event_unref (event);
2251 gst_object_unref (trans);
2257 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2259 switch (GST_EVENT_TYPE (event)) {
2260 case GST_EVENT_FLUSH_START:
2262 case GST_EVENT_FLUSH_STOP:
2263 GST_OBJECT_LOCK (trans);
2264 /* reset QoS parameters */
2265 trans->priv->proportion = 1.0;
2266 trans->priv->earliest_time = -1;
2267 trans->priv->discont = FALSE;
2268 trans->priv->processed = 0;
2269 trans->priv->dropped = 0;
2270 GST_OBJECT_UNLOCK (trans);
2271 /* we need new segment info after the flush. */
2272 trans->have_newsegment = FALSE;
2273 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2274 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2280 case GST_EVENT_NEWSEGMENT:
2283 gdouble rate, arate;
2284 gint64 start, stop, time;
2287 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2288 &start, &stop, &time);
2290 trans->have_newsegment = TRUE;
2292 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2293 format, start, stop, time);
2295 if (format == GST_FORMAT_TIME) {
2296 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2297 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2298 ", accum %" GST_TIME_FORMAT,
2299 GST_TIME_ARGS (trans->segment.start),
2300 GST_TIME_ARGS (trans->segment.stop),
2301 GST_TIME_ARGS (trans->segment.time),
2302 GST_TIME_ARGS (trans->segment.accum));
2304 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2305 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2306 ", accum %" G_GINT64_FORMAT,
2307 trans->segment.start, trans->segment.stop,
2308 trans->segment.time, trans->segment.accum);
2320 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2322 GstBaseTransform *trans;
2323 GstBaseTransformClass *bclass;
2324 gboolean ret = TRUE;
2326 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2327 if (G_UNLIKELY (trans == NULL)) {
2328 gst_event_unref (event);
2332 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2334 if (bclass->src_event)
2335 ret = bclass->src_event (trans, event);
2337 gst_event_unref (event);
2339 gst_object_unref (trans);
2345 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2349 GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2351 switch (GST_EVENT_TYPE (event)) {
2352 case GST_EVENT_SEEK:
2354 case GST_EVENT_NAVIGATION:
2359 GstClockTimeDiff diff;
2360 GstClockTime timestamp;
2362 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2363 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2370 ret = gst_pad_push_event (trans->sinkpad, event);
2375 /* perform a transform on @inbuf and put the result in @outbuf.
2377 * This function is common to the push and pull-based operations.
2379 * This function takes ownership of @inbuf */
2380 static GstFlowReturn
2381 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2382 GstBuffer ** outbuf)
2384 GstBaseTransformClass *bclass;
2385 GstFlowReturn ret = GST_FLOW_OK;
2386 gboolean want_in_place, reconfigure;
2387 GstClockTime running_time;
2388 GstClockTime timestamp;
2391 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2393 if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2394 GST_OBJECT_LOCK (trans);
2395 reconfigure = trans->priv->reconfigure;
2396 trans->priv->reconfigure = FALSE;
2397 GST_OBJECT_UNLOCK (trans);
2399 if (G_UNLIKELY (reconfigure)) {
2400 GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2401 /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2402 * will reconfigure the transform with the new output format. We can only
2403 * do this if the buffer actually has caps. */
2404 if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2405 goto not_negotiated;
2409 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2410 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2411 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2412 GST_BUFFER_OFFSET (inbuf));
2414 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2415 inbuf, GST_BUFFER_SIZE (inbuf));
2417 /* Don't allow buffer handling before negotiation, except in passthrough mode
2418 * or if the class doesn't implement a set_caps function (in which case it doesn't
2421 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2422 goto not_negotiated;
2424 /* Set discont flag so we can mark the outgoing buffer */
2425 if (GST_BUFFER_IS_DISCONT (inbuf)) {
2426 GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2427 trans->priv->discont = TRUE;
2430 /* can only do QoS if the segment is in TIME */
2431 if (trans->segment.format != GST_FORMAT_TIME)
2434 /* QOS is done on the running time of the buffer, get it now */
2435 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2436 running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2439 if (running_time != -1) {
2441 GstClockTime earliest_time;
2444 /* lock for getting the QoS parameters that are set (in a different thread)
2445 * with the QOS events */
2446 GST_OBJECT_LOCK (trans);
2447 earliest_time = trans->priv->earliest_time;
2448 proportion = trans->priv->proportion;
2449 /* check for QoS, don't perform conversion for buffers
2450 * that are known to be late. */
2451 need_skip = trans->priv->qos_enabled &&
2452 earliest_time != -1 && running_time <= earliest_time;
2453 GST_OBJECT_UNLOCK (trans);
2456 GstMessage *qos_msg;
2457 GstClockTime duration;
2458 guint64 stream_time;
2461 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2462 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2463 GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2465 trans->priv->dropped++;
2467 duration = GST_BUFFER_DURATION (inbuf);
2469 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2471 jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2474 gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2475 stream_time, timestamp, duration);
2476 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2477 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2478 trans->priv->processed, trans->priv->dropped);
2479 gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2481 /* mark discont for next buffer */
2482 trans->priv->discont = TRUE;
2489 /* first try to allocate an output buffer based on the currently negotiated
2490 * format. While we call pad-alloc we could renegotiate the srcpad format or
2491 * have a new suggestion for upstream buffer-alloc.
2492 * In any case, outbuf will contain a buffer suitable for doing the configured
2493 * transform after this function. */
2494 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2495 if (G_UNLIKELY (ret != GST_FLOW_OK))
2498 /* now perform the needed transform */
2499 if (trans->passthrough) {
2500 /* In passthrough mode, give transform_ip a look at the
2501 * buffer, without making it writable, or just push the
2503 if (bclass->transform_ip) {
2504 GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2505 ret = bclass->transform_ip (trans, *outbuf);
2507 GST_DEBUG_OBJECT (trans, "element is in passthrough");
2510 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2512 if (want_in_place) {
2513 GST_DEBUG_OBJECT (trans, "doing inplace transform");
2515 if (inbuf != *outbuf) {
2516 guint8 *indata, *outdata;
2518 /* Different buffer. The data can still be the same when we are dealing
2519 * with subbuffers of the same buffer. Note that because of the FIXME in
2520 * prepare_output_buffer() we have decreased the refcounts of inbuf and
2521 * outbuf to keep them writable */
2522 indata = GST_BUFFER_DATA (inbuf);
2523 outdata = GST_BUFFER_DATA (*outbuf);
2525 if (indata != outdata)
2526 memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2528 ret = bclass->transform_ip (trans, *outbuf);
2530 GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2532 if (bclass->transform)
2533 ret = bclass->transform (trans, inbuf, *outbuf);
2535 ret = GST_FLOW_NOT_SUPPORTED;
2540 /* only unref input buffer if we allocated a new outbuf buffer */
2541 if (*outbuf != inbuf)
2542 gst_buffer_unref (inbuf);
2544 /* pushed a buffer, we can now try an alloc */
2545 GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2546 trans->priv->force_alloc = TRUE;
2552 gst_buffer_unref (inbuf);
2553 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2554 ("not negotiated"), ("not negotiated"));
2555 return GST_FLOW_NOT_NEGOTIATED;
2559 gst_buffer_unref (inbuf);
2560 GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2561 gst_flow_get_name (ret));
2567 gst_base_transform_check_get_range (GstPad * pad)
2569 GstBaseTransform *trans;
2572 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2574 ret = gst_pad_check_pull_range (trans->sinkpad);
2576 gst_object_unref (trans);
2581 /* FIXME, getrange is broken, need to pull range from the other
2582 * end based on the transform_size result.
2584 static GstFlowReturn
2585 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2586 guint length, GstBuffer ** buffer)
2588 GstBaseTransform *trans;
2589 GstBaseTransformClass *klass;
2593 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2595 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2596 if (G_UNLIKELY (ret != GST_FLOW_OK))
2599 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2600 if (klass->before_transform)
2601 klass->before_transform (trans, inbuf);
2603 GST_BASE_TRANSFORM_LOCK (trans);
2604 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2605 GST_BASE_TRANSFORM_UNLOCK (trans);
2608 gst_object_unref (trans);
2615 GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2616 gst_flow_get_name (ret));
2621 static GstFlowReturn
2622 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2624 GstBaseTransform *trans;
2625 GstBaseTransformClass *klass;
2627 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2628 GstClockTime timestamp, duration;
2629 GstBuffer *outbuf = NULL;
2631 trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2633 timestamp = GST_BUFFER_TIMESTAMP (buffer);
2634 duration = GST_BUFFER_DURATION (buffer);
2636 /* calculate end position of the incoming buffer */
2637 if (timestamp != GST_CLOCK_TIME_NONE) {
2638 if (duration != GST_CLOCK_TIME_NONE)
2639 last_stop = timestamp + duration;
2641 last_stop = timestamp;
2644 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2645 if (klass->before_transform)
2646 klass->before_transform (trans, buffer);
2648 gst_base_transform_send_delayed_events (trans);
2650 /* protect transform method and concurrent buffer alloc */
2651 GST_BASE_TRANSFORM_LOCK (trans);
2652 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2653 GST_BASE_TRANSFORM_UNLOCK (trans);
2655 /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2656 * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2657 if (outbuf != NULL) {
2658 if (ret == GST_FLOW_OK) {
2659 GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2661 /* Remember last stop position */
2662 if (last_stop != GST_CLOCK_TIME_NONE &&
2663 trans->segment.format == GST_FORMAT_TIME)
2664 gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2666 if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2667 last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2668 if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2669 last_stop_out += GST_BUFFER_DURATION (outbuf);
2670 } else if (last_stop != GST_CLOCK_TIME_NONE) {
2671 last_stop_out = last_stop;
2673 if (last_stop_out != GST_CLOCK_TIME_NONE
2674 && trans->segment.format == GST_FORMAT_TIME)
2675 trans->priv->last_stop_out = last_stop_out;
2677 /* apply DISCONT flag if the buffer is not yet marked as such */
2678 if (trans->priv->discont) {
2679 if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2680 outbuf = gst_buffer_make_metadata_writable (outbuf);
2681 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2683 trans->priv->discont = FALSE;
2685 trans->priv->processed++;
2687 ret = gst_pad_push (trans->srcpad, outbuf);
2689 gst_buffer_unref (outbuf);
2693 /* convert internal flow to OK and mark discont for the next buffer. */
2694 if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2695 trans->priv->discont = TRUE;
2703 gst_base_transform_set_property (GObject * object, guint prop_id,
2704 const GValue * value, GParamSpec * pspec)
2706 GstBaseTransform *trans;
2708 trans = GST_BASE_TRANSFORM (object);
2712 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2715 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2721 gst_base_transform_get_property (GObject * object, guint prop_id,
2722 GValue * value, GParamSpec * pspec)
2724 GstBaseTransform *trans;
2726 trans = GST_BASE_TRANSFORM (object);
2730 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2733 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2738 /* not a vmethod of anything, just an internal method */
2740 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2742 GstBaseTransformClass *bclass;
2743 gboolean result = TRUE;
2745 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2747 GST_OBJECT_LOCK (trans);
2748 gst_base_transform_clear_transformed_caps_cache (trans);
2749 GST_OBJECT_UNLOCK (trans);
2752 if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2753 result &= bclass->start (trans);
2755 GST_OBJECT_LOCK (trans);
2757 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2758 trans->have_same_caps =
2759 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2760 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2762 trans->have_same_caps = trans->passthrough;
2763 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2764 trans->negotiated = FALSE;
2765 trans->have_newsegment = FALSE;
2766 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2767 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2768 trans->priv->proportion = 1.0;
2769 trans->priv->earliest_time = -1;
2770 trans->priv->discont = FALSE;
2771 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2772 trans->priv->processed = 0;
2773 trans->priv->dropped = 0;
2774 trans->priv->force_alloc = TRUE;
2776 GST_OBJECT_UNLOCK (trans);
2778 /* We must make sure streaming has finished before resetting things
2779 * and calling the ::stop vfunc */
2780 GST_PAD_STREAM_LOCK (trans->sinkpad);
2781 GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2783 gst_base_transform_drop_delayed_events (trans);
2785 trans->have_same_caps = FALSE;
2786 /* We can only reset the passthrough mode if the instance told us to
2787 handle it in configure_caps */
2788 if (bclass->passthrough_on_same_caps) {
2789 gst_base_transform_set_passthrough (trans, FALSE);
2791 gst_caps_replace (&trans->cache_caps1, NULL);
2792 gst_caps_replace (&trans->cache_caps2, NULL);
2793 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2794 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2796 if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2797 result &= bclass->stop (trans);
2804 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2806 gboolean result = TRUE;
2807 GstBaseTransform *trans;
2809 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2811 result = gst_base_transform_activate (trans, active);
2814 trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2816 gst_object_unref (trans);
2822 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2824 gboolean result = FALSE;
2825 GstBaseTransform *trans;
2827 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2829 result = gst_pad_activate_pull (trans->sinkpad, active);
2832 result &= gst_base_transform_activate (trans, active);
2835 trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2837 gst_object_unref (trans);
2843 * gst_base_transform_set_passthrough:
2844 * @trans: the #GstBaseTransform to set
2845 * @passthrough: boolean indicating passthrough mode.
2847 * Set passthrough mode for this filter by default. This is mostly
2848 * useful for filters that do not care about negotiation.
2850 * Always TRUE for filters which don't implement either a transform
2851 * or transform_ip method.
2856 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2857 gboolean passthrough)
2859 GstBaseTransformClass *bclass;
2861 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2863 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2865 GST_OBJECT_LOCK (trans);
2866 if (passthrough == FALSE) {
2867 if (bclass->transform_ip || bclass->transform)
2868 trans->passthrough = FALSE;
2870 trans->passthrough = TRUE;
2873 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2874 GST_OBJECT_UNLOCK (trans);
2878 * gst_base_transform_is_passthrough:
2879 * @trans: the #GstBaseTransform to query
2881 * See if @trans is configured as a passthrough transform.
2883 * Returns: TRUE is the transform is configured in passthrough mode.
2888 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2892 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2894 GST_OBJECT_LOCK (trans);
2895 result = trans->passthrough;
2896 GST_OBJECT_UNLOCK (trans);
2902 * gst_base_transform_set_in_place:
2903 * @trans: the #GstBaseTransform to modify
2904 * @in_place: Boolean value indicating that we would like to operate
2905 * on in_place buffers.
2907 * Determines whether a non-writable buffer will be copied before passing
2908 * to the transform_ip function.
2910 * <listitem>Always TRUE if no transform function is implemented.</listitem>
2911 * <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2917 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2919 GstBaseTransformClass *bclass;
2921 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2923 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2925 GST_OBJECT_LOCK (trans);
2928 if (bclass->transform_ip) {
2929 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2930 trans->always_in_place = TRUE;
2933 if (bclass->transform) {
2934 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2935 trans->always_in_place = FALSE;
2939 GST_OBJECT_UNLOCK (trans);
2943 * gst_base_transform_is_in_place:
2944 * @trans: the #GstBaseTransform to query
2946 * See if @trans is configured as a in_place transform.
2948 * Returns: TRUE is the transform is configured in in_place mode.
2953 gst_base_transform_is_in_place (GstBaseTransform * trans)
2957 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2959 GST_OBJECT_LOCK (trans);
2960 result = trans->always_in_place;
2961 GST_OBJECT_UNLOCK (trans);
2967 * gst_base_transform_update_qos:
2968 * @trans: a #GstBaseTransform
2969 * @proportion: the proportion
2970 * @diff: the diff against the clock
2971 * @timestamp: the timestamp of the buffer generating the QoS expressed in
2974 * Set the QoS parameters in the transform. This function is called internally
2975 * when a QOS event is received but subclasses can provide custom information
2983 gst_base_transform_update_qos (GstBaseTransform * trans,
2984 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2987 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2989 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2990 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2991 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2993 GST_OBJECT_LOCK (trans);
2994 trans->priv->proportion = proportion;
2995 trans->priv->earliest_time = timestamp + diff;
2996 GST_OBJECT_UNLOCK (trans);
3000 * gst_base_transform_set_qos_enabled:
3001 * @trans: a #GstBaseTransform
3002 * @enabled: new state
3004 * Enable or disable QoS handling in the transform.
3011 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
3013 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3015 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
3017 GST_OBJECT_LOCK (trans);
3018 trans->priv->qos_enabled = enabled;
3019 GST_OBJECT_UNLOCK (trans);
3023 * gst_base_transform_is_qos_enabled:
3024 * @trans: a #GstBaseTransform
3026 * Queries if the transform will handle QoS.
3028 * Returns: TRUE if QoS is enabled.
3035 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
3039 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
3041 GST_OBJECT_LOCK (trans);
3042 result = trans->priv->qos_enabled;
3043 GST_OBJECT_UNLOCK (trans);
3049 * gst_base_transform_set_gap_aware:
3050 * @trans: a #GstBaseTransform
3051 * @gap_aware: New state
3053 * If @gap_aware is %FALSE (the default), output buffers will have the
3054 * %GST_BUFFER_FLAG_GAP flag unset.
3056 * If set to %TRUE, the element must handle output buffers with this flag set
3057 * correctly, i.e. it can assume that the buffer contains neutral data but must
3058 * unset the flag if the output is no neutral data.
3065 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
3067 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3069 GST_OBJECT_LOCK (trans);
3070 trans->priv->gap_aware = gap_aware;
3071 GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
3072 GST_OBJECT_UNLOCK (trans);
3076 * gst_base_transform_suggest:
3077 * @trans: a #GstBaseTransform
3078 * @caps: (transfer none): caps to suggest
3079 * @size: buffer size to suggest
3081 * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
3087 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
3090 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3092 GST_OBJECT_LOCK (trans->sinkpad);
3093 if (trans->priv->sink_suggest)
3094 gst_caps_unref (trans->priv->sink_suggest);
3096 caps = gst_caps_copy (caps);
3097 trans->priv->sink_suggest = caps;
3098 trans->priv->size_suggest = size;
3099 trans->priv->suggest_pending = TRUE;
3100 gst_base_transform_clear_transformed_caps_cache (trans);
3101 GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
3102 GST_OBJECT_UNLOCK (trans->sinkpad);
3106 * gst_base_transform_reconfigure:
3107 * @trans: a #GstBaseTransform
3109 * Instructs @trans to renegotiate a new downstream transform on the next
3110 * buffer. This function is typically called after properties on the transform
3111 * were set that influence the output format.
3116 gst_base_transform_reconfigure (GstBaseTransform * trans)
3118 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3120 GST_OBJECT_LOCK (trans);
3121 GST_DEBUG_OBJECT (trans, "marking reconfigure");
3122 trans->priv->reconfigure = TRUE;
3123 gst_base_transform_clear_transformed_caps_cache (trans);
3124 gst_caps_replace (&trans->priv->sink_alloc, NULL);
3125 GST_OBJECT_UNLOCK (trans);