2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2005 Wim Taymans <wim@fluendo.com>
4 * 2005 Andy Wingo <wingo@fluendo.com>
5 * 2005 Thomas Vander Stichele <thomas at apestaart dot org>
6 * 2008 Wim Taymans <wim.taymans@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:gstbasetransform
26 * @short_description: Base class for simple transform filters
27 * @see_also: #GstBaseSrc, #GstBaseSink
29 * This base class is for filter elements that process data.
33 * <listitem><para>one sinkpad and one srcpad</para></listitem>
35 * Possible formats on sink and source pad implemented
36 * with custom transform_caps function. By default uses
37 * same format on sink and source.
39 * <listitem><para>Handles state changes</para></listitem>
40 * <listitem><para>Does flushing</para></listitem>
41 * <listitem><para>Push mode</para></listitem>
43 * Pull mode if the sub-class transform can operate on arbitrary data
48 * <title>Use Cases</title>
52 * <itemizedlist><title>Passthrough mode</title>
54 * Element has no interest in modifying the buffer. It may want to inspect it,
55 * in which case the element should have a transform_ip function. If there
56 * is no transform_ip function in passthrough mode, the buffer is pushed
60 * On the GstBaseTransformClass is the passthrough_on_same_caps variable
61 * which will automatically set/unset passthrough based on whether the
62 * element negotiates the same caps on both pads.
65 * passthrough_on_same_caps on an element that doesn't implement a
66 * transform_caps function is useful for elements that only inspect data
71 * <title>Example elements</title>
72 * <listitem>Level</listitem>
73 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
74 * certain modes.</listitem>
79 * <title>Modifications in-place - input buffer and output buffer are the
82 * The element must implement a transform_ip function.
85 * Output buffer size must <= input buffer size
88 * If the always_in_place flag is set, non-writable buffers will be copied
89 * and passed to the transform_ip function, otherwise a new buffer will be
90 * created and the transform function called.
93 * Incoming writable buffers will be passed to the transform_ip function
94 * immediately. </para></listitem>
96 * only implementing transform_ip and not transform implies always_in_place
101 * <title>Example elements</title>
102 * <listitem>Volume</listitem>
103 * <listitem>Audioconvert in certain modes (signed/unsigned
104 * conversion)</listitem>
105 * <listitem>ffmpegcolorspace in certain modes (endianness
106 * swapping)</listitem>
111 * <title>Modifications only to the caps/metadata of a buffer</title>
113 * The element does not require writable data, but non-writable buffers
114 * should be subbuffered so that the meta-information can be replaced.
117 * Elements wishing to operate in this mode should replace the
118 * prepare_output_buffer method to create subbuffers of the input buffer
119 * and set always_in_place to TRUE
123 * <title>Example elements</title>
124 * <listitem>Capsfilter when setting caps on outgoing buffers that have
126 * <listitem>identity when it is going to re-timestamp buffers by
127 * datarate.</listitem>
131 * <itemizedlist><title>Normal mode</title>
133 * always_in_place flag is not set, or there is no transform_ip function
136 * Element will receive an input buffer and output buffer to operate on.
139 * Output buffer is allocated by calling the prepare_output_buffer function.
143 * <title>Example elements</title>
144 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
145 * scaling/conversions</listitem>
149 * <itemizedlist><title>Special output buffer allocations</title>
151 * Elements which need to do special allocation of their output buffers
152 * other than what gst_buffer_pad_alloc allows should implement a
153 * prepare_output_buffer method, which calls the parent implementation and
154 * passes the newly allocated buffer.
158 * <title>Example elements</title>
159 * <listitem>efence</listitem>
166 * <title>Sub-class settable flags on GstBaseTransform</title>
170 * <itemizedlist><title>passthrough</title>
172 * Implies that in the current configuration, the sub-class is not
173 * interested in modifying the buffers.
176 * Elements which are always in passthrough mode whenever the same caps
177 * has been negotiated on both pads can set the class variable
178 * passthrough_on_same_caps to have this behaviour automatically.
183 * <itemizedlist><title>always_in_place</title>
185 * Determines whether a non-writable buffer will be copied before passing
186 * to the transform_ip function.
189 * Implied TRUE if no transform function is implemented.
192 * Implied FALSE if ONLY transform function is implemented.
208 #include "../../../gst/gst_private.h"
209 #include "../../../gst/gst-i18n-lib.h"
210 #include "gstbasetransform.h"
211 #include <gst/gstmarshal.h>
213 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
214 #define GST_CAT_DEFAULT gst_base_transform_debug
216 /* BaseTransform signals and args */
223 #define DEFAULT_PROP_QOS FALSE
231 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \
232 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
234 struct _GstBaseTransformPrivate
236 /* QoS *//* with LOCK */
237 gboolean qos_enabled;
239 GstClockTime earliest_time;
240 /* previous buffer had a discont */
243 GstActivateMode pad_mode;
247 /* caps used for allocating buffers */
248 gboolean proxy_alloc;
253 * This flag controls if basetransform should explicitly
254 * do a pad alloc when it receives a buffer even if it operates on
255 * passthrough, this is needed to check for downstream caps suggestions
256 * and this newly alloc'ed buffer is discarded.
258 * Without this flag basetransform would try a pad alloc whenever it
259 * gets a new buffer and pipelines like:
260 * "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
261 * Would have a 3 pad allocs for each buffer pushed downstream from the src.
263 * This flag is set to TRUE on start up, on setcaps and when a buffer is
264 * pushed downstream. It is set to FALSE after a pad alloc has been requested
266 * The rationale is that when a pad alloc flows through the pipeline, all
267 * basetransform elements on passthrough will avoid pad alloc'ing when they
270 gboolean force_alloc;
272 /* upstream caps and size suggestions */
273 GstCaps *sink_suggest;
275 gboolean suggest_pending;
277 gboolean reconfigure;
283 GstClockTime last_stop_out;
284 GList *delayed_events;
287 static GstElementClass *parent_class = NULL;
289 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
290 static void gst_base_transform_init (GstBaseTransform * trans,
291 GstBaseTransformClass * klass);
292 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
293 * trans, GstBuffer * input, GstBuffer ** buf);
296 gst_base_transform_get_type (void)
298 static volatile gsize base_transform_type = 0;
300 if (g_once_init_enter (&base_transform_type)) {
302 static const GTypeInfo base_transform_info = {
303 sizeof (GstBaseTransformClass),
306 (GClassInitFunc) gst_base_transform_class_init,
309 sizeof (GstBaseTransform),
311 (GInstanceInitFunc) gst_base_transform_init,
314 _type = g_type_register_static (GST_TYPE_ELEMENT,
315 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
316 g_once_init_leave (&base_transform_type, _type);
318 return base_transform_type;
321 static void gst_base_transform_finalize (GObject * object);
322 static void gst_base_transform_set_property (GObject * object, guint prop_id,
323 const GValue * value, GParamSpec * pspec);
324 static void gst_base_transform_get_property (GObject * object, guint prop_id,
325 GValue * value, GParamSpec * pspec);
326 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
328 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
330 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
332 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
333 GstCaps * caps, guint * size);
335 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
336 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
338 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
339 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
341 static gboolean gst_base_transform_check_get_range (GstPad * pad);
342 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
343 guint length, GstBuffer ** buffer);
344 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
346 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
347 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
348 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
349 GstPadDirection direction, GstCaps * caps);
350 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
351 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
352 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
353 static gboolean gst_base_transform_query (GstPad * pad, GstQuery * query);
354 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
355 GstPadDirection direction, GstQuery * query);
356 static const GstQueryType *gst_base_transform_query_type (GstPad * pad);
358 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
361 gst_base_transform_drop_delayed_events (GstBaseTransform * trans)
363 GST_OBJECT_LOCK (trans);
364 if (trans->priv->delayed_events) {
365 g_list_foreach (trans->priv->delayed_events, (GFunc) gst_event_unref, NULL);
366 g_list_free (trans->priv->delayed_events);
367 trans->priv->delayed_events = NULL;
369 GST_OBJECT_UNLOCK (trans);
373 gst_base_transform_finalize (GObject * object)
375 GstBaseTransform *trans;
377 trans = GST_BASE_TRANSFORM (object);
379 gst_base_transform_drop_delayed_events (trans);
380 gst_caps_replace (&trans->priv->sink_suggest, NULL);
381 g_mutex_free (trans->transform_lock);
383 G_OBJECT_CLASS (parent_class)->finalize (object);
387 gst_base_transform_class_init (GstBaseTransformClass * klass)
389 GObjectClass *gobject_class;
391 gobject_class = G_OBJECT_CLASS (klass);
393 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
394 "basetransform element");
396 GST_DEBUG ("gst_base_transform_class_init");
398 g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
400 parent_class = g_type_class_peek_parent (klass);
402 gobject_class->set_property = gst_base_transform_set_property;
403 gobject_class->get_property = gst_base_transform_get_property;
405 g_object_class_install_property (gobject_class, PROP_QOS,
406 g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
407 DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
409 gobject_class->finalize = gst_base_transform_finalize;
411 klass->passthrough_on_same_caps = FALSE;
412 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
413 klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
415 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
416 klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
420 gst_base_transform_init (GstBaseTransform * trans,
421 GstBaseTransformClass * bclass)
423 GstPadTemplate *pad_template;
425 GST_DEBUG ("gst_base_transform_init");
427 trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
430 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
431 g_return_if_fail (pad_template != NULL);
432 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
433 gst_pad_set_getcaps_function (trans->sinkpad,
434 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
435 gst_pad_set_acceptcaps_function (trans->sinkpad,
436 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
437 gst_pad_set_setcaps_function (trans->sinkpad,
438 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
439 gst_pad_set_event_function (trans->sinkpad,
440 GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
441 gst_pad_set_chain_function (trans->sinkpad,
442 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
443 gst_pad_set_activatepush_function (trans->sinkpad,
444 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
445 gst_pad_set_bufferalloc_function (trans->sinkpad,
446 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
447 gst_pad_set_query_function (trans->sinkpad,
448 GST_DEBUG_FUNCPTR (gst_base_transform_query));
449 gst_pad_set_query_type_function (trans->sinkpad,
450 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
451 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
454 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
455 g_return_if_fail (pad_template != NULL);
456 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
457 gst_pad_set_getcaps_function (trans->srcpad,
458 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
459 gst_pad_set_acceptcaps_function (trans->srcpad,
460 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
461 gst_pad_set_event_function (trans->srcpad,
462 GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
463 gst_pad_set_checkgetrange_function (trans->srcpad,
464 GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
465 gst_pad_set_getrange_function (trans->srcpad,
466 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
467 gst_pad_set_activatepull_function (trans->srcpad,
468 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
469 gst_pad_set_query_function (trans->srcpad,
470 GST_DEBUG_FUNCPTR (gst_base_transform_query));
471 gst_pad_set_query_type_function (trans->srcpad,
472 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
473 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
475 trans->transform_lock = g_mutex_new ();
476 trans->pending_configure = FALSE;
477 trans->priv->qos_enabled = DEFAULT_PROP_QOS;
478 trans->cache_caps1 = NULL;
479 trans->cache_caps2 = NULL;
480 trans->priv->pad_mode = GST_ACTIVATE_NONE;
481 trans->priv->gap_aware = FALSE;
482 trans->priv->delayed_events = NULL;
484 trans->passthrough = FALSE;
485 if (bclass->transform == NULL) {
486 /* If no transform function, always_in_place is TRUE */
487 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
488 trans->always_in_place = TRUE;
490 if (bclass->transform_ip == NULL) {
491 GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
492 trans->passthrough = TRUE;
496 trans->priv->processed = 0;
497 trans->priv->dropped = 0;
498 trans->priv->force_alloc = TRUE;
501 /* given @caps on the src or sink pad (given by @direction)
502 * calculate the possible caps on the other pad.
504 * Returns new caps, unref after usage.
507 gst_base_transform_transform_caps (GstBaseTransform * trans,
508 GstPadDirection direction, GstCaps * caps)
511 GstBaseTransformClass *klass;
516 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
518 /* if there is a custom transform function, use this */
519 if (klass->transform_caps) {
523 /* start with empty caps */
524 ret = gst_caps_new_empty ();
525 GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
527 if (gst_caps_is_any (caps)) {
528 /* for any caps we still have to call the transform function */
529 GST_DEBUG_OBJECT (trans, "from: ANY");
530 temp = klass->transform_caps (trans, direction, caps);
531 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
533 temp = gst_caps_make_writable (temp);
534 gst_caps_append (ret, temp);
536 gint n = gst_caps_get_size (caps);
537 /* we send caps with just one structure to the transform
538 * function as this is easier for the element */
539 for (i = 0; i < n; i++) {
542 nth = gst_caps_copy_nth (caps, i);
543 GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
544 temp = klass->transform_caps (trans, direction, nth);
545 gst_caps_unref (nth);
546 GST_LOG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
548 temp = gst_caps_make_writable (temp);
550 /* here we need to only append those structures, that are not yet
551 * in there, we use the merge function for this */
552 gst_caps_merge (ret, temp);
554 GST_LOG_OBJECT (trans, " merged[%d]: %" GST_PTR_FORMAT, i, ret);
556 GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
557 /* FIXME: we can't do much simplification here because we don't really want to
558 * change the caps order
559 gst_caps_do_simplify (ret);
560 GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
564 GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
565 /* no transform function, use the identity transform */
566 ret = gst_caps_ref (caps);
569 GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
575 /* transform a buffer of @size with @caps on the pad with @direction to
576 * the size of a buffer with @othercaps and store the result in @othersize
578 * We have two ways of doing this:
579 * 1) use a custom transform size function, this is for complicated custom
580 * cases with no fixed unit_size.
581 * 2) use the unit_size functions where there is a relationship between the
582 * caps and the size of a buffer.
585 gst_base_transform_transform_size (GstBaseTransform * trans,
586 GstPadDirection direction, GstCaps * caps,
587 guint size, GstCaps * othercaps, guint * othersize)
589 guint inunitsize, outunitsize, units;
590 GstBaseTransformClass *klass;
593 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
595 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
596 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
597 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
599 if (klass->transform_size) {
600 /* if there is a custom transform function, use this */
601 ret = klass->transform_size (trans, direction, caps, size, othercaps,
603 } else if (klass->get_unit_size == NULL) {
604 /* if there is no transform_size and no unit_size, it means the
605 * element does not modify the size of a buffer */
609 /* there is no transform_size function, we have to use the unit_size
610 * functions. This method assumes there is a fixed unit_size associated with
611 * each caps. We provide the same amount of units on both sides. */
612 if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
615 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
618 /* input size must be a multiple of the unit_size of the input caps */
619 if (inunitsize == 0 || (size % inunitsize != 0))
622 /* get the amount of units */
623 units = size / inunitsize;
625 /* now get the unit size of the output */
626 if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
629 /* the output size is the unit_size times the amount of units on the
631 *othersize = units * outunitsize;
632 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
641 GST_DEBUG_OBJECT (trans, "could not get in_size");
642 g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
647 GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
649 g_warning ("%s: size %u is not a multiple of unit size %u",
650 GST_ELEMENT_NAME (trans), size, inunitsize);
655 GST_DEBUG_OBJECT (trans, "could not get out_size");
656 g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
661 /* get the caps that can be handled by @pad. We perform:
663 * - take the caps of peer of otherpad,
664 * - filter against the padtemplate of otherpad,
665 * - calculate all transforms of remaining caps
666 * - filter against template of @pad
668 * If there is no peer, we simply return the caps of the padtemplate of pad.
671 gst_base_transform_getcaps (GstPad * pad)
673 GstBaseTransform *trans;
675 const GstCaps *templ;
676 GstCaps *peercaps, *caps, *temp;
678 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
680 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
682 /* we can do what the peer can */
683 peercaps = gst_pad_peer_get_caps_reffed (otherpad);
685 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peercaps);
687 /* filtered against our padtemplate on the other side */
688 templ = gst_pad_get_pad_template_caps (otherpad);
689 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
690 temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
691 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
693 temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
694 GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
698 /* then see what we can transform this to */
699 caps = gst_base_transform_transform_caps (trans,
700 GST_PAD_DIRECTION (otherpad), temp);
701 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
702 gst_caps_unref (temp);
706 /* and filter against the template of this pad */
707 templ = gst_pad_get_pad_template_caps (pad);
708 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
709 /* We keep the caps sorted like the returned caps */
710 temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
711 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
712 gst_caps_unref (caps);
716 /* Now try if we can put the untransformed downstream caps first */
717 temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
718 if (!gst_caps_is_empty (temp)) {
719 gst_caps_merge (temp, caps);
722 gst_caps_unref (temp);
727 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
730 gst_caps_unref (peercaps);
732 gst_object_unref (trans);
737 /* function triggered when the in and out caps are negotiated and need
738 * to be configured in the subclass. */
740 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
744 GstBaseTransformClass *klass;
746 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
748 GST_DEBUG_OBJECT (trans, "in caps: %" GST_PTR_FORMAT, in);
749 GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
751 /* clear the cache */
752 gst_caps_replace (&trans->cache_caps1, NULL);
753 gst_caps_replace (&trans->cache_caps2, NULL);
755 /* figure out same caps state */
756 trans->have_same_caps = gst_caps_is_equal (in, out);
757 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
759 /* If we've a transform_ip method and same input/output caps, set in_place
760 * by default. If for some reason the sub-class prefers using a transform
761 * function, it can clear the in place flag in the set_caps */
762 gst_base_transform_set_in_place (trans,
763 klass->transform_ip && trans->have_same_caps);
765 /* Set the passthrough if the class wants passthrough_on_same_caps
766 * and we have the same caps on each pad */
767 if (klass->passthrough_on_same_caps)
768 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
770 /* now configure the element with the caps */
771 if (klass->set_caps) {
772 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
773 ret = klass->set_caps (trans, in, out);
776 GST_OBJECT_LOCK (trans);
777 /* make sure we reevaluate how the buffer_alloc works wrt to proxy allocating
778 * the buffer. FIXME, this triggers some quite heavy codepaths that don't need
780 trans->priv->suggest_pending = TRUE;
781 GST_OBJECT_UNLOCK (trans);
782 trans->negotiated = ret;
787 /* check if caps @in on @pad can be transformed to @out on the other pad.
788 * We don't have a vmethod to test this yet so we have to do a somewhat less
789 * efficient check for this.
792 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
793 GstCaps * in, GstCaps * out)
797 /* convert the in caps to all possible out caps */
799 gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
801 /* check if transform is empty */
802 if (!othercaps || gst_caps_is_empty (othercaps))
805 /* check if the out caps is a subset of the othercaps */
806 if (!gst_caps_can_intersect (out, othercaps))
810 gst_caps_unref (othercaps);
812 GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
813 GST_DEBUG_OBJECT (trans, "to %" GST_PTR_FORMAT, out);
820 GST_DEBUG_OBJECT (trans,
821 "transform returned useless %" GST_PTR_FORMAT, othercaps);
823 gst_caps_unref (othercaps);
828 GST_DEBUG_OBJECT (trans, "no subset");
830 gst_caps_unref (othercaps);
835 /* given a fixed @caps on @pad, create the best possible caps for the
837 * @caps must be fixed when calling this function.
839 * This function calls the transform caps vmethod of the basetransform to figure
840 * out the possible target formats. It then tries to select the best format from
843 * - attempt passthrough if the target caps is a superset of the input caps
844 * - fixating by using peer caps
845 * - fixating with transform fixate function
846 * - fixating with pad fixate functions.
848 * this function returns a caps that can be transformed into and is accepted by
852 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
855 GstBaseTransformClass *klass;
856 GstPad *otherpad, *otherpeer;
858 gboolean peer_checked = FALSE;
861 /* caps must be fixed here, this is a programming error if it's not */
862 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
864 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
866 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
867 otherpeer = gst_pad_get_peer (otherpad);
869 /* see how we can transform the input caps. We need to do this even for
870 * passthrough because it might be possible that this element cannot support
871 * passthrough at all. */
872 othercaps = gst_base_transform_transform_caps (trans,
873 GST_PAD_DIRECTION (pad), caps);
875 /* The caps we can actually output is the intersection of the transformed
876 * caps with the pad template for the pad */
879 const GstCaps *templ_caps;
881 templ_caps = gst_pad_get_pad_template_caps (otherpad);
882 GST_DEBUG_OBJECT (trans,
883 "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
886 gst_caps_intersect_full (othercaps, templ_caps,
887 GST_CAPS_INTERSECT_FIRST);
889 gst_caps_unref (othercaps);
890 othercaps = intersect;
893 /* check if transform is empty */
894 if (!othercaps || gst_caps_is_empty (othercaps))
897 /* if the othercaps are not fixed, we need to fixate them, first attempt
898 * is by attempting passthrough if the othercaps are a superset of caps. */
899 /* FIXME. maybe the caps is not fixed because it has multiple structures of
901 is_fixed = gst_caps_is_fixed (othercaps);
903 GST_DEBUG_OBJECT (trans,
904 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
906 /* see if the target caps are a superset of the source caps, in this
907 * case we can try to perform passthrough */
908 if (gst_caps_can_intersect (othercaps, caps)) {
909 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
911 /* try passthrough. we know it's fixed, because caps is fixed */
912 if (gst_pad_accept_caps (otherpeer, caps)) {
913 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
914 /* peer accepted unmodified caps, we free the original non-fixed
915 * caps and work with the passthrough caps */
916 gst_caps_unref (othercaps);
917 othercaps = gst_caps_ref (caps);
919 /* mark that we checked othercaps with the peer, this
920 * makes sure we don't call accept_caps again with these same
924 GST_DEBUG_OBJECT (trans,
925 "peer did not accept %" GST_PTR_FORMAT, caps);
928 GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
929 gst_caps_unref (othercaps);
930 othercaps = gst_caps_ref (caps);
936 /* second attempt at fixation is done by intersecting with
938 if (!is_fixed && otherpeer) {
939 /* intersect against what the peer can do */
943 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
945 peercaps = gst_pad_get_caps_reffed (otherpeer);
946 intersect = gst_caps_intersect (peercaps, othercaps);
947 gst_caps_unref (peercaps);
948 gst_caps_unref (othercaps);
949 othercaps = intersect;
950 peer_checked = FALSE;
952 is_fixed = gst_caps_is_fixed (othercaps);
954 GST_DEBUG_OBJECT (trans,
955 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
958 if (gst_caps_is_empty (othercaps))
959 goto no_transform_possible;
961 /* third attempt at fixation, call the fixate vmethod and
962 * ultimately call the pad fixate function. */
964 GST_DEBUG_OBJECT (trans,
965 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
966 othercaps, GST_DEBUG_PAD_NAME (otherpad));
968 /* since we have no other way to fixate left, we might as well just take
969 * the first of the caps list and fixate that */
971 /* FIXME: when fixating using the vmethod, it might make sense to fixate
972 * each of the caps; but Wim doesn't see a use case for that yet */
973 gst_caps_truncate (othercaps);
974 peer_checked = FALSE;
976 if (klass->fixate_caps) {
977 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
978 " using caps %" GST_PTR_FORMAT
979 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
980 GST_DEBUG_PAD_NAME (otherpad));
981 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
982 is_fixed = gst_caps_is_fixed (othercaps);
984 /* if still not fixed, no other option but to let the default pad fixate
985 * function do its job */
987 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
988 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
989 GST_DEBUG_PAD_NAME (otherpad));
990 gst_pad_fixate_caps (otherpad, othercaps);
991 is_fixed = gst_caps_is_fixed (othercaps);
993 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
995 GST_DEBUG ("caps are fixed");
996 /* else caps are fixed but the subclass may want to add fields */
997 if (klass->fixate_caps) {
998 othercaps = gst_caps_make_writable (othercaps);
1000 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1001 " using caps %" GST_PTR_FORMAT
1002 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1003 GST_DEBUG_PAD_NAME (otherpad));
1005 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1006 is_fixed = gst_caps_is_fixed (othercaps);
1010 /* caps should be fixed now, if not we have to fail. */
1012 goto could_not_fixate;
1014 /* and peer should accept, don't check again if we already checked the
1015 * othercaps against the peer. */
1016 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
1017 goto peer_no_accept;
1019 GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1020 ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1023 gst_object_unref (otherpeer);
1030 GST_DEBUG_OBJECT (trans,
1031 "transform returned useless %" GST_PTR_FORMAT, othercaps);
1034 no_transform_possible:
1036 GST_DEBUG_OBJECT (trans,
1037 "transform could not transform %" GST_PTR_FORMAT
1038 " in anything we support", caps);
1043 GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1048 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1049 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1055 gst_object_unref (otherpeer);
1057 gst_caps_unref (othercaps);
1063 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1064 GstPadDirection direction, GstCaps * caps)
1068 GstCaps *othercaps = NULL;
1070 gboolean ret = TRUE;
1073 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1075 /* we need fixed caps for the check, fall back to the default implementation
1077 if (!gst_caps_is_fixed (caps))
1082 GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1084 /* get all the formats we can handle on this pad */
1085 if (direction == GST_PAD_SRC)
1086 allowed = gst_pad_get_caps_reffed (trans->srcpad);
1088 allowed = gst_pad_get_caps_reffed (trans->sinkpad);
1091 GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1092 goto no_transform_possible;
1095 GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1097 /* intersect with the requested format */
1098 ret = gst_caps_can_intersect (allowed, caps);
1099 gst_caps_unref (allowed);
1102 goto no_transform_possible;
1106 GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1108 /* find best possible caps for the other pad as a way to see if we can
1109 * transform this caps. */
1110 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1111 if (!othercaps || gst_caps_is_empty (othercaps))
1112 goto no_transform_possible;
1114 GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1120 /* We know it's always NULL since we never use it */
1122 gst_caps_unref (othercaps);
1128 no_transform_possible:
1130 GST_DEBUG_OBJECT (trans,
1131 "transform could not transform %" GST_PTR_FORMAT
1132 " in anything we support", caps);
1139 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1141 gboolean ret = TRUE;
1142 GstBaseTransform *trans;
1143 GstBaseTransformClass *bclass;
1145 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1146 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1148 if (bclass->accept_caps)
1149 ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1151 gst_object_unref (trans);
1156 /* called when new caps arrive on the sink or source pad,
1157 * We try to find the best caps for the other side using our _find_transform()
1158 * function. If there are caps, we configure the transform for this new
1161 * FIXME, this function is currently commutative but this should not really be
1162 * because we never set caps starting from the srcpad.
1165 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1167 GstBaseTransform *trans;
1168 GstPad *otherpad, *otherpeer;
1169 GstCaps *othercaps = NULL;
1170 gboolean ret = TRUE;
1171 GstCaps *incaps, *outcaps;
1173 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1175 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1176 otherpeer = gst_pad_get_peer (otherpad);
1178 /* if we get called recursively, we bail out now to avoid an
1180 if (GST_PAD_IS_IN_SETCAPS (otherpad))
1183 GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1185 /* find best possible caps for the other pad */
1186 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1187 if (!othercaps || gst_caps_is_empty (othercaps))
1188 goto no_transform_possible;
1190 /* configure the element now */
1191 /* make sure in and out caps are correct */
1192 if (pad == trans->sinkpad) {
1194 outcaps = othercaps;
1200 /* if we have the same caps, we can optimize and reuse the input caps */
1201 if (gst_caps_is_equal (incaps, outcaps)) {
1202 GST_INFO_OBJECT (trans, "reuse caps");
1203 gst_caps_unref (othercaps);
1204 outcaps = othercaps = gst_caps_ref (incaps);
1207 /* call configure now */
1208 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1209 goto failed_configure;
1211 /* we know this will work, we implement the setcaps */
1212 gst_pad_set_caps (otherpad, othercaps);
1214 if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1216 ret &= gst_pad_set_caps (otherpeer, othercaps);
1218 GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1224 /* new caps, force alloc on next buffer on the chain */
1225 trans->priv->force_alloc = TRUE;
1227 gst_object_unref (otherpeer);
1229 gst_caps_unref (othercaps);
1231 trans->negotiated = ret;
1233 gst_object_unref (trans);
1238 no_transform_possible:
1240 GST_WARNING_OBJECT (trans,
1241 "transform could not transform %" GST_PTR_FORMAT
1242 " in anything we support", caps);
1248 GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1249 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1256 gst_base_transform_default_query (GstBaseTransform * trans,
1257 GstPadDirection direction, GstQuery * query)
1259 gboolean ret = FALSE;
1262 otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1264 switch (GST_QUERY_TYPE (query)) {
1265 case GST_QUERY_POSITION:{
1268 gst_query_parse_position (query, &format, NULL);
1269 if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1273 if ((direction == GST_PAD_SINK)
1274 || (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
1276 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1277 trans->segment.last_stop);
1279 pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1280 trans->priv->last_stop_out);
1282 gst_query_set_position (query, format, pos);
1284 ret = gst_pad_peer_query (otherpad, query);
1289 ret = gst_pad_peer_query (otherpad, query);
1297 gst_base_transform_query (GstPad * pad, GstQuery * query)
1299 GstBaseTransform *trans;
1300 GstBaseTransformClass *bclass;
1303 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1304 if (G_UNLIKELY (trans == NULL))
1307 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1310 ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1312 ret = gst_pad_query_default (pad, query);
1314 gst_object_unref (trans);
1319 static const GstQueryType *
1320 gst_base_transform_query_type (GstPad * pad)
1322 static const GstQueryType types[] = {
1331 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1335 GstBaseTransformPrivate *priv = trans->priv;
1337 GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1339 /* we cannot convert the current buffer but we might be able to suggest a
1340 * new format upstream, try to find what the best format is. */
1341 othercaps = gst_base_transform_find_transform (trans, trans->srcpad, caps);
1344 GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1345 /* we received caps that we cannot transform. Upstream is behaving badly
1346 * because it should have checked if we could handle these caps. We can
1347 * simply ignore these caps and produce a buffer with our original caps. */
1351 GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1353 /* not a subset, we have a new upstream suggestion, remember it and
1354 * allocate a default buffer. First we try to convert the size */
1355 if (gst_base_transform_transform_size (trans,
1356 GST_PAD_SRC, caps, expsize, othercaps, &size_suggest)) {
1358 /* ok, remember the suggestions now */
1359 GST_DEBUG_OBJECT (trans,
1360 "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1361 size_suggest, othercaps);
1363 GST_OBJECT_LOCK (trans->sinkpad);
1364 if (priv->sink_suggest)
1365 gst_caps_unref (priv->sink_suggest);
1366 priv->sink_suggest = gst_caps_ref (othercaps);
1367 priv->size_suggest = size_suggest;
1368 trans->priv->suggest_pending = TRUE;
1369 GST_OBJECT_UNLOCK (trans->sinkpad);
1371 gst_caps_unref (othercaps);
1375 /* Allocate a buffer using gst_pad_alloc_buffer
1377 * This function can do renegotiation on the source pad
1379 * The output buffer is always writable. outbuf can be equal to
1380 * inbuf, the caller should be prepared for this and perform
1381 * appropriate refcounting.
1383 static GstFlowReturn
1384 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1385 GstBuffer * in_buf, GstBuffer ** out_buf)
1387 GstBaseTransformClass *bclass;
1388 GstBaseTransformPrivate *priv;
1389 GstFlowReturn ret = GST_FLOW_OK;
1390 guint outsize, newsize, expsize;
1391 gboolean discard, setcaps, copymeta;
1392 GstCaps *incaps, *oldcaps, *newcaps, *outcaps;
1394 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1400 /* figure out how to allocate a buffer based on the current configuration */
1401 if (trans->passthrough) {
1402 GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1403 /* passthrough, we don't really need to call pad alloc but we still need to
1404 * in order to get upstream negotiation. The output size is the same as the
1406 outsize = GST_BUFFER_SIZE (in_buf);
1407 /* we always alloc and discard here */
1410 gboolean want_in_place = (bclass->transform_ip != NULL)
1411 && trans->always_in_place;
1413 if (want_in_place) {
1414 GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1415 /* we alloc a buffer of the same size as the input */
1416 outsize = GST_BUFFER_SIZE (in_buf);
1417 /* only discard it when the input was not writable, otherwise, we reuse
1418 * the input buffer. */
1419 discard = gst_buffer_is_writable (in_buf);
1420 GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1422 GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1423 /* copy transform, figure out the output size */
1424 if (!gst_base_transform_transform_size (trans,
1425 GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1426 GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1430 /* never discard this buffer, we need it for storing the output */
1435 oldcaps = GST_PAD_CAPS (trans->srcpad);
1437 if (bclass->prepare_output_buffer) {
1438 GST_DEBUG_OBJECT (trans,
1439 "calling prepare buffer with caps %p %" GST_PTR_FORMAT, oldcaps,
1442 bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1445 /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1446 * update the pad caps if it wants */
1447 oldcaps = GST_PAD_CAPS (trans->srcpad);
1450 * decrease refcount again if vmethod returned refcounted in_buf. This
1451 * is because we need to make sure that the buffer is writable for the
1452 * in_place transform. The docs of the vmethod say that you should return
1453 * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1454 if (in_buf == *out_buf)
1455 gst_buffer_unref (in_buf);
1457 /* never discard the buffer from the prepare_buffer method */
1458 if (*out_buf != NULL)
1462 if (ret != GST_FLOW_OK)
1465 if (*out_buf == NULL) {
1466 if (trans->passthrough && !trans->priv->force_alloc) {
1467 GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
1468 *out_buf = gst_buffer_ref (in_buf);
1470 GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
1473 ret = gst_pad_alloc_buffer (trans->srcpad,
1474 GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1475 if (ret != GST_FLOW_OK)
1480 /* must always have a buffer by now */
1481 if (*out_buf == NULL)
1484 /* check if we got different caps on this new output buffer */
1485 newcaps = GST_BUFFER_CAPS (*out_buf);
1486 newsize = GST_BUFFER_SIZE (*out_buf);
1488 if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1490 gboolean can_convert;
1492 GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1494 incaps = GST_PAD_CAPS (trans->sinkpad);
1496 /* check if we can convert the current incaps to the new target caps */
1498 gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1502 GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1504 gst_base_transform_transform_size (trans,
1505 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1507 compute_upstream_suggestion (trans, expsize, newcaps);
1509 /* we got a suggested caps but we can't transform to it. See if there is
1510 * another downstream format that we can transform to */
1512 gst_base_transform_find_transform (trans, trans->sinkpad, incaps);
1514 if (othercaps && !gst_caps_is_empty (othercaps)) {
1515 GST_DEBUG_OBJECT (trans, "we found target caps %" GST_PTR_FORMAT,
1517 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1518 gst_buffer_set_caps (*out_buf, othercaps);
1519 gst_caps_unref (othercaps);
1520 newcaps = GST_BUFFER_CAPS (*out_buf);
1522 } else if (othercaps)
1523 gst_caps_unref (othercaps);
1526 /* it's possible that the buffer we got is of the wrong size, get the
1527 * expected size here, we will check the size if we are going to use the
1528 * buffer later on. */
1529 gst_base_transform_transform_size (trans,
1530 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1533 GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1535 /* subclass might want to add fields to the caps */
1536 if (bclass->fixate_caps != NULL) {
1537 newcaps = gst_caps_copy (newcaps);
1539 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1540 " using caps %" GST_PTR_FORMAT
1541 " on pad %s:%s using fixate_caps vmethod", newcaps, incaps,
1542 GST_DEBUG_PAD_NAME (trans->srcpad));
1543 bclass->fixate_caps (trans, GST_PAD_SINK, incaps, newcaps);
1545 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1546 gst_buffer_set_caps (*out_buf, newcaps);
1547 gst_caps_unref (newcaps);
1548 newcaps = GST_BUFFER_CAPS (*out_buf);
1551 /* caps not empty, try to renegotiate to the new format */
1552 if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1553 /* not sure we need to fail hard here, we can simply continue our
1554 * conversion with what we negotiated before */
1555 goto failed_configure;
1557 /* new format configure, and use the new output buffer */
1558 gst_pad_set_caps (trans->srcpad, newcaps);
1560 /* clear previous cached sink-pad caps, so buffer_alloc knows that
1561 * it needs to revisit the decision about whether to proxy or not: */
1562 gst_caps_replace (&priv->sink_alloc, NULL);
1563 /* if we got a buffer of the wrong size, discard it now and make sure we
1564 * allocate a properly sized buffer later. */
1565 if (newsize != expsize) {
1566 if (in_buf != *out_buf)
1567 gst_buffer_unref (*out_buf);
1572 compute_upstream_suggestion (trans, expsize, newcaps);
1574 if (in_buf != *out_buf)
1575 gst_buffer_unref (*out_buf);
1578 } else if (outsize != newsize) {
1579 GST_WARNING_OBJECT (trans, "Caps did not change but allocated size does "
1580 "not match expected size (%d != %d)", newsize, outsize);
1581 if (in_buf != *out_buf)
1582 gst_buffer_unref (*out_buf);
1586 /* these are the final output caps */
1587 outcaps = GST_PAD_CAPS (trans->srcpad);
1590 if (*out_buf == NULL) {
1592 GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1594 /* no valid buffer yet, make one, metadata is writable */
1595 *out_buf = gst_buffer_new_and_alloc (outsize);
1596 gst_buffer_copy_metadata (*out_buf, in_buf,
1597 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1599 GST_DEBUG_OBJECT (trans, "reuse input buffer");
1603 if (trans->passthrough && in_buf != *out_buf) {
1604 /* we are asked to perform a passthrough transform but the input and
1605 * output buffers are different. We have to discard the output buffer and
1606 * reuse the input buffer. */
1607 GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1611 GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1612 gst_buffer_unref (*out_buf);
1615 GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", in_buf,
1617 /* if we have different buffers, check if the metadata is ok */
1618 if (*out_buf != in_buf) {
1621 mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
1622 GST_BUFFER_FLAG_DELTA_UNIT | GST_BUFFER_FLAG_DISCONT |
1623 GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_MEDIA1 |
1624 GST_BUFFER_FLAG_MEDIA2 | GST_BUFFER_FLAG_MEDIA3;
1625 /* see if the flags and timestamps match */
1627 (GST_MINI_OBJECT_FLAGS (*out_buf) & mask) ==
1628 (GST_MINI_OBJECT_FLAGS (in_buf) & mask);
1630 GST_BUFFER_TIMESTAMP (*out_buf) != GST_BUFFER_TIMESTAMP (in_buf) ||
1631 GST_BUFFER_DURATION (*out_buf) != GST_BUFFER_DURATION (in_buf) ||
1632 GST_BUFFER_OFFSET (*out_buf) != GST_BUFFER_OFFSET (in_buf) ||
1633 GST_BUFFER_OFFSET_END (*out_buf) != GST_BUFFER_OFFSET_END (in_buf);
1638 /* check if we need to make things writable. We need this when we need to
1639 * update the caps or the metadata on the output buffer. */
1640 newcaps = GST_BUFFER_CAPS (*out_buf);
1641 /* we check the pointers as a quick check and then go to the more involved
1642 * check. This is needed when we receive different pointers on the sinkpad
1643 * that mean the same caps. What we then want to do is prefer those caps over
1644 * the ones on the srcpad and set the srcpad caps to the buffer caps */
1645 setcaps = !newcaps || ((newcaps != outcaps)
1646 && (!gst_caps_is_equal (newcaps, outcaps)));
1647 /* we need to modify the metadata when the element is not gap aware,
1648 * passthrough is not used and the gap flag is set */
1649 copymeta |= !trans->priv->gap_aware && !trans->passthrough
1650 && (GST_MINI_OBJECT_FLAGS (*out_buf) & GST_BUFFER_FLAG_GAP);
1652 if (setcaps || copymeta) {
1653 GST_DEBUG_OBJECT (trans, "setcaps %d, copymeta %d", setcaps, copymeta);
1654 if (!gst_buffer_is_metadata_writable (*out_buf)) {
1655 GST_DEBUG_OBJECT (trans, "buffer metadata %p not writable", *out_buf);
1656 if (in_buf == *out_buf)
1657 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
1659 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1661 /* when we get here, the metadata should be writable */
1663 gst_buffer_set_caps (*out_buf, outcaps);
1665 gst_buffer_copy_metadata (*out_buf, in_buf,
1666 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1667 /* clear the GAP flag when the subclass does not understand it */
1668 if (!trans->priv->gap_aware)
1669 GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1677 GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1682 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1683 ("Sub-class failed to provide an output buffer"), (NULL));
1684 return GST_FLOW_ERROR;
1688 GST_ERROR_OBJECT (trans, "unknown output size");
1689 return GST_FLOW_ERROR;
1693 GST_WARNING_OBJECT (trans, "failed to configure caps");
1694 return GST_FLOW_NOT_NEGOTIATED;
1698 /* Given @caps calcultate the size of one unit.
1700 * For video caps, this is the size of one frame (and thus one buffer).
1701 * For audio caps, this is the size of one sample.
1703 * These values are cached since they do not change and the calculation
1704 * potentially involves parsing caps and other expensive stuff.
1706 * We have two cache locations to store the size, one for the source caps
1707 * and one for the sink caps.
1709 * this function returns FALSE if no size could be calculated.
1712 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1715 gboolean res = FALSE;
1716 GstBaseTransformClass *bclass;
1718 /* see if we have the result cached */
1719 if (trans->cache_caps1 == caps) {
1720 *size = trans->cache_caps1_size;
1721 GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1724 if (trans->cache_caps2 == caps) {
1725 *size = trans->cache_caps2_size;
1726 GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1730 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1731 if (bclass->get_unit_size) {
1732 res = bclass->get_unit_size (trans, caps, size);
1733 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1734 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1737 /* and cache the values */
1738 if (trans->cache_caps1 == NULL) {
1739 gst_caps_replace (&trans->cache_caps1, caps);
1740 trans->cache_caps1_size = *size;
1741 GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1742 } else if (trans->cache_caps2 == NULL) {
1743 gst_caps_replace (&trans->cache_caps2, caps);
1744 trans->cache_caps2_size = *size;
1745 GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1747 GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1751 GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1756 /* your upstream peer wants to send you a buffer
1757 * that buffer has the given offset, size and caps
1758 * you're requested to allocate a buffer
1760 static GstFlowReturn
1761 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1762 GstCaps * caps, GstBuffer ** buf)
1764 GstBaseTransform *trans;
1765 GstBaseTransformClass *klass;
1766 GstBaseTransformPrivate *priv;
1768 gboolean alloced = FALSE;
1769 gboolean proxy, suggest, same_caps;
1770 GstCaps *sink_suggest = NULL;
1773 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1774 if (G_UNLIKELY (trans == NULL))
1775 return GST_FLOW_WRONG_STATE;
1776 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1779 GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1782 /* if the code below does not come up with a better buffer, we will return _OK
1783 * and an empty buffer. This will trigger the core to allocate a buffer with
1784 * given input size and caps. */
1788 /* we remember our previous alloc request to quickly see if we can proxy or
1789 * not. We skip this check if we have a pending suggestion. */
1790 GST_OBJECT_LOCK (pad);
1791 same_caps = !priv->suggest_pending && caps &&
1792 gst_caps_is_equal (priv->sink_alloc, caps);
1793 GST_OBJECT_UNLOCK (pad);
1796 /* we have seen this before, see below if we need to proxy */
1797 GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1798 gst_caps_replace (&sink_suggest, caps);
1799 size_suggest = size;
1802 GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1804 /* if we have a suggestion, pretend we got these as input */
1805 GST_OBJECT_LOCK (pad);
1806 if ((priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest))) {
1807 sink_suggest = gst_caps_ref (priv->sink_suggest);
1808 size_suggest = priv->size_suggest;
1809 GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1810 sink_suggest, sink_suggest, priv->size_suggest);
1811 /* suggest is TRUE when we have a custom suggestion pending that we need
1812 * to unref later. */
1815 GST_DEBUG_OBJECT (trans, "using caps %p %" GST_PTR_FORMAT " size %u",
1817 gst_caps_replace (&sink_suggest, caps);
1818 size_suggest = size;
1821 priv->suggest_pending = FALSE;
1822 GST_OBJECT_UNLOCK (pad);
1824 /* check if we actually handle this format on the sinkpad */
1826 const GstCaps *templ;
1828 if (!gst_caps_is_fixed (sink_suggest)) {
1831 GST_DEBUG_OBJECT (trans, "Suggested caps is not fixed: %"
1832 GST_PTR_FORMAT, sink_suggest);
1835 gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1836 /* try fixating by intersecting with peer caps */
1841 gst_caps_intersect_full (sink_suggest, peercaps,
1842 GST_CAPS_INTERSECT_FIRST);
1843 gst_caps_unref (peercaps);
1844 gst_caps_unref (sink_suggest);
1845 sink_suggest = intersect;
1848 if (gst_caps_is_empty (sink_suggest))
1851 /* try the alloc caps if it is still not fixed */
1852 if (!gst_caps_is_fixed (sink_suggest)) {
1855 GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1856 "with the non-fixed caps suggestion");
1858 gst_caps_intersect_full (sink_suggest, caps,
1859 GST_CAPS_INTERSECT_FIRST);
1860 if (!gst_caps_is_empty (intersect)) {
1861 GST_DEBUG_OBJECT (trans, "It is, using it");
1862 gst_caps_replace (&sink_suggest, caps);
1864 gst_caps_unref (intersect);
1867 /* be safe and call default fixate */
1868 sink_suggest = gst_caps_make_writable (sink_suggest);
1869 gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1871 if (!gst_caps_is_fixed (sink_suggest)) {
1872 gst_caps_unref (sink_suggest);
1873 sink_suggest = NULL;
1876 GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1881 templ = gst_pad_get_pad_template_caps (pad);
1883 if (!gst_caps_can_intersect (sink_suggest, templ)) {
1887 GST_DEBUG_OBJECT (trans,
1888 "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1890 /* the requested pad alloc caps are not supported, so let's try
1891 * picking something allowed between the pads (they are linked,
1892 * there must be something) */
1893 allowed = gst_pad_get_allowed_caps (pad);
1894 if (allowed && !gst_caps_is_empty (allowed)) {
1895 GST_DEBUG_OBJECT (trans,
1896 "pads could agree on one of the following caps: " "%"
1897 GST_PTR_FORMAT, allowed);
1898 allowed = gst_caps_make_writable (allowed);
1900 if (klass->fixate_caps) {
1902 gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1903 klass->fixate_caps (trans, GST_PAD_SRC, peercaps, allowed);
1904 gst_caps_unref (peercaps);
1907 /* Fixate them to be safe if the subclass didn't do it */
1908 gst_caps_truncate (allowed);
1909 gst_pad_fixate_caps (pad, allowed);
1910 gst_caps_replace (&sink_suggest, allowed);
1911 gst_caps_unref (allowed);
1915 GST_DEBUG_OBJECT (trans, "Fixated suggestion caps to %"
1916 GST_PTR_FORMAT, sink_suggest);
1919 gst_caps_unref (allowed);
1926 /* find the best format for the other side here we decide if we will proxy
1927 * the caps or not. */
1928 if (sink_suggest == NULL) {
1929 /* always proxy when the caps are NULL. When this is a new format, see if
1930 * we can proxy it downstream */
1931 GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
1932 priv->proxy_alloc = TRUE;
1936 /* we have a new format, see what we need to proxy to */
1937 othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
1938 if (!othercaps || gst_caps_is_empty (othercaps)) {
1939 /* no transform possible, we certainly can't proxy */
1940 GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
1941 priv->proxy_alloc = FALSE;
1943 /* we transformed into something */
1944 if (gst_caps_is_equal (sink_suggest, othercaps)) {
1945 GST_DEBUG_OBJECT (trans,
1946 "best caps same as input, marking for proxy");
1947 priv->proxy_alloc = TRUE;
1949 GST_DEBUG_OBJECT (trans,
1950 "best caps different from input, disable proxy");
1951 priv->proxy_alloc = FALSE;
1955 gst_caps_unref (othercaps);
1958 /* remember the new caps */
1959 GST_OBJECT_LOCK (pad);
1960 gst_caps_replace (&priv->sink_alloc, sink_suggest);
1961 GST_OBJECT_UNLOCK (pad);
1963 proxy = priv->proxy_alloc;
1964 GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
1967 /* we only want to proxy if we have no suggestion pending, FIXME */
1968 if (proxy && !suggest) {
1971 GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
1972 ", size %u", caps, caps, size);
1974 /* we always proxy the input caps, never the suggestion. The reason is that
1975 * We don't yet handle the caps of renegotiation in here. FIXME */
1976 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
1977 if (res != GST_FLOW_OK)
1981 /* check if the caps changed */
1982 newcaps = GST_BUFFER_CAPS (*buf);
1984 GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
1986 if (!gst_caps_is_equal (newcaps, caps)) {
1987 GST_DEBUG_OBJECT (trans, "caps are new");
1988 /* we have new caps, see if we can proxy downstream */
1989 if (gst_pad_peer_accept_caps (pad, newcaps)) {
1990 /* peer accepts the caps, return a buffer in this format */
1991 GST_DEBUG_OBJECT (trans, "peer accepted new caps");
1992 /* remember the format */
1993 GST_OBJECT_LOCK (pad);
1994 gst_caps_replace (&priv->sink_alloc, newcaps);
1995 GST_OBJECT_UNLOCK (pad);
1997 GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
1998 /* peer does not accept the caps, disable proxy_alloc, free the
1999 * buffer we received and create a buffer of the requested format
2000 * by the default handler. */
2001 GST_DEBUG_OBJECT (trans, "disabling proxy");
2002 priv->proxy_alloc = FALSE;
2003 gst_buffer_unref (*buf);
2007 GST_DEBUG_OBJECT (trans, "received required caps from peer");
2012 /* there was a custom suggestion, create a buffer of this format and return
2013 * it. Note that this format */
2014 *buf = gst_buffer_new_and_alloc (size_suggest);
2015 GST_DEBUG_OBJECT (trans,
2016 "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2017 sink_suggest, sink_suggest);
2018 GST_BUFFER_CAPS (*buf) = sink_suggest;
2019 sink_suggest = NULL;
2023 gst_caps_unref (sink_suggest);
2025 if (res == GST_FLOW_OK && alloced) {
2026 /* just alloc'ed a buffer, so we only want to do this again if we
2027 * received a buffer */
2028 GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2029 trans->priv->force_alloc = FALSE;
2032 gst_object_unref (trans);
2038 GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2040 gst_caps_unref (sink_suggest);
2041 gst_object_unref (trans);
2046 GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2048 gst_caps_unref (sink_suggest);
2049 gst_object_unref (trans);
2050 return GST_FLOW_NOT_NEGOTIATED;
2055 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2059 GST_OBJECT_LOCK (trans);
2060 list = trans->priv->delayed_events;
2061 trans->priv->delayed_events = NULL;
2062 GST_OBJECT_UNLOCK (trans);
2066 for (tmp = list; tmp; tmp = tmp->next) {
2067 GstEvent *ev = tmp->data;
2069 GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2070 GST_EVENT_TYPE_NAME (ev));
2071 gst_pad_push_event (trans->srcpad, ev);
2077 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2079 GstBaseTransform *trans;
2080 GstBaseTransformClass *bclass;
2081 gboolean ret = TRUE;
2082 gboolean forward = TRUE;
2084 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2085 if (G_UNLIKELY (trans == NULL)) {
2086 gst_event_unref (event);
2089 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2092 forward = bclass->event (trans, event);
2094 /* FIXME, do this in the default event handler so the subclass can do
2095 * something different. */
2097 gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2099 /* src caps may not yet be set, so we delay any serialized events
2100 that we receive before (in particular newsegment events), except
2101 EOS and flush stops, since those'll obsolete previous events */
2102 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2103 gst_base_transform_drop_delayed_events (trans);
2106 delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2107 && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2111 GST_OBJECT_LOCK (trans);
2112 trans->priv->delayed_events =
2113 g_list_append (trans->priv->delayed_events, event);
2114 GST_OBJECT_UNLOCK (trans);
2116 if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2117 gst_base_transform_send_delayed_events (trans);
2118 ret = gst_pad_push_event (trans->srcpad, event);
2121 gst_event_unref (event);
2123 gst_object_unref (trans);
2129 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2131 switch (GST_EVENT_TYPE (event)) {
2132 case GST_EVENT_FLUSH_START:
2134 case GST_EVENT_FLUSH_STOP:
2135 GST_OBJECT_LOCK (trans);
2136 /* reset QoS parameters */
2137 trans->priv->proportion = 1.0;
2138 trans->priv->earliest_time = -1;
2139 trans->priv->discont = FALSE;
2140 trans->priv->processed = 0;
2141 trans->priv->dropped = 0;
2142 GST_OBJECT_UNLOCK (trans);
2143 /* we need new segment info after the flush. */
2144 trans->have_newsegment = FALSE;
2145 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2146 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2152 case GST_EVENT_NEWSEGMENT:
2155 gdouble rate, arate;
2156 gint64 start, stop, time;
2159 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2160 &start, &stop, &time);
2162 trans->have_newsegment = TRUE;
2164 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2165 format, start, stop, time);
2167 if (format == GST_FORMAT_TIME) {
2168 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2169 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2170 ", accum %" GST_TIME_FORMAT,
2171 GST_TIME_ARGS (trans->segment.start),
2172 GST_TIME_ARGS (trans->segment.stop),
2173 GST_TIME_ARGS (trans->segment.time),
2174 GST_TIME_ARGS (trans->segment.accum));
2176 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2177 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2178 ", accum %" G_GINT64_FORMAT,
2179 trans->segment.start, trans->segment.stop,
2180 trans->segment.time, trans->segment.accum);
2192 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2194 GstBaseTransform *trans;
2195 GstBaseTransformClass *bclass;
2196 gboolean ret = TRUE;
2198 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2199 if (G_UNLIKELY (trans == NULL)) {
2200 gst_event_unref (event);
2204 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2206 if (bclass->src_event)
2207 ret = bclass->src_event (trans, event);
2209 gst_event_unref (event);
2211 gst_object_unref (trans);
2217 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2221 GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2223 switch (GST_EVENT_TYPE (event)) {
2224 case GST_EVENT_SEEK:
2226 case GST_EVENT_NAVIGATION:
2231 GstClockTimeDiff diff;
2232 GstClockTime timestamp;
2234 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2235 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2242 ret = gst_pad_push_event (trans->sinkpad, event);
2247 /* perform a transform on @inbuf and put the result in @outbuf.
2249 * This function is common to the push and pull-based operations.
2251 * This function takes ownership of @inbuf */
2252 static GstFlowReturn
2253 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2254 GstBuffer ** outbuf)
2256 GstBaseTransformClass *bclass;
2257 GstFlowReturn ret = GST_FLOW_OK;
2258 gboolean want_in_place, reconfigure;
2259 GstClockTime running_time;
2260 GstClockTime timestamp;
2263 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2265 if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2266 GST_OBJECT_LOCK (trans);
2267 reconfigure = trans->priv->reconfigure;
2268 trans->priv->reconfigure = FALSE;
2269 GST_OBJECT_UNLOCK (trans);
2271 if (G_UNLIKELY (reconfigure)) {
2272 GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2273 /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2274 * will reconfigure the transform with the new output format. We can only
2275 * do this if the buffer actually has caps. */
2276 if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2277 goto not_negotiated;
2281 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2282 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2283 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2284 GST_BUFFER_OFFSET (inbuf));
2286 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2287 inbuf, GST_BUFFER_SIZE (inbuf));
2289 /* Don't allow buffer handling before negotiation, except in passthrough mode
2290 * or if the class doesn't implement a set_caps function (in which case it doesn't
2293 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2294 goto not_negotiated;
2296 /* Set discont flag so we can mark the outgoing buffer */
2297 if (GST_BUFFER_IS_DISCONT (inbuf)) {
2298 GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2299 trans->priv->discont = TRUE;
2302 /* can only do QoS if the segment is in TIME */
2303 if (trans->segment.format != GST_FORMAT_TIME)
2306 /* QOS is done on the running time of the buffer, get it now */
2307 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2308 running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2311 if (running_time != -1) {
2313 GstClockTime earliest_time;
2316 /* lock for getting the QoS parameters that are set (in a different thread)
2317 * with the QOS events */
2318 GST_OBJECT_LOCK (trans);
2319 earliest_time = trans->priv->earliest_time;
2320 proportion = trans->priv->proportion;
2321 /* check for QoS, don't perform conversion for buffers
2322 * that are known to be late. */
2323 need_skip = trans->priv->qos_enabled &&
2324 earliest_time != -1 && running_time <= earliest_time;
2325 GST_OBJECT_UNLOCK (trans);
2328 GstMessage *qos_msg;
2329 GstClockTime duration;
2330 guint64 stream_time;
2333 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2334 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2335 GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2337 trans->priv->dropped++;
2339 duration = GST_BUFFER_DURATION (inbuf);
2341 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2343 jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2346 gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2347 stream_time, timestamp, duration);
2348 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2349 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2350 trans->priv->processed, trans->priv->dropped);
2351 gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2353 /* mark discont for next buffer */
2354 trans->priv->discont = TRUE;
2361 /* first try to allocate an output buffer based on the currently negotiated
2362 * format. While we call pad-alloc we could renegotiate the srcpad format or
2363 * have a new suggestion for upstream buffer-alloc.
2364 * In any case, outbuf will contain a buffer suitable for doing the configured
2365 * transform after this function. */
2366 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2367 if (G_UNLIKELY (ret != GST_FLOW_OK))
2370 /* now perform the needed transform */
2371 if (trans->passthrough) {
2372 /* In passthrough mode, give transform_ip a look at the
2373 * buffer, without making it writable, or just push the
2375 if (bclass->transform_ip) {
2376 GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2377 ret = bclass->transform_ip (trans, *outbuf);
2379 GST_DEBUG_OBJECT (trans, "element is in passthrough");
2382 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2384 if (want_in_place) {
2385 GST_DEBUG_OBJECT (trans, "doing inplace transform");
2387 if (inbuf != *outbuf) {
2388 guint8 *indata, *outdata;
2390 /* Different buffer. The data can still be the same when we are dealing
2391 * with subbuffers of the same buffer. Note that because of the FIXME in
2392 * prepare_output_buffer() we have decreased the refcounts of inbuf and
2393 * outbuf to keep them writable */
2394 indata = GST_BUFFER_DATA (inbuf);
2395 outdata = GST_BUFFER_DATA (*outbuf);
2397 if (indata != outdata)
2398 memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2400 ret = bclass->transform_ip (trans, *outbuf);
2402 GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2404 if (bclass->transform)
2405 ret = bclass->transform (trans, inbuf, *outbuf);
2407 ret = GST_FLOW_NOT_SUPPORTED;
2412 /* only unref input buffer if we allocated a new outbuf buffer */
2413 if (*outbuf != inbuf)
2414 gst_buffer_unref (inbuf);
2416 /* pushed a buffer, we can now try an alloc */
2417 GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2418 trans->priv->force_alloc = TRUE;
2424 gst_buffer_unref (inbuf);
2425 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2426 ("not negotiated"), ("not negotiated"));
2427 return GST_FLOW_NOT_NEGOTIATED;
2431 gst_buffer_unref (inbuf);
2432 GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2433 gst_flow_get_name (ret));
2439 gst_base_transform_check_get_range (GstPad * pad)
2441 GstBaseTransform *trans;
2444 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2446 ret = gst_pad_check_pull_range (trans->sinkpad);
2448 gst_object_unref (trans);
2453 /* FIXME, getrange is broken, need to pull range from the other
2454 * end based on the transform_size result.
2456 static GstFlowReturn
2457 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2458 guint length, GstBuffer ** buffer)
2460 GstBaseTransform *trans;
2461 GstBaseTransformClass *klass;
2465 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2467 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2468 if (G_UNLIKELY (ret != GST_FLOW_OK))
2471 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2472 if (klass->before_transform)
2473 klass->before_transform (trans, inbuf);
2475 GST_BASE_TRANSFORM_LOCK (trans);
2476 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2477 GST_BASE_TRANSFORM_UNLOCK (trans);
2480 gst_object_unref (trans);
2487 GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2488 gst_flow_get_name (ret));
2493 static GstFlowReturn
2494 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2496 GstBaseTransform *trans;
2497 GstBaseTransformClass *klass;
2499 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2500 GstClockTime timestamp, duration;
2501 GstBuffer *outbuf = NULL;
2503 trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2505 timestamp = GST_BUFFER_TIMESTAMP (buffer);
2506 duration = GST_BUFFER_DURATION (buffer);
2508 /* calculate end position of the incoming buffer */
2509 if (timestamp != GST_CLOCK_TIME_NONE) {
2510 if (duration != GST_CLOCK_TIME_NONE)
2511 last_stop = timestamp + duration;
2513 last_stop = timestamp;
2516 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2517 if (klass->before_transform)
2518 klass->before_transform (trans, buffer);
2520 /* protect transform method and concurrent buffer alloc */
2521 GST_BASE_TRANSFORM_LOCK (trans);
2522 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2523 GST_BASE_TRANSFORM_UNLOCK (trans);
2525 /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2526 * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2527 if (outbuf != NULL) {
2528 if ((ret == GST_FLOW_OK)) {
2529 GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2531 /* Remember last stop position */
2532 if (last_stop != GST_CLOCK_TIME_NONE &&
2533 trans->segment.format == GST_FORMAT_TIME)
2534 gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2536 if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2537 last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2538 if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2539 last_stop_out += GST_BUFFER_DURATION (outbuf);
2540 } else if (last_stop != GST_CLOCK_TIME_NONE) {
2541 last_stop_out = last_stop;
2543 if (last_stop_out != GST_CLOCK_TIME_NONE
2544 && trans->segment.format == GST_FORMAT_TIME)
2545 trans->priv->last_stop_out = last_stop_out;
2547 /* apply DISCONT flag if the buffer is not yet marked as such */
2548 if (trans->priv->discont) {
2549 if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2550 outbuf = gst_buffer_make_metadata_writable (outbuf);
2551 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2553 trans->priv->discont = FALSE;
2555 trans->priv->processed++;
2557 gst_base_transform_send_delayed_events (trans);
2559 ret = gst_pad_push (trans->srcpad, outbuf);
2561 gst_buffer_unref (outbuf);
2565 /* convert internal flow to OK and mark discont for the next buffer. */
2566 if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2567 trans->priv->discont = TRUE;
2575 gst_base_transform_set_property (GObject * object, guint prop_id,
2576 const GValue * value, GParamSpec * pspec)
2578 GstBaseTransform *trans;
2580 trans = GST_BASE_TRANSFORM (object);
2584 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2587 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2593 gst_base_transform_get_property (GObject * object, guint prop_id,
2594 GValue * value, GParamSpec * pspec)
2596 GstBaseTransform *trans;
2598 trans = GST_BASE_TRANSFORM (object);
2602 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2605 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2610 /* not a vmethod of anything, just an internal method */
2612 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2614 GstBaseTransformClass *bclass;
2615 gboolean result = TRUE;
2617 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2620 if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2621 result &= bclass->start (trans);
2623 GST_OBJECT_LOCK (trans);
2625 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2626 trans->have_same_caps =
2627 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2628 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2630 trans->have_same_caps = trans->passthrough;
2631 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2632 trans->negotiated = FALSE;
2633 trans->have_newsegment = FALSE;
2634 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2635 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2636 trans->priv->proportion = 1.0;
2637 trans->priv->earliest_time = -1;
2638 trans->priv->discont = FALSE;
2639 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2640 trans->priv->processed = 0;
2641 trans->priv->dropped = 0;
2642 trans->priv->force_alloc = TRUE;
2644 GST_OBJECT_UNLOCK (trans);
2646 /* We must make sure streaming has finished before resetting things
2647 * and calling the ::stop vfunc */
2648 GST_PAD_STREAM_LOCK (trans->sinkpad);
2649 GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2651 gst_base_transform_drop_delayed_events (trans);
2653 trans->have_same_caps = FALSE;
2654 /* We can only reset the passthrough mode if the instance told us to
2655 handle it in configure_caps */
2656 if (bclass->passthrough_on_same_caps) {
2657 gst_base_transform_set_passthrough (trans, FALSE);
2659 gst_caps_replace (&trans->cache_caps1, NULL);
2660 gst_caps_replace (&trans->cache_caps2, NULL);
2661 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2662 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2664 if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2665 result &= bclass->stop (trans);
2672 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2674 gboolean result = TRUE;
2675 GstBaseTransform *trans;
2677 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2679 result = gst_base_transform_activate (trans, active);
2682 trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2684 gst_object_unref (trans);
2690 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2692 gboolean result = FALSE;
2693 GstBaseTransform *trans;
2695 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2697 result = gst_pad_activate_pull (trans->sinkpad, active);
2700 result &= gst_base_transform_activate (trans, active);
2703 trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2705 gst_object_unref (trans);
2711 * gst_base_transform_set_passthrough:
2712 * @trans: the #GstBaseTransform to set
2713 * @passthrough: boolean indicating passthrough mode.
2715 * Set passthrough mode for this filter by default. This is mostly
2716 * useful for filters that do not care about negotiation.
2718 * Always TRUE for filters which don't implement either a transform
2719 * or transform_ip method.
2724 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2725 gboolean passthrough)
2727 GstBaseTransformClass *bclass;
2729 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2731 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2733 GST_OBJECT_LOCK (trans);
2734 if (passthrough == FALSE) {
2735 if (bclass->transform_ip || bclass->transform)
2736 trans->passthrough = FALSE;
2738 trans->passthrough = TRUE;
2741 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2742 GST_OBJECT_UNLOCK (trans);
2746 * gst_base_transform_is_passthrough:
2747 * @trans: the #GstBaseTransform to query
2749 * See if @trans is configured as a passthrough transform.
2751 * Returns: TRUE is the transform is configured in passthrough mode.
2756 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2760 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2762 GST_OBJECT_LOCK (trans);
2763 result = trans->passthrough;
2764 GST_OBJECT_UNLOCK (trans);
2770 * gst_base_transform_set_in_place:
2771 * @trans: the #GstBaseTransform to modify
2772 * @in_place: Boolean value indicating that we would like to operate
2773 * on in_place buffers.
2775 * Determines whether a non-writable buffer will be copied before passing
2776 * to the transform_ip function.
2778 * <listitem>Always TRUE if no transform function is implemented.</listitem>
2779 * <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2785 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2787 GstBaseTransformClass *bclass;
2789 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2791 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2793 GST_OBJECT_LOCK (trans);
2796 if (bclass->transform_ip) {
2797 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2798 trans->always_in_place = TRUE;
2801 if (bclass->transform) {
2802 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2803 trans->always_in_place = FALSE;
2807 GST_OBJECT_UNLOCK (trans);
2811 * gst_base_transform_is_in_place:
2812 * @trans: the #GstBaseTransform to query
2814 * See if @trans is configured as a in_place transform.
2816 * Returns: TRUE is the transform is configured in in_place mode.
2821 gst_base_transform_is_in_place (GstBaseTransform * trans)
2825 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2827 GST_OBJECT_LOCK (trans);
2828 result = trans->always_in_place;
2829 GST_OBJECT_UNLOCK (trans);
2835 * gst_base_transform_update_qos:
2836 * @trans: a #GstBaseTransform
2837 * @proportion: the proportion
2838 * @diff: the diff against the clock
2839 * @timestamp: the timestamp of the buffer generating the QoS expressed in
2842 * Set the QoS parameters in the transform. This function is called internally
2843 * when a QOS event is received but subclasses can provide custom information
2851 gst_base_transform_update_qos (GstBaseTransform * trans,
2852 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2855 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2857 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2858 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2859 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2861 GST_OBJECT_LOCK (trans);
2862 trans->priv->proportion = proportion;
2863 trans->priv->earliest_time = timestamp + diff;
2864 GST_OBJECT_UNLOCK (trans);
2868 * gst_base_transform_set_qos_enabled:
2869 * @trans: a #GstBaseTransform
2870 * @enabled: new state
2872 * Enable or disable QoS handling in the transform.
2879 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2881 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2883 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2885 GST_OBJECT_LOCK (trans);
2886 trans->priv->qos_enabled = enabled;
2887 GST_OBJECT_UNLOCK (trans);
2891 * gst_base_transform_is_qos_enabled:
2892 * @trans: a #GstBaseTransform
2894 * Queries if the transform will handle QoS.
2896 * Returns: TRUE if QoS is enabled.
2903 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2907 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2909 GST_OBJECT_LOCK (trans);
2910 result = trans->priv->qos_enabled;
2911 GST_OBJECT_UNLOCK (trans);
2917 * gst_base_transform_set_gap_aware:
2918 * @trans: a #GstBaseTransform
2919 * @gap_aware: New state
2921 * If @gap_aware is %FALSE (the default), output buffers will have the
2922 * %GST_BUFFER_FLAG_GAP flag unset.
2924 * If set to %TRUE, the element must handle output buffers with this flag set
2925 * correctly, i.e. it can assume that the buffer contains neutral data but must
2926 * unset the flag if the output is no neutral data.
2933 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2935 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2937 GST_OBJECT_LOCK (trans);
2938 trans->priv->gap_aware = gap_aware;
2939 GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2940 GST_OBJECT_UNLOCK (trans);
2944 * gst_base_transform_suggest:
2945 * @trans: a #GstBaseTransform
2946 * @caps: (transfer none): caps to suggest
2947 * @size: buffer size to suggest
2949 * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
2955 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
2958 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2960 GST_OBJECT_LOCK (trans->sinkpad);
2961 if (trans->priv->sink_suggest)
2962 gst_caps_unref (trans->priv->sink_suggest);
2964 caps = gst_caps_copy (caps);
2965 trans->priv->sink_suggest = caps;
2966 trans->priv->size_suggest = size;
2967 trans->priv->suggest_pending = TRUE;
2968 GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
2969 GST_OBJECT_UNLOCK (trans->sinkpad);
2973 * gst_base_transform_reconfigure:
2974 * @trans: a #GstBaseTransform
2976 * Instructs @trans to renegotiate a new downstream transform on the next
2977 * buffer. This function is typically called after properties on the transform
2978 * were set that influence the output format.
2983 gst_base_transform_reconfigure (GstBaseTransform * trans)
2985 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2987 GST_OBJECT_LOCK (trans);
2988 GST_DEBUG_OBJECT (trans, "marking reconfigure");
2989 trans->priv->reconfigure = TRUE;
2990 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2991 GST_OBJECT_UNLOCK (trans);