2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2005 Wim Taymans <wim@fluendo.com>
5 * 2005 Andy Wingo <wingo@fluendo.com>
6 * 2005 Thomas Vander Stichele <thomas at apestaart dot org>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:gstbasetransform
26 * @short_description: Base class for simple tranform filters
27 * @see_also: #GstBaseSrc, #GstBaseSink
29 * This base class is for filter elements that process data.
33 * <listitem><para>one sinkpad and one srcpad</para></listitem>
35 * Possible formats on sink and source pad implemented
36 * with custom transform_caps function. By default uses
37 * same format on sink and source.
39 * <listitem><para>Handles state changes</para></listitem>
40 * <listitem><para>Does flushing</para></listitem>
41 * <listitem><para>Push mode</para></listitem>
43 * Pull mode if the sub-class transform can operate on arbitrary data
50 * <itemizedlist><title>Passthrough mode</title>
52 * Element has no interest in modifying the buffer. It may want to inspect it,
53 * in which case the element should have a transform_ip function. If there
54 * is no transform_ip function in passthrough mode, the buffer is pushed
58 * On the GstBaseTransformClass is the passthrough_on_same_caps variable
59 * which will automatically set/unset passthrough based on whether the
60 * element negotiates the same caps on both pads.
63 * passthrough_on_same_caps on an element that doesn't implement a transform_caps
64 * function is useful for elements that only inspect data (such as level)
68 * <title>Example elements</title>
69 * <listitem>Level</listitem>
70 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in certain modes.</listitem>
74 * <itemizedlist><title>Modifications in-place - input buffer and output buffer are the same thing.</title>
76 * The element must implement a transform_ip function.
79 * Output buffer size must <= input buffer size
82 * If the always_in_place flag is set, non-writable buffers will be copied and
83 * passed to the transform_ip function, otherwise a new buffer will be created
84 * and the transform function called.
87 * Incoming writable buffers will be passed to the transform_ip function immediately.
90 * only implementing transform_ip and not transform implies always_in_place =
95 * <title>Example elements</title>
96 * <listitem>Volume</listitem>
97 * <listitem>Audioconvert in certain modes (signed/unsigned conversion)</listitem>
98 * <listitem>ffmpegcolorspace in certain modes (endianness swapping)</listitem>
102 * <itemizedlist><title>Modifications only to the caps/metadata of a buffer</title>
104 * The element does not require writable data, but non-writable buffers should
105 * be subbuffered so that the meta-information can be replaced.
108 * Elements wishing to operate in this mode should replace the
109 * prepare_output_buffer method to create subbuffers of the input buffer and
110 * set always_in_place to TRUE
114 * <title>Example elements</title>
115 * <listitem>Capsfilter when setting caps on outgoing buffers that have none.</listitem>
116 * <listitem>identity when it is going to re-timestamp buffers by datarate.</listitem>
120 * <itemizedlist><title>Normal mode</title>
122 * always_in_place flag is not set, or there is no transform_ip function
125 * Element will receive an input buffer and output buffer to operate on.
128 * Output buffer is allocated by calling the prepare_output_buffer function.
132 * <title>Example elements</title>
133 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing scaling/conversions</listitem>
137 * <itemizedlist><title>Special output buffer allocations</title>
139 * Elements which need to do special allocation of their output buffers other
140 * than what gst_buffer_pad_alloc allows should implement a
141 * prepare_output_buffer method, which calls the parent implementation and
142 * passes the newly allocated buffer.
146 * <title>Example elements</title>
147 * <listitem>efence</listitem>
152 * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
154 * <itemizedlist><title>passthrough</title>
156 * Implies that in the current configuration, the sub-class is not
157 * interested in modifying the buffers.
160 * Elements which are always in passthrough mode whenever the same caps has
161 * been negotiated on both pads can set the class variable
162 * passthrough_on_same_caps to have this behaviour automatically.
167 * <itemizedlist><title>always_in_place</title>
169 * Determines whether a non-writable buffer will be copied before passing
170 * to the transform_ip function.
173 * Implied TRUE if no transform function is implemented.
176 * Implied FALSE if ONLY transform function is implemented.
191 #include "../gst-i18n-lib.h"
192 #include "gstbasetransform.h"
193 #include <gst/gstmarshal.h>
195 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
196 #define GST_CAT_DEFAULT gst_base_transform_debug
198 /* BaseTransform signals and args */
210 static GstElementClass *parent_class = NULL;
212 static void gst_base_transform_base_init (gpointer g_class);
213 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
214 static void gst_base_transform_init (GstBaseTransform * trans,
215 GstBaseTransformClass * klass);
216 static GstFlowReturn gst_base_transform_prepare_output_buf (GstBaseTransform *
217 trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
220 gst_base_transform_get_type (void)
222 static GType base_transform_type = 0;
224 if (!base_transform_type) {
225 static const GTypeInfo base_transform_info = {
226 sizeof (GstBaseTransformClass),
227 (GBaseInitFunc) gst_base_transform_base_init,
229 (GClassInitFunc) gst_base_transform_class_init,
232 sizeof (GstBaseTransform),
234 (GInstanceInitFunc) gst_base_transform_init,
237 base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
238 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
240 return base_transform_type;
243 static void gst_base_transform_finalize (GObject * object);
244 static void gst_base_transform_set_property (GObject * object, guint prop_id,
245 const GValue * value, GParamSpec * pspec);
246 static void gst_base_transform_get_property (GObject * object, guint prop_id,
247 GValue * value, GParamSpec * pspec);
248 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
250 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
252 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
253 GstCaps * caps, guint * size);
255 static GstStateChangeReturn gst_base_transform_change_state (GstElement *
256 element, GstStateChange transition);
258 static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event);
259 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
260 guint length, GstBuffer ** buffer);
261 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
263 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
264 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
265 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
266 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
268 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
271 gst_base_transform_base_init (gpointer g_class)
273 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
274 "basetransform element");
278 gst_base_transform_finalize (GObject * object)
280 GstBaseTransform *trans;
282 trans = GST_BASE_TRANSFORM (object);
284 g_mutex_free (trans->transform_lock);
286 G_OBJECT_CLASS (parent_class)->finalize (object);
290 gst_base_transform_class_init (GstBaseTransformClass * klass)
292 GObjectClass *gobject_class;
293 GstElementClass *gstelement_class;
295 gobject_class = G_OBJECT_CLASS (klass);
296 gstelement_class = GST_ELEMENT_CLASS (klass);
298 parent_class = g_type_class_peek_parent (klass);
300 gobject_class->set_property =
301 GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
302 gobject_class->get_property =
303 GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
305 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
307 gstelement_class->change_state =
308 GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
310 klass->passthrough_on_same_caps = FALSE;
314 gst_base_transform_init (GstBaseTransform * trans,
315 GstBaseTransformClass * bclass)
317 GstPadTemplate *pad_template;
319 GST_DEBUG ("gst_base_transform_init");
322 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
323 g_return_if_fail (pad_template != NULL);
324 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
325 gst_pad_set_getcaps_function (trans->sinkpad,
326 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
327 gst_pad_set_setcaps_function (trans->sinkpad,
328 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
329 gst_pad_set_event_function (trans->sinkpad,
330 GST_DEBUG_FUNCPTR (gst_base_transform_event));
331 gst_pad_set_chain_function (trans->sinkpad,
332 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
333 gst_pad_set_activatepush_function (trans->sinkpad,
334 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
335 gst_pad_set_bufferalloc_function (trans->sinkpad,
336 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
337 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
340 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
341 g_return_if_fail (pad_template != NULL);
342 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
343 gst_pad_set_getcaps_function (trans->srcpad,
344 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
345 gst_pad_set_setcaps_function (trans->srcpad,
346 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
347 gst_pad_set_getrange_function (trans->srcpad,
348 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
349 gst_pad_set_activatepull_function (trans->srcpad,
350 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
351 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
353 trans->transform_lock = g_mutex_new ();
354 trans->delay_configure = FALSE;
355 trans->pending_configure = FALSE;
356 trans->cache_caps1 = NULL;
357 trans->cache_caps2 = NULL;
359 trans->passthrough = FALSE;
360 if (bclass->transform == NULL) {
361 /* If no transform function, always_in_place is TRUE */
362 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
363 trans->always_in_place = TRUE;
365 if (bclass->transform_ip == NULL)
366 trans->passthrough = TRUE;
371 gst_base_transform_transform_caps (GstBaseTransform * trans,
372 GstPadDirection direction, GstCaps * caps)
375 GstBaseTransformClass *klass;
377 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
379 /* if there is a custom transform function, use this */
380 if (klass->transform_caps) {
384 ret = gst_caps_new_empty ();
386 if (gst_caps_is_any (caps)) {
387 /* for any caps we still have to call the transform function */
388 GST_DEBUG_OBJECT (trans, "from ANY:");
389 temp = klass->transform_caps (trans, direction, caps);
390 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
392 gst_caps_append (ret, temp);
394 /* we send caps with just one structure to the transform
395 * function as this is easier for the element */
396 for (i = 0; i < gst_caps_get_size (caps); i++) {
399 nth = gst_caps_copy_nth (caps, i);
400 GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
401 temp = klass->transform_caps (trans, direction, nth);
402 gst_caps_unref (nth);
403 GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
405 gst_caps_append (ret, temp);
409 /* else use the identity transform */
410 ret = gst_caps_ref (caps);
413 GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
419 gst_base_transform_transform_size (GstBaseTransform * trans,
420 GstPadDirection direction, GstCaps * caps,
421 guint size, GstCaps * othercaps, guint * othersize)
423 guint inunitsize, outunitsize, units;
424 GstBaseTransformClass *klass;
427 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
429 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
430 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
431 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
433 /* if there is a custom transform function, use this */
434 if (klass->transform_size) {
435 ret = klass->transform_size (trans, direction, caps, size, othercaps,
438 gboolean got_in_unit_size, got_out_unit_size;
440 got_in_unit_size = gst_base_transform_get_unit_size (trans, caps,
442 g_return_val_if_fail (got_in_unit_size == TRUE, FALSE);
443 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
445 g_return_val_if_fail (inunitsize != 0, FALSE);
446 if (size % inunitsize != 0) {
447 g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
451 units = size / inunitsize;
452 got_out_unit_size = gst_base_transform_get_unit_size (trans, othercaps,
454 g_return_val_if_fail (got_out_unit_size == TRUE, FALSE);
456 *othersize = units * outunitsize;
457 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
464 gst_base_transform_getcaps (GstPad * pad)
466 GstBaseTransform *trans;
470 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
472 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
474 /* we can do what the peer can */
475 caps = gst_pad_peer_get_caps (otherpad);
478 const GstCaps *templ;
480 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
482 /* filtered against our padtemplate */
483 templ = gst_pad_get_pad_template_caps (otherpad);
484 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
485 temp = gst_caps_intersect (caps, templ);
486 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
487 gst_caps_unref (caps);
488 /* then see what we can tranform this to */
489 caps = gst_base_transform_transform_caps (trans,
490 GST_PAD_DIRECTION (otherpad), temp);
491 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
492 gst_caps_unref (temp);
496 /* and filter against the template again */
497 templ = gst_pad_get_pad_template_caps (pad);
498 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
499 temp = gst_caps_intersect (caps, templ);
500 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
501 gst_caps_unref (caps);
502 /* this is what we can do */
505 /* no peer, our padtemplate is enough then */
506 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
510 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
512 gst_object_unref (trans);
518 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
522 GstBaseTransformClass *klass;
524 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
526 /* clear the cache */
527 gst_caps_replace (&trans->cache_caps1, NULL);
528 gst_caps_replace (&trans->cache_caps2, NULL);
530 /* If we've a transform_ip method and same input/output caps, set in_place
531 * by default. If for some reason the sub-class prefers using a transform
532 * function, it can clear the in place flag in the set_caps */
533 gst_base_transform_set_in_place (trans,
534 klass->transform_ip && trans->have_same_caps);
536 /* Set the passthrough if the class wants passthrough_on_same_caps
537 * and we have the same caps on each pad */
538 if (klass->passthrough_on_same_caps)
539 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
541 /* now configure the element with the caps */
542 if (klass->set_caps) {
543 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
544 ret = klass->set_caps (trans, in, out);
547 trans->negotiated = ret;
553 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
555 GstBaseTransform *trans;
556 GstBaseTransformClass *klass;
557 GstPad *otherpad, *otherpeer;
558 GstCaps *othercaps = NULL;
560 gboolean peer_checked = FALSE;
562 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
563 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
565 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
566 otherpeer = gst_pad_get_peer (otherpad);
568 /* if we get called recursively, we bail out now to avoid an
570 if (GST_PAD_IS_IN_SETCAPS (otherpad))
573 /* caps must be fixed here */
574 if (!gst_caps_is_fixed (caps))
577 /* see how we can transform the input caps. */
578 othercaps = gst_base_transform_transform_caps (trans,
579 GST_PAD_DIRECTION (pad), caps);
581 /* The caps we can actually output is the intersection of the transformed
582 * caps with the pad template for the pad */
585 const GstCaps *templ_caps;
587 templ_caps = gst_pad_get_pad_template_caps (otherpad);
588 intersect = gst_caps_intersect (othercaps, templ_caps);
590 gst_caps_unref (othercaps);
591 othercaps = intersect;
594 /* check if transform is empty */
595 if (!othercaps || gst_caps_is_empty (othercaps))
598 /* if the othercaps are not fixed, we need to fixate them, first attempt
599 * is by attempting passthrough if the othercaps are a superset of caps. */
600 if (!gst_caps_is_fixed (othercaps)) {
603 GST_DEBUG_OBJECT (trans,
604 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
606 /* see if the target caps are a superset of the source caps, in this
607 * case we can try to perform passthrough */
608 temp = gst_caps_intersect (othercaps, caps);
609 GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
611 if (!gst_caps_is_empty (temp) && otherpeer) {
612 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
613 /* try passthrough. we know it's fixed, because caps is fixed */
614 if (gst_pad_accept_caps (otherpeer, caps)) {
615 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
616 /* peer accepted unmodified caps, we free the original non-fixed
617 * caps and work with the passthrough caps */
618 gst_caps_unref (othercaps);
619 othercaps = gst_caps_ref (caps);
620 /* mark that we checked othercaps with the peer, this
621 * makes sure we don't call accept_caps again with these same
625 GST_DEBUG_OBJECT (trans,
626 "peer did not accept %" GST_PTR_FORMAT, caps);
629 gst_caps_unref (temp);
633 /* second attempt at fixation is done by intersecting with
635 if (!gst_caps_is_fixed (othercaps) && otherpeer) {
636 /* intersect against what the peer can do */
640 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
642 peercaps = gst_pad_get_caps (otherpeer);
643 intersect = gst_caps_intersect (peercaps, othercaps);
644 gst_caps_unref (peercaps);
645 gst_caps_unref (othercaps);
646 othercaps = intersect;
647 peer_checked = FALSE;
649 GST_DEBUG_OBJECT (trans,
650 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
653 if (gst_caps_is_empty (othercaps))
654 goto no_transform_possible;
656 /* third attempt at fixation, call the fixate vmethod and
657 * ultimately call the pad fixate function. */
658 if (!gst_caps_is_fixed (othercaps)) {
661 GST_DEBUG_OBJECT (trans,
662 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
663 othercaps, GST_DEBUG_PAD_NAME (otherpad));
665 /* since we have no other way to fixate left, we might as well just take
666 * the first of the caps list and fixate that */
668 /* FIXME: when fixating using the vmethod, it might make sense to fixate
669 * each of the caps; but Wim doesn't see a use case for that yet */
670 temp = gst_caps_copy_nth (othercaps, 0);
671 gst_caps_unref (othercaps);
673 peer_checked = FALSE;
675 if (klass->fixate_caps) {
676 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
677 " using caps %" GST_PTR_FORMAT
678 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
679 GST_DEBUG_PAD_NAME (otherpad));
680 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
682 /* if still not fixed, no other option but to let the default pad fixate
683 * function do its job */
684 if (!gst_caps_is_fixed (othercaps)) {
685 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
686 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
687 GST_DEBUG_PAD_NAME (otherpad));
688 gst_pad_fixate_caps (otherpad, othercaps);
690 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
693 /* caps should be fixed now, if not we have to fail. */
694 if (!gst_caps_is_fixed (othercaps))
695 goto could_not_fixate;
697 /* and peer should accept, don't check again if we already checked the
698 * othercaps against the peer. */
699 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
702 GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
704 trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
705 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
707 /* see if we have to configure the element now */
708 if (!trans->delay_configure) {
709 GstCaps *incaps, *outcaps;
711 /* make sure in and out caps are correct */
712 if (pad == trans->sinkpad) {
719 /* call configure now */
720 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
721 goto failed_configure;
723 /* set pending configure, the configure will happen later with the
724 * caps we set on the pads above. */
725 trans->pending_configure = TRUE;
728 /* we know this will work, we implement the setcaps */
729 gst_pad_set_caps (otherpad, othercaps);
733 gst_object_unref (otherpeer);
735 gst_caps_unref (othercaps);
737 trans->negotiated = ret;
739 gst_object_unref (trans);
746 GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps);
752 GST_DEBUG_OBJECT (trans,
753 "transform returned useless %" GST_PTR_FORMAT, othercaps);
757 no_transform_possible:
759 GST_DEBUG_OBJECT (trans,
760 "transform could not transform %" GST_PTR_FORMAT
761 " in anything we support", caps);
767 GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
773 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
774 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
780 GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
781 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
787 /* Allocate a buffer using gst_pad_alloc_buffer.
789 * This function can trigger a renegotiation on the source pad when the
790 * peer alloc_buffer function sets new caps. Since we currently are
791 * processing a buffer on the sinkpad when this function is called, we cannot
792 * reconfigure the transform with sinkcaps different from those of the current
793 * buffer. FIXME, we currently don't check if the pluging can transform to the
794 * new srcpad caps using the same sinkcaps, we alloc a proper outbuf buffer
798 gst_base_transform_prepare_output_buf (GstBaseTransform * trans,
799 GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
801 GstBaseTransformClass *bclass;
802 GstFlowReturn ret = GST_FLOW_OK;
803 gboolean copy_inbuf = FALSE;
805 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
807 /* we cannot reconfigure the element yet as we are still processing
808 * the old buffer. We will therefore delay the reconfiguration of the
809 * element until we have processed this last buffer. */
810 trans->delay_configure = TRUE;
811 /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS
812 macro. If a set_caps occurs during this function this caps will become
813 invalid. We want to keep them during preparation of the output buffer. */
815 gst_caps_ref (out_caps);
817 /* see if the subclass wants to alloc a buffer */
818 if (bclass->prepare_output_buffer) {
820 bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
822 if (ret != GST_FLOW_OK)
826 /* See if we want to prepare the buffer for in place output */
827 if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
828 && bclass->transform_ip) {
829 if (gst_buffer_is_writable (in_buf)) {
830 if (trans->have_same_caps) {
831 /* Input buffer is already writable and caps are the same, just ref and return it */
833 gst_buffer_ref (in_buf);
835 /* Writable buffer, but need to change caps => subbuffer */
836 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
837 gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
841 /* Make a writable buffer below and copy the data */
846 if (*out_buf == NULL) {
847 /* Sub-class didn't already provide a buffer for us. Make one */
848 ret = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET (in_buf),
849 out_size, out_caps, out_buf);
850 if (ret != GST_FLOW_OK || *out_buf == NULL)
853 /* allocated buffer could be of different caps than what we requested */
854 if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
855 /* FIXME, it is possible we can reconfigure the transform with new caps at this
856 * point but for now we just create a buffer ourselves */
857 gst_buffer_unref (*out_buf);
858 *out_buf = gst_buffer_new_and_alloc (out_size);
859 gst_buffer_set_caps (*out_buf, out_caps);
863 /* If the output buffer metadata is modifiable, copy timestamps and
865 if (*out_buf != in_buf && GST_MINI_OBJECT_REFCOUNT_VALUE (*out_buf) == 1) {
867 if (copy_inbuf && gst_buffer_is_writable (*out_buf))
868 memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
870 gst_buffer_stamp (*out_buf, in_buf);
871 GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
872 (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
873 GST_BUFFER_FLAG_DELTA_UNIT);
878 gst_caps_unref (out_caps);
879 trans->delay_configure = FALSE;
885 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
888 gboolean res = FALSE;
889 GstBaseTransformClass *bclass;
891 /* see if we have the result cached */
892 if (trans->cache_caps1 == caps) {
893 *size = trans->cache_caps1_size;
894 GST_DEBUG_OBJECT (trans, "get size returned cached 1 %d", *size);
897 if (trans->cache_caps2 == caps) {
898 *size = trans->cache_caps2_size;
899 GST_DEBUG_OBJECT (trans, "get size returned cached 2 %d", *size);
903 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
904 if (bclass->get_unit_size) {
905 res = bclass->get_unit_size (trans, caps, size);
906 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
907 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
910 if (trans->cache_caps1 == NULL) {
911 gst_caps_replace (&trans->cache_caps1, caps);
912 trans->cache_caps1_size = *size;
913 } else if (trans->cache_caps2 == NULL) {
914 gst_caps_replace (&trans->cache_caps2, caps);
915 trans->cache_caps2_size = *size;
919 GST_DEBUG ("Sub-class does not implement get_unit_size");
924 /* your upstream peer wants to send you a buffer
925 * that buffer has the given offset, size and caps
926 * you're requested to allocate a buffer
929 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
930 GstCaps * caps, GstBuffer ** buf)
932 GstBaseTransform *trans;
936 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
938 /* we cannot run this when we are transforming data and as such doing
939 * another negotiation in the transform method. */
940 g_mutex_lock (trans->transform_lock);
944 GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size, offset);
945 if (offset == GST_BUFFER_OFFSET_NONE)
946 GST_DEBUG_OBJECT (trans, "... and offset NONE");
948 GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
950 /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
951 * a renegotiation and change that to FALSE */
952 if (trans->have_same_caps) {
953 /* request a buffer with the same caps */
954 GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
956 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
958 /* if we are configured, request a buffer with the src caps */
959 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
964 GST_DEBUG_OBJECT (trans, "calling transform_size");
965 if (!gst_base_transform_transform_size (trans,
966 GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
967 gst_caps_unref (srccaps);
971 res = gst_pad_alloc_buffer (trans->srcpad, offset, new_size, srccaps, buf);
972 gst_caps_unref (srccaps);
975 if (res == GST_FLOW_OK && !trans->have_same_caps) {
976 /* note that we might have had same caps before, but calling the
977 alloc_buffer caused setcaps to switch us out of in_place -- in any case
978 the alloc_buffer served to transmit caps information but we can't use the
979 buffer. fall through and allocate a buffer corresponding to our sink
981 GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
982 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
987 if (!gst_base_transform_transform_size (trans,
988 GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
989 sinkcaps, &new_size)) {
990 gst_caps_unref (srccaps);
991 gst_caps_unref (sinkcaps);
995 gst_buffer_unref (*buf);
997 *buf = gst_buffer_new_and_alloc (new_size);
998 gst_buffer_set_caps (*buf, sinkcaps);
999 GST_BUFFER_OFFSET (*buf) = offset;
1002 gst_caps_unref (srccaps);
1003 gst_caps_unref (sinkcaps);
1005 g_mutex_unlock (trans->transform_lock);
1007 gst_object_unref (trans);
1013 /* let the default allocator handle it */
1014 GST_DEBUG_OBJECT (trans, "not configured");
1016 gst_buffer_unref (*buf);
1019 g_mutex_unlock (trans->transform_lock);
1020 gst_object_unref (trans);
1025 /* let the default allocator handle it */
1026 GST_DEBUG_OBJECT (trans, "unknown size");
1028 gst_buffer_unref (*buf);
1031 g_mutex_unlock (trans->transform_lock);
1032 gst_object_unref (trans);
1038 gst_base_transform_event (GstPad * pad, GstEvent * event)
1040 GstBaseTransform *trans;
1041 GstBaseTransformClass *bclass;
1042 gboolean ret = FALSE;
1044 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1045 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1048 bclass->event (trans, event);
1050 switch (GST_EVENT_TYPE (event)) {
1051 case GST_EVENT_FLUSH_START:
1053 case GST_EVENT_FLUSH_STOP:
1054 /* we need new segment info after the flush. */
1055 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1061 case GST_EVENT_NEWSEGMENT:
1065 gint64 start, stop, time;
1068 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
1071 gst_segment_set_newsegment (&trans->segment, update, rate, format, start,
1074 trans->have_newsegment = TRUE;
1076 if (format == GST_FORMAT_TIME) {
1077 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT
1078 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1079 ", accum %" GST_TIME_FORMAT,
1080 GST_TIME_ARGS (trans->segment.start),
1081 GST_TIME_ARGS (trans->segment.stop),
1082 GST_TIME_ARGS (trans->segment.time),
1083 GST_TIME_ARGS (trans->segment.accum));
1085 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1086 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1087 ", accum %" G_GINT64_FORMAT,
1088 trans->segment.start, trans->segment.stop,
1089 trans->segment.time, trans->segment.accum);
1096 ret = gst_pad_event_default (pad, event);
1098 gst_object_unref (trans);
1103 static GstFlowReturn
1104 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1105 GstBuffer ** outbuf)
1107 GstBaseTransformClass *bclass;
1108 GstFlowReturn ret = GST_FLOW_OK;
1110 gboolean want_in_place;
1112 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1114 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1115 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1116 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1117 GST_BUFFER_OFFSET (inbuf));
1119 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1120 inbuf, GST_BUFFER_SIZE (inbuf));
1122 /* Don't allow buffer handling before negotiation, except in passthrough mode
1123 * or if the class doesn't implement a set_caps function (in which case it doesn't
1126 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1127 goto not_negotiated;
1129 if (trans->passthrough) {
1130 /* In passthrough mode, give transform_ip a look at the
1131 * buffer, without making it writable, or just push the
1133 GST_LOG_OBJECT (trans, "element is in passthrough mode");
1135 if (bclass->transform_ip)
1136 ret = bclass->transform_ip (trans, inbuf);
1143 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1146 if (want_in_place) {
1147 /* If want_in_place is TRUE, we may need to prepare a new output buffer
1148 * Sub-classes can implement a prepare_output_buffer function as they
1150 GST_LOG_OBJECT (trans, "doing inplace transform");
1152 ret = gst_base_transform_prepare_output_buf (trans, inbuf,
1153 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
1154 if (G_UNLIKELY (ret != GST_FLOW_OK))
1157 ret = bclass->transform_ip (trans, *outbuf);
1160 GST_LOG_OBJECT (trans, "doing non-inplace transform");
1162 /* not transforming inplace, figure out the output size */
1163 if (trans->always_in_place) {
1164 out_size = GST_BUFFER_SIZE (inbuf);
1166 if (!gst_base_transform_transform_size (trans,
1167 GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
1168 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
1170 /* we have an error */
1175 /* no in place transform, get buffer, this might renegotiate. */
1176 ret = gst_base_transform_prepare_output_buf (trans, inbuf, out_size,
1177 GST_PAD_CAPS (trans->srcpad), outbuf);
1178 if (ret != GST_FLOW_OK)
1181 if (bclass->transform)
1182 ret = bclass->transform (trans, inbuf, *outbuf);
1184 ret = GST_FLOW_NOT_SUPPORTED;
1187 /* if we got renegotiated we can configure now */
1188 if (trans->pending_configure) {
1192 gst_base_transform_configure_caps (trans,
1193 GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
1195 trans->pending_configure = FALSE;
1198 goto configure_failed;
1200 gst_buffer_unref (inbuf);
1207 gst_buffer_unref (inbuf);
1208 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1209 ("not negotiated"), ("not negotiated"));
1210 return GST_FLOW_NOT_NEGOTIATED;
1214 gst_buffer_unref (inbuf);
1215 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1216 ("subclass did not specify output size"),
1217 ("subclass did not specify output size"));
1218 return GST_FLOW_ERROR;
1222 gst_buffer_unref (inbuf);
1223 GST_DEBUG_OBJECT (trans, "could not get buffer from pool");
1228 gst_buffer_unref (inbuf);
1229 GST_DEBUG_OBJECT (trans, "could not negotiate");
1230 return GST_FLOW_NOT_NEGOTIATED;
1234 /* FIXME, getrange is broken, need to pull range from the other
1235 * end based on the transform_size result.
1237 static GstFlowReturn
1238 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1239 guint length, GstBuffer ** buffer)
1241 GstBaseTransform *trans;
1245 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1247 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1248 if (ret == GST_FLOW_OK) {
1249 g_mutex_lock (trans->transform_lock);
1250 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1251 g_mutex_unlock (trans->transform_lock);
1254 gst_object_unref (trans);
1259 static GstFlowReturn
1260 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1262 GstBaseTransform *trans;
1264 GstBuffer *outbuf = NULL;
1266 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1268 /* protect transform method and concurrent buffer alloc */
1269 g_mutex_lock (trans->transform_lock);
1270 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1271 g_mutex_unlock (trans->transform_lock);
1273 if (ret == GST_FLOW_OK) {
1274 ret = gst_pad_push (trans->srcpad, outbuf);
1275 } else if (outbuf != NULL)
1276 gst_buffer_unref (outbuf);
1278 gst_object_unref (trans);
1284 gst_base_transform_set_property (GObject * object, guint prop_id,
1285 const GValue * value, GParamSpec * pspec)
1287 GstBaseTransform *trans;
1289 trans = GST_BASE_TRANSFORM (object);
1293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1299 gst_base_transform_get_property (GObject * object, guint prop_id,
1300 GValue * value, GParamSpec * pspec)
1302 GstBaseTransform *trans;
1304 trans = GST_BASE_TRANSFORM (object);
1308 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1314 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1316 gboolean result = TRUE;
1317 GstBaseTransform *trans;
1318 GstBaseTransformClass *bclass;
1320 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1321 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1325 result = bclass->start (trans);
1327 gst_object_unref (trans);
1333 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1335 gboolean result = FALSE;
1336 GstBaseTransform *trans;
1337 GstBaseTransformClass *bclass;
1339 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1340 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1342 result = gst_pad_activate_pull (trans->sinkpad, active);
1345 if (result && bclass->start)
1346 result &= bclass->start (trans);
1348 gst_object_unref (trans);
1353 static GstStateChangeReturn
1354 gst_base_transform_change_state (GstElement * element,
1355 GstStateChange transition)
1357 GstBaseTransform *trans;
1358 GstBaseTransformClass *bclass;
1359 GstStateChangeReturn result;
1361 trans = GST_BASE_TRANSFORM (element);
1362 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1365 switch (transition) {
1366 case GST_STATE_CHANGE_NULL_TO_READY:
1368 case GST_STATE_CHANGE_READY_TO_PAUSED:
1369 GST_OBJECT_LOCK (trans);
1370 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1371 trans->have_same_caps =
1372 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1373 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1375 trans->have_same_caps = trans->passthrough;
1376 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1377 trans->negotiated = FALSE;
1378 trans->have_newsegment = FALSE;
1379 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1380 GST_OBJECT_UNLOCK (trans);
1382 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1384 case GST_STATE_CHANGE_PAUSED_TO_READY:
1385 gst_caps_replace (&trans->cache_caps1, NULL);
1386 gst_caps_replace (&trans->cache_caps2, NULL);
1391 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1393 switch (transition) {
1394 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1396 case GST_STATE_CHANGE_PAUSED_TO_READY:
1398 result = bclass->stop (trans);
1400 case GST_STATE_CHANGE_READY_TO_NULL:
1410 * gst_base_transform_set_passthrough:
1411 * @trans: the #GstBaseTransform to set
1412 * @passthrough: boolean indicating passthrough mode.
1414 * Set passthrough mode for this filter by default. This is mostly
1415 * useful for filters that do not care about negotiation.
1417 * Always TRUE for filters which don't implement either a transform
1418 * or transform_ip method.
1423 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1424 gboolean passthrough)
1426 GstBaseTransformClass *bclass;
1428 g_return_if_fail (trans != NULL);
1430 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1432 GST_OBJECT_LOCK (trans);
1433 if (passthrough == FALSE) {
1434 if (bclass->transform_ip || bclass->transform)
1435 trans->passthrough = FALSE;
1437 trans->passthrough = TRUE;
1440 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
1441 GST_OBJECT_UNLOCK (trans);
1445 * gst_base_transform_is_passthrough:
1446 * @trans: the #GstBaseTransform to query
1448 * See if @trans is configured as a passthrough transform.
1450 * Returns: TRUE is the transform is configured in passthrough mode.
1455 gst_base_transform_is_passthrough (GstBaseTransform * trans)
1459 g_return_val_if_fail (trans != NULL, FALSE);
1461 GST_OBJECT_LOCK (trans);
1462 result = trans->passthrough;
1463 GST_OBJECT_UNLOCK (trans);
1469 * gst_base_transform_set_in_place:
1470 * @trans: the #GstBaseTransform to modify
1471 * @in_place: Boolean value indicating that we would like to operate
1472 * on in_place buffers.
1474 * Determines whether a non-writable buffer will be copied before passing
1475 * to the transform_ip function.
1477 * <listitem>Always TRUE if no transform function is implemented.</listitem>
1478 * <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
1484 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
1486 GstBaseTransformClass *bclass;
1488 g_return_if_fail (trans != NULL);
1490 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1492 GST_OBJECT_LOCK (trans);
1495 if (bclass->transform_ip) {
1496 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
1497 trans->always_in_place = TRUE;
1500 if (bclass->transform) {
1501 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
1502 trans->always_in_place = FALSE;
1506 GST_OBJECT_UNLOCK (trans);
1510 * gst_base_transform_is_in_place:
1511 * @trans: the #GstBaseTransform to query
1513 * See if @trans is configured as a in_place transform.
1515 * Returns: TRUE is the transform is configured in in_place mode.
1520 gst_base_transform_is_in_place (GstBaseTransform * trans)
1524 g_return_val_if_fail (trans != NULL, FALSE);
1526 GST_OBJECT_LOCK (trans);
1527 result = trans->always_in_place;
1528 GST_OBJECT_UNLOCK (trans);