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 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
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
64 * transform_caps function is useful for elements that only inspect data
69 * <title>Example elements</title>
70 * <listitem>Level</listitem>
71 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
72 * certain modes.</listitem>
77 * <title>Modifications in-place - input buffer and output buffer are the
80 * The element must implement a transform_ip function.
83 * Output buffer size must <= input buffer size
86 * If the always_in_place flag is set, non-writable buffers will be copied
87 * and passed to the transform_ip function, otherwise a new buffer will be
88 * created and the transform function called.
91 * Incoming writable buffers will be passed to the transform_ip function
92 * immediately. </para></listitem>
94 * only implementing transform_ip and not transform implies always_in_place
99 * <title>Example elements</title>
100 * <listitem>Volume</listitem>
101 * <listitem>Audioconvert in certain modes (signed/unsigned
102 * conversion)</listitem>
103 * <listitem>ffmpegcolorspace in certain modes (endianness
104 * swapping)</listitem>
109 * <title>Modifications only to the caps/metadata of a buffer</title>
111 * The element does not require writable data, but non-writable buffers
112 * should be subbuffered so that the meta-information can be replaced.
115 * Elements wishing to operate in this mode should replace the
116 * prepare_output_buffer method to create subbuffers of the input buffer
117 * and set always_in_place to TRUE
121 * <title>Example elements</title>
122 * <listitem>Capsfilter when setting caps on outgoing buffers that have
124 * <listitem>identity when it is going to re-timestamp buffers by
125 * datarate.</listitem>
129 * <itemizedlist><title>Normal mode</title>
131 * always_in_place flag is not set, or there is no transform_ip function
134 * Element will receive an input buffer and output buffer to operate on.
137 * Output buffer is allocated by calling the prepare_output_buffer function.
141 * <title>Example elements</title>
142 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
143 * scaling/conversions</listitem>
147 * <itemizedlist><title>Special output buffer allocations</title>
149 * Elements which need to do special allocation of their output buffers
150 * other than what gst_buffer_pad_alloc allows should implement a
151 * prepare_output_buffer method, which calls the parent implementation and
152 * passes the newly allocated buffer.
156 * <title>Example elements</title>
157 * <listitem>efence</listitem>
162 * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
164 * <itemizedlist><title>passthrough</title>
166 * Implies that in the current configuration, the sub-class is not
167 * interested in modifying the buffers.
170 * Elements which are always in passthrough mode whenever the same caps
171 * has been negotiated on both pads can set the class variable
172 * passthrough_on_same_caps to have this behaviour automatically.
177 * <itemizedlist><title>always_in_place</title>
179 * Determines whether a non-writable buffer will be copied before passing
180 * to the transform_ip function.
183 * Implied TRUE if no transform function is implemented.
186 * Implied FALSE if ONLY transform function is implemented.
201 #include "../../../gst/gst_private.h"
202 #include "../../../gst/gst-i18n-lib.h"
203 #include "gstbasetransform.h"
204 #include <gst/gstmarshal.h>
206 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
207 #define GST_CAT_DEFAULT gst_base_transform_debug
209 /* BaseTransform signals and args */
216 #define DEFAULT_PROP_QOS FALSE
224 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \
225 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
227 struct _GstBaseTransformPrivate
229 /* QoS *//* with LOCK */
230 gboolean qos_enabled;
232 GstClockTime earliest_time;
235 static GstElementClass *parent_class = NULL;
237 static void gst_base_transform_base_init (gpointer g_class);
238 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
239 static void gst_base_transform_init (GstBaseTransform * trans,
240 GstBaseTransformClass * klass);
241 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
242 * trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
245 gst_base_transform_get_type (void)
247 static GType base_transform_type = 0;
249 if (!base_transform_type) {
250 static const GTypeInfo base_transform_info = {
251 sizeof (GstBaseTransformClass),
252 (GBaseInitFunc) gst_base_transform_base_init,
254 (GClassInitFunc) gst_base_transform_class_init,
257 sizeof (GstBaseTransform),
259 (GInstanceInitFunc) gst_base_transform_init,
262 base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
263 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
265 return base_transform_type;
268 static void gst_base_transform_finalize (GObject * object);
269 static void gst_base_transform_set_property (GObject * object, guint prop_id,
270 const GValue * value, GParamSpec * pspec);
271 static void gst_base_transform_get_property (GObject * object, guint prop_id,
272 GValue * value, GParamSpec * pspec);
273 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
275 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
277 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
278 GstCaps * caps, guint * size);
280 static GstStateChangeReturn gst_base_transform_change_state (GstElement *
281 element, GstStateChange transition);
283 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
284 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
286 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
287 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
289 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
290 guint length, GstBuffer ** buffer);
291 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
293 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
294 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
295 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
296 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
298 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
301 gst_base_transform_base_init (gpointer g_class)
303 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
304 "basetransform element");
308 gst_base_transform_finalize (GObject * object)
310 GstBaseTransform *trans;
312 trans = GST_BASE_TRANSFORM (object);
314 g_mutex_free (trans->transform_lock);
316 G_OBJECT_CLASS (parent_class)->finalize (object);
320 gst_base_transform_class_init (GstBaseTransformClass * klass)
322 GObjectClass *gobject_class;
323 GstElementClass *gstelement_class;
325 gobject_class = G_OBJECT_CLASS (klass);
326 gstelement_class = GST_ELEMENT_CLASS (klass);
328 g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
330 parent_class = g_type_class_peek_parent (klass);
332 gobject_class->set_property =
333 GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
334 gobject_class->get_property =
335 GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
337 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QOS,
338 g_param_spec_boolean ("qos", "QoS", "handle QoS messages",
339 DEFAULT_PROP_QOS, G_PARAM_READWRITE));
341 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
343 gstelement_class->change_state =
344 GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
346 klass->passthrough_on_same_caps = FALSE;
347 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
348 klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
352 gst_base_transform_init (GstBaseTransform * trans,
353 GstBaseTransformClass * bclass)
355 GstPadTemplate *pad_template;
357 GST_DEBUG ("gst_base_transform_init");
359 trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
362 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
363 g_return_if_fail (pad_template != NULL);
364 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
365 gst_pad_set_getcaps_function (trans->sinkpad,
366 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
367 gst_pad_set_setcaps_function (trans->sinkpad,
368 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
369 gst_pad_set_event_function (trans->sinkpad,
370 GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
371 gst_pad_set_chain_function (trans->sinkpad,
372 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
373 gst_pad_set_activatepush_function (trans->sinkpad,
374 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
375 gst_pad_set_bufferalloc_function (trans->sinkpad,
376 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
377 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
380 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
381 g_return_if_fail (pad_template != NULL);
382 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
383 gst_pad_set_getcaps_function (trans->srcpad,
384 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
385 gst_pad_set_setcaps_function (trans->srcpad,
386 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
387 gst_pad_set_event_function (trans->srcpad,
388 GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
389 gst_pad_set_getrange_function (trans->srcpad,
390 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
391 gst_pad_set_activatepull_function (trans->srcpad,
392 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
393 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
395 trans->transform_lock = g_mutex_new ();
396 trans->delay_configure = FALSE;
397 trans->pending_configure = FALSE;
398 trans->priv->qos_enabled = DEFAULT_PROP_QOS;
399 trans->cache_caps1 = NULL;
400 trans->cache_caps2 = NULL;
402 trans->passthrough = FALSE;
403 if (bclass->transform == NULL) {
404 /* If no transform function, always_in_place is TRUE */
405 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
406 trans->always_in_place = TRUE;
408 if (bclass->transform_ip == NULL)
409 trans->passthrough = TRUE;
413 /* given @caps on the src or sink pad (given by @direction)
414 * calculate the possible caps on the other pad.
416 * Returns new caps, unref after usage.
419 gst_base_transform_transform_caps (GstBaseTransform * trans,
420 GstPadDirection direction, GstCaps * caps)
423 GstBaseTransformClass *klass;
425 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
427 /* if there is a custom transform function, use this */
428 if (klass->transform_caps) {
432 /* start with empty caps */
433 ret = gst_caps_new_empty ();
435 if (gst_caps_is_any (caps)) {
436 /* for any caps we still have to call the transform function */
437 GST_DEBUG_OBJECT (trans, "from ANY:");
438 temp = klass->transform_caps (trans, direction, caps);
439 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
441 temp = gst_caps_make_writable (temp);
442 gst_caps_append (ret, temp);
444 /* we send caps with just one structure to the transform
445 * function as this is easier for the element */
446 for (i = 0; i < gst_caps_get_size (caps); i++) {
449 nth = gst_caps_copy_nth (caps, i);
450 GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
451 temp = klass->transform_caps (trans, direction, nth);
452 gst_caps_unref (nth);
453 GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
455 temp = gst_caps_make_writable (temp);
456 gst_caps_append (ret, temp);
460 /* else use the identity transform */
461 ret = gst_caps_ref (caps);
464 GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
470 gst_base_transform_transform_size (GstBaseTransform * trans,
471 GstPadDirection direction, GstCaps * caps,
472 guint size, GstCaps * othercaps, guint * othersize)
474 guint inunitsize, outunitsize, units;
475 GstBaseTransformClass *klass;
478 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
480 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
481 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
482 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
484 /* if there is a custom transform function, use this */
485 if (klass->transform_size) {
486 ret = klass->transform_size (trans, direction, caps, size, othercaps,
489 if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
492 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
495 if (inunitsize == 0 || (size % inunitsize != 0))
498 units = size / inunitsize;
499 if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
502 *othersize = units * outunitsize;
503 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
512 GST_DEBUG_OBJECT (trans, "could not get in_size");
513 g_warning ("could not get in_size");
518 GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
520 g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
525 GST_DEBUG_OBJECT (trans, "could not get out_size");
526 g_warning ("could not get out_size");
532 gst_base_transform_getcaps (GstPad * pad)
534 GstBaseTransform *trans;
538 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
540 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
542 /* we can do what the peer can */
543 caps = gst_pad_peer_get_caps (otherpad);
546 const GstCaps *templ;
548 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
550 /* filtered against our padtemplate */
551 templ = gst_pad_get_pad_template_caps (otherpad);
552 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
553 temp = gst_caps_intersect (caps, templ);
554 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
555 gst_caps_unref (caps);
556 /* then see what we can transform this to */
557 caps = gst_base_transform_transform_caps (trans,
558 GST_PAD_DIRECTION (otherpad), temp);
559 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
560 gst_caps_unref (temp);
564 /* and filter against the template again */
565 templ = gst_pad_get_pad_template_caps (pad);
566 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
567 temp = gst_caps_intersect (caps, templ);
568 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
569 gst_caps_unref (caps);
570 /* this is what we can do */
573 /* no peer, our padtemplate is enough then */
574 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
578 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
580 gst_object_unref (trans);
585 /* function triggered when the in and out caps are negotiated and need
586 * to be configured in the subclass. */
588 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
592 GstBaseTransformClass *klass;
594 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
596 /* clear the cache */
597 gst_caps_replace (&trans->cache_caps1, NULL);
598 gst_caps_replace (&trans->cache_caps2, NULL);
600 /* If we've a transform_ip method and same input/output caps, set in_place
601 * by default. If for some reason the sub-class prefers using a transform
602 * function, it can clear the in place flag in the set_caps */
603 gst_base_transform_set_in_place (trans,
604 klass->transform_ip && trans->have_same_caps);
606 /* Set the passthrough if the class wants passthrough_on_same_caps
607 * and we have the same caps on each pad */
608 if (klass->passthrough_on_same_caps)
609 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
611 /* now configure the element with the caps */
612 if (klass->set_caps) {
613 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
614 ret = klass->set_caps (trans, in, out);
617 trans->negotiated = ret;
622 /* called when new caps arrive on the sink or source pad */
624 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
626 GstBaseTransform *trans;
627 GstBaseTransformClass *klass;
628 GstPad *otherpad, *otherpeer;
629 GstCaps *othercaps = NULL;
631 gboolean peer_checked = FALSE;
633 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
634 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
636 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
637 otherpeer = gst_pad_get_peer (otherpad);
639 /* if we get called recursively, we bail out now to avoid an
641 if (GST_PAD_IS_IN_SETCAPS (otherpad))
644 /* caps must be fixed here */
645 if (!gst_caps_is_fixed (caps))
648 /* see how we can transform the input caps. */
649 othercaps = gst_base_transform_transform_caps (trans,
650 GST_PAD_DIRECTION (pad), caps);
652 /* The caps we can actually output is the intersection of the transformed
653 * caps with the pad template for the pad */
656 const GstCaps *templ_caps;
658 templ_caps = gst_pad_get_pad_template_caps (otherpad);
659 intersect = gst_caps_intersect (othercaps, templ_caps);
661 gst_caps_unref (othercaps);
662 othercaps = intersect;
665 /* check if transform is empty */
666 if (!othercaps || gst_caps_is_empty (othercaps))
669 /* if the othercaps are not fixed, we need to fixate them, first attempt
670 * is by attempting passthrough if the othercaps are a superset of caps. */
671 if (!gst_caps_is_fixed (othercaps)) {
674 GST_DEBUG_OBJECT (trans,
675 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
677 /* see if the target caps are a superset of the source caps, in this
678 * case we can try to perform passthrough */
679 temp = gst_caps_intersect (othercaps, caps);
680 GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
682 if (!gst_caps_is_empty (temp) && otherpeer) {
683 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
684 /* try passthrough. we know it's fixed, because caps is fixed */
685 if (gst_pad_accept_caps (otherpeer, caps)) {
686 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
687 /* peer accepted unmodified caps, we free the original non-fixed
688 * caps and work with the passthrough caps */
689 gst_caps_unref (othercaps);
690 othercaps = gst_caps_ref (caps);
691 /* mark that we checked othercaps with the peer, this
692 * makes sure we don't call accept_caps again with these same
696 GST_DEBUG_OBJECT (trans,
697 "peer did not accept %" GST_PTR_FORMAT, caps);
700 gst_caps_unref (temp);
704 /* second attempt at fixation is done by intersecting with
706 if (!gst_caps_is_fixed (othercaps) && otherpeer) {
707 /* intersect against what the peer can do */
711 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
713 peercaps = gst_pad_get_caps (otherpeer);
714 intersect = gst_caps_intersect (peercaps, othercaps);
715 gst_caps_unref (peercaps);
716 gst_caps_unref (othercaps);
717 othercaps = intersect;
718 peer_checked = FALSE;
720 GST_DEBUG_OBJECT (trans,
721 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
724 if (gst_caps_is_empty (othercaps))
725 goto no_transform_possible;
727 /* third attempt at fixation, call the fixate vmethod and
728 * ultimately call the pad fixate function. */
729 if (!gst_caps_is_fixed (othercaps)) {
732 GST_DEBUG_OBJECT (trans,
733 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
734 othercaps, GST_DEBUG_PAD_NAME (otherpad));
736 /* since we have no other way to fixate left, we might as well just take
737 * the first of the caps list and fixate that */
739 /* FIXME: when fixating using the vmethod, it might make sense to fixate
740 * each of the caps; but Wim doesn't see a use case for that yet */
741 temp = gst_caps_copy_nth (othercaps, 0);
742 gst_caps_unref (othercaps);
744 peer_checked = FALSE;
746 if (klass->fixate_caps) {
747 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
748 " using caps %" GST_PTR_FORMAT
749 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
750 GST_DEBUG_PAD_NAME (otherpad));
751 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
753 /* if still not fixed, no other option but to let the default pad fixate
754 * function do its job */
755 if (!gst_caps_is_fixed (othercaps)) {
756 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
757 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
758 GST_DEBUG_PAD_NAME (otherpad));
759 gst_pad_fixate_caps (otherpad, othercaps);
761 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
764 /* caps should be fixed now, if not we have to fail. */
765 if (!gst_caps_is_fixed (othercaps))
766 goto could_not_fixate;
768 /* and peer should accept, don't check again if we already checked the
769 * othercaps against the peer. */
770 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
773 GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
775 trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
776 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
778 /* see if we have to configure the element now */
779 if (!trans->delay_configure) {
780 GstCaps *incaps, *outcaps;
782 /* make sure in and out caps are correct */
783 if (pad == trans->sinkpad) {
790 /* call configure now */
791 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
792 goto failed_configure;
794 /* set pending configure, the configure will happen later with the
795 * caps we set on the pads above. */
796 trans->pending_configure = TRUE;
799 /* we know this will work, we implement the setcaps */
800 gst_pad_set_caps (otherpad, othercaps);
804 gst_object_unref (otherpeer);
806 gst_caps_unref (othercaps);
808 trans->negotiated = ret;
810 gst_object_unref (trans);
817 GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps);
823 GST_DEBUG_OBJECT (trans,
824 "transform returned useless %" GST_PTR_FORMAT, othercaps);
828 no_transform_possible:
830 GST_DEBUG_OBJECT (trans,
831 "transform could not transform %" GST_PTR_FORMAT
832 " in anything we support", caps);
838 GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
844 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
845 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
851 GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
852 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
858 /* Allocate a buffer using gst_pad_alloc_buffer
860 * This function does not do renegotiation on the source pad
863 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
864 GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
866 GstBaseTransformClass *bclass;
867 GstFlowReturn ret = GST_FLOW_OK;
868 gboolean copy_inbuf = FALSE;
870 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
872 /* we cannot reconfigure the element yet as we are still processing
873 * the old buffer. We will therefore delay the reconfiguration of the
874 * element until we have processed this last buffer. */
875 trans->delay_configure = TRUE;
876 /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS
877 macro. If a set_caps occurs during this function this caps will become
878 invalid. We want to keep them during preparation of the output buffer. */
880 gst_caps_ref (out_caps);
882 /* see if the subclass wants to alloc a buffer */
883 if (bclass->prepare_output_buffer) {
885 bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
887 if (ret != GST_FLOW_OK)
891 /* See if we want to prepare the buffer for in place output */
892 if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
893 && bclass->transform_ip) {
894 if (gst_buffer_is_writable (in_buf)) {
895 if (trans->have_same_caps) {
896 /* Input buffer is already writable and caps are the same, just ref and return it */
898 gst_buffer_ref (in_buf);
900 /* Writable buffer, but need to change caps => subbuffer */
901 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
902 gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
906 /* Make a writable buffer below and copy the data */
911 if (*out_buf == NULL) {
912 /* Sub-class didn't already provide a buffer for us. Make one */
913 ret = gst_pad_alloc_buffer (trans->srcpad,
914 GST_BUFFER_OFFSET (in_buf), out_size, out_caps, out_buf);
915 if (ret != GST_FLOW_OK || *out_buf == NULL)
918 /* allocated buffer could be of different caps than what we requested */
919 if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
920 /* FIXME, it is possible we can reconfigure the transform with new caps at this
921 * point but for now we just create a buffer ourselves */
922 gst_buffer_unref (*out_buf);
923 *out_buf = gst_buffer_new_and_alloc (out_size);
924 gst_buffer_set_caps (*out_buf, out_caps);
928 /* If the output buffer metadata is modifiable, copy timestamps and
930 if (*out_buf != in_buf && gst_buffer_is_metadata_writable (*out_buf)) {
932 if (copy_inbuf && gst_buffer_is_writable (*out_buf))
933 memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
935 gst_buffer_stamp (*out_buf, in_buf);
936 GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
937 (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_DISCONT |
938 GST_BUFFER_FLAG_IN_CAPS | GST_BUFFER_FLAG_DELTA_UNIT);
943 gst_caps_unref (out_caps);
944 trans->delay_configure = FALSE;
949 /* Given @caps calcultate the size of one unit.
951 * For video caps, this is the size of one frame (and thus one buffer).
952 * For audio caps, this is the size of one sample.
954 * These values are cached since they do not change and the calculation
955 * potentially involves parsing caps and other expensive stuff.
957 * We have two cache locations to store the size, one for the source caps
958 * and one for the sink caps.
960 * this function returns FALSE if no size could be calculated.
963 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
966 gboolean res = FALSE;
967 GstBaseTransformClass *bclass;
969 /* see if we have the result cached */
970 if (trans->cache_caps1 == caps) {
971 *size = trans->cache_caps1_size;
972 GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
975 if (trans->cache_caps2 == caps) {
976 *size = trans->cache_caps2_size;
977 GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
981 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
982 if (bclass->get_unit_size) {
983 res = bclass->get_unit_size (trans, caps, size);
984 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
985 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
988 /* and cache the values */
989 if (trans->cache_caps1 == NULL) {
990 gst_caps_replace (&trans->cache_caps1, caps);
991 trans->cache_caps1_size = *size;
992 GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
993 } else if (trans->cache_caps2 == NULL) {
994 gst_caps_replace (&trans->cache_caps2, caps);
995 trans->cache_caps2_size = *size;
996 GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
998 GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1002 GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1007 /* your upstream peer wants to send you a buffer
1008 * that buffer has the given offset, size and caps
1009 * you're requested to allocate a buffer
1011 static GstFlowReturn
1012 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1013 GstCaps * caps, GstBuffer ** buf)
1015 GstBaseTransform *trans;
1019 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1021 /* we cannot run this when we are transforming data and as such doing
1022 * another negotiation in the transform method. */
1023 g_mutex_lock (trans->transform_lock);
1027 GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size);
1028 if (offset == GST_BUFFER_OFFSET_NONE)
1029 GST_DEBUG_OBJECT (trans, "... and offset NONE");
1031 GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
1033 /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
1034 * a renegotiation and change that to FALSE */
1035 if (trans->have_same_caps) {
1036 /* request a buffer with the same caps */
1037 GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
1040 gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, size, caps,
1043 /* if we are configured, request a buffer with the src caps */
1044 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
1045 GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
1048 goto not_configured;
1050 if (sinkcaps != NULL) {
1051 if (sinkcaps != caps || !gst_caps_is_equal (sinkcaps, caps)) {
1052 gst_caps_unref (sinkcaps);
1053 gst_caps_unref (srccaps);
1054 goto not_configured;
1056 gst_caps_unref (sinkcaps);
1059 GST_DEBUG_OBJECT (trans, "calling transform_size");
1060 if (!gst_base_transform_transform_size (trans,
1061 GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
1062 gst_caps_unref (srccaps);
1067 gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, new_size,
1069 gst_caps_unref (srccaps);
1072 if (res == GST_FLOW_OK && !trans->have_same_caps) {
1073 /* note that we might have had same caps before, but calling the
1074 alloc_buffer caused setcaps to switch us out of in_place -- in any case
1075 the alloc_buffer served to transmit caps information but we can't use the
1076 buffer. fall through and allocate a buffer corresponding to our sink
1078 GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
1079 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
1082 goto not_configured;
1084 if (!gst_base_transform_transform_size (trans,
1085 GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
1086 sinkcaps, &new_size)) {
1087 gst_caps_unref (srccaps);
1088 gst_caps_unref (sinkcaps);
1092 gst_buffer_unref (*buf);
1094 *buf = gst_buffer_new_and_alloc (new_size);
1095 gst_buffer_set_caps (*buf, sinkcaps);
1096 GST_BUFFER_OFFSET (*buf) = offset;
1099 gst_caps_unref (srccaps);
1100 gst_caps_unref (sinkcaps);
1104 g_mutex_unlock (trans->transform_lock);
1105 gst_object_unref (trans);
1111 /* let the default allocator handle it */
1112 GST_DEBUG_OBJECT (trans, "not configured");
1113 gst_buffer_replace (buf, NULL);
1119 /* let the default allocator handle it */
1120 GST_DEBUG_OBJECT (trans, "unknown size");
1121 gst_buffer_replace (buf, NULL);
1128 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
1130 GstBaseTransform *trans;
1131 GstBaseTransformClass *bclass;
1132 gboolean ret = TRUE;
1134 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1135 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1138 ret = bclass->event (trans, event);
1140 /* FIXME, do this in the default event handler so the subclass can do
1141 * something different. */
1143 ret = gst_pad_push_event (trans->srcpad, event);
1145 gst_object_unref (trans);
1151 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1153 switch (GST_EVENT_TYPE (event)) {
1154 case GST_EVENT_FLUSH_START:
1156 case GST_EVENT_FLUSH_STOP:
1157 GST_OBJECT_LOCK (trans);
1158 /* reset QoS parameters */
1159 trans->priv->proportion = 1.0;
1160 trans->priv->earliest_time = -1;
1161 GST_OBJECT_UNLOCK (trans);
1162 /* we need new segment info after the flush. */
1163 trans->have_newsegment = FALSE;
1164 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1170 case GST_EVENT_NEWSEGMENT:
1173 gdouble rate, arate;
1174 gint64 start, stop, time;
1177 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1178 &start, &stop, &time);
1180 if (trans->segment.format != format)
1181 gst_segment_init (&trans->segment, format);
1183 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
1184 format, start, stop, time);
1186 trans->have_newsegment = TRUE;
1188 if (format == GST_FORMAT_TIME) {
1189 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1190 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1191 ", accum %" GST_TIME_FORMAT,
1192 GST_TIME_ARGS (trans->segment.start),
1193 GST_TIME_ARGS (trans->segment.stop),
1194 GST_TIME_ARGS (trans->segment.time),
1195 GST_TIME_ARGS (trans->segment.accum));
1197 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1198 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1199 ", accum %" G_GINT64_FORMAT,
1200 trans->segment.start, trans->segment.stop,
1201 trans->segment.time, trans->segment.accum);
1213 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
1215 GstBaseTransform *trans;
1216 GstBaseTransformClass *bclass;
1217 gboolean ret = TRUE;
1219 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1220 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1222 if (bclass->src_event)
1223 ret = bclass->src_event (trans, event);
1225 gst_object_unref (trans);
1231 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1235 switch (GST_EVENT_TYPE (event)) {
1236 case GST_EVENT_SEEK:
1238 case GST_EVENT_NAVIGATION:
1243 GstClockTimeDiff diff;
1244 GstClockTime timestamp;
1246 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1247 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1254 ret = gst_pad_push_event (trans->sinkpad, event);
1259 static GstFlowReturn
1260 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1261 GstBuffer ** outbuf)
1263 GstBaseTransformClass *bclass;
1264 GstFlowReturn ret = GST_FLOW_OK;
1266 gboolean want_in_place;
1267 GstClockTime qostime;
1269 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1271 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1272 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1273 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1274 GST_BUFFER_OFFSET (inbuf));
1276 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1277 inbuf, GST_BUFFER_SIZE (inbuf));
1279 /* Don't allow buffer handling before negotiation, except in passthrough mode
1280 * or if the class doesn't implement a set_caps function (in which case it doesn't
1283 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1284 goto not_negotiated;
1286 /* can only do QoS if the segment is in TIME */
1287 if (trans->segment.format != GST_FORMAT_TIME)
1290 qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1291 GST_BUFFER_TIMESTAMP (inbuf));
1293 if (qostime != -1) {
1295 GstClockTime earliest_time;
1297 GST_OBJECT_LOCK (trans);
1298 earliest_time = trans->priv->earliest_time;
1299 /* check for QoS, don't perform conversion for buffers
1300 * that are known to be late. */
1301 need_skip = trans->priv->qos_enabled &&
1302 earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
1303 GST_OBJECT_UNLOCK (trans);
1306 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1307 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1308 GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1314 if (trans->passthrough) {
1315 /* In passthrough mode, give transform_ip a look at the
1316 * buffer, without making it writable, or just push the
1318 GST_LOG_OBJECT (trans, "element is in passthrough mode");
1320 if (bclass->transform_ip)
1321 ret = bclass->transform_ip (trans, inbuf);
1328 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1331 if (want_in_place) {
1332 /* If want_in_place is TRUE, we may need to prepare a new output buffer
1333 * Sub-classes can implement a prepare_output_buffer function as they
1335 GST_LOG_OBJECT (trans, "doing inplace transform");
1337 ret = gst_base_transform_prepare_output_buffer (trans, inbuf,
1338 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
1339 if (G_UNLIKELY (ret != GST_FLOW_OK))
1342 ret = bclass->transform_ip (trans, *outbuf);
1345 GST_LOG_OBJECT (trans, "doing non-inplace transform");
1347 /* not transforming inplace, figure out the output size */
1348 if (trans->always_in_place) {
1349 out_size = GST_BUFFER_SIZE (inbuf);
1351 if (!gst_base_transform_transform_size (trans,
1352 GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
1353 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
1355 /* we have an error */
1360 /* no in place transform, get buffer, this might renegotiate. */
1361 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, out_size,
1362 GST_PAD_CAPS (trans->srcpad), outbuf);
1363 if (ret != GST_FLOW_OK)
1366 if (bclass->transform)
1367 ret = bclass->transform (trans, inbuf, *outbuf);
1369 ret = GST_FLOW_NOT_SUPPORTED;
1372 /* if we got renegotiated we can configure now */
1373 if (trans->pending_configure) {
1377 gst_base_transform_configure_caps (trans,
1378 GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
1380 trans->pending_configure = FALSE;
1383 goto configure_failed;
1386 gst_buffer_unref (inbuf);
1393 gst_buffer_unref (inbuf);
1394 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1395 ("not negotiated"), ("not negotiated"));
1396 return GST_FLOW_NOT_NEGOTIATED;
1400 gst_buffer_unref (inbuf);
1401 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1402 ("subclass did not specify output size"),
1403 ("subclass did not specify output size"));
1404 return GST_FLOW_ERROR;
1408 gst_buffer_unref (inbuf);
1409 GST_DEBUG_OBJECT (trans, "could not get buffer from pool: %s",
1410 gst_flow_get_name (ret));
1415 gst_buffer_unref (inbuf);
1416 GST_DEBUG_OBJECT (trans, "could not negotiate");
1417 return GST_FLOW_NOT_NEGOTIATED;
1421 /* FIXME, getrange is broken, need to pull range from the other
1422 * end based on the transform_size result.
1424 static GstFlowReturn
1425 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1426 guint length, GstBuffer ** buffer)
1428 GstBaseTransform *trans;
1432 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1434 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1435 if (ret == GST_FLOW_OK) {
1436 g_mutex_lock (trans->transform_lock);
1437 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1438 g_mutex_unlock (trans->transform_lock);
1441 gst_object_unref (trans);
1446 static GstFlowReturn
1447 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1449 GstBaseTransform *trans;
1451 GstBuffer *outbuf = NULL;
1453 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1455 /* protect transform method and concurrent buffer alloc */
1456 g_mutex_lock (trans->transform_lock);
1457 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1458 g_mutex_unlock (trans->transform_lock);
1460 /* outbuf can be NULL, this means a dropped buffer */
1461 if (outbuf != NULL) {
1462 if (ret == GST_FLOW_OK)
1463 ret = gst_pad_push (trans->srcpad, outbuf);
1465 gst_buffer_unref (outbuf);
1468 gst_object_unref (trans);
1474 gst_base_transform_set_property (GObject * object, guint prop_id,
1475 const GValue * value, GParamSpec * pspec)
1477 GstBaseTransform *trans;
1479 trans = GST_BASE_TRANSFORM (object);
1483 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
1486 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1492 gst_base_transform_get_property (GObject * object, guint prop_id,
1493 GValue * value, GParamSpec * pspec)
1495 GstBaseTransform *trans;
1497 trans = GST_BASE_TRANSFORM (object);
1501 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
1504 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1510 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1512 gboolean result = TRUE;
1513 GstBaseTransform *trans;
1514 GstBaseTransformClass *bclass;
1516 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1517 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1521 result = bclass->start (trans);
1523 gst_object_unref (trans);
1529 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1531 gboolean result = FALSE;
1532 GstBaseTransform *trans;
1533 GstBaseTransformClass *bclass;
1535 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1536 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1538 result = gst_pad_activate_pull (trans->sinkpad, active);
1541 if (result && bclass->start)
1542 result &= bclass->start (trans);
1544 gst_object_unref (trans);
1549 static GstStateChangeReturn
1550 gst_base_transform_change_state (GstElement * element,
1551 GstStateChange transition)
1553 GstBaseTransform *trans;
1554 GstBaseTransformClass *bclass;
1555 GstStateChangeReturn result;
1557 trans = GST_BASE_TRANSFORM (element);
1558 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1561 switch (transition) {
1562 case GST_STATE_CHANGE_NULL_TO_READY:
1564 case GST_STATE_CHANGE_READY_TO_PAUSED:
1565 GST_OBJECT_LOCK (trans);
1566 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1567 trans->have_same_caps =
1568 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1569 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1571 trans->have_same_caps = trans->passthrough;
1572 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1573 trans->negotiated = FALSE;
1574 trans->have_newsegment = FALSE;
1575 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1576 trans->priv->proportion = 1.0;
1577 trans->priv->earliest_time = -1;
1578 GST_OBJECT_UNLOCK (trans);
1580 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1586 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1588 switch (transition) {
1589 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1591 case GST_STATE_CHANGE_PAUSED_TO_READY:
1592 trans->have_same_caps = FALSE;
1593 /* We can only reset the passthrough mode if the instance told us to
1594 handle it in configure_caps */
1595 if (bclass->passthrough_on_same_caps) {
1596 gst_base_transform_set_passthrough (trans, FALSE);
1598 gst_caps_replace (&trans->cache_caps1, NULL);
1599 gst_caps_replace (&trans->cache_caps2, NULL);
1601 result = bclass->stop (trans);
1603 case GST_STATE_CHANGE_READY_TO_NULL:
1613 * gst_base_transform_set_passthrough:
1614 * @trans: the #GstBaseTransform to set
1615 * @passthrough: boolean indicating passthrough mode.
1617 * Set passthrough mode for this filter by default. This is mostly
1618 * useful for filters that do not care about negotiation.
1620 * Always TRUE for filters which don't implement either a transform
1621 * or transform_ip method.
1626 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1627 gboolean passthrough)
1629 GstBaseTransformClass *bclass;
1631 g_return_if_fail (trans != NULL);
1633 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1635 GST_OBJECT_LOCK (trans);
1636 if (passthrough == FALSE) {
1637 if (bclass->transform_ip || bclass->transform)
1638 trans->passthrough = FALSE;
1640 trans->passthrough = TRUE;
1643 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
1644 GST_OBJECT_UNLOCK (trans);
1648 * gst_base_transform_is_passthrough:
1649 * @trans: the #GstBaseTransform to query
1651 * See if @trans is configured as a passthrough transform.
1653 * Returns: TRUE is the transform is configured in passthrough mode.
1658 gst_base_transform_is_passthrough (GstBaseTransform * trans)
1662 g_return_val_if_fail (trans != NULL, FALSE);
1664 GST_OBJECT_LOCK (trans);
1665 result = trans->passthrough;
1666 GST_OBJECT_UNLOCK (trans);
1672 * gst_base_transform_set_in_place:
1673 * @trans: the #GstBaseTransform to modify
1674 * @in_place: Boolean value indicating that we would like to operate
1675 * on in_place buffers.
1677 * Determines whether a non-writable buffer will be copied before passing
1678 * to the transform_ip function.
1680 * <listitem>Always TRUE if no transform function is implemented.</listitem>
1681 * <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
1687 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
1689 GstBaseTransformClass *bclass;
1691 g_return_if_fail (trans != NULL);
1693 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1695 GST_OBJECT_LOCK (trans);
1698 if (bclass->transform_ip) {
1699 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
1700 trans->always_in_place = TRUE;
1703 if (bclass->transform) {
1704 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
1705 trans->always_in_place = FALSE;
1709 GST_OBJECT_UNLOCK (trans);
1713 * gst_base_transform_is_in_place:
1714 * @trans: the #GstBaseTransform to query
1716 * See if @trans is configured as a in_place transform.
1718 * Returns: TRUE is the transform is configured in in_place mode.
1723 gst_base_transform_is_in_place (GstBaseTransform * trans)
1727 g_return_val_if_fail (trans != NULL, FALSE);
1729 GST_OBJECT_LOCK (trans);
1730 result = trans->always_in_place;
1731 GST_OBJECT_UNLOCK (trans);
1737 * gst_base_transform_update_qos:
1738 * @trans: a #GstBaseTransform
1739 * @proportion: the proportion
1740 * @diff: the diff against the clock
1741 * @timestamp: the timestamp of the buffer generating the QoS
1743 * Set the QoS parameters in the transform.
1750 gst_base_transform_update_qos (GstBaseTransform * trans,
1751 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
1754 g_return_if_fail (trans != NULL);
1756 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
1757 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
1758 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
1760 GST_OBJECT_LOCK (trans);
1761 trans->priv->proportion = proportion;
1762 trans->priv->earliest_time = timestamp + diff;
1763 GST_OBJECT_UNLOCK (trans);
1767 * gst_base_transform_set_qos_enabled:
1768 * @trans: a #GstBaseTransform
1769 * @enabled: new state
1771 * Enable or disable QoS handling in the transform.
1778 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
1780 g_return_if_fail (trans != NULL);
1782 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
1784 GST_OBJECT_LOCK (trans);
1785 trans->priv->qos_enabled = enabled;
1786 GST_OBJECT_UNLOCK (trans);
1790 * gst_base_transform_is_qos_enabled:
1791 * @trans: a #GstBaseTransform
1793 * Queries if the transform will handle QoS.
1795 * Returns: TRUE if QoS is enabled.
1802 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
1806 g_return_val_if_fail (trans != NULL, FALSE);
1808 GST_OBJECT_LOCK (trans);
1809 result = trans->priv->qos_enabled;
1810 GST_OBJECT_UNLOCK (trans);