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 gboolean gst_base_transform_eventfunc (GstBaseTransform * trans,
261 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
262 guint length, GstBuffer ** buffer);
263 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
265 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
266 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
267 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
268 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
270 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
273 gst_base_transform_base_init (gpointer g_class)
275 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
276 "basetransform element");
280 gst_base_transform_finalize (GObject * object)
282 GstBaseTransform *trans;
284 trans = GST_BASE_TRANSFORM (object);
286 g_mutex_free (trans->transform_lock);
288 G_OBJECT_CLASS (parent_class)->finalize (object);
292 gst_base_transform_class_init (GstBaseTransformClass * klass)
294 GObjectClass *gobject_class;
295 GstElementClass *gstelement_class;
297 gobject_class = G_OBJECT_CLASS (klass);
298 gstelement_class = GST_ELEMENT_CLASS (klass);
300 parent_class = g_type_class_peek_parent (klass);
302 gobject_class->set_property =
303 GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
304 gobject_class->get_property =
305 GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
307 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
309 gstelement_class->change_state =
310 GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
312 klass->passthrough_on_same_caps = FALSE;
313 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_eventfunc);
317 gst_base_transform_init (GstBaseTransform * trans,
318 GstBaseTransformClass * bclass)
320 GstPadTemplate *pad_template;
322 GST_DEBUG ("gst_base_transform_init");
325 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
326 g_return_if_fail (pad_template != NULL);
327 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
328 gst_pad_set_getcaps_function (trans->sinkpad,
329 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
330 gst_pad_set_setcaps_function (trans->sinkpad,
331 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
332 gst_pad_set_event_function (trans->sinkpad,
333 GST_DEBUG_FUNCPTR (gst_base_transform_event));
334 gst_pad_set_chain_function (trans->sinkpad,
335 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
336 gst_pad_set_activatepush_function (trans->sinkpad,
337 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
338 gst_pad_set_bufferalloc_function (trans->sinkpad,
339 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
340 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
343 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
344 g_return_if_fail (pad_template != NULL);
345 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
346 gst_pad_set_getcaps_function (trans->srcpad,
347 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
348 gst_pad_set_setcaps_function (trans->srcpad,
349 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
350 gst_pad_set_getrange_function (trans->srcpad,
351 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
352 gst_pad_set_activatepull_function (trans->srcpad,
353 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
354 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
356 trans->transform_lock = g_mutex_new ();
357 trans->delay_configure = FALSE;
358 trans->pending_configure = FALSE;
359 trans->cache_caps1 = NULL;
360 trans->cache_caps2 = NULL;
362 trans->passthrough = FALSE;
363 if (bclass->transform == NULL) {
364 /* If no transform function, always_in_place is TRUE */
365 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
366 trans->always_in_place = TRUE;
368 if (bclass->transform_ip == NULL)
369 trans->passthrough = TRUE;
374 gst_base_transform_transform_caps (GstBaseTransform * trans,
375 GstPadDirection direction, GstCaps * caps)
378 GstBaseTransformClass *klass;
380 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
382 /* if there is a custom transform function, use this */
383 if (klass->transform_caps) {
387 ret = gst_caps_new_empty ();
389 if (gst_caps_is_any (caps)) {
390 /* for any caps we still have to call the transform function */
391 GST_DEBUG_OBJECT (trans, "from ANY:");
392 temp = klass->transform_caps (trans, direction, caps);
393 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
395 gst_caps_append (ret, temp);
397 /* we send caps with just one structure to the transform
398 * function as this is easier for the element */
399 for (i = 0; i < gst_caps_get_size (caps); i++) {
402 nth = gst_caps_copy_nth (caps, i);
403 GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
404 temp = klass->transform_caps (trans, direction, nth);
405 gst_caps_unref (nth);
406 GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
408 gst_caps_append (ret, temp);
412 /* else use the identity transform */
413 ret = gst_caps_ref (caps);
416 GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
422 gst_base_transform_transform_size (GstBaseTransform * trans,
423 GstPadDirection direction, GstCaps * caps,
424 guint size, GstCaps * othercaps, guint * othersize)
426 guint inunitsize, outunitsize, units;
427 GstBaseTransformClass *klass;
430 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
432 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
433 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
434 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
436 /* if there is a custom transform function, use this */
437 if (klass->transform_size) {
438 ret = klass->transform_size (trans, direction, caps, size, othercaps,
441 gboolean got_in_unit_size, got_out_unit_size;
443 got_in_unit_size = gst_base_transform_get_unit_size (trans, caps,
445 g_return_val_if_fail (got_in_unit_size == TRUE, FALSE);
446 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
448 g_return_val_if_fail (inunitsize != 0, FALSE);
449 if (size % inunitsize != 0) {
450 g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
454 units = size / inunitsize;
455 got_out_unit_size = gst_base_transform_get_unit_size (trans, othercaps,
457 g_return_val_if_fail (got_out_unit_size == TRUE, FALSE);
459 *othersize = units * outunitsize;
460 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
467 gst_base_transform_getcaps (GstPad * pad)
469 GstBaseTransform *trans;
473 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
475 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
477 /* we can do what the peer can */
478 caps = gst_pad_peer_get_caps (otherpad);
481 const GstCaps *templ;
483 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
485 /* filtered against our padtemplate */
486 templ = gst_pad_get_pad_template_caps (otherpad);
487 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
488 temp = gst_caps_intersect (caps, templ);
489 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
490 gst_caps_unref (caps);
491 /* then see what we can tranform this to */
492 caps = gst_base_transform_transform_caps (trans,
493 GST_PAD_DIRECTION (otherpad), temp);
494 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
495 gst_caps_unref (temp);
499 /* and filter against the template again */
500 templ = gst_pad_get_pad_template_caps (pad);
501 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
502 temp = gst_caps_intersect (caps, templ);
503 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
504 gst_caps_unref (caps);
505 /* this is what we can do */
508 /* no peer, our padtemplate is enough then */
509 caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
513 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
515 gst_object_unref (trans);
521 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
525 GstBaseTransformClass *klass;
527 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
529 /* clear the cache */
530 gst_caps_replace (&trans->cache_caps1, NULL);
531 gst_caps_replace (&trans->cache_caps2, NULL);
533 /* If we've a transform_ip method and same input/output caps, set in_place
534 * by default. If for some reason the sub-class prefers using a transform
535 * function, it can clear the in place flag in the set_caps */
536 gst_base_transform_set_in_place (trans,
537 klass->transform_ip && trans->have_same_caps);
539 /* Set the passthrough if the class wants passthrough_on_same_caps
540 * and we have the same caps on each pad */
541 if (klass->passthrough_on_same_caps)
542 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
544 /* now configure the element with the caps */
545 if (klass->set_caps) {
546 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
547 ret = klass->set_caps (trans, in, out);
550 trans->negotiated = ret;
556 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
558 GstBaseTransform *trans;
559 GstBaseTransformClass *klass;
560 GstPad *otherpad, *otherpeer;
561 GstCaps *othercaps = NULL;
563 gboolean peer_checked = FALSE;
565 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
566 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
568 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
569 otherpeer = gst_pad_get_peer (otherpad);
571 /* if we get called recursively, we bail out now to avoid an
573 if (GST_PAD_IS_IN_SETCAPS (otherpad))
576 /* caps must be fixed here */
577 if (!gst_caps_is_fixed (caps))
580 /* see how we can transform the input caps. */
581 othercaps = gst_base_transform_transform_caps (trans,
582 GST_PAD_DIRECTION (pad), caps);
584 /* The caps we can actually output is the intersection of the transformed
585 * caps with the pad template for the pad */
588 const GstCaps *templ_caps;
590 templ_caps = gst_pad_get_pad_template_caps (otherpad);
591 intersect = gst_caps_intersect (othercaps, templ_caps);
593 gst_caps_unref (othercaps);
594 othercaps = intersect;
597 /* check if transform is empty */
598 if (!othercaps || gst_caps_is_empty (othercaps))
601 /* if the othercaps are not fixed, we need to fixate them, first attempt
602 * is by attempting passthrough if the othercaps are a superset of caps. */
603 if (!gst_caps_is_fixed (othercaps)) {
606 GST_DEBUG_OBJECT (trans,
607 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
609 /* see if the target caps are a superset of the source caps, in this
610 * case we can try to perform passthrough */
611 temp = gst_caps_intersect (othercaps, caps);
612 GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
614 if (!gst_caps_is_empty (temp) && otherpeer) {
615 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
616 /* try passthrough. we know it's fixed, because caps is fixed */
617 if (gst_pad_accept_caps (otherpeer, caps)) {
618 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
619 /* peer accepted unmodified caps, we free the original non-fixed
620 * caps and work with the passthrough caps */
621 gst_caps_unref (othercaps);
622 othercaps = gst_caps_ref (caps);
623 /* mark that we checked othercaps with the peer, this
624 * makes sure we don't call accept_caps again with these same
628 GST_DEBUG_OBJECT (trans,
629 "peer did not accept %" GST_PTR_FORMAT, caps);
632 gst_caps_unref (temp);
636 /* second attempt at fixation is done by intersecting with
638 if (!gst_caps_is_fixed (othercaps) && otherpeer) {
639 /* intersect against what the peer can do */
643 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
645 peercaps = gst_pad_get_caps (otherpeer);
646 intersect = gst_caps_intersect (peercaps, othercaps);
647 gst_caps_unref (peercaps);
648 gst_caps_unref (othercaps);
649 othercaps = intersect;
650 peer_checked = FALSE;
652 GST_DEBUG_OBJECT (trans,
653 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
656 if (gst_caps_is_empty (othercaps))
657 goto no_transform_possible;
659 /* third attempt at fixation, call the fixate vmethod and
660 * ultimately call the pad fixate function. */
661 if (!gst_caps_is_fixed (othercaps)) {
664 GST_DEBUG_OBJECT (trans,
665 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
666 othercaps, GST_DEBUG_PAD_NAME (otherpad));
668 /* since we have no other way to fixate left, we might as well just take
669 * the first of the caps list and fixate that */
671 /* FIXME: when fixating using the vmethod, it might make sense to fixate
672 * each of the caps; but Wim doesn't see a use case for that yet */
673 temp = gst_caps_copy_nth (othercaps, 0);
674 gst_caps_unref (othercaps);
676 peer_checked = FALSE;
678 if (klass->fixate_caps) {
679 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
680 " using caps %" GST_PTR_FORMAT
681 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
682 GST_DEBUG_PAD_NAME (otherpad));
683 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
685 /* if still not fixed, no other option but to let the default pad fixate
686 * function do its job */
687 if (!gst_caps_is_fixed (othercaps)) {
688 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
689 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
690 GST_DEBUG_PAD_NAME (otherpad));
691 gst_pad_fixate_caps (otherpad, othercaps);
693 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
696 /* caps should be fixed now, if not we have to fail. */
697 if (!gst_caps_is_fixed (othercaps))
698 goto could_not_fixate;
700 /* and peer should accept, don't check again if we already checked the
701 * othercaps against the peer. */
702 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
705 GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
707 trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
708 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
710 /* see if we have to configure the element now */
711 if (!trans->delay_configure) {
712 GstCaps *incaps, *outcaps;
714 /* make sure in and out caps are correct */
715 if (pad == trans->sinkpad) {
722 /* call configure now */
723 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
724 goto failed_configure;
726 /* set pending configure, the configure will happen later with the
727 * caps we set on the pads above. */
728 trans->pending_configure = TRUE;
731 /* we know this will work, we implement the setcaps */
732 gst_pad_set_caps (otherpad, othercaps);
736 gst_object_unref (otherpeer);
738 gst_caps_unref (othercaps);
740 trans->negotiated = ret;
742 gst_object_unref (trans);
749 GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps);
755 GST_DEBUG_OBJECT (trans,
756 "transform returned useless %" GST_PTR_FORMAT, othercaps);
760 no_transform_possible:
762 GST_DEBUG_OBJECT (trans,
763 "transform could not transform %" GST_PTR_FORMAT
764 " in anything we support", caps);
770 GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
776 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
777 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
783 GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
784 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
790 /* Allocate a buffer using gst_pad_alloc_buffer.
792 * This function can trigger a renegotiation on the source pad when the
793 * peer alloc_buffer function sets new caps. Since we currently are
794 * processing a buffer on the sinkpad when this function is called, we cannot
795 * reconfigure the transform with sinkcaps different from those of the current
796 * buffer. FIXME, we currently don't check if the pluging can transform to the
797 * new srcpad caps using the same sinkcaps, we alloc a proper outbuf buffer
801 gst_base_transform_prepare_output_buf (GstBaseTransform * trans,
802 GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
804 GstBaseTransformClass *bclass;
805 GstFlowReturn ret = GST_FLOW_OK;
806 gboolean copy_inbuf = FALSE;
808 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
810 /* we cannot reconfigure the element yet as we are still processing
811 * the old buffer. We will therefore delay the reconfiguration of the
812 * element until we have processed this last buffer. */
813 trans->delay_configure = TRUE;
814 /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS
815 macro. If a set_caps occurs during this function this caps will become
816 invalid. We want to keep them during preparation of the output buffer. */
818 gst_caps_ref (out_caps);
820 /* see if the subclass wants to alloc a buffer */
821 if (bclass->prepare_output_buffer) {
823 bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
825 if (ret != GST_FLOW_OK)
829 /* See if we want to prepare the buffer for in place output */
830 if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
831 && bclass->transform_ip) {
832 if (gst_buffer_is_writable (in_buf)) {
833 if (trans->have_same_caps) {
834 /* Input buffer is already writable and caps are the same, just ref and return it */
836 gst_buffer_ref (in_buf);
838 /* Writable buffer, but need to change caps => subbuffer */
839 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
840 gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
844 /* Make a writable buffer below and copy the data */
849 if (*out_buf == NULL) {
850 /* Sub-class didn't already provide a buffer for us. Make one */
851 ret = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET (in_buf),
852 out_size, out_caps, out_buf);
853 if (ret != GST_FLOW_OK || *out_buf == NULL)
856 /* allocated buffer could be of different caps than what we requested */
857 if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
858 /* FIXME, it is possible we can reconfigure the transform with new caps at this
859 * point but for now we just create a buffer ourselves */
860 gst_buffer_unref (*out_buf);
861 *out_buf = gst_buffer_new_and_alloc (out_size);
862 gst_buffer_set_caps (*out_buf, out_caps);
866 /* If the output buffer metadata is modifiable, copy timestamps and
868 if (*out_buf != in_buf && GST_MINI_OBJECT_REFCOUNT_VALUE (*out_buf) == 1) {
870 if (copy_inbuf && gst_buffer_is_writable (*out_buf))
871 memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
873 gst_buffer_stamp (*out_buf, in_buf);
874 GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
875 (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
876 GST_BUFFER_FLAG_DELTA_UNIT);
881 gst_caps_unref (out_caps);
882 trans->delay_configure = FALSE;
888 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
891 gboolean res = FALSE;
892 GstBaseTransformClass *bclass;
894 /* see if we have the result cached */
895 if (trans->cache_caps1 == caps) {
896 *size = trans->cache_caps1_size;
897 GST_DEBUG_OBJECT (trans, "get size returned cached 1 %d", *size);
900 if (trans->cache_caps2 == caps) {
901 *size = trans->cache_caps2_size;
902 GST_DEBUG_OBJECT (trans, "get size returned cached 2 %d", *size);
906 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
907 if (bclass->get_unit_size) {
908 res = bclass->get_unit_size (trans, caps, size);
909 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
910 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
913 if (trans->cache_caps1 == NULL) {
914 gst_caps_replace (&trans->cache_caps1, caps);
915 trans->cache_caps1_size = *size;
916 } else if (trans->cache_caps2 == NULL) {
917 gst_caps_replace (&trans->cache_caps2, caps);
918 trans->cache_caps2_size = *size;
922 GST_DEBUG ("Sub-class does not implement get_unit_size");
927 /* your upstream peer wants to send you a buffer
928 * that buffer has the given offset, size and caps
929 * you're requested to allocate a buffer
932 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
933 GstCaps * caps, GstBuffer ** buf)
935 GstBaseTransform *trans;
939 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
941 /* we cannot run this when we are transforming data and as such doing
942 * another negotiation in the transform method. */
943 g_mutex_lock (trans->transform_lock);
947 GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size, offset);
948 if (offset == GST_BUFFER_OFFSET_NONE)
949 GST_DEBUG_OBJECT (trans, "... and offset NONE");
951 GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
953 /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
954 * a renegotiation and change that to FALSE */
955 if (trans->have_same_caps) {
956 /* request a buffer with the same caps */
957 GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
959 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
961 /* if we are configured, request a buffer with the src caps */
962 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
967 GST_DEBUG_OBJECT (trans, "calling transform_size");
968 if (!gst_base_transform_transform_size (trans,
969 GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
970 gst_caps_unref (srccaps);
974 res = gst_pad_alloc_buffer (trans->srcpad, offset, new_size, srccaps, buf);
975 gst_caps_unref (srccaps);
978 if (res == GST_FLOW_OK && !trans->have_same_caps) {
979 /* note that we might have had same caps before, but calling the
980 alloc_buffer caused setcaps to switch us out of in_place -- in any case
981 the alloc_buffer served to transmit caps information but we can't use the
982 buffer. fall through and allocate a buffer corresponding to our sink
984 GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
985 GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
990 if (!gst_base_transform_transform_size (trans,
991 GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
992 sinkcaps, &new_size)) {
993 gst_caps_unref (srccaps);
994 gst_caps_unref (sinkcaps);
998 gst_buffer_unref (*buf);
1000 *buf = gst_buffer_new_and_alloc (new_size);
1001 gst_buffer_set_caps (*buf, sinkcaps);
1002 GST_BUFFER_OFFSET (*buf) = offset;
1005 gst_caps_unref (srccaps);
1006 gst_caps_unref (sinkcaps);
1008 g_mutex_unlock (trans->transform_lock);
1010 gst_object_unref (trans);
1016 /* let the default allocator handle it */
1017 GST_DEBUG_OBJECT (trans, "not configured");
1019 gst_buffer_unref (*buf);
1022 g_mutex_unlock (trans->transform_lock);
1023 gst_object_unref (trans);
1028 /* let the default allocator handle it */
1029 GST_DEBUG_OBJECT (trans, "unknown size");
1031 gst_buffer_unref (*buf);
1034 g_mutex_unlock (trans->transform_lock);
1035 gst_object_unref (trans);
1041 gst_base_transform_event (GstPad * pad, GstEvent * event)
1043 GstBaseTransform *trans;
1044 GstBaseTransformClass *bclass;
1045 gboolean ret = TRUE;
1047 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1048 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1051 ret = bclass->event (trans, event);
1054 ret = gst_pad_event_default (pad, event);
1056 gst_object_unref (trans);
1062 gst_base_transform_eventfunc (GstBaseTransform * trans, GstEvent * event)
1064 switch (GST_EVENT_TYPE (event)) {
1065 case GST_EVENT_FLUSH_START:
1067 case GST_EVENT_FLUSH_STOP:
1068 /* we need new segment info after the flush. */
1069 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1075 case GST_EVENT_NEWSEGMENT:
1079 gint64 start, stop, time;
1082 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
1085 gst_segment_set_newsegment (&trans->segment, update, rate, format, start,
1088 trans->have_newsegment = TRUE;
1090 if (format == GST_FORMAT_TIME) {
1091 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT
1092 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1093 ", accum %" GST_TIME_FORMAT,
1094 GST_TIME_ARGS (trans->segment.start),
1095 GST_TIME_ARGS (trans->segment.stop),
1096 GST_TIME_ARGS (trans->segment.time),
1097 GST_TIME_ARGS (trans->segment.accum));
1099 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1100 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1101 ", accum %" G_GINT64_FORMAT,
1102 trans->segment.start, trans->segment.stop,
1103 trans->segment.time, trans->segment.accum);
1114 static GstFlowReturn
1115 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1116 GstBuffer ** outbuf)
1118 GstBaseTransformClass *bclass;
1119 GstFlowReturn ret = GST_FLOW_OK;
1121 gboolean want_in_place;
1123 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1125 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1126 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1127 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1128 GST_BUFFER_OFFSET (inbuf));
1130 GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1131 inbuf, GST_BUFFER_SIZE (inbuf));
1133 /* Don't allow buffer handling before negotiation, except in passthrough mode
1134 * or if the class doesn't implement a set_caps function (in which case it doesn't
1137 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1138 goto not_negotiated;
1140 if (trans->passthrough) {
1141 /* In passthrough mode, give transform_ip a look at the
1142 * buffer, without making it writable, or just push the
1144 GST_LOG_OBJECT (trans, "element is in passthrough mode");
1146 if (bclass->transform_ip)
1147 ret = bclass->transform_ip (trans, inbuf);
1154 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1157 if (want_in_place) {
1158 /* If want_in_place is TRUE, we may need to prepare a new output buffer
1159 * Sub-classes can implement a prepare_output_buffer function as they
1161 GST_LOG_OBJECT (trans, "doing inplace transform");
1163 ret = gst_base_transform_prepare_output_buf (trans, inbuf,
1164 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
1165 if (G_UNLIKELY (ret != GST_FLOW_OK))
1168 ret = bclass->transform_ip (trans, *outbuf);
1171 GST_LOG_OBJECT (trans, "doing non-inplace transform");
1173 /* not transforming inplace, figure out the output size */
1174 if (trans->always_in_place) {
1175 out_size = GST_BUFFER_SIZE (inbuf);
1177 if (!gst_base_transform_transform_size (trans,
1178 GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
1179 GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
1181 /* we have an error */
1186 /* no in place transform, get buffer, this might renegotiate. */
1187 ret = gst_base_transform_prepare_output_buf (trans, inbuf, out_size,
1188 GST_PAD_CAPS (trans->srcpad), outbuf);
1189 if (ret != GST_FLOW_OK)
1192 if (bclass->transform)
1193 ret = bclass->transform (trans, inbuf, *outbuf);
1195 ret = GST_FLOW_NOT_SUPPORTED;
1198 /* if we got renegotiated we can configure now */
1199 if (trans->pending_configure) {
1203 gst_base_transform_configure_caps (trans,
1204 GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
1206 trans->pending_configure = FALSE;
1209 goto configure_failed;
1211 gst_buffer_unref (inbuf);
1218 gst_buffer_unref (inbuf);
1219 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1220 ("not negotiated"), ("not negotiated"));
1221 return GST_FLOW_NOT_NEGOTIATED;
1225 gst_buffer_unref (inbuf);
1226 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1227 ("subclass did not specify output size"),
1228 ("subclass did not specify output size"));
1229 return GST_FLOW_ERROR;
1233 gst_buffer_unref (inbuf);
1234 GST_DEBUG_OBJECT (trans, "could not get buffer from pool");
1239 gst_buffer_unref (inbuf);
1240 GST_DEBUG_OBJECT (trans, "could not negotiate");
1241 return GST_FLOW_NOT_NEGOTIATED;
1245 /* FIXME, getrange is broken, need to pull range from the other
1246 * end based on the transform_size result.
1248 static GstFlowReturn
1249 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1250 guint length, GstBuffer ** buffer)
1252 GstBaseTransform *trans;
1256 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1258 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1259 if (ret == GST_FLOW_OK) {
1260 g_mutex_lock (trans->transform_lock);
1261 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1262 g_mutex_unlock (trans->transform_lock);
1265 gst_object_unref (trans);
1270 static GstFlowReturn
1271 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1273 GstBaseTransform *trans;
1275 GstBuffer *outbuf = NULL;
1277 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1279 /* protect transform method and concurrent buffer alloc */
1280 g_mutex_lock (trans->transform_lock);
1281 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1282 g_mutex_unlock (trans->transform_lock);
1284 if (ret == GST_FLOW_OK) {
1285 ret = gst_pad_push (trans->srcpad, outbuf);
1286 } else if (outbuf != NULL)
1287 gst_buffer_unref (outbuf);
1289 gst_object_unref (trans);
1295 gst_base_transform_set_property (GObject * object, guint prop_id,
1296 const GValue * value, GParamSpec * pspec)
1298 GstBaseTransform *trans;
1300 trans = GST_BASE_TRANSFORM (object);
1304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1310 gst_base_transform_get_property (GObject * object, guint prop_id,
1311 GValue * value, GParamSpec * pspec)
1313 GstBaseTransform *trans;
1315 trans = GST_BASE_TRANSFORM (object);
1319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1325 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1327 gboolean result = TRUE;
1328 GstBaseTransform *trans;
1329 GstBaseTransformClass *bclass;
1331 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1332 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1336 result = bclass->start (trans);
1338 gst_object_unref (trans);
1344 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1346 gboolean result = FALSE;
1347 GstBaseTransform *trans;
1348 GstBaseTransformClass *bclass;
1350 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1351 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1353 result = gst_pad_activate_pull (trans->sinkpad, active);
1356 if (result && bclass->start)
1357 result &= bclass->start (trans);
1359 gst_object_unref (trans);
1364 static GstStateChangeReturn
1365 gst_base_transform_change_state (GstElement * element,
1366 GstStateChange transition)
1368 GstBaseTransform *trans;
1369 GstBaseTransformClass *bclass;
1370 GstStateChangeReturn result;
1372 trans = GST_BASE_TRANSFORM (element);
1373 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1376 switch (transition) {
1377 case GST_STATE_CHANGE_NULL_TO_READY:
1379 case GST_STATE_CHANGE_READY_TO_PAUSED:
1380 GST_OBJECT_LOCK (trans);
1381 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1382 trans->have_same_caps =
1383 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1384 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1386 trans->have_same_caps = trans->passthrough;
1387 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1388 trans->negotiated = FALSE;
1389 trans->have_newsegment = FALSE;
1390 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1391 GST_OBJECT_UNLOCK (trans);
1393 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1395 case GST_STATE_CHANGE_PAUSED_TO_READY:
1396 gst_caps_replace (&trans->cache_caps1, NULL);
1397 gst_caps_replace (&trans->cache_caps2, NULL);
1402 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1404 switch (transition) {
1405 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1407 case GST_STATE_CHANGE_PAUSED_TO_READY:
1409 result = bclass->stop (trans);
1411 case GST_STATE_CHANGE_READY_TO_NULL:
1421 * gst_base_transform_set_passthrough:
1422 * @trans: the #GstBaseTransform to set
1423 * @passthrough: boolean indicating passthrough mode.
1425 * Set passthrough mode for this filter by default. This is mostly
1426 * useful for filters that do not care about negotiation.
1428 * Always TRUE for filters which don't implement either a transform
1429 * or transform_ip method.
1434 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1435 gboolean passthrough)
1437 GstBaseTransformClass *bclass;
1439 g_return_if_fail (trans != NULL);
1441 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1443 GST_OBJECT_LOCK (trans);
1444 if (passthrough == FALSE) {
1445 if (bclass->transform_ip || bclass->transform)
1446 trans->passthrough = FALSE;
1448 trans->passthrough = TRUE;
1451 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
1452 GST_OBJECT_UNLOCK (trans);
1456 * gst_base_transform_is_passthrough:
1457 * @trans: the #GstBaseTransform to query
1459 * See if @trans is configured as a passthrough transform.
1461 * Returns: TRUE is the transform is configured in passthrough mode.
1466 gst_base_transform_is_passthrough (GstBaseTransform * trans)
1470 g_return_val_if_fail (trans != NULL, FALSE);
1472 GST_OBJECT_LOCK (trans);
1473 result = trans->passthrough;
1474 GST_OBJECT_UNLOCK (trans);
1480 * gst_base_transform_set_in_place:
1481 * @trans: the #GstBaseTransform to modify
1482 * @in_place: Boolean value indicating that we would like to operate
1483 * on in_place buffers.
1485 * Determines whether a non-writable buffer will be copied before passing
1486 * to the transform_ip function.
1488 * <listitem>Always TRUE if no transform function is implemented.</listitem>
1489 * <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
1495 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
1497 GstBaseTransformClass *bclass;
1499 g_return_if_fail (trans != NULL);
1501 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1503 GST_OBJECT_LOCK (trans);
1506 if (bclass->transform_ip) {
1507 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
1508 trans->always_in_place = TRUE;
1511 if (bclass->transform) {
1512 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
1513 trans->always_in_place = FALSE;
1517 GST_OBJECT_UNLOCK (trans);
1521 * gst_base_transform_is_in_place:
1522 * @trans: the #GstBaseTransform to query
1524 * See if @trans is configured as a in_place transform.
1526 * Returns: TRUE is the transform is configured in in_place mode.
1531 gst_base_transform_is_in_place (GstBaseTransform * trans)
1535 g_return_val_if_fail (trans != NULL, FALSE);
1537 GST_OBJECT_LOCK (trans);
1538 result = trans->always_in_place;
1539 GST_OBJECT_UNLOCK (trans);