2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2005 Wim Taymans <wim@fluendo.com>
5 * 2005 Andy Wingo <wingo@fluendo.com>
6 * 2005 Thomas Vander Stichele <thomas at apestaart dot org>
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 tranform 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
50 * <itemizedlist><title>Passthrough mode</title>
52 * Element has no interest in modifying the buffer. It may want to inspect it,
53 * in which case the element should have a transform_ip function. If there
54 * is no transform_ip function in passthrough mode, the buffer is pushed
58 * On the GstBaseTransformClass is the passthrough_on_same_caps variable
59 * which will automatically set/unset passthrough based on whether the
60 * element negotiates the same caps on both pads.
63 * passthrough_on_same_caps on an element that doesn't implement a transform_caps
64 * function is useful for elements that only inspect data (such as level)
68 * <title>Example elements</title>
69 * <listitem>Level</listitem>
70 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in certain modes.</listitem>
74 * <itemizedlist><title>Modifications in-place - input buffer and output buffer are the same thing.</title>
76 * The element must implement a transform_ip function.
79 * Output buffer size must <= input buffer size
82 * If the always_in_place flag is set, non-writable buffers will be copied and
83 * passed to the transform_ip function, otherwise a new buffer will be created
84 * and the transform function called.
87 * Incoming writable buffers will be passed to the transform_ip function immediately.
90 * only implementing transform_ip and not transform implies always_in_place =
95 * <title>Example elements</title>
96 * <listitem>Volume</listitem>
97 * <listitem>Audioconvert in certain modes (signed/unsigned conversion)</listitem>
98 * <listitem>ffmpegcolorspace in certain modes (endianness swapping)</listitem>
102 * <itemizedlist><title>Modifications only to the caps/metadata of a buffer</title>
104 * The element does not require writable data, but non-writable buffers should
105 * be subbuffered so that the meta-information can be replaced.
108 * Elements wishing to operate in this mode should replace the
109 * prepare_output_buffer method to create subbuffers of the input buffer and
110 * set always_in_place to TRUE
114 * <title>Example elements</title>
115 * <listitem>Capsfilter when setting caps on outgoing buffers that have none.</listitem>
116 * <listitem>identity when it is going to re-timestamp buffers by datarate.</listitem>
120 * <itemizedlist><title>Normal mode</title>
122 * always_in_place flag is not set, or there is no transform_ip function
125 * Element will receive an input buffer and output buffer to operate on.
128 * Output buffer is allocated by calling the prepare_output_buffer function.
132 * <title>Example elements</title>
133 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing scaling/conversions</listitem>
137 * <itemizedlist><title>Special output buffer allocations</title>
139 * Elements which need to do special allocation of their output buffers other
140 * than what gst_buffer_pad_alloc allows should implement a
141 * prepare_output_buffer method, which calls the parent implementation and
142 * passes the newly allocated buffer.
146 * <title>Example elements</title>
147 * <listitem>efence</listitem>
152 * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
154 * <itemizedlist><title>passthrough</title>
156 * Implies that in the current configuration, the sub-class is not
157 * interested in modifying the buffers.
160 * Elements which are always in passthrough mode whenever the same caps has
161 * been negotiated on both pads can set the class variable
162 * passthrough_on_same_caps to have this behaviour automatically.
167 * <itemizedlist><title>always_in_place</title>
169 * Determines whether a non-writable buffer will be copied before passing
170 * to the transform_ip function.
173 * Implied TRUE if no transform function is implemented.
176 * Implied FALSE if ONLY transform function is implemented.
191 #include "../gst-i18n-lib.h"
192 #include "gstbasetransform.h"
193 #include <gst/gstmarshal.h>
195 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
196 #define GST_CAT_DEFAULT gst_base_transform_debug
198 /* BaseTransform signals and args */
210 static GstElementClass *parent_class = NULL;
212 static void gst_base_transform_base_init (gpointer g_class);
213 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
214 static void gst_base_transform_init (GstBaseTransform * trans,
215 GstBaseTransformClass * klass);
216 static GstFlowReturn gst_base_transform_prepare_output_buf (GstBaseTransform *
217 trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
220 gst_base_transform_get_type (void)
222 static GType base_transform_type = 0;
224 if (!base_transform_type) {
225 static const GTypeInfo base_transform_info = {
226 sizeof (GstBaseTransformClass),
227 (GBaseInitFunc) gst_base_transform_base_init,
229 (GClassInitFunc) gst_base_transform_class_init,
232 sizeof (GstBaseTransform),
234 (GInstanceInitFunc) gst_base_transform_init,
237 base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
238 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
240 return base_transform_type;
243 static void gst_base_transform_finalize (GObject * object);
244 static void gst_base_transform_set_property (GObject * object, guint prop_id,
245 const GValue * value, GParamSpec * pspec);
246 static void gst_base_transform_get_property (GObject * object, guint prop_id,
247 GValue * value, GParamSpec * pspec);
248 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
250 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
252 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
253 GstCaps * caps, guint * size);
255 static GstStateChangeReturn gst_base_transform_change_state (GstElement *
256 element, GstStateChange transition);
258 static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event);
259 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
260 guint length, GstBuffer ** buffer);
261 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
263 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
264 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
265 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
266 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
268 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
271 gst_base_transform_base_init (gpointer g_class)
273 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
274 "basetransform element");
278 gst_base_transform_finalize (GObject * object)
280 GstBaseTransform *trans;
282 trans = GST_BASE_TRANSFORM (object);
284 g_mutex_free (trans->transform_lock);
286 G_OBJECT_CLASS (parent_class)->finalize (object);
290 gst_base_transform_class_init (GstBaseTransformClass * klass)
292 GObjectClass *gobject_class;
293 GstElementClass *gstelement_class;
295 gobject_class = G_OBJECT_CLASS (klass);
296 gstelement_class = GST_ELEMENT_CLASS (klass);
298 parent_class = g_type_class_peek_parent (klass);
300 gobject_class->set_property =
301 GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
302 gobject_class->get_property =
303 GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
305 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
307 gstelement_class->change_state =
308 GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
310 klass->passthrough_on_same_caps = FALSE;
314 gst_base_transform_init (GstBaseTransform * trans,
315 GstBaseTransformClass * bclass)
317 GstPadTemplate *pad_template;
319 GST_DEBUG ("gst_base_transform_init");
322 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
323 g_return_if_fail (pad_template != NULL);
324 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
325 gst_pad_set_getcaps_function (trans->sinkpad,
326 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
327 gst_pad_set_setcaps_function (trans->sinkpad,
328 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
329 gst_pad_set_event_function (trans->sinkpad,
330 GST_DEBUG_FUNCPTR (gst_base_transform_event));
331 gst_pad_set_chain_function (trans->sinkpad,
332 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
333 gst_pad_set_activatepush_function (trans->sinkpad,
334 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
335 gst_pad_set_bufferalloc_function (trans->sinkpad,
336 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
337 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
340 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
341 g_return_if_fail (pad_template != NULL);
342 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
343 gst_pad_set_getcaps_function (trans->srcpad,
344 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
345 gst_pad_set_setcaps_function (trans->srcpad,
346 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
347 gst_pad_set_getrange_function (trans->srcpad,
348 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
349 gst_pad_set_activatepull_function (trans->srcpad,
350 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
351 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
353 trans->transform_lock = g_mutex_new ();
354 trans->delay_configure = FALSE;
355 trans->pending_configure = FALSE;
356 trans->cache_caps1 = NULL;
357 trans->cache_caps2 = NULL;
359 trans->passthrough = FALSE;
360 if (bclass->transform == NULL) {
361 /* If no transform function, always_in_place is TRUE */
362 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
363 trans->always_in_place = TRUE;
365 if (bclass->transform_ip == NULL)
366 trans->passthrough = TRUE;
371 gst_base_transform_transform_caps (GstBaseTransform * trans,
372 GstPadDirection direction, GstCaps * caps)
375 GstBaseTransformClass *klass;
377 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
379 /* if there is a custom transform function, use this */
380 if (klass->transform_caps) {
384 ret = gst_caps_new_empty ();
386 if (gst_caps_is_any (caps)) {
387 /* for any caps we still have to call the transform function */
388 GST_DEBUG_OBJECT (trans, "from ANY:");
389 temp = klass->transform_caps (trans, direction, caps);
390 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
392 gst_caps_append (ret, temp);
394 /* we send caps with just one structure to the transform
395 * function as this is easier for the element */
396 for (i = 0; i < gst_caps_get_size (caps); i++) {
399 nth = gst_caps_copy_nth (caps, i);
400 GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
401 temp = klass->transform_caps (trans, direction, nth);
402 gst_caps_unref (nth);
403 GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
405 gst_caps_append (ret, temp);
409 /* else use the identity transform */
410 ret = gst_caps_ref (caps);
413 GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
419 gst_base_transform_transform_size (GstBaseTransform * trans,
420 GstPadDirection direction, GstCaps * caps,
421 guint size, GstCaps * othercaps, guint * othersize)
423 guint inunitsize, outunitsize, units;
424 GstBaseTransformClass *klass;
427 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
429 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
430 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
431 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
433 /* if there is a custom transform function, use this */
434 if (klass->transform_size) {
435 ret = klass->transform_size (trans, direction, caps, size, othercaps,
438 gboolean got_in_unit_size, got_out_unit_size;
440 got_in_unit_size = gst_base_transform_get_unit_size (trans, caps,
442 g_return_val_if_fail (got_in_unit_size == TRUE, FALSE);
443 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
445 g_return_val_if_fail (inunitsize != 0, FALSE);
446 if (size % inunitsize != 0) {
447 g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
451 units = size / inunitsize;
452 got_out_unit_size = gst_base_transform_get_unit_size (trans, othercaps,
454 g_return_val_if_fail (got_out_unit_size == TRUE, FALSE);
456 *othersize = units * outunitsize;
457 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
464 gst_base_transform_getcaps (GstPad * pad)
466 GstBaseTransform *trans;
470 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
472 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
474 /* we can do what the peer can */
475 caps = gst_pad_peer_get_caps (otherpad);
478 const GstCaps *templ;
480 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
482 /* filtered against our padtemplate */
483 templ = gst_pad_get_pad_template_caps (otherpad);
484 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
485 temp = gst_caps_intersect (caps, templ);
486 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
487 gst_caps_unref (caps);
488 /* then see what we can tranform this to */
489 caps = gst_base_transform_transform_caps (trans,
490 GST_PAD_DIRECTION (otherpad), temp);
491 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
492 gst_caps_unref (temp);
496 /* and filter against the template again */
497 templ = gst_pad_get_pad_template_caps (pad);
498 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
499 temp = gst_caps_intersect (caps, templ);
500 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
501 gst_caps_unref (caps);
502 /* this is what we can do */
505 /* no peer, our padtemplate is enough then */
506 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
510 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
512 gst_object_unref (trans);
518 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
522 GstBaseTransformClass *klass;
524 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
526 /* clear the cache */
527 gst_caps_replace (&trans->cache_caps1, NULL);
528 gst_caps_replace (&trans->cache_caps2, NULL);
530 /* If we've a transform_ip method and same input/output caps, set in_place
531 * by default. If for some reason the sub-class prefers using a transform
532 * function, it can clear the in place flag in the set_caps */
533 gst_base_transform_set_in_place (trans,
534 klass->transform_ip && trans->have_same_caps);
536 /* Set the passthrough if the class wants passthrough_on_same_caps
537 * and we have the same caps on each pad */
538 if (klass->passthrough_on_same_caps)
539 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
541 /* now configure the element with the caps */
542 if (klass->set_caps) {
543 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
544 ret = klass->set_caps (trans, in, out);
547 trans->negotiated = ret;
553 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
555 GstBaseTransform *trans;
556 GstBaseTransformClass *klass;
557 GstPad *otherpad, *otherpeer;
558 GstCaps *othercaps = NULL;
560 gboolean peer_checked = FALSE;
562 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
563 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
565 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
566 otherpeer = gst_pad_get_peer (otherpad);
568 /* if we get called recursively, we bail out now to avoid an
570 if (GST_PAD_IS_IN_SETCAPS (otherpad))
573 /* caps must be fixed here */
574 if (!gst_caps_is_fixed (caps))
577 /* see how we can transform the input caps. */
578 othercaps = gst_base_transform_transform_caps (trans,
579 GST_PAD_DIRECTION (pad), caps);
581 /* The caps we can actually output is the intersection of the transformed
582 * caps with the pad template for the pad */
585 const GstCaps *templ_caps;
587 templ_caps = gst_pad_get_pad_template_caps (otherpad);
588 intersect = gst_caps_intersect (othercaps, templ_caps);
590 gst_caps_unref (othercaps);
591 othercaps = intersect;
594 /* check if transform is empty */
595 if (!othercaps || gst_caps_is_empty (othercaps))
598 /* if the othercaps are not fixed, we need to fixate them, first attempt
599 * is by attempting passthrough if the othercaps are a superset of caps. */
600 if (!gst_caps_is_fixed (othercaps)) {
603 GST_DEBUG_OBJECT (trans,
604 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
606 /* see if the target caps are a superset of the source caps, in this
607 * case we can try to perform passthrough */
608 temp = gst_caps_intersect (othercaps, caps);
609 GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
611 if (!gst_caps_is_empty (temp) && otherpeer) {
612 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
613 /* try passthrough. we know it's fixed, because caps is fixed */
614 if (gst_pad_accept_caps (otherpeer, caps)) {
615 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
616 /* peer accepted unmodified caps, we free the original non-fixed
617 * caps and work with the passthrough caps */
618 gst_caps_unref (othercaps);
619 othercaps = gst_caps_ref (caps);
620 /* mark that we checked othercaps with the peer, this
621 * makes sure we don't call accept_caps again with these same
625 GST_DEBUG_OBJECT (trans,
626 "peer did not accept %" GST_PTR_FORMAT, caps);
629 gst_caps_unref (temp);
633 /* second attempt at fixation is done by intersecting with
635 if (!gst_caps_is_fixed (othercaps) && otherpeer) {
636 /* intersect against what the peer can do */
640 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
642 peercaps = gst_pad_get_caps (otherpeer);
643 intersect = gst_caps_intersect (peercaps, othercaps);
644 gst_caps_unref (peercaps);
645 gst_caps_unref (othercaps);
646 othercaps = intersect;
647 peer_checked = FALSE;
649 GST_DEBUG_OBJECT (trans,
650 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
653 if (gst_caps_is_empty (othercaps))
654 goto no_transform_possible;
656 /* third attempt at fixation, call the fixate vmethod and
657 * ultimately call the pad fixate function. */
658 if (!gst_caps_is_fixed (othercaps)) {
661 GST_DEBUG_OBJECT (trans,
662 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
663 othercaps, GST_DEBUG_PAD_NAME (otherpad));
665 /* since we have no other way to fixate left, we might as well just take
666 * the first of the caps list and fixate that */
668 /* FIXME: when fixating using the vmethod, it might make sense to fixate
669 * each of the caps; but Wim doesn't see a use case for that yet */
670 temp = gst_caps_copy_nth (othercaps, 0);
671 gst_caps_unref (othercaps);
673 peer_checked = FALSE;
675 if (klass->fixate_caps) {
676 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
677 " using caps %" GST_PTR_FORMAT
678 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
679 GST_DEBUG_PAD_NAME (otherpad));
680 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
682 /* if still not fixed, no other option but to let the default pad fixate
683 * function do its job */
684 if (!gst_caps_is_fixed (othercaps)) {
685 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
686 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
687 GST_DEBUG_PAD_NAME (otherpad));
688 gst_pad_fixate_caps (otherpad, othercaps);
690 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
693 /* caps should be fixed now, if not we have to fail. */
694 if (!gst_caps_is_fixed (othercaps))
695 goto could_not_fixate;
697 /* and peer should accept, don't check again if we already checked the
698 * othercaps against the peer. */
699 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
702 GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
704 trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
705 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
707 /* see if we have to configure the element now */
708 if (!trans->delay_configure) {
709 GstCaps *incaps, *outcaps;
711 /* make sure in and out caps are correct */
712 if (pad == trans->sinkpad) {
719 /* call configure now */
720 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
721 goto failed_configure;
723 /* set pending configure, the configure will happen later with the
724 * caps we set on the pads above. */
725 trans->pending_configure = TRUE;
728 /* we know this will work, we implement the setcaps */
729 gst_pad_set_caps (otherpad, othercaps);
733 gst_object_unref (otherpeer);
735 gst_caps_unref (othercaps);
737 trans->negotiated = ret;
739 gst_object_unref (trans);
746 GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps);
752 GST_DEBUG_OBJECT (trans,
753 "transform returned useless %" GST_PTR_FORMAT, othercaps);
757 no_transform_possible:
759 GST_DEBUG_OBJECT (trans,
760 "transform could not transform %" GST_PTR_FORMAT
761 " in anything we support", caps);
767 GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
773 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
774 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
780 GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
781 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
787 /* Allocate a buffer using gst_pad_alloc_buffer.
789 * This function can trigger a renegotiation on the source pad when the
790 * peer alloc_buffer function sets new caps. Since we currently are
791 * processing a buffer on the sinkpad when this function is called, we cannot
792 * reconfigure the transform with sinkcaps different from those of the current
793 * buffer. FIXME, we currently don't check if the pluging can transform to the
794 * new srcpad caps using the same sinkcaps, we alloc a proper outbuf buffer
798 gst_base_transform_prepare_output_buf (GstBaseTransform * trans,
799 GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
801 GstBaseTransformClass *bclass;
802 GstFlowReturn ret = GST_FLOW_OK;
803 gboolean copy_inbuf = FALSE;
805 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
807 /* we cannot reconfigure the element yet as we are still processing
808 * the old buffer. We will therefore delay the reconfiguration of the
809 * element until we have processed this last buffer. */
810 trans->delay_configure = TRUE;
811 /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS
812 macro. If a set_caps occurs during this function this caps will become
813 invalid. We want to keep them during preparation of the output buffer. */
815 gst_caps_ref (out_caps);
817 /* see if the subclass wants to alloc a buffer */
818 if (bclass->prepare_output_buffer) {
820 bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
822 if (ret != GST_FLOW_OK)
826 /* See if we want to prepare the buffer for in place output */
827 if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
828 && bclass->transform_ip) {
829 if (gst_buffer_is_writable (in_buf)) {
830 if (trans->have_same_caps) {
831 /* Input buffer is already writable and caps are the same, just ref and return it */
833 gst_buffer_ref (in_buf);
835 /* Writable buffer, but need to change caps => subbuffer */
836 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
837 gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
841 /* Make a writable buffer below and copy the data */
846 if (*out_buf == NULL) {
847 /* Sub-class didn't already provide a buffer for us. Make one */
848 ret = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET (in_buf),
849 out_size, out_caps, out_buf);
850 if (ret != GST_FLOW_OK || *out_buf == NULL)
853 /* allocated buffer could be of different caps than what we requested */
854 if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
855 /* FIXME, it is possible we can reconfigure the transform with new caps at this
856 * point but for now we just create a buffer ourselves */
857 *out_buf = gst_buffer_new_and_alloc (out_size);
858 gst_buffer_set_caps (*out_buf, out_caps);
862 /* If the output buffer metadata is modifiable, copy timestamps and
864 if (*out_buf != in_buf && GST_MINI_OBJECT_REFCOUNT_VALUE (*out_buf) == 1) {
866 if (copy_inbuf && gst_buffer_is_writable (*out_buf))
867 memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
869 gst_buffer_stamp (*out_buf, in_buf);
870 GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
871 (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
872 GST_BUFFER_FLAG_DELTA_UNIT);
877 gst_caps_unref (out_caps);
878 trans->delay_configure = FALSE;
884 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
887 gboolean res = FALSE;
888 GstBaseTransformClass *bclass;
890 /* see if we have the result cached */
891 if (trans->cache_caps1 == caps) {
892 *size = trans->cache_caps1_size;
893 GST_DEBUG_OBJECT (trans, "get size returned cached 1 %d", *size);
896 if (trans->cache_caps2 == caps) {
897 *size = trans->cache_caps2_size;
898 GST_DEBUG_OBJECT (trans, "get size returned cached 2 %d", *size);
902 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
903 if (bclass->get_unit_size) {
904 res = bclass->get_unit_size (trans, caps, size);
905 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
906 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
909 if (trans->cache_caps1 == NULL) {
910 gst_caps_replace (&trans->cache_caps1, caps);
911 trans->cache_caps1_size = *size;
912 } else if (trans->cache_caps2 == NULL) {
913 gst_caps_replace (&trans->cache_caps2, caps);
914 trans->cache_caps2_size = *size;
918 GST_DEBUG ("Sub-class does not implement get_unit_size");
923 /* your upstream peer wants to send you a buffer
924 * that buffer has the given offset, size and caps
925 * you're requested to allocate a buffer
928 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
929 GstCaps * caps, GstBuffer ** buf)
931 GstBaseTransform *trans;
935 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
937 /* we cannot run this when we are transforming data and as such doing
938 * another negotiation in the transform method. */
939 g_mutex_lock (trans->transform_lock);
943 GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size, offset);
944 if (offset == GST_BUFFER_OFFSET_NONE)
945 GST_DEBUG_OBJECT (trans, "... and offset NONE");
947 GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
949 /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
950 * a renegotiation and change that to FALSE */
951 if (trans->have_same_caps) {
952 /* request a buffer with the same caps */
953 GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
955 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
957 /* if we are configured, request a buffer with the src caps */
958 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
963 GST_DEBUG_OBJECT (trans, "calling transform_size");
964 if (!gst_base_transform_transform_size (trans,
965 GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
966 gst_caps_unref (srccaps);
970 res = gst_pad_alloc_buffer (trans->srcpad, offset, new_size, srccaps, buf);
971 gst_caps_unref (srccaps);
974 if (res == GST_FLOW_OK && !trans->have_same_caps) {
975 /* note that we might have had same caps before, but calling the
976 alloc_buffer caused setcaps to switch us out of in_place -- in any case
977 the alloc_buffer served to transmit caps information but we can't use the
978 buffer. fall through and allocate a buffer corresponding to our sink
980 GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
981 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
986 if (!gst_base_transform_transform_size (trans,
987 GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
988 sinkcaps, &new_size)) {
989 gst_caps_unref (srccaps);
990 gst_caps_unref (sinkcaps);
994 gst_buffer_unref (*buf);
996 *buf = gst_buffer_new_and_alloc (new_size);
997 gst_buffer_set_caps (*buf, sinkcaps);
998 GST_BUFFER_OFFSET (*buf) = offset;
1001 gst_caps_unref (srccaps);
1002 gst_caps_unref (sinkcaps);
1004 g_mutex_unlock (trans->transform_lock);
1006 gst_object_unref (trans);
1012 /* let the default allocator handle it */
1013 GST_DEBUG_OBJECT (trans, "not configured");
1015 gst_buffer_unref (*buf);
1018 g_mutex_unlock (trans->transform_lock);
1019 gst_object_unref (trans);
1024 /* let the default allocator handle it */
1025 GST_DEBUG_OBJECT (trans, "unknown size");
1027 gst_buffer_unref (*buf);
1030 g_mutex_unlock (trans->transform_lock);
1031 gst_object_unref (trans);
1037 gst_base_transform_event (GstPad * pad, GstEvent * event)
1039 GstBaseTransform *trans;
1040 GstBaseTransformClass *bclass;
1041 gboolean ret = FALSE;
1044 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1045 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1048 bclass->event (trans, event);
1052 switch (GST_EVENT_TYPE (event)) {
1053 case GST_EVENT_FLUSH_START:
1055 case GST_EVENT_FLUSH_STOP:
1056 GST_STREAM_LOCK (pad);
1058 /* we need new segment info after the flush. */
1059 trans->segment_rate = 1.0;
1060 trans->segment_start = -1;
1061 trans->segment_stop = -1;
1062 trans->segment_base = -1;
1063 GST_DEBUG_OBJECT (trans, "reset accum %" GST_TIME_FORMAT,
1064 GST_TIME_ARGS (trans->segment_accum));
1065 trans->segment_accum = 0;
1068 GST_STREAM_LOCK (pad);
1072 GST_STREAM_LOCK (pad);
1075 case GST_EVENT_NEWSEGMENT:
1079 gint64 start, stop, time, duration;
1082 GST_STREAM_LOCK (pad);
1084 gst_event_parse_newsegment (event, &update, &rate, &format, &start, &stop,
1087 /* any other format with 0 also gives time 0, the other values are
1088 * invalid as time though. */
1089 if (format != GST_FORMAT_TIME) {
1090 GST_DEBUG_OBJECT (trans,
1091 "non-time newsegment with start 0, coaxing into FORMAT_TIME");
1092 format = GST_FORMAT_TIME;
1101 /* check if we really have a new segment or the previous one is
1104 /* the new segment has to be aligned with the old segment.
1105 * We first update the accumulated time of the previous
1106 * segment. the accumulated time is used when syncing to the
1107 * clock. A flush event sets the accumulated time back to 0
1109 if (GST_CLOCK_TIME_IS_VALID (trans->segment_stop)) {
1110 duration = trans->segment_stop - trans->segment_start;
1115 if (GST_CLOCK_TIME_IS_VALID (start))
1116 duration = start - trans->segment_start;
1121 trans->have_newsegment = TRUE;
1123 trans->segment_accum += gst_gdouble_to_guint64 (
1124 (gst_guint64_to_gdouble (duration) / ABS (trans->segment_rate)));;
1125 trans->segment_rate = rate;
1126 trans->segment_start = start;
1127 trans->segment_stop = stop;
1128 trans->segment_base = time;
1130 if (format == GST_FORMAT_TIME) {
1131 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT
1132 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1133 ", accum %" GST_TIME_FORMAT,
1134 GST_TIME_ARGS (trans->segment_start),
1135 GST_TIME_ARGS (trans->segment_stop),
1136 GST_TIME_ARGS (trans->segment_base),
1137 GST_TIME_ARGS (trans->segment_accum));
1139 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1140 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1141 ", accum %" G_GINT64_FORMAT,
1142 trans->segment_start, trans->segment_stop,
1143 trans->segment_base, trans->segment_accum);
1150 ret = gst_pad_event_default (pad, event);
1152 GST_STREAM_UNLOCK (pad);
1154 gst_object_unref (trans);
1159 static GstFlowReturn
1160 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1161 GstBuffer ** outbuf)
1163 GstBaseTransformClass *bclass;
1164 GstFlowReturn ret = GST_FLOW_OK;
1166 gboolean want_in_place;
1168 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1170 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1171 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1172 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1173 GST_BUFFER_OFFSET (inbuf));
1175 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1176 inbuf, GST_BUFFER_SIZE (inbuf));
1178 /* Don't allow buffer handling before negotiation, except in passthrough mode
1179 * or if the class doesn't implement a set_caps function (in which case it doesn't
1182 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1183 goto not_negotiated;
1185 if (trans->passthrough) {
1186 /* In passthrough mode, give transform_ip a look at the
1187 * buffer, without making it writable, or just push the
1189 GST_LOG_OBJECT (trans, "element is in passthrough mode");
1191 if (bclass->transform_ip)
1192 ret = bclass->transform_ip (trans, inbuf);
1199 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1202 if (want_in_place) {
1203 /* If want_in_place is TRUE, we may need to prepare a new output buffer
1204 * Sub-classes can implement a prepare_output_buffer function as they
1206 GST_LOG_OBJECT (trans, "doing inplace transform");
1208 ret = gst_base_transform_prepare_output_buf (trans, inbuf,
1209 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
1210 if (G_UNLIKELY (ret != GST_FLOW_OK))
1213 ret = bclass->transform_ip (trans, *outbuf);
1216 GST_LOG_OBJECT (trans, "doing non-inplace transform");
1218 /* not transforming inplace, figure out the output size */
1219 if (trans->always_in_place) {
1220 out_size = GST_BUFFER_SIZE (inbuf);
1222 if (!gst_base_transform_transform_size (trans,
1223 GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
1224 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
1226 /* we have an error */
1231 /* no in place transform, get buffer, this might renegotiate. */
1232 ret = gst_base_transform_prepare_output_buf (trans, inbuf, out_size,
1233 GST_PAD_CAPS (trans->srcpad), outbuf);
1234 if (ret != GST_FLOW_OK)
1237 if (bclass->transform)
1238 ret = bclass->transform (trans, inbuf, *outbuf);
1240 ret = GST_FLOW_NOT_SUPPORTED;
1243 /* if we got renegotiated we can configure now */
1244 if (trans->pending_configure) {
1248 gst_base_transform_configure_caps (trans,
1249 GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
1251 trans->pending_configure = FALSE;
1254 goto configure_failed;
1256 gst_buffer_unref (inbuf);
1263 gst_buffer_unref (inbuf);
1264 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1265 ("not negotiated"), ("not negotiated"));
1266 return GST_FLOW_NOT_NEGOTIATED;
1270 gst_buffer_unref (inbuf);
1271 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1272 ("subclass did not specify output size"),
1273 ("subclass did not specify output size"));
1274 return GST_FLOW_ERROR;
1278 gst_buffer_unref (inbuf);
1279 GST_DEBUG_OBJECT (trans, "could not get buffer from pool");
1284 gst_buffer_unref (inbuf);
1285 GST_DEBUG_OBJECT (trans, "could not negotiate");
1286 return GST_FLOW_NOT_NEGOTIATED;
1290 /* FIXME, getrange is broken, need to pull range from the other
1291 * end based on the transform_size result.
1293 static GstFlowReturn
1294 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1295 guint length, GstBuffer ** buffer)
1297 GstBaseTransform *trans;
1301 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1303 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1304 if (ret == GST_FLOW_OK) {
1305 g_mutex_lock (trans->transform_lock);
1306 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1307 g_mutex_unlock (trans->transform_lock);
1310 gst_object_unref (trans);
1315 static GstFlowReturn
1316 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1318 GstBaseTransform *trans;
1320 GstBuffer *outbuf = NULL;
1322 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1324 /* protect transform method and concurrent buffer alloc */
1325 g_mutex_lock (trans->transform_lock);
1326 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1327 g_mutex_unlock (trans->transform_lock);
1329 if (ret == GST_FLOW_OK) {
1330 ret = gst_pad_push (trans->srcpad, outbuf);
1331 } else if (outbuf != NULL)
1332 gst_buffer_unref (outbuf);
1334 gst_object_unref (trans);
1340 gst_base_transform_set_property (GObject * object, guint prop_id,
1341 const GValue * value, GParamSpec * pspec)
1343 GstBaseTransform *trans;
1345 trans = GST_BASE_TRANSFORM (object);
1349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1355 gst_base_transform_get_property (GObject * object, guint prop_id,
1356 GValue * value, GParamSpec * pspec)
1358 GstBaseTransform *trans;
1360 trans = GST_BASE_TRANSFORM (object);
1364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1370 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1372 gboolean result = TRUE;
1373 GstBaseTransform *trans;
1374 GstBaseTransformClass *bclass;
1376 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1377 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1381 result = bclass->start (trans);
1383 gst_object_unref (trans);
1389 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1391 gboolean result = FALSE;
1392 GstBaseTransform *trans;
1393 GstBaseTransformClass *bclass;
1395 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1396 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1398 result = gst_pad_activate_pull (trans->sinkpad, active);
1401 if (result && bclass->start)
1402 result &= bclass->start (trans);
1404 gst_object_unref (trans);
1409 static GstStateChangeReturn
1410 gst_base_transform_change_state (GstElement * element,
1411 GstStateChange transition)
1413 GstBaseTransform *trans;
1414 GstBaseTransformClass *bclass;
1415 GstStateChangeReturn result;
1417 trans = GST_BASE_TRANSFORM (element);
1418 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1421 switch (transition) {
1422 case GST_STATE_CHANGE_NULL_TO_READY:
1424 case GST_STATE_CHANGE_READY_TO_PAUSED:
1426 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1427 trans->have_same_caps =
1428 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1429 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1431 trans->have_same_caps = trans->passthrough;
1432 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1433 trans->negotiated = FALSE;
1434 trans->have_newsegment = FALSE;
1435 trans->segment_rate = 1.0;
1436 trans->segment_start = 0;
1437 trans->segment_stop = -1;
1438 trans->segment_base = 0;
1439 trans->segment_accum = 0;
1442 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1444 case GST_STATE_CHANGE_PAUSED_TO_READY:
1445 gst_caps_replace (&trans->cache_caps1, NULL);
1446 gst_caps_replace (&trans->cache_caps2, NULL);
1451 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1453 switch (transition) {
1454 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1456 case GST_STATE_CHANGE_PAUSED_TO_READY:
1458 result = bclass->stop (trans);
1460 case GST_STATE_CHANGE_READY_TO_NULL:
1470 * gst_base_transform_set_passthrough:
1471 * @trans: the #GstBaseTransform to set
1472 * @passthrough: boolean indicating passthrough mode.
1474 * Set passthrough mode for this filter by default. This is mostly
1475 * useful for filters that do not care about negotiation.
1477 * Always TRUE for filters which don't implement either a transform
1478 * or transform_ip method.
1483 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1484 gboolean passthrough)
1486 GstBaseTransformClass *bclass;
1488 g_return_if_fail (trans != NULL);
1490 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1493 if (passthrough == FALSE) {
1494 if (bclass->transform_ip || bclass->transform)
1495 trans->passthrough = FALSE;
1497 trans->passthrough = TRUE;
1500 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
1505 * gst_base_transform_is_passthrough:
1506 * @trans: the #GstBaseTransform to query
1508 * See if @trans is configured as a passthrough transform.
1510 * Returns: TRUE is the transform is configured in passthrough mode.
1515 gst_base_transform_is_passthrough (GstBaseTransform * trans)
1519 g_return_val_if_fail (trans != NULL, FALSE);
1522 result = trans->passthrough;
1529 * gst_base_transform_set_in_place:
1530 * @trans: the #GstBaseTransform to modify
1531 * @in_place: Boolean value indicating that we would like to operate
1532 * on in_place buffers.
1534 * Determines whether a non-writable buffer will be copied before passing
1535 * to the transform_ip function.
1537 * <listitem>Always TRUE if no transform function is implemented.</listitem>
1538 * <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
1544 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
1546 GstBaseTransformClass *bclass;
1548 g_return_if_fail (trans != NULL);
1550 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1555 if (bclass->transform_ip) {
1556 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
1557 trans->always_in_place = TRUE;
1560 if (bclass->transform) {
1561 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
1562 trans->always_in_place = FALSE;
1570 * gst_base_transform_is_in_place:
1571 * @trans: the #GstBaseTransform to query
1573 * See if @trans is configured as a in_place transform.
1575 * Returns: TRUE is the transform is configured in in_place mode.
1580 gst_base_transform_is_in_place (GstBaseTransform * trans)
1584 g_return_val_if_fail (trans != NULL, FALSE);
1587 result = trans->always_in_place;