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 #include "../../../gst/gst_private.h"
209 #include "../../../gst/gst-i18n-lib.h"
210 #include "gstbasetransform.h"
211 #include <gst/gstmarshal.h>
213 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
214 #define GST_CAT_DEFAULT gst_base_transform_debug
216 /* BaseTransform signals and args */
223 #define DEFAULT_PROP_QOS FALSE
231 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \
232 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
234 struct _GstBaseTransformPrivate
236 /* QoS *//* with LOCK */
237 gboolean qos_enabled;
239 GstClockTime earliest_time;
240 /* previous buffer had a discont */
243 GstActivateMode pad_mode;
247 /* caps used for allocating buffers */
248 gboolean proxy_alloc;
251 /* upstream caps and size suggestions */
252 GstCaps *sink_suggest;
254 gboolean suggest_pending;
256 gboolean reconfigure;
259 static GstElementClass *parent_class = NULL;
261 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
262 static void gst_base_transform_init (GstBaseTransform * trans,
263 GstBaseTransformClass * klass);
264 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
265 * trans, GstBuffer * input, GstBuffer ** buf);
268 gst_base_transform_get_type (void)
270 static GType base_transform_type = 0;
272 if (!base_transform_type) {
273 static const GTypeInfo base_transform_info = {
274 sizeof (GstBaseTransformClass),
277 (GClassInitFunc) gst_base_transform_class_init,
280 sizeof (GstBaseTransform),
282 (GInstanceInitFunc) gst_base_transform_init,
285 base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
286 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
288 return base_transform_type;
291 static void gst_base_transform_finalize (GObject * object);
292 static void gst_base_transform_set_property (GObject * object, guint prop_id,
293 const GValue * value, GParamSpec * pspec);
294 static void gst_base_transform_get_property (GObject * object, guint prop_id,
295 GValue * value, GParamSpec * pspec);
296 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
298 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
300 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
302 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
303 GstCaps * caps, guint * size);
305 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
306 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
308 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
309 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
311 static gboolean gst_base_transform_check_get_range (GstPad * pad);
312 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
313 guint length, GstBuffer ** buffer);
314 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
316 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
317 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
318 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
319 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
320 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
322 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
325 gst_base_transform_finalize (GObject * object)
327 GstBaseTransform *trans;
329 trans = GST_BASE_TRANSFORM (object);
331 gst_caps_replace (&trans->priv->sink_suggest, NULL);
332 g_mutex_free (trans->transform_lock);
334 G_OBJECT_CLASS (parent_class)->finalize (object);
338 gst_base_transform_class_init (GstBaseTransformClass * klass)
340 GObjectClass *gobject_class;
342 gobject_class = G_OBJECT_CLASS (klass);
344 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
345 "basetransform element");
347 GST_DEBUG ("gst_base_transform_class_init");
349 g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
351 parent_class = g_type_class_peek_parent (klass);
353 gobject_class->set_property =
354 GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
355 gobject_class->get_property =
356 GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
358 g_object_class_install_property (gobject_class, PROP_QOS,
359 g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
360 DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
364 klass->passthrough_on_same_caps = FALSE;
365 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
366 klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
370 gst_base_transform_init (GstBaseTransform * trans,
371 GstBaseTransformClass * bclass)
373 GstPadTemplate *pad_template;
375 GST_DEBUG ("gst_base_transform_init");
377 trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
380 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
381 g_return_if_fail (pad_template != NULL);
382 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
383 gst_pad_set_getcaps_function (trans->sinkpad,
384 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
385 gst_pad_set_acceptcaps_function (trans->sinkpad,
386 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
387 gst_pad_set_setcaps_function (trans->sinkpad,
388 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
389 gst_pad_set_event_function (trans->sinkpad,
390 GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
391 gst_pad_set_chain_function (trans->sinkpad,
392 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
393 gst_pad_set_activatepush_function (trans->sinkpad,
394 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
395 gst_pad_set_bufferalloc_function (trans->sinkpad,
396 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
397 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
400 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
401 g_return_if_fail (pad_template != NULL);
402 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
403 gst_pad_set_getcaps_function (trans->srcpad,
404 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
405 gst_pad_set_acceptcaps_function (trans->srcpad,
406 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
407 gst_pad_set_event_function (trans->srcpad,
408 GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
409 gst_pad_set_checkgetrange_function (trans->srcpad,
410 GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
411 gst_pad_set_getrange_function (trans->srcpad,
412 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
413 gst_pad_set_activatepull_function (trans->srcpad,
414 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
415 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
417 trans->transform_lock = g_mutex_new ();
418 trans->pending_configure = FALSE;
419 trans->priv->qos_enabled = DEFAULT_PROP_QOS;
420 trans->cache_caps1 = NULL;
421 trans->cache_caps2 = NULL;
422 trans->priv->pad_mode = GST_ACTIVATE_NONE;
423 trans->priv->gap_aware = FALSE;
425 trans->passthrough = FALSE;
426 if (bclass->transform == NULL) {
427 /* If no transform function, always_in_place is TRUE */
428 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
429 trans->always_in_place = TRUE;
431 if (bclass->transform_ip == NULL) {
432 GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
433 trans->passthrough = TRUE;
438 /* given @caps on the src or sink pad (given by @direction)
439 * calculate the possible caps on the other pad.
441 * Returns new caps, unref after usage.
444 gst_base_transform_transform_caps (GstBaseTransform * trans,
445 GstPadDirection direction, GstCaps * caps)
448 GstBaseTransformClass *klass;
453 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
455 /* if there is a custom transform function, use this */
456 if (klass->transform_caps) {
460 /* start with empty caps */
461 ret = gst_caps_new_empty ();
462 GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
464 if (gst_caps_is_any (caps)) {
465 /* for any caps we still have to call the transform function */
466 GST_DEBUG_OBJECT (trans, "from: ANY");
467 temp = klass->transform_caps (trans, direction, caps);
468 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
470 temp = gst_caps_make_writable (temp);
471 gst_caps_append (ret, temp);
473 /* we send caps with just one structure to the transform
474 * function as this is easier for the element */
475 for (i = 0; i < gst_caps_get_size (caps); i++) {
478 nth = gst_caps_copy_nth (caps, i);
479 GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
480 temp = klass->transform_caps (trans, direction, nth);
481 gst_caps_unref (nth);
482 GST_LOG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
484 temp = gst_caps_make_writable (temp);
486 /* here we need to only append those structures, that are not yet
487 * in there, we use the merge function for this */
488 gst_caps_merge (ret, temp);
490 GST_LOG_OBJECT (trans, " merged[%d]: %" GST_PTR_FORMAT, i, ret);
492 GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
493 /* we can't do much simplification here because we don't really want to
494 * change the caps order */
497 GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
498 /* no transform function, use the identity transform */
499 ret = gst_caps_ref (caps);
502 GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
508 /* transform a buffer of @size with @caps on the pad with @direction to
509 * the size of a buffer with @othercaps and store the result in @othersize
511 * We have two ways of doing this:
512 * 1) use a custom transform size function, this is for complicated custom
513 * cases with no fixed unit_size.
514 * 2) use the unit_size functions where there is a relationship between the
515 * caps and the size of a buffer.
518 gst_base_transform_transform_size (GstBaseTransform * trans,
519 GstPadDirection direction, GstCaps * caps,
520 guint size, GstCaps * othercaps, guint * othersize)
522 guint inunitsize, outunitsize, units;
523 GstBaseTransformClass *klass;
526 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
528 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
529 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
530 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
532 if (klass->transform_size) {
533 /* if there is a custom transform function, use this */
534 ret = klass->transform_size (trans, direction, caps, size, othercaps,
537 /* there is no transform_size function, we have to use the unit_size
538 * functions. This method assumes there is a fixed unit_size associated with
539 * each caps. We provide the same amount of units on both sides. */
540 if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
543 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
546 /* input size must be a multiple of the unit_size of the input caps */
547 if (inunitsize == 0 || (size % inunitsize != 0))
550 /* get the amount of units */
551 units = size / inunitsize;
553 /* now get the unit size of the output */
554 if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
557 /* the output size is the unit_size times the amount of units on the
559 *othersize = units * outunitsize;
560 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
569 GST_DEBUG_OBJECT (trans, "could not get in_size");
570 g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
575 GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
577 g_warning ("%s: size %u is not a multiple of unit size %u",
578 GST_ELEMENT_NAME (trans), size, inunitsize);
583 GST_DEBUG_OBJECT (trans, "could not get out_size");
584 g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
589 /* get the caps that can be handled by @pad. We perforn:
591 * - take the caps of peer of otherpad,
592 * - filter against the padtemplate of otherpad,
593 * - calculate all transforms of remaining caps
594 * - filter against template of @pad
596 * If there is no peer, we simply return the caps of the padtemplate of pad.
599 gst_base_transform_getcaps (GstPad * pad)
601 GstBaseTransform *trans;
605 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
607 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
609 /* we can do what the peer can */
610 caps = gst_pad_peer_get_caps (otherpad);
613 const GstCaps *templ;
615 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
617 /* filtered against our padtemplate */
618 templ = gst_pad_get_pad_template_caps (otherpad);
619 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
620 temp = gst_caps_intersect (caps, templ);
621 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
622 gst_caps_unref (caps);
624 /* then see what we can transform this to */
625 caps = gst_base_transform_transform_caps (trans,
626 GST_PAD_DIRECTION (otherpad), temp);
627 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
628 gst_caps_unref (temp);
632 /* and filter against the template again */
633 templ = gst_pad_get_pad_template_caps (pad);
634 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
635 temp = gst_caps_intersect (caps, templ);
636 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
637 gst_caps_unref (caps);
638 /* this is what we can do */
641 /* no peer or the peer can do anything, our padtemplate is enough then */
642 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
646 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
648 gst_object_unref (trans);
653 /* function triggered when the in and out caps are negotiated and need
654 * to be configured in the subclass. */
656 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
660 GstBaseTransformClass *klass;
662 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
664 GST_DEBUG_OBJECT (trans, "in caps: %" GST_PTR_FORMAT, in);
665 GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
667 /* clear the cache */
668 gst_caps_replace (&trans->cache_caps1, NULL);
669 gst_caps_replace (&trans->cache_caps2, NULL);
671 /* figure out same caps state */
672 trans->have_same_caps = gst_caps_is_equal (in, out);
673 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
675 /* If we've a transform_ip method and same input/output caps, set in_place
676 * by default. If for some reason the sub-class prefers using a transform
677 * function, it can clear the in place flag in the set_caps */
678 gst_base_transform_set_in_place (trans,
679 klass->transform_ip && trans->have_same_caps);
681 /* Set the passthrough if the class wants passthrough_on_same_caps
682 * and we have the same caps on each pad */
683 if (klass->passthrough_on_same_caps)
684 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
686 /* now configure the element with the caps */
687 if (klass->set_caps) {
688 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
689 ret = klass->set_caps (trans, in, out);
692 trans->negotiated = ret;
697 /* check if caps @in on @pad can be transformed to @out on the other pad.
698 * We don't have a vmethod to test this yet so we have to do a somewhat less
699 * efficient check for this.
702 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
703 GstCaps * in, GstCaps * out)
707 /* convert the in caps to all possible out caps */
709 gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
711 /* check if transform is empty */
712 if (!othercaps || gst_caps_is_empty (othercaps))
715 /* check if the out caps is a subset of the othercaps */
716 if (!gst_caps_is_subset (out, othercaps))
720 gst_caps_unref (othercaps);
722 GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
723 GST_DEBUG_OBJECT (trans, "to %" GST_PTR_FORMAT, out);
730 GST_DEBUG_OBJECT (trans,
731 "transform returned useless %" GST_PTR_FORMAT, othercaps);
733 gst_caps_unref (othercaps);
738 GST_DEBUG_OBJECT (trans, "no subset");
740 gst_caps_unref (othercaps);
745 /* given a fixed @caps on @pad, create the best possible caps for the
747 * @caps must be fixed when calling this function.
749 * This function calls the transform caps vmethod of the basetransform to figure
750 * out the possible target formats. It then tries to select the best format from
753 * - attempt passthrough if the target caps is a superset of the input caps
754 * - fixating by using peer caps
755 * - fixating with transform fixate function
756 * - fixating with pad fixate functions.
758 * this function returns a caps that can be transformed into and is accepted by
762 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
765 GstBaseTransformClass *klass;
766 GstPad *otherpad, *otherpeer;
768 gboolean peer_checked = FALSE;
770 /* caps must be fixed here, this is a programming error if it's not */
771 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
773 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
775 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
776 otherpeer = gst_pad_get_peer (otherpad);
778 /* see how we can transform the input caps. We need to do this even for
779 * passthrough because it might be possible that this element cannot support
780 * passthrough at all. */
781 othercaps = gst_base_transform_transform_caps (trans,
782 GST_PAD_DIRECTION (pad), caps);
784 /* The caps we can actually output is the intersection of the transformed
785 * caps with the pad template for the pad */
788 const GstCaps *templ_caps;
790 templ_caps = gst_pad_get_pad_template_caps (otherpad);
791 GST_DEBUG_OBJECT (trans,
792 "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
794 intersect = gst_caps_intersect (othercaps, templ_caps);
796 gst_caps_unref (othercaps);
797 othercaps = intersect;
800 /* check if transform is empty */
801 if (!othercaps || gst_caps_is_empty (othercaps))
804 /* if the othercaps are not fixed, we need to fixate them, first attempt
805 * is by attempting passthrough if the othercaps are a superset of caps. */
806 /* FIXME. maybe the caps is not fixed because it has multiple structures of
808 if (!gst_caps_is_fixed (othercaps)) {
811 GST_DEBUG_OBJECT (trans,
812 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
814 /* see if the target caps are a superset of the source caps, in this
815 * case we can try to perform passthrough */
816 temp = gst_caps_intersect (othercaps, caps);
817 GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
819 if (!gst_caps_is_empty (temp)) {
820 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
822 /* try passthrough. we know it's fixed, because caps is fixed */
823 if (gst_pad_accept_caps (otherpeer, caps)) {
824 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
825 /* peer accepted unmodified caps, we free the original non-fixed
826 * caps and work with the passthrough caps */
827 gst_caps_unref (othercaps);
828 othercaps = gst_caps_ref (caps);
829 /* mark that we checked othercaps with the peer, this
830 * makes sure we don't call accept_caps again with these same
834 GST_DEBUG_OBJECT (trans,
835 "peer did not accept %" GST_PTR_FORMAT, caps);
838 GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
839 gst_caps_unref (othercaps);
840 othercaps = gst_caps_ref (caps);
843 gst_caps_unref (temp);
847 /* second attempt at fixation is done by intersecting with
849 if (!gst_caps_is_fixed (othercaps) && otherpeer) {
850 /* intersect against what the peer can do */
854 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
856 peercaps = gst_pad_get_caps (otherpeer);
857 intersect = gst_caps_intersect (peercaps, othercaps);
858 gst_caps_unref (peercaps);
859 gst_caps_unref (othercaps);
860 othercaps = intersect;
861 peer_checked = FALSE;
863 GST_DEBUG_OBJECT (trans,
864 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
867 if (gst_caps_is_empty (othercaps))
868 goto no_transform_possible;
870 /* third attempt at fixation, call the fixate vmethod and
871 * ultimately call the pad fixate function. */
872 if (!gst_caps_is_fixed (othercaps)) {
875 GST_DEBUG_OBJECT (trans,
876 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
877 othercaps, GST_DEBUG_PAD_NAME (otherpad));
879 /* since we have no other way to fixate left, we might as well just take
880 * the first of the caps list and fixate that */
882 /* FIXME: when fixating using the vmethod, it might make sense to fixate
883 * each of the caps; but Wim doesn't see a use case for that yet */
884 temp = gst_caps_copy_nth (othercaps, 0);
885 gst_caps_unref (othercaps);
887 peer_checked = FALSE;
889 if (klass->fixate_caps) {
890 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
891 " using caps %" GST_PTR_FORMAT
892 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
893 GST_DEBUG_PAD_NAME (otherpad));
894 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
896 /* if still not fixed, no other option but to let the default pad fixate
897 * function do its job */
898 if (!gst_caps_is_fixed (othercaps)) {
899 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
900 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
901 GST_DEBUG_PAD_NAME (otherpad));
902 gst_pad_fixate_caps (otherpad, othercaps);
904 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
906 /* else caps are fixed but the subclass may want to add fields */
907 if (klass->fixate_caps) {
908 othercaps = gst_caps_make_writable (othercaps);
910 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
911 " using caps %" GST_PTR_FORMAT
912 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
913 GST_DEBUG_PAD_NAME (otherpad));
915 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
919 /* caps should be fixed now, if not we have to fail. */
920 if (!gst_caps_is_fixed (othercaps))
921 goto could_not_fixate;
923 /* and peer should accept, don't check again if we already checked the
924 * othercaps against the peer. */
925 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
928 GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
929 ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
932 gst_object_unref (otherpeer);
939 GST_DEBUG_OBJECT (trans,
940 "transform returned useless %" GST_PTR_FORMAT, othercaps);
943 no_transform_possible:
945 GST_DEBUG_OBJECT (trans,
946 "transform could not transform %" GST_PTR_FORMAT
947 " in anything we support", caps);
952 GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
957 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
958 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
964 gst_object_unref (otherpeer);
966 gst_caps_unref (othercaps);
972 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
974 GstBaseTransform *trans;
976 GstCaps *othercaps = NULL;
979 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
980 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
983 /* we need fixed caps for the check, fall back to the default implementation
985 if (!gst_caps_is_fixed (caps))
988 GstCaps *allowed, *intersect;
990 GST_DEBUG_OBJECT (pad, "non fixed accept caps %" GST_PTR_FORMAT, caps);
992 /* get all the formats we can handle on this pad */
993 allowed = gst_pad_get_caps (pad);
995 goto no_transform_possible;
997 /* intersect with the requested format */
998 intersect = gst_caps_intersect (allowed, caps);
1000 GST_DEBUG_OBJECT (pad, "intersection %" GST_PTR_FORMAT, intersect);
1002 /* we can accept if the intersection is not empty */
1003 ret = !gst_caps_is_empty (intersect);
1004 gst_caps_unref (intersect);
1005 gst_caps_unref (allowed);
1008 goto no_transform_possible;
1012 GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1014 /* find best possible caps for the other pad as a way to see if we can
1015 * transform this caps. */
1016 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1017 if (!othercaps || gst_caps_is_empty (othercaps))
1018 goto no_transform_possible;
1020 GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1026 gst_caps_unref (othercaps);
1027 gst_object_unref (trans);
1032 no_transform_possible:
1034 GST_WARNING_OBJECT (trans,
1035 "transform could not transform %" GST_PTR_FORMAT
1036 " in anything we support", caps);
1042 /* called when new caps arrive on the sink or source pad,
1043 * We try to find the best caps for the other side using our _find_transform()
1044 * function. If there are caps, we configure the transform for this new
1047 * FIXME, this function is currently commutative but this should not really be
1048 * because we never set caps starting from the srcpad.
1051 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1053 GstBaseTransform *trans;
1054 GstBaseTransformClass *klass;
1055 GstPad *otherpad, *otherpeer;
1056 GstCaps *othercaps = NULL;
1057 gboolean ret = TRUE;
1058 GstCaps *incaps, *outcaps;
1060 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1061 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1063 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1064 otherpeer = gst_pad_get_peer (otherpad);
1066 /* if we get called recursively, we bail out now to avoid an
1068 if (GST_PAD_IS_IN_SETCAPS (otherpad))
1071 GST_DEBUG_OBJECT (pad, "have new caps %" GST_PTR_FORMAT, caps);
1073 /* find best possible caps for the other pad */
1074 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1075 if (!othercaps || gst_caps_is_empty (othercaps))
1076 goto no_transform_possible;
1078 /* configure the element now */
1079 /* make sure in and out caps are correct */
1080 if (pad == trans->sinkpad) {
1082 outcaps = othercaps;
1089 /* if we have the same caps, we can optimize and reuse the input caps */
1090 if (gst_caps_is_equal (incaps, outcaps)) {
1091 GST_INFO_OBJECT (trans, "reuse caps");
1092 gst_caps_unref (outcaps);
1093 outcaps = gst_caps_ref (incaps);
1097 /* call configure now */
1098 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1099 goto failed_configure;
1101 /* we know this will work, we implement the setcaps */
1102 gst_pad_set_caps (otherpad, othercaps);
1104 if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1106 ret &= gst_pad_set_caps (otherpeer, othercaps);
1108 GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1115 gst_object_unref (otherpeer);
1117 gst_caps_unref (othercaps);
1119 trans->negotiated = ret;
1121 gst_object_unref (trans);
1126 no_transform_possible:
1128 GST_WARNING_OBJECT (trans,
1129 "transform could not transform %" GST_PTR_FORMAT
1130 " in anything we support", caps);
1136 GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1137 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1143 /* Allocate a buffer using gst_pad_alloc_buffer
1145 * This function can do renegotiation on the source pad
1147 * The output buffer is always writable. outbuf can be equal to
1148 * inbuf, the caller should be prepared for this and perform
1149 * appropriate refcounting.
1151 static GstFlowReturn
1152 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1153 GstBuffer * in_buf, GstBuffer ** out_buf)
1155 GstBaseTransformClass *bclass;
1156 GstBaseTransformPrivate *priv;
1157 GstFlowReturn ret = GST_FLOW_OK;
1158 guint outsize, newsize, expsize;
1160 GstCaps *incaps, *oldcaps, *newcaps;
1162 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1168 /* figure out how to allocate a buffer based on the current configuration */
1169 if (trans->passthrough) {
1170 GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1171 /* passthrough, we don't really need to call pad alloc but we still need to
1172 * in order to get upstream negotiation. The output size is the same as the
1174 outsize = GST_BUFFER_SIZE (in_buf);
1175 /* we always alloc and discard here */
1178 gboolean want_in_place = (bclass->transform_ip != NULL)
1179 && trans->always_in_place;
1181 if (want_in_place) {
1182 GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1183 /* we alloc a buffer of the same size as the input */
1184 outsize = GST_BUFFER_SIZE (in_buf);
1185 /* only discard it when the input was not writable, otherwise, we reuse
1186 * the input buffer. */
1187 discard = gst_buffer_is_writable (in_buf);
1188 GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1190 GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1191 /* copy transform, figure out the output size */
1192 if (!gst_base_transform_transform_size (trans,
1193 GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1194 GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1198 /* never discard this buffer, we need it for storing the output */
1203 oldcaps = GST_PAD_CAPS (trans->srcpad);
1205 if (bclass->prepare_output_buffer) {
1206 GST_DEBUG_OBJECT (trans,
1207 "calling prepare buffer with caps %" GST_PTR_FORMAT, oldcaps);
1209 bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1212 /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1213 * update the pad caps if it wants */
1214 oldcaps = GST_PAD_CAPS (trans->srcpad);
1217 * decrease refcount again if vmethod returned refcounted in_buf. This
1218 * is because we need to make sure that the buffer is writable for the
1219 * in_place transform. The docs of the vmethod say that you should return
1220 * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1221 if (in_buf == *out_buf)
1222 gst_buffer_unref (in_buf);
1224 /* never discard the buffer from the prepare_buffer method */
1225 if (*out_buf != NULL)
1229 if (ret != GST_FLOW_OK)
1232 if (*out_buf == NULL) {
1233 GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT, oldcaps);
1235 ret = gst_pad_alloc_buffer (trans->srcpad,
1236 GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1237 if (ret != GST_FLOW_OK)
1241 /* must always have a buffer by now */
1242 if (*out_buf == NULL)
1245 /* check if we got different caps on this new output buffer */
1246 newcaps = GST_BUFFER_CAPS (*out_buf);
1247 newsize = GST_BUFFER_SIZE (*out_buf);
1248 if (!gst_caps_is_equal (newcaps, oldcaps)) {
1250 gboolean can_convert;
1252 GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1254 incaps = GST_PAD_CAPS (trans->sinkpad);
1256 /* it's possible that the buffer we got is of the wrong size, get the
1257 * expected size here, we will check the size if we are going to use the
1258 * buffer later on. */
1259 gst_base_transform_transform_size (trans,
1260 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1262 /* check if we can convert the current incaps to the new target caps */
1264 gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1268 GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1269 /* caps not empty, try to renegotiate to the new format */
1270 if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1271 /* not sure we need to fail hard here, we can simply continue our
1272 * conversion with what we negotiated before */
1273 goto failed_configure;
1275 /* new format configure, and use the new output buffer */
1276 gst_pad_set_caps (trans->srcpad, newcaps);
1278 /* if we got a buffer of the wrong size, discard it now and make sure we
1279 * allocate a propertly sized buffer later. */
1280 if (newsize != expsize) {
1281 if (in_buf != *out_buf)
1282 gst_buffer_unref (*out_buf);
1287 GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1289 /* we cannot convert the current buffer but we might be able to suggest a
1290 * new format upstream, try to find what the best format is. */
1292 gst_base_transform_find_transform (trans, trans->srcpad, newcaps);
1295 GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1296 /* we received caps that we cannot transform. Upstream is behaving badly
1297 * because it should have checked if we could handle these caps. We can
1298 * simply ignore these caps and produce a buffer with our original caps. */
1302 GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1304 /* not a subset, we have a new upstream suggestion, remember it and
1305 * allocate a default buffer. First we try to convert the size */
1306 if (gst_base_transform_transform_size (trans,
1307 GST_PAD_SRC, newcaps, expsize, othercaps, &size_suggest)) {
1309 /* ok, remember the suggestions now */
1310 GST_DEBUG_OBJECT (trans,
1311 "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1312 size_suggest, othercaps);
1314 GST_OBJECT_LOCK (trans->sinkpad);
1315 if (priv->sink_suggest)
1316 gst_caps_unref (priv->sink_suggest);
1317 priv->sink_suggest = gst_caps_ref (othercaps);
1318 priv->size_suggest = size_suggest;
1319 trans->priv->suggest_pending = TRUE;
1320 GST_OBJECT_UNLOCK (trans->sinkpad);
1322 gst_caps_unref (othercaps);
1324 if (in_buf != *out_buf)
1325 gst_buffer_unref (*out_buf);
1330 if (*out_buf == NULL) {
1332 GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1334 /* no valid buffer yet, make one */
1335 *out_buf = gst_buffer_new_and_alloc (outsize);
1336 gst_buffer_copy_metadata (*out_buf, in_buf,
1337 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1339 GST_DEBUG_OBJECT (trans, "reuse input buffer");
1343 if (trans->passthrough && in_buf != *out_buf) {
1344 /* we are asked to perform a passthrough transform but the input and
1345 * output buffers are different. We have to discard the output buffer and
1346 * reuse the input buffer. */
1347 GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1351 GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1352 gst_buffer_unref (*out_buf);
1355 GST_DEBUG_OBJECT (trans, "using allocated buffer");
1356 gst_buffer_copy_metadata (*out_buf, in_buf,
1357 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1360 gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (trans->srcpad));
1362 /* clear the GAP flag when the subclass does not understand it */
1363 if (!trans->priv->gap_aware)
1364 GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1371 GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1376 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1377 ("Sub-class failed to provide an output buffer"), (NULL));
1378 return GST_FLOW_ERROR;
1382 GST_ERROR_OBJECT (trans, "unknown output size");
1383 return GST_FLOW_ERROR;
1387 GST_WARNING_OBJECT (trans, "failed to configure caps");
1388 return GST_FLOW_NOT_NEGOTIATED;
1392 /* Given @caps calcultate the size of one unit.
1394 * For video caps, this is the size of one frame (and thus one buffer).
1395 * For audio caps, this is the size of one sample.
1397 * These values are cached since they do not change and the calculation
1398 * potentially involves parsing caps and other expensive stuff.
1400 * We have two cache locations to store the size, one for the source caps
1401 * and one for the sink caps.
1403 * this function returns FALSE if no size could be calculated.
1406 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1409 gboolean res = FALSE;
1410 GstBaseTransformClass *bclass;
1412 /* see if we have the result cached */
1413 if (trans->cache_caps1 == caps) {
1414 *size = trans->cache_caps1_size;
1415 GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1418 if (trans->cache_caps2 == caps) {
1419 *size = trans->cache_caps2_size;
1420 GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1424 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1425 if (bclass->get_unit_size) {
1426 res = bclass->get_unit_size (trans, caps, size);
1427 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1428 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1431 /* and cache the values */
1432 if (trans->cache_caps1 == NULL) {
1433 gst_caps_replace (&trans->cache_caps1, caps);
1434 trans->cache_caps1_size = *size;
1435 GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1436 } else if (trans->cache_caps2 == NULL) {
1437 gst_caps_replace (&trans->cache_caps2, caps);
1438 trans->cache_caps2_size = *size;
1439 GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1441 GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1445 GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1450 /* your upstream peer wants to send you a buffer
1451 * that buffer has the given offset, size and caps
1452 * you're requested to allocate a buffer
1454 static GstFlowReturn
1455 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1456 GstCaps * caps, GstBuffer ** buf)
1458 GstBaseTransform *trans;
1459 GstBaseTransformPrivate *priv;
1461 gboolean proxy, suggest, same_caps;
1462 GstCaps *sink_suggest;
1465 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1468 GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1471 /* if the code below does not come up with a better buffer, we will return _OK
1472 * and an empty buffer. This will trigger the core to allocate a buffer with
1473 * given input size and caps. */
1477 /* we remember our previous alloc request to quickly see if we can proxy or
1478 * not. We skip this check if we have a pending suggestion. */
1479 GST_OBJECT_LOCK (pad);
1480 same_caps = !priv->suggest_pending && caps &&
1481 gst_caps_is_equal (priv->sink_alloc, caps);
1482 GST_OBJECT_UNLOCK (pad);
1485 /* we have seen this before, see below if we need to proxy */
1486 GST_DEBUG_OBJECT (trans, "have old caps");
1487 sink_suggest = caps;
1488 size_suggest = size;
1492 const GstCaps *templ;
1495 GST_DEBUG_OBJECT (trans, "new format %" GST_PTR_FORMAT, caps);
1497 /* if we have a suggestion, pretend we got these as input */
1498 GST_OBJECT_LOCK (pad);
1499 if ((priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest))) {
1500 sink_suggest = gst_caps_ref (priv->sink_suggest);
1501 size_suggest = priv->size_suggest;
1502 GST_DEBUG_OBJECT (trans, "have suggestion %" GST_PTR_FORMAT,
1504 /* suggest is TRUE when we have a custom suggestion pending that we need
1505 * to unref later. */
1508 GST_DEBUG_OBJECT (trans, "using caps %" GST_PTR_FORMAT, caps);
1509 sink_suggest = caps;
1510 size_suggest = size;
1513 priv->suggest_pending = FALSE;
1514 GST_OBJECT_UNLOCK (pad);
1516 /* check if we actually handle this format on the sinkpad */
1518 templ = gst_pad_get_pad_template_caps (pad);
1519 temp = gst_caps_intersect (sink_suggest, templ);
1521 empty = gst_caps_is_empty (temp);
1522 gst_caps_unref (temp);
1528 /* find the best format for the other side here we decide if we will proxy
1529 * the caps or not. */
1530 if (sink_suggest == NULL) {
1531 /* always proxy when the caps are NULL. When this is a new format, see if
1532 * we can proxy it downstream */
1533 GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
1534 priv->proxy_alloc = TRUE;
1538 /* we have a new format, see what we need to proxy to */
1539 othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
1540 if (!othercaps || gst_caps_is_empty (othercaps)) {
1541 /* no transform possible, we certainly can't proxy */
1542 GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
1543 priv->proxy_alloc = FALSE;
1545 /* we transformed into something */
1546 if (gst_caps_is_equal (caps, othercaps)) {
1547 GST_DEBUG_OBJECT (trans,
1548 "best caps same as input, marking for proxy");
1549 priv->proxy_alloc = TRUE;
1551 GST_DEBUG_OBJECT (trans,
1552 "best caps different from input, disable proxy");
1553 priv->proxy_alloc = FALSE;
1557 gst_caps_unref (othercaps);
1560 /* remember the new caps */
1561 GST_OBJECT_LOCK (pad);
1562 gst_caps_replace (&priv->sink_alloc, sink_suggest);
1563 GST_OBJECT_UNLOCK (pad);
1565 proxy = priv->proxy_alloc;
1566 GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d", proxy);
1568 /* we only want to proxy if we have no suggestion pending, FIXME */
1569 if (proxy && !suggest) {
1572 GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %" GST_PTR_FORMAT
1573 ", size %u", caps, size);
1575 /* we always proxy the input caps, never the suggestion. The reason is that
1576 * We don't yet handle the caps of renegotiation in here. FIXME */
1577 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
1578 if (res != GST_FLOW_OK)
1581 /* check if the caps changed */
1582 newcaps = GST_BUFFER_CAPS (*buf);
1584 GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
1586 if (!gst_caps_is_equal (newcaps, caps)) {
1587 GST_DEBUG_OBJECT (trans, "caps are new");
1588 /* we have new caps, see if we can proxy downstream */
1589 if (gst_pad_peer_accept_caps (pad, newcaps)) {
1590 /* peer accepts the caps, return a buffer in this format */
1591 GST_DEBUG_OBJECT (trans, "peer accepted new caps");
1592 /* remember the format */
1593 GST_OBJECT_LOCK (pad);
1594 gst_caps_replace (&priv->sink_alloc, newcaps);
1595 GST_OBJECT_UNLOCK (pad);
1597 GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
1598 /* peer does not accept the caps, free the buffer we received and
1599 * create a buffer of the requested format by the default handler. */
1600 gst_buffer_unref (*buf);
1604 GST_DEBUG_OBJECT (trans, "received required caps from peer");
1609 /* there was a custom suggestion, create a buffer of this format and return
1610 * it. Note that this format */
1611 *buf = gst_buffer_new_and_alloc (size_suggest);
1612 GST_DEBUG_OBJECT (trans,
1613 "doing suggestion of size %u, caps %" GST_PTR_FORMAT, size_suggest,
1615 GST_BUFFER_CAPS (*buf) = sink_suggest;
1618 gst_object_unref (trans);
1625 GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
1627 gst_caps_unref (sink_suggest);
1628 gst_object_unref (trans);
1633 GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
1635 gst_caps_unref (sink_suggest);
1636 gst_object_unref (trans);
1637 return GST_FLOW_NOT_NEGOTIATED;
1642 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
1644 GstBaseTransform *trans;
1645 GstBaseTransformClass *bclass;
1646 gboolean ret = TRUE;
1647 gboolean forward = TRUE;
1649 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1650 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1653 forward = bclass->event (trans, event);
1655 /* FIXME, do this in the default event handler so the subclass can do
1656 * something different. */
1658 ret = gst_pad_push_event (trans->srcpad, event);
1660 gst_event_unref (event);
1662 gst_object_unref (trans);
1668 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1670 switch (GST_EVENT_TYPE (event)) {
1671 case GST_EVENT_FLUSH_START:
1673 case GST_EVENT_FLUSH_STOP:
1674 GST_OBJECT_LOCK (trans);
1675 /* reset QoS parameters */
1676 trans->priv->proportion = 1.0;
1677 trans->priv->earliest_time = -1;
1678 trans->priv->discont = FALSE;
1679 GST_OBJECT_UNLOCK (trans);
1680 /* we need new segment info after the flush. */
1681 trans->have_newsegment = FALSE;
1682 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1688 case GST_EVENT_NEWSEGMENT:
1691 gdouble rate, arate;
1692 gint64 start, stop, time;
1695 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1696 &start, &stop, &time);
1698 trans->have_newsegment = TRUE;
1700 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
1701 format, start, stop, time);
1703 if (format == GST_FORMAT_TIME) {
1704 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1705 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1706 ", accum %" GST_TIME_FORMAT,
1707 GST_TIME_ARGS (trans->segment.start),
1708 GST_TIME_ARGS (trans->segment.stop),
1709 GST_TIME_ARGS (trans->segment.time),
1710 GST_TIME_ARGS (trans->segment.accum));
1712 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1713 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1714 ", accum %" G_GINT64_FORMAT,
1715 trans->segment.start, trans->segment.stop,
1716 trans->segment.time, trans->segment.accum);
1728 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
1730 GstBaseTransform *trans;
1731 GstBaseTransformClass *bclass;
1732 gboolean ret = TRUE;
1734 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1735 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1737 if (bclass->src_event)
1738 ret = bclass->src_event (trans, event);
1740 gst_object_unref (trans);
1746 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1750 switch (GST_EVENT_TYPE (event)) {
1751 case GST_EVENT_SEEK:
1753 case GST_EVENT_NAVIGATION:
1758 GstClockTimeDiff diff;
1759 GstClockTime timestamp;
1761 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1762 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1769 ret = gst_pad_push_event (trans->sinkpad, event);
1774 /* perform a transform on @inbuf and put the result in @outbuf.
1776 * This function is common to the push and pull-based operations.
1778 * This function takes ownership of @inbuf */
1779 static GstFlowReturn
1780 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1781 GstBuffer ** outbuf)
1783 GstBaseTransformClass *bclass;
1784 GstFlowReturn ret = GST_FLOW_OK;
1785 gboolean want_in_place, reconfigure;
1786 GstClockTime qostime;
1789 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1791 if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
1792 GST_OBJECT_LOCK (trans);
1793 reconfigure = trans->priv->reconfigure;
1794 trans->priv->reconfigure = FALSE;
1795 GST_OBJECT_UNLOCK (trans);
1797 if (G_UNLIKELY (reconfigure)) {
1798 GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
1799 /* if we need to reconfigure we pretend a buffer with new caps arrived. This
1800 * will reconfigure the transform with the new output format. We can only
1801 * do this if the buffer actually has caps. */
1802 if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
1803 goto not_negotiated;
1807 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1808 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1809 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1810 GST_BUFFER_OFFSET (inbuf));
1812 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1813 inbuf, GST_BUFFER_SIZE (inbuf));
1815 /* Don't allow buffer handling before negotiation, except in passthrough mode
1816 * or if the class doesn't implement a set_caps function (in which case it doesn't
1819 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1820 goto not_negotiated;
1822 /* Set discont flag so we can mark the outgoing buffer */
1823 if (GST_BUFFER_IS_DISCONT (inbuf)) {
1824 GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
1825 trans->priv->discont = TRUE;
1828 /* can only do QoS if the segment is in TIME */
1829 if (trans->segment.format != GST_FORMAT_TIME)
1832 /* QOS is done on the running time of the buffer, get it now */
1833 qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1834 GST_BUFFER_TIMESTAMP (inbuf));
1836 if (qostime != -1) {
1838 GstClockTime earliest_time;
1840 /* lock for getting the QoS parameters that are set (in a different thread)
1841 * with the QOS events */
1842 GST_OBJECT_LOCK (trans);
1843 earliest_time = trans->priv->earliest_time;
1844 /* check for QoS, don't perform conversion for buffers
1845 * that are known to be late. */
1846 need_skip = trans->priv->qos_enabled &&
1847 earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
1848 GST_OBJECT_UNLOCK (trans);
1851 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1852 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1853 GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1854 /* mark discont for next buffer */
1855 trans->priv->discont = TRUE;
1862 /* first try to allocate an output buffer based on the currently negotiated
1863 * format. While we call pad-alloc we could renegotiate the srcpad format or
1864 * have a new suggestion for upstream buffer-alloc.
1865 * In any case, outbuf will contain a buffer suitable for doing the configured
1866 * transform after this function. */
1867 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
1868 if (G_UNLIKELY (ret != GST_FLOW_OK))
1871 /* now perform the needed transform */
1872 if (trans->passthrough) {
1873 /* In passthrough mode, give transform_ip a look at the
1874 * buffer, without making it writable, or just push the
1876 if (bclass->transform_ip) {
1877 GST_DEBUG_OBJECT (trans, "doing passthrough transform");
1878 ret = bclass->transform_ip (trans, *outbuf);
1880 GST_DEBUG_OBJECT (trans, "element is in passthrough");
1883 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1885 if (want_in_place) {
1886 GST_DEBUG_OBJECT (trans, "doing inplace transform");
1888 if (inbuf != *outbuf) {
1889 /* different buffers, copy the input to the output first, we then do an
1890 * in-place transform on the output buffer. */
1891 memcpy (GST_BUFFER_DATA (*outbuf), GST_BUFFER_DATA (inbuf),
1892 GST_BUFFER_SIZE (inbuf));
1894 ret = bclass->transform_ip (trans, *outbuf);
1896 GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
1898 if (bclass->transform)
1899 ret = bclass->transform (trans, inbuf, *outbuf);
1901 ret = GST_FLOW_NOT_SUPPORTED;
1906 /* only unref input buffer if we allocated a new outbuf buffer */
1907 if (*outbuf != inbuf)
1908 gst_buffer_unref (inbuf);
1915 gst_buffer_unref (inbuf);
1916 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1917 ("not negotiated"), ("not negotiated"));
1918 return GST_FLOW_NOT_NEGOTIATED;
1922 gst_buffer_unref (inbuf);
1923 GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
1924 gst_flow_get_name (ret));
1930 gst_base_transform_check_get_range (GstPad * pad)
1932 GstBaseTransform *trans;
1935 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1937 ret = gst_pad_check_pull_range (trans->sinkpad);
1939 gst_object_unref (trans);
1944 /* FIXME, getrange is broken, need to pull range from the other
1945 * end based on the transform_size result.
1947 static GstFlowReturn
1948 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1949 guint length, GstBuffer ** buffer)
1951 GstBaseTransform *trans;
1952 GstBaseTransformClass *klass;
1956 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1958 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1959 if (G_UNLIKELY (ret != GST_FLOW_OK))
1962 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1963 if (klass->before_transform)
1964 klass->before_transform (trans, inbuf);
1966 GST_BASE_TRANSFORM_LOCK (trans);
1967 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1968 GST_BASE_TRANSFORM_UNLOCK (trans);
1971 gst_object_unref (trans);
1978 GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
1979 gst_flow_get_name (ret));
1984 static GstFlowReturn
1985 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1987 GstBaseTransform *trans;
1988 GstBaseTransformClass *klass;
1990 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
1991 GstBuffer *outbuf = NULL;
1993 trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
1995 /* calculate end position of the incoming buffer */
1996 if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) {
1997 if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
1998 last_stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
2000 last_stop = GST_BUFFER_TIMESTAMP (buffer);
2003 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2004 if (klass->before_transform)
2005 klass->before_transform (trans, buffer);
2007 /* protect transform method and concurrent buffer alloc */
2008 GST_BASE_TRANSFORM_LOCK (trans);
2009 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2010 GST_BASE_TRANSFORM_UNLOCK (trans);
2012 /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2013 * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2014 if (outbuf != NULL) {
2015 if ((ret == GST_FLOW_OK)) {
2016 /* Remember last stop position */
2017 if ((last_stop != GST_CLOCK_TIME_NONE) &&
2018 (trans->segment.format == GST_FORMAT_TIME))
2019 gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2021 /* apply DISCONT flag if the buffer is not yet marked as such */
2022 if (trans->priv->discont) {
2023 if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2024 outbuf = gst_buffer_make_metadata_writable (outbuf);
2025 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2027 trans->priv->discont = FALSE;
2029 ret = gst_pad_push (trans->srcpad, outbuf);
2031 gst_buffer_unref (outbuf);
2034 /* convert internal flow to OK and mark discont for the next buffer. */
2035 if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2036 trans->priv->discont = TRUE;
2044 gst_base_transform_set_property (GObject * object, guint prop_id,
2045 const GValue * value, GParamSpec * pspec)
2047 GstBaseTransform *trans;
2049 trans = GST_BASE_TRANSFORM (object);
2053 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2056 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2062 gst_base_transform_get_property (GObject * object, guint prop_id,
2063 GValue * value, GParamSpec * pspec)
2065 GstBaseTransform *trans;
2067 trans = GST_BASE_TRANSFORM (object);
2071 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2074 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2079 /* not a vmethod of anything, just an internal method */
2081 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2083 GstBaseTransformClass *bclass;
2084 gboolean result = TRUE;
2086 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2089 if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2090 result &= bclass->start (trans);
2092 GST_OBJECT_LOCK (trans);
2094 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2095 trans->have_same_caps =
2096 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2097 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2099 trans->have_same_caps = trans->passthrough;
2100 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2101 trans->negotiated = FALSE;
2102 trans->have_newsegment = FALSE;
2103 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2104 trans->priv->proportion = 1.0;
2105 trans->priv->earliest_time = -1;
2106 trans->priv->discont = FALSE;
2107 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2109 GST_OBJECT_UNLOCK (trans);
2111 /* We must make sure streaming has finished before resetting things
2112 * and calling the ::stop vfunc */
2113 GST_PAD_STREAM_LOCK (trans->sinkpad);
2114 GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2116 trans->have_same_caps = FALSE;
2117 /* We can only reset the passthrough mode if the instance told us to
2118 handle it in configure_caps */
2119 if (bclass->passthrough_on_same_caps) {
2120 gst_base_transform_set_passthrough (trans, FALSE);
2122 gst_caps_replace (&trans->cache_caps1, NULL);
2123 gst_caps_replace (&trans->cache_caps2, NULL);
2124 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2125 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2127 if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2128 result &= bclass->stop (trans);
2135 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2137 gboolean result = TRUE;
2138 GstBaseTransform *trans;
2140 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2142 result = gst_base_transform_activate (trans, active);
2145 trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2147 gst_object_unref (trans);
2153 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2155 gboolean result = FALSE;
2156 GstBaseTransform *trans;
2158 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2160 result = gst_pad_activate_pull (trans->sinkpad, active);
2163 result &= gst_base_transform_activate (trans, active);
2166 trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2168 gst_object_unref (trans);
2174 * gst_base_transform_set_passthrough:
2175 * @trans: the #GstBaseTransform to set
2176 * @passthrough: boolean indicating passthrough mode.
2178 * Set passthrough mode for this filter by default. This is mostly
2179 * useful for filters that do not care about negotiation.
2181 * Always TRUE for filters which don't implement either a transform
2182 * or transform_ip method.
2187 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2188 gboolean passthrough)
2190 GstBaseTransformClass *bclass;
2192 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2194 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2196 GST_OBJECT_LOCK (trans);
2197 if (passthrough == FALSE) {
2198 if (bclass->transform_ip || bclass->transform)
2199 trans->passthrough = FALSE;
2201 trans->passthrough = TRUE;
2204 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2205 GST_OBJECT_UNLOCK (trans);
2209 * gst_base_transform_is_passthrough:
2210 * @trans: the #GstBaseTransform to query
2212 * See if @trans is configured as a passthrough transform.
2214 * Returns: TRUE is the transform is configured in passthrough mode.
2219 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2223 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2225 GST_OBJECT_LOCK (trans);
2226 result = trans->passthrough;
2227 GST_OBJECT_UNLOCK (trans);
2233 * gst_base_transform_set_in_place:
2234 * @trans: the #GstBaseTransform to modify
2235 * @in_place: Boolean value indicating that we would like to operate
2236 * on in_place buffers.
2238 * Determines whether a non-writable buffer will be copied before passing
2239 * to the transform_ip function.
2241 * <listitem>Always TRUE if no transform function is implemented.</listitem>
2242 * <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2248 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2250 GstBaseTransformClass *bclass;
2252 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2254 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2256 GST_OBJECT_LOCK (trans);
2259 if (bclass->transform_ip) {
2260 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2261 trans->always_in_place = TRUE;
2264 if (bclass->transform) {
2265 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2266 trans->always_in_place = FALSE;
2270 GST_OBJECT_UNLOCK (trans);
2274 * gst_base_transform_is_in_place:
2275 * @trans: the #GstBaseTransform to query
2277 * See if @trans is configured as a in_place transform.
2279 * Returns: TRUE is the transform is configured in in_place mode.
2284 gst_base_transform_is_in_place (GstBaseTransform * trans)
2288 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2290 GST_OBJECT_LOCK (trans);
2291 result = trans->always_in_place;
2292 GST_OBJECT_UNLOCK (trans);
2298 * gst_base_transform_update_qos:
2299 * @trans: a #GstBaseTransform
2300 * @proportion: the proportion
2301 * @diff: the diff against the clock
2302 * @timestamp: the timestamp of the buffer generating the QoS expressed in
2305 * Set the QoS parameters in the transform. This function is called internally
2306 * when a QOS event is received but subclasses can provide custom information
2314 gst_base_transform_update_qos (GstBaseTransform * trans,
2315 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2318 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2320 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2321 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2322 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2324 GST_OBJECT_LOCK (trans);
2325 trans->priv->proportion = proportion;
2326 trans->priv->earliest_time = timestamp + diff;
2327 GST_OBJECT_UNLOCK (trans);
2331 * gst_base_transform_set_qos_enabled:
2332 * @trans: a #GstBaseTransform
2333 * @enabled: new state
2335 * Enable or disable QoS handling in the transform.
2342 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2344 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2346 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2348 GST_OBJECT_LOCK (trans);
2349 trans->priv->qos_enabled = enabled;
2350 GST_OBJECT_UNLOCK (trans);
2354 * gst_base_transform_is_qos_enabled:
2355 * @trans: a #GstBaseTransform
2357 * Queries if the transform will handle QoS.
2359 * Returns: TRUE if QoS is enabled.
2366 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2370 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2372 GST_OBJECT_LOCK (trans);
2373 result = trans->priv->qos_enabled;
2374 GST_OBJECT_UNLOCK (trans);
2380 * gst_base_transform_set_gap_aware:
2381 * @trans: a #GstBaseTransform
2382 * @gap_aware: New state
2384 * If @gap_aware is %FALSE (the default), output buffers will have the
2385 * %GST_BUFFER_FLAG_GAP flag unset.
2387 * If set to %TRUE, the element must handle output buffers with this flag set
2388 * correctly, i.e. it can assume that the buffer contains neutral data but must
2389 * unset the flag if the output is no neutral data.
2396 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2398 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2400 GST_OBJECT_LOCK (trans);
2401 trans->priv->gap_aware = gap_aware;
2402 GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2403 GST_OBJECT_UNLOCK (trans);
2407 * gst_base_transform_suggest:
2408 * @trans: a #GstBaseTransform
2409 * @caps: caps to suggest
2410 * @size: buffer size to suggest
2412 * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
2418 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
2421 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2423 GST_OBJECT_LOCK (trans->sinkpad);
2424 if (trans->priv->sink_suggest)
2425 gst_caps_unref (trans->priv->sink_suggest);
2427 caps = gst_caps_copy (caps);
2428 trans->priv->sink_suggest = caps;
2429 trans->priv->size_suggest = size;
2430 trans->priv->suggest_pending = TRUE;
2431 GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
2432 GST_OBJECT_UNLOCK (trans->sinkpad);
2436 * gst_base_transform_reconfigure:
2437 * @trans: a #GstBaseTransform
2439 * Instructs @trans to renegotiate a new downstream transform on the next
2440 * buffer. This function is typically called after properties on the transform
2441 * were set that influence the output format.
2446 gst_base_transform_reconfigure (GstBaseTransform * trans)
2448 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2450 GST_OBJECT_LOCK (trans);
2451 GST_DEBUG_OBJECT (trans, "marking reconfigure");
2452 trans->priv->reconfigure = TRUE;
2453 GST_OBJECT_UNLOCK (trans);