1 /* GStreamer
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>
7 *
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.
12 *
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.
17 *
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.
22 */
24 /**
25 * SECTION:gstbasetransform
26 * @short_description: Base class for simple transform filters
27 * @see_also: #GstBaseSrc, #GstBaseSink
28 *
29 * This base class is for filter elements that process data.
30 *
31 * It provides for:
32 * <itemizedlist>
33 * <listitem><para>one sinkpad and one srcpad</para></listitem>
34 * <listitem><para>
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.
38 * </para></listitem>
39 * <listitem><para>Handles state changes</para></listitem>
40 * <listitem><para>Does flushing</para></listitem>
41 * <listitem><para>Push mode</para></listitem>
42 * <listitem><para>
43 * Pull mode if the sub-class transform can operate on arbitrary data
44 * </para></listitem>
45 * </itemizedlist>
46 *
47 * <refsect2>
48 * <title>Use Cases</title>
49 * <para>
50 * <orderedlist>
51 * <listitem>
52 * <itemizedlist><title>Passthrough mode</title>
53 * <listitem><para>
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
57 * intact.
58 * </para></listitem>
59 * <listitem><para>
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.
63 * </para></listitem>
64 * <listitem><para>
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
67 * (such as level)
68 * </para></listitem>
69 * </itemizedlist>
70 * <itemizedlist>
71 * <title>Example elements</title>
72 * <listitem>Level</listitem>
73 * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
74 * certain modes.</listitem>
75 * </itemizedlist>
76 * </listitem>
77 * <listitem>
78 * <itemizedlist>
79 * <title>Modifications in-place - input buffer and output buffer are the
80 * same thing.</title>
81 * <listitem><para>
82 * The element must implement a transform_ip function.
83 * </para></listitem>
84 * <listitem><para>
85 * Output buffer size must <= input buffer size
86 * </para></listitem>
87 * <listitem><para>
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.
91 * </para></listitem>
92 * <listitem><para>
93 * Incoming writable buffers will be passed to the transform_ip function
94 * immediately. </para></listitem>
95 * <listitem><para>
96 * only implementing transform_ip and not transform implies always_in_place
97 * = TRUE
98 * </para></listitem>
99 * </itemizedlist>
100 * <itemizedlist>
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>
107 * </itemizedlist>
108 * </listitem>
109 * <listitem>
110 * <itemizedlist>
111 * <title>Modifications only to the caps/metadata of a buffer</title>
112 * <listitem><para>
113 * The element does not require writable data, but non-writable buffers
114 * should be subbuffered so that the meta-information can be replaced.
115 * </para></listitem>
116 * <listitem><para>
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
120 * </para></listitem>
121 * </itemizedlist>
122 * <itemizedlist>
123 * <title>Example elements</title>
124 * <listitem>Capsfilter when setting caps on outgoing buffers that have
125 * none.</listitem>
126 * <listitem>identity when it is going to re-timestamp buffers by
127 * datarate.</listitem>
128 * </itemizedlist>
129 * </listitem>
130 * <listitem>
131 * <itemizedlist><title>Normal mode</title>
132 * <listitem><para>
133 * always_in_place flag is not set, or there is no transform_ip function
134 * </para></listitem>
135 * <listitem><para>
136 * Element will receive an input buffer and output buffer to operate on.
137 * </para></listitem>
138 * <listitem><para>
139 * Output buffer is allocated by calling the prepare_output_buffer function.
140 * </para></listitem>
141 * </itemizedlist>
142 * <itemizedlist>
143 * <title>Example elements</title>
144 * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
145 * scaling/conversions</listitem>
146 * </itemizedlist>
147 * </listitem>
148 * <listitem>
149 * <itemizedlist><title>Special output buffer allocations</title>
150 * <listitem><para>
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.
155 * </para></listitem>
156 * </itemizedlist>
157 * <itemizedlist>
158 * <title>Example elements</title>
159 * <listitem>efence</listitem>
160 * </itemizedlist>
161 * </listitem>
162 * </orderedlist>
163 * </para>
164 * </refsect2>
165 * <refsect2>
166 * <title>Sub-class settable flags on GstBaseTransform</title>
167 * <para>
168 * <itemizedlist>
169 * <listitem><para>
170 * <itemizedlist><title>passthrough</title>
171 * <listitem><para>
172 * Implies that in the current configuration, the sub-class is not
173 * interested in modifying the buffers.
174 * </para></listitem>
175 * <listitem><para>
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.
179 * </para></listitem>
180 * </itemizedlist>
181 * </para></listitem>
182 * <listitem><para>
183 * <itemizedlist><title>always_in_place</title>
184 * <listitem><para>
185 * Determines whether a non-writable buffer will be copied before passing
186 * to the transform_ip function.
187 * </para></listitem>
188 * <listitem><para>
189 * Implied TRUE if no transform function is implemented.
190 * </para></listitem>
191 * <listitem><para>
192 * Implied FALSE if ONLY transform function is implemented.
193 * </para></listitem>
194 * </itemizedlist>
195 * </para></listitem>
196 * </itemizedlist>
197 * </para>
198 * </refsect2>
199 */
201 #ifdef HAVE_CONFIG_H
202 # include "config.h"
203 #endif
205 #include <stdlib.h>
206 #include <string.h>
208 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
209 * with newer GLib versions (>= 2.31.0) */
210 #define GLIB_DISABLE_DEPRECATION_WARNINGS
211 #include "../../../gst/gst_private.h"
212 #include "../../../gst/gst-i18n-lib.h"
213 #include "../../../gst/glib-compat-private.h"
214 #include "gstbasetransform.h"
215 #include <gst/gstmarshal.h>
217 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
218 #define GST_CAT_DEFAULT gst_base_transform_debug
220 /* BaseTransform signals and args */
221 enum
222 {
223 /* FILL ME */
224 LAST_SIGNAL
225 };
227 #define DEFAULT_PROP_QOS FALSE
229 enum
230 {
231 PROP_0,
232 PROP_QOS
233 };
235 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \
236 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
238 struct _GstBaseTransformPrivate
239 {
240 /* QoS *//* with LOCK */
241 gboolean qos_enabled;
242 gdouble proportion;
243 GstClockTime earliest_time;
244 /* previous buffer had a discont */
245 gboolean discont;
247 GstActivateMode pad_mode;
249 gboolean gap_aware;
251 /* caps used for allocating buffers */
252 gboolean proxy_alloc;
253 GstCaps *sink_alloc;
254 GstCaps *src_alloc;
256 /*
257 * This flag controls if basetransform should explicitly
258 * do a pad alloc when it receives a buffer even if it operates on
259 * passthrough, this is needed to check for downstream caps suggestions
260 * and this newly alloc'ed buffer is discarded.
261 *
262 * Without this flag basetransform would try a pad alloc whenever it
263 * gets a new buffer and pipelines like:
264 * "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
265 * Would have a 3 pad allocs for each buffer pushed downstream from the src.
266 *
267 * This flag is set to TRUE on start up, on setcaps and when a buffer is
268 * pushed downstream. It is set to FALSE after a pad alloc has been requested
269 * downstream.
270 * The rationale is that when a pad alloc flows through the pipeline, all
271 * basetransform elements on passthrough will avoid pad alloc'ing when they
272 * get the buffer.
273 */
274 gboolean force_alloc;
276 /* upstream caps and size suggestions */
277 GstCaps *sink_suggest;
278 guint size_suggest;
279 gboolean suggest_pending;
281 gboolean reconfigure;
283 /* QoS stats */
284 guint64 processed;
285 guint64 dropped;
287 GstClockTime last_stop_out;
288 GList *delayed_events;
290 GstCaps *cached_peer_caps[2];
291 GstCaps *cached_transformed_caps[2];
292 };
294 static GstElementClass *parent_class = NULL;
296 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
297 static void gst_base_transform_init (GstBaseTransform * trans,
298 GstBaseTransformClass * klass);
299 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
300 * trans, GstBuffer * input, GstBuffer ** buf);
302 GType
303 gst_base_transform_get_type (void)
304 {
305 static volatile gsize base_transform_type = 0;
307 if (g_once_init_enter (&base_transform_type)) {
308 GType _type;
309 static const GTypeInfo base_transform_info = {
310 sizeof (GstBaseTransformClass),
311 NULL,
312 NULL,
313 (GClassInitFunc) gst_base_transform_class_init,
314 NULL,
315 NULL,
316 sizeof (GstBaseTransform),
317 0,
318 (GInstanceInitFunc) gst_base_transform_init,
319 };
321 _type = g_type_register_static (GST_TYPE_ELEMENT,
322 "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
323 g_once_init_leave (&base_transform_type, _type);
324 }
325 return base_transform_type;
326 }
328 static void gst_base_transform_finalize (GObject * object);
329 static void gst_base_transform_set_property (GObject * object, guint prop_id,
330 const GValue * value, GParamSpec * pspec);
331 static void gst_base_transform_get_property (GObject * object, guint prop_id,
332 GValue * value, GParamSpec * pspec);
333 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
334 gboolean active);
335 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
336 gboolean active);
337 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
338 gboolean active);
339 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
340 GstCaps * caps, guint * size);
342 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
343 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
344 GstEvent * event);
345 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
346 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
347 GstEvent * event);
348 static gboolean gst_base_transform_check_get_range (GstPad * pad);
349 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
350 guint length, GstBuffer ** buffer);
351 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
352 GstBuffer * buffer);
353 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
354 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
355 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
356 GstPadDirection direction, GstCaps * caps);
357 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
358 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
359 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
360 static gboolean gst_base_transform_query (GstPad * pad, GstQuery * query);
361 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
362 GstPadDirection direction, GstQuery * query);
363 static const GstQueryType *gst_base_transform_query_type (GstPad * pad);
365 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
367 static void
368 gst_base_transform_drop_delayed_events (GstBaseTransform * trans)
369 {
370 GST_OBJECT_LOCK (trans);
371 if (trans->priv->delayed_events) {
372 g_list_foreach (trans->priv->delayed_events, (GFunc) gst_event_unref, NULL);
373 g_list_free (trans->priv->delayed_events);
374 trans->priv->delayed_events = NULL;
375 }
376 GST_OBJECT_UNLOCK (trans);
377 }
379 static void
380 gst_base_transform_clear_transformed_caps_cache (GstBaseTransform * trans)
381 {
382 struct _GstBaseTransformPrivate *priv = trans->priv;
383 int n;
385 for (n = 0; n < 2; ++n) {
386 if (priv->cached_peer_caps[n]) {
387 gst_caps_unref (priv->cached_peer_caps[n]);
388 priv->cached_peer_caps[n] = NULL;
389 }
390 if (priv->cached_transformed_caps[n]) {
391 gst_caps_unref (priv->cached_transformed_caps[n]);
392 priv->cached_transformed_caps[n] = NULL;
393 }
394 }
395 }
397 static void
398 gst_base_transform_finalize (GObject * object)
399 {
400 GstBaseTransform *trans;
402 trans = GST_BASE_TRANSFORM (object);
404 gst_base_transform_drop_delayed_events (trans);
405 gst_caps_replace (&trans->priv->sink_suggest, NULL);
406 g_mutex_free (trans->transform_lock);
408 gst_base_transform_clear_transformed_caps_cache (trans);
410 G_OBJECT_CLASS (parent_class)->finalize (object);
411 }
413 static void
414 gst_base_transform_class_init (GstBaseTransformClass * klass)
415 {
416 GObjectClass *gobject_class;
418 gobject_class = G_OBJECT_CLASS (klass);
420 GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
421 "basetransform element");
423 GST_DEBUG ("gst_base_transform_class_init");
425 g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
427 parent_class = g_type_class_peek_parent (klass);
429 gobject_class->set_property = gst_base_transform_set_property;
430 gobject_class->get_property = gst_base_transform_get_property;
432 g_object_class_install_property (gobject_class, PROP_QOS,
433 g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
434 DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
436 gobject_class->finalize = gst_base_transform_finalize;
438 klass->passthrough_on_same_caps = FALSE;
439 klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
440 klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
441 klass->accept_caps =
442 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
443 klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
444 }
446 static void
447 gst_base_transform_init (GstBaseTransform * trans,
448 GstBaseTransformClass * bclass)
449 {
450 GstPadTemplate *pad_template;
452 GST_DEBUG ("gst_base_transform_init");
454 trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
456 pad_template =
457 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
458 g_return_if_fail (pad_template != NULL);
459 trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
460 gst_pad_set_getcaps_function (trans->sinkpad,
461 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
462 gst_pad_set_acceptcaps_function (trans->sinkpad,
463 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
464 gst_pad_set_setcaps_function (trans->sinkpad,
465 GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
466 gst_pad_set_event_function (trans->sinkpad,
467 GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
468 gst_pad_set_chain_function (trans->sinkpad,
469 GST_DEBUG_FUNCPTR (gst_base_transform_chain));
470 gst_pad_set_activatepush_function (trans->sinkpad,
471 GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
472 gst_pad_set_bufferalloc_function (trans->sinkpad,
473 GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
474 gst_pad_set_query_function (trans->sinkpad,
475 GST_DEBUG_FUNCPTR (gst_base_transform_query));
476 gst_pad_set_query_type_function (trans->sinkpad,
477 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
478 gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
480 pad_template =
481 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
482 g_return_if_fail (pad_template != NULL);
483 trans->srcpad = gst_pad_new_from_template (pad_template, "src");
484 gst_pad_set_getcaps_function (trans->srcpad,
485 GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
486 gst_pad_set_acceptcaps_function (trans->srcpad,
487 GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
488 gst_pad_set_event_function (trans->srcpad,
489 GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
490 gst_pad_set_checkgetrange_function (trans->srcpad,
491 GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
492 gst_pad_set_getrange_function (trans->srcpad,
493 GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
494 gst_pad_set_activatepull_function (trans->srcpad,
495 GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
496 gst_pad_set_query_function (trans->srcpad,
497 GST_DEBUG_FUNCPTR (gst_base_transform_query));
498 gst_pad_set_query_type_function (trans->srcpad,
499 GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
500 gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
502 trans->transform_lock = g_mutex_new ();
503 trans->pending_configure = FALSE;
504 trans->priv->qos_enabled = DEFAULT_PROP_QOS;
505 trans->cache_caps1 = NULL;
506 trans->cache_caps2 = NULL;
507 trans->priv->pad_mode = GST_ACTIVATE_NONE;
508 trans->priv->gap_aware = FALSE;
509 trans->priv->delayed_events = NULL;
511 trans->passthrough = FALSE;
512 if (bclass->transform == NULL) {
513 /* If no transform function, always_in_place is TRUE */
514 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
515 trans->always_in_place = TRUE;
517 if (bclass->transform_ip == NULL) {
518 GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
519 trans->passthrough = TRUE;
520 }
521 }
523 trans->priv->processed = 0;
524 trans->priv->dropped = 0;
525 trans->priv->force_alloc = TRUE;
526 }
528 /* given @caps on the src or sink pad (given by @direction)
529 * calculate the possible caps on the other pad.
530 *
531 * Returns new caps, unref after usage.
532 */
533 static GstCaps *
534 gst_base_transform_transform_caps (GstBaseTransform * trans,
535 GstPadDirection direction, GstCaps * caps)
536 {
537 GstCaps *ret;
538 GstBaseTransformClass *klass;
540 if (caps == NULL)
541 return NULL;
543 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
545 /* if there is a custom transform function, use this */
546 if (klass->transform_caps) {
547 GstCaps *temp;
548 gint i;
550 /* start with empty caps */
551 ret = gst_caps_new_empty ();
552 GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
554 if (gst_caps_is_any (caps)) {
555 /* for any caps we still have to call the transform function */
556 GST_DEBUG_OBJECT (trans, "from: ANY");
557 temp = klass->transform_caps (trans, direction, caps);
558 GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
560 temp = gst_caps_make_writable (temp);
561 gst_caps_append (ret, temp);
562 } else {
563 gint n = gst_caps_get_size (caps);
564 /* we send caps with just one structure to the transform
565 * function as this is easier for the element */
566 for (i = 0; i < n; i++) {
567 GstCaps *nth;
569 nth = gst_caps_copy_nth (caps, i);
570 GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
571 temp = klass->transform_caps (trans, direction, nth);
572 gst_caps_unref (nth);
573 GST_LOG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
575 temp = gst_caps_make_writable (temp);
577 /* here we need to only append those structures, that are not yet
578 * in there, we use the merge function for this */
579 gst_caps_merge (ret, temp);
581 GST_LOG_OBJECT (trans, " merged[%d]: %" GST_PTR_FORMAT, i, ret);
582 }
583 GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
584 /* FIXME: we can't do much simplification here because we don't really want to
585 * change the caps order
586 gst_caps_do_simplify (ret);
587 GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
588 */
589 }
590 } else {
591 GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
592 /* no transform function, use the identity transform */
593 ret = gst_caps_ref (caps);
594 }
596 GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
597 ret);
599 return ret;
600 }
602 /* transform a buffer of @size with @caps on the pad with @direction to
603 * the size of a buffer with @othercaps and store the result in @othersize
604 *
605 * We have two ways of doing this:
606 * 1) use a custom transform size function, this is for complicated custom
607 * cases with no fixed unit_size.
608 * 2) use the unit_size functions where there is a relationship between the
609 * caps and the size of a buffer.
610 */
611 static gboolean
612 gst_base_transform_transform_size (GstBaseTransform * trans,
613 GstPadDirection direction, GstCaps * caps,
614 guint size, GstCaps * othercaps, guint * othersize)
615 {
616 guint inunitsize, outunitsize, units;
617 GstBaseTransformClass *klass;
618 gboolean ret;
620 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
622 GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
623 GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
624 size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
626 if (klass->transform_size) {
627 /* if there is a custom transform function, use this */
628 ret = klass->transform_size (trans, direction, caps, size, othercaps,
629 othersize);
630 } else if (klass->get_unit_size == NULL) {
631 /* if there is no transform_size and no unit_size, it means the
632 * element does not modify the size of a buffer */
633 *othersize = size;
634 ret = TRUE;
635 } else {
636 /* there is no transform_size function, we have to use the unit_size
637 * functions. This method assumes there is a fixed unit_size associated with
638 * each caps. We provide the same amount of units on both sides. */
639 if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
640 goto no_in_size;
642 GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
643 inunitsize);
645 /* input size must be a multiple of the unit_size of the input caps */
646 if (inunitsize == 0 || (size % inunitsize != 0))
647 goto no_multiple;
649 /* get the amount of units */
650 units = size / inunitsize;
652 /* now get the unit size of the output */
653 if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
654 goto no_out_size;
656 /* the output size is the unit_size times the amount of units on the
657 * input */
658 *othersize = units * outunitsize;
659 GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
661 ret = TRUE;
662 }
663 return ret;
665 /* ERRORS */
666 no_in_size:
667 {
668 GST_DEBUG_OBJECT (trans, "could not get in_size");
669 g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
670 return FALSE;
671 }
672 no_multiple:
673 {
674 GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
675 inunitsize);
676 g_warning ("%s: size %u is not a multiple of unit size %u",
677 GST_ELEMENT_NAME (trans), size, inunitsize);
678 return FALSE;
679 }
680 no_out_size:
681 {
682 GST_DEBUG_OBJECT (trans, "could not get out_size");
683 g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
684 return FALSE;
685 }
686 }
688 /* get the caps that can be handled by @pad. We perform:
689 *
690 * - take the caps of peer of otherpad,
691 * - filter against the padtemplate of otherpad,
692 * - calculate all transforms of remaining caps
693 * - filter against template of @pad
694 *
695 * If there is no peer, we simply return the caps of the padtemplate of pad.
696 */
697 static GstCaps *
698 gst_base_transform_getcaps (GstPad * pad)
699 {
700 GstBaseTransform *trans;
701 GstPad *otherpad;
702 const GstCaps *templ;
703 GstCaps *peercaps, *caps, *temp;
704 gboolean samecaps;
705 int cache_index;
707 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
709 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
710 cache_index = (pad == trans->srcpad) ? 0 : 1;
712 /* we can do what the peer can */
713 peercaps = gst_pad_peer_get_caps_reffed (otherpad);
714 GST_OBJECT_LOCK (trans);
715 samecaps = (peercaps && trans->priv->cached_peer_caps[cache_index]
716 && gst_caps_is_strictly_equal (peercaps,
717 trans->priv->cached_peer_caps[cache_index]));
718 if (!samecaps) {
719 if (trans->priv->cached_peer_caps[cache_index]) {
720 gst_caps_unref (trans->priv->cached_peer_caps[cache_index]);
721 trans->priv->cached_peer_caps[cache_index] = NULL;
722 }
723 if (trans->priv->cached_transformed_caps[cache_index]) {
724 gst_caps_unref (trans->priv->cached_transformed_caps[cache_index]);
725 trans->priv->cached_transformed_caps[cache_index] = NULL;
726 }
727 } else {
728 GST_DEBUG_OBJECT (trans,
729 "Returning cached transformed caps (index = %d)", cache_index);
730 caps = gst_caps_ref (trans->priv->cached_transformed_caps[cache_index]);
731 goto done;
732 }
733 GST_OBJECT_UNLOCK (trans);
735 if (peercaps) {
736 GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peercaps);
738 /* filtered against our padtemplate on the other side */
739 templ = gst_pad_get_pad_template_caps (otherpad);
740 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
741 temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
742 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
743 } else {
744 temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
745 GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
746 temp);
747 }
749 /* then see what we can transform this to */
750 caps = gst_base_transform_transform_caps (trans,
751 GST_PAD_DIRECTION (otherpad), temp);
752 GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
753 gst_caps_unref (temp);
754 if (caps == NULL)
755 goto done_update_cache;
757 /* and filter against the template of this pad */
758 templ = gst_pad_get_pad_template_caps (pad);
759 GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
760 /* We keep the caps sorted like the returned caps */
761 temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
762 GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
763 gst_caps_unref (caps);
764 caps = temp;
766 if (peercaps) {
767 /* Now try if we can put the untransformed downstream caps first */
768 temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
769 if (!gst_caps_is_empty (temp)) {
770 gst_caps_merge (temp, caps);
771 caps = temp;
772 } else {
773 gst_caps_unref (temp);
774 }
775 }
777 done_update_cache:
778 GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
780 GST_OBJECT_LOCK (trans);
781 if (peercaps) {
782 trans->priv->cached_peer_caps[cache_index] = gst_caps_ref (peercaps);
783 }
784 if (caps) {
785 trans->priv->cached_transformed_caps[cache_index] = gst_caps_ref (caps);
786 }
788 done:
789 GST_OBJECT_UNLOCK (trans);
791 if (peercaps)
792 gst_caps_unref (peercaps);
794 gst_object_unref (trans);
796 return caps;
797 }
799 /* function triggered when the in and out caps are negotiated and need
800 * to be configured in the subclass. */
801 static gboolean
802 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
803 GstCaps * out)
804 {
805 gboolean ret = TRUE;
806 GstBaseTransformClass *klass;
808 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
810 GST_DEBUG_OBJECT (trans, "in caps: %" GST_PTR_FORMAT, in);
811 GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
813 /* clear the cache */
814 gst_caps_replace (&trans->cache_caps1, NULL);
815 gst_caps_replace (&trans->cache_caps2, NULL);
817 /* figure out same caps state */
818 trans->have_same_caps = gst_caps_is_equal (in, out);
819 GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
821 /* If we've a transform_ip method and same input/output caps, set in_place
822 * by default. If for some reason the sub-class prefers using a transform
823 * function, it can clear the in place flag in the set_caps */
824 gst_base_transform_set_in_place (trans,
825 klass->transform_ip && trans->have_same_caps);
827 /* Set the passthrough if the class wants passthrough_on_same_caps
828 * and we have the same caps on each pad */
829 if (klass->passthrough_on_same_caps)
830 gst_base_transform_set_passthrough (trans, trans->have_same_caps);
832 /* now configure the element with the caps */
833 if (klass->set_caps) {
834 GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
835 ret = klass->set_caps (trans, in, out);
836 }
838 GST_OBJECT_LOCK (trans);
839 /* make sure we reevaluate how the buffer_alloc works wrt to proxy allocating
840 * the buffer. FIXME, this triggers some quite heavy codepaths that don't need
841 * to be taken.. */
842 trans->priv->suggest_pending = TRUE;
843 GST_OBJECT_UNLOCK (trans);
844 trans->negotiated = ret;
846 return ret;
847 }
849 /* check if caps @in on @pad can be transformed to @out on the other pad.
850 * We don't have a vmethod to test this yet so we have to do a somewhat less
851 * efficient check for this.
852 */
853 static gboolean
854 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
855 GstCaps * in, GstCaps * out)
856 {
857 GstCaps *othercaps;
859 /* convert the in caps to all possible out caps */
860 othercaps =
861 gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
863 /* check if transform is empty */
864 if (!othercaps || gst_caps_is_empty (othercaps))
865 goto no_transform;
867 /* check if the out caps is a subset of the othercaps */
868 if (!gst_caps_can_intersect (out, othercaps))
869 goto no_subset;
871 if (othercaps)
872 gst_caps_unref (othercaps);
874 GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
875 GST_DEBUG_OBJECT (trans, "to %" GST_PTR_FORMAT, out);
877 return TRUE;
879 /* ERRORS */
880 no_transform:
881 {
882 GST_DEBUG_OBJECT (trans,
883 "transform returned useless %" GST_PTR_FORMAT, othercaps);
884 if (othercaps)
885 gst_caps_unref (othercaps);
886 return FALSE;
887 }
888 no_subset:
889 {
890 GST_DEBUG_OBJECT (trans, "no subset");
891 if (othercaps)
892 gst_caps_unref (othercaps);
893 return FALSE;
894 }
895 }
897 /* given a fixed @caps on @pad, create the best possible caps for the
898 * other pad.
899 * @caps must be fixed when calling this function.
900 *
901 * This function calls the transform caps vmethod of the basetransform to figure
902 * out the possible target formats. It then tries to select the best format from
903 * this list by:
904 *
905 * - attempt passthrough if the target caps is a superset of the input caps
906 * - fixating by using peer caps
907 * - fixating with transform fixate function
908 * - fixating with pad fixate functions.
909 *
910 * this function returns a caps that can be transformed into and is accepted by
911 * the peer element.
912 */
913 static GstCaps *
914 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
915 GstCaps * caps)
916 {
917 GstBaseTransformClass *klass;
918 GstPad *otherpad, *otherpeer;
919 GstCaps *othercaps;
920 gboolean peer_checked = FALSE;
921 gboolean is_fixed;
923 /* caps must be fixed here, this is a programming error if it's not */
924 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
926 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
928 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
929 otherpeer = gst_pad_get_peer (otherpad);
931 /* see how we can transform the input caps. We need to do this even for
932 * passthrough because it might be possible that this element cannot support
933 * passthrough at all. */
934 othercaps = gst_base_transform_transform_caps (trans,
935 GST_PAD_DIRECTION (pad), caps);
937 /* The caps we can actually output is the intersection of the transformed
938 * caps with the pad template for the pad */
939 if (othercaps) {
940 GstCaps *intersect;
941 const GstCaps *templ_caps;
943 templ_caps = gst_pad_get_pad_template_caps (otherpad);
944 GST_DEBUG_OBJECT (trans,
945 "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
947 intersect =
948 gst_caps_intersect_full (othercaps, templ_caps,
949 GST_CAPS_INTERSECT_FIRST);
951 gst_caps_unref (othercaps);
952 othercaps = intersect;
953 }
955 /* check if transform is empty */
956 if (!othercaps || gst_caps_is_empty (othercaps))
957 goto no_transform;
959 /* if the othercaps are not fixed, we need to fixate them, first attempt
960 * is by attempting passthrough if the othercaps are a superset of caps. */
961 /* FIXME. maybe the caps is not fixed because it has multiple structures of
962 * fixed caps */
963 is_fixed = gst_caps_is_fixed (othercaps);
964 if (!is_fixed) {
965 GST_DEBUG_OBJECT (trans,
966 "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
968 /* see if the target caps are a superset of the source caps, in this
969 * case we can try to perform passthrough */
970 if (gst_caps_can_intersect (othercaps, caps)) {
971 GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
972 if (otherpeer) {
973 /* try passthrough. we know it's fixed, because caps is fixed */
974 if (gst_pad_accept_caps (otherpeer, caps)) {
975 GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
976 /* peer accepted unmodified caps, we free the original non-fixed
977 * caps and work with the passthrough caps */
978 gst_caps_unref (othercaps);
979 othercaps = gst_caps_ref (caps);
980 is_fixed = TRUE;
981 /* mark that we checked othercaps with the peer, this
982 * makes sure we don't call accept_caps again with these same
983 * caps */
984 peer_checked = TRUE;
985 } else {
986 GST_DEBUG_OBJECT (trans,
987 "peer did not accept %" GST_PTR_FORMAT, caps);
988 }
989 } else {
990 GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
991 gst_caps_unref (othercaps);
992 othercaps = gst_caps_ref (caps);
993 is_fixed = TRUE;
994 }
995 }
996 }
998 /* second attempt at fixation is done by intersecting with
999 * the peer caps */
1000 if (!is_fixed && otherpeer) {
1001 /* intersect against what the peer can do */
1002 GstCaps *peercaps;
1003 GstCaps *intersect;
1005 GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
1007 peercaps = gst_pad_get_caps_reffed (otherpeer);
1008 intersect = gst_caps_intersect (peercaps, othercaps);
1009 gst_caps_unref (peercaps);
1010 gst_caps_unref (othercaps);
1011 othercaps = intersect;
1012 peer_checked = FALSE;
1014 is_fixed = gst_caps_is_fixed (othercaps);
1016 GST_DEBUG_OBJECT (trans,
1017 "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
1018 }
1020 if (gst_caps_is_empty (othercaps))
1021 goto no_transform_possible;
1023 /* third attempt at fixation, call the fixate vmethod and
1024 * ultimately call the pad fixate function. */
1025 if (!is_fixed) {
1026 GST_DEBUG_OBJECT (trans,
1027 "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
1028 othercaps, GST_DEBUG_PAD_NAME (otherpad));
1030 /* since we have no other way to fixate left, we might as well just take
1031 * the first of the caps list and fixate that */
1033 /* FIXME: when fixating using the vmethod, it might make sense to fixate
1034 * each of the caps; but Wim doesn't see a use case for that yet */
1035 gst_caps_truncate (othercaps);
1036 peer_checked = FALSE;
1038 if (klass->fixate_caps) {
1039 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1040 " using caps %" GST_PTR_FORMAT
1041 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1042 GST_DEBUG_PAD_NAME (otherpad));
1043 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1044 is_fixed = gst_caps_is_fixed (othercaps);
1045 }
1046 /* if still not fixed, no other option but to let the default pad fixate
1047 * function do its job */
1048 if (!is_fixed) {
1049 GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1050 " on pad %s:%s using gst_pad_fixate_caps", othercaps,
1051 GST_DEBUG_PAD_NAME (otherpad));
1052 gst_pad_fixate_caps (otherpad, othercaps);
1053 is_fixed = gst_caps_is_fixed (othercaps);
1054 }
1055 GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
1056 } else {
1057 GST_DEBUG ("caps are fixed");
1058 /* else caps are fixed but the subclass may want to add fields */
1059 if (klass->fixate_caps) {
1060 othercaps = gst_caps_make_writable (othercaps);
1062 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1063 " using caps %" GST_PTR_FORMAT
1064 " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1065 GST_DEBUG_PAD_NAME (otherpad));
1067 klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1068 is_fixed = gst_caps_is_fixed (othercaps);
1069 }
1070 }
1072 /* caps should be fixed now, if not we have to fail. */
1073 if (!is_fixed)
1074 goto could_not_fixate;
1076 /* and peer should accept, don't check again if we already checked the
1077 * othercaps against the peer. */
1078 if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
1079 goto peer_no_accept;
1081 GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1082 ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1084 if (otherpeer)
1085 gst_object_unref (otherpeer);
1087 return othercaps;
1089 /* ERRORS */
1090 no_transform:
1091 {
1092 GST_DEBUG_OBJECT (trans,
1093 "transform returned useless %" GST_PTR_FORMAT, othercaps);
1094 goto error_cleanup;
1095 }
1096 no_transform_possible:
1097 {
1098 GST_DEBUG_OBJECT (trans,
1099 "transform could not transform %" GST_PTR_FORMAT
1100 " in anything we support", caps);
1101 goto error_cleanup;
1102 }
1103 could_not_fixate:
1104 {
1105 GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1106 goto error_cleanup;
1107 }
1108 peer_no_accept:
1109 {
1110 GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1111 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1112 goto error_cleanup;
1113 }
1114 error_cleanup:
1115 {
1116 if (otherpeer)
1117 gst_object_unref (otherpeer);
1118 if (othercaps)
1119 gst_caps_unref (othercaps);
1120 return NULL;
1121 }
1122 }
1124 static gboolean
1125 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1126 GstPadDirection direction, GstCaps * caps)
1127 {
1128 #if 0
1129 GstPad *otherpad;
1130 GstCaps *othercaps = NULL;
1131 #endif
1132 gboolean ret = TRUE;
1134 #if 0
1135 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1137 /* we need fixed caps for the check, fall back to the default implementation
1138 * if we don't */
1139 if (!gst_caps_is_fixed (caps))
1140 #endif
1141 {
1142 GstCaps *allowed;
1144 GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1146 /* get all the formats we can handle on this pad */
1147 if (direction == GST_PAD_SRC)
1148 allowed = gst_pad_get_caps_reffed (trans->srcpad);
1149 else
1150 allowed = gst_pad_get_caps_reffed (trans->sinkpad);
1152 if (!allowed) {
1153 GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1154 goto no_transform_possible;
1155 }
1157 GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1159 /* intersect with the requested format */
1160 ret = gst_caps_can_intersect (allowed, caps);
1161 gst_caps_unref (allowed);
1163 if (!ret)
1164 goto no_transform_possible;
1165 }
1166 #if 0
1167 else {
1168 GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1170 /* find best possible caps for the other pad as a way to see if we can
1171 * transform this caps. */
1172 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1173 if (!othercaps || gst_caps_is_empty (othercaps))
1174 goto no_transform_possible;
1176 GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1177 }
1178 #endif
1180 done:
1181 #if 0
1182 /* We know it's always NULL since we never use it */
1183 if (othercaps)
1184 gst_caps_unref (othercaps);
1185 #endif
1187 return ret;
1189 /* ERRORS */
1190 no_transform_possible:
1191 {
1192 GST_DEBUG_OBJECT (trans,
1193 "transform could not transform %" GST_PTR_FORMAT
1194 " in anything we support", caps);
1195 ret = FALSE;
1196 goto done;
1197 }
1198 }
1200 static gboolean
1201 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1202 {
1203 gboolean ret = TRUE;
1204 GstBaseTransform *trans;
1205 GstBaseTransformClass *bclass;
1207 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1208 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1210 if (bclass->accept_caps)
1211 ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1213 gst_object_unref (trans);
1215 return ret;
1216 }
1218 /* called when new caps arrive on the sink or source pad,
1219 * We try to find the best caps for the other side using our _find_transform()
1220 * function. If there are caps, we configure the transform for this new
1221 * transformation.
1222 *
1223 * FIXME, this function is currently commutative but this should not really be
1224 * because we never set caps starting from the srcpad.
1225 */
1226 static gboolean
1227 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1228 {
1229 GstBaseTransform *trans;
1230 GstPad *otherpad, *otherpeer;
1231 GstCaps *othercaps = NULL;
1232 gboolean ret = TRUE;
1233 GstCaps *incaps, *outcaps;
1235 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1237 otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1238 otherpeer = gst_pad_get_peer (otherpad);
1240 /* if we get called recursively, we bail out now to avoid an
1241 * infinite loop. */
1242 if (GST_PAD_IS_IN_SETCAPS (otherpad))
1243 goto done;
1245 GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1247 /* find best possible caps for the other pad */
1248 othercaps = gst_base_transform_find_transform (trans, pad, caps);
1249 if (!othercaps || gst_caps_is_empty (othercaps))
1250 goto no_transform_possible;
1252 /* configure the element now */
1253 /* make sure in and out caps are correct */
1254 if (pad == trans->sinkpad) {
1255 incaps = caps;
1256 outcaps = othercaps;
1257 } else {
1258 incaps = othercaps;
1259 outcaps = caps;
1260 }
1262 /* if we have the same caps, we can optimize and reuse the input caps */
1263 if (gst_caps_is_equal (incaps, outcaps)) {
1264 GST_INFO_OBJECT (trans, "reuse caps");
1265 gst_caps_unref (othercaps);
1266 outcaps = othercaps = gst_caps_ref (incaps);
1267 }
1269 /* call configure now */
1270 if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1271 goto failed_configure;
1273 /* we know this will work, we implement the setcaps */
1274 gst_pad_set_caps (otherpad, othercaps);
1276 if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1277 /* FIXME hm? */
1278 ret &= gst_pad_set_caps (otherpeer, othercaps);
1279 if (!ret) {
1280 GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1281 othercaps);
1282 }
1283 }
1285 done:
1286 /* new caps, force alloc on next buffer on the chain */
1287 trans->priv->force_alloc = TRUE;
1288 if (otherpeer)
1289 gst_object_unref (otherpeer);
1290 if (othercaps)
1291 gst_caps_unref (othercaps);
1293 trans->negotiated = ret;
1295 gst_object_unref (trans);
1297 return ret;
1299 /* ERRORS */
1300 no_transform_possible:
1301 {
1302 GST_WARNING_OBJECT (trans,
1303 "transform could not transform %" GST_PTR_FORMAT
1304 " in anything we support", caps);
1305 ret = FALSE;
1306 goto done;
1307 }
1308 failed_configure:
1309 {
1310 GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1311 " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1312 ret = FALSE;
1313 goto done;
1314 }
1315 }
1317 static gboolean
1318 gst_base_transform_default_query (GstBaseTransform * trans,
1319 GstPadDirection direction, GstQuery * query)
1320 {
1321 gboolean ret = FALSE;
1322 GstPad *otherpad;
1324 otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1326 switch (GST_QUERY_TYPE (query)) {
1327 case GST_QUERY_POSITION:{
1328 GstFormat format;
1330 gst_query_parse_position (query, &format, NULL);
1331 if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1332 gint64 pos;
1333 ret = TRUE;
1335 if ((direction == GST_PAD_SINK)
1336 || (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
1337 pos =
1338 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1339 trans->segment.last_stop);
1340 } else {
1341 pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1342 trans->priv->last_stop_out);
1343 }
1344 gst_query_set_position (query, format, pos);
1345 } else {
1346 ret = gst_pad_peer_query (otherpad, query);
1347 }
1348 break;
1349 }
1350 default:
1351 ret = gst_pad_peer_query (otherpad, query);
1352 break;
1353 }
1355 return ret;
1356 }
1358 static gboolean
1359 gst_base_transform_query (GstPad * pad, GstQuery * query)
1360 {
1361 GstBaseTransform *trans;
1362 GstBaseTransformClass *bclass;
1363 gboolean ret;
1365 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1366 if (G_UNLIKELY (trans == NULL))
1367 return FALSE;
1369 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1371 if (bclass->query)
1372 ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1373 else
1374 ret = gst_pad_query_default (pad, query);
1376 gst_object_unref (trans);
1378 return ret;
1379 }
1381 static const GstQueryType *
1382 gst_base_transform_query_type (GstPad * pad)
1383 {
1384 static const GstQueryType types[] = {
1385 GST_QUERY_POSITION,
1386 GST_QUERY_NONE
1387 };
1389 return types;
1390 }
1392 static void
1393 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1394 GstCaps * caps)
1395 {
1396 GstCaps *othercaps;
1397 GstBaseTransformPrivate *priv = trans->priv;
1399 GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1401 /* we cannot convert the current buffer but we might be able to suggest a
1402 * new format upstream, try to find what the best format is. */
1403 othercaps = gst_base_transform_find_transform (trans, trans->srcpad, caps);
1405 if (!othercaps) {
1406 GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1407 /* we received caps that we cannot transform. Upstream is behaving badly
1408 * because it should have checked if we could handle these caps. We can
1409 * simply ignore these caps and produce a buffer with our original caps. */
1410 } else {
1411 guint size_suggest;
1413 GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1415 /* not a subset, we have a new upstream suggestion, remember it and
1416 * allocate a default buffer. First we try to convert the size */
1417 if (gst_base_transform_transform_size (trans,
1418 GST_PAD_SRC, caps, expsize, othercaps, &size_suggest)) {
1420 /* ok, remember the suggestions now */
1421 GST_DEBUG_OBJECT (trans,
1422 "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1423 size_suggest, othercaps);
1425 GST_OBJECT_LOCK (trans->sinkpad);
1426 if (priv->sink_suggest)
1427 gst_caps_unref (priv->sink_suggest);
1428 priv->sink_suggest = gst_caps_ref (othercaps);
1429 priv->size_suggest = size_suggest;
1430 trans->priv->suggest_pending = TRUE;
1431 GST_OBJECT_UNLOCK (trans->sinkpad);
1432 }
1433 gst_caps_unref (othercaps);
1434 }
1435 }
1437 /* Allocate a buffer using gst_pad_alloc_buffer
1438 *
1439 * This function can do renegotiation on the source pad
1440 *
1441 * The output buffer is always writable. outbuf can be equal to
1442 * inbuf, the caller should be prepared for this and perform
1443 * appropriate refcounting.
1444 */
1445 static GstFlowReturn
1446 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1447 GstBuffer * in_buf, GstBuffer ** out_buf)
1448 {
1449 GstBaseTransformClass *bclass;
1450 GstBaseTransformPrivate *priv;
1451 GstFlowReturn ret = GST_FLOW_OK;
1452 guint outsize, newsize, expsize;
1453 gboolean discard, setcaps, copymeta;
1454 GstCaps *incaps, *oldcaps, *newcaps, *outcaps;
1456 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1458 priv = trans->priv;
1460 *out_buf = NULL;
1462 /* figure out how to allocate a buffer based on the current configuration */
1463 if (trans->passthrough) {
1464 GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1465 /* passthrough, we don't really need to call pad alloc but we still need to
1466 * in order to get upstream negotiation. The output size is the same as the
1467 * input size. */
1468 outsize = GST_BUFFER_SIZE (in_buf);
1469 /* we always alloc and discard here */
1470 discard = TRUE;
1471 } else {
1472 gboolean want_in_place = (bclass->transform_ip != NULL)
1473 && trans->always_in_place;
1475 if (want_in_place) {
1476 GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1477 /* we alloc a buffer of the same size as the input */
1478 outsize = GST_BUFFER_SIZE (in_buf);
1479 /* only discard it when the input was not writable, otherwise, we reuse
1480 * the input buffer. */
1481 discard = gst_buffer_is_writable (in_buf);
1482 GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1483 } else {
1484 GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1485 /* copy transform, figure out the output size */
1486 if (!gst_base_transform_transform_size (trans,
1487 GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1488 GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1489 &outsize)) {
1490 goto unknown_size;
1491 }
1492 /* never discard this buffer, we need it for storing the output */
1493 discard = FALSE;
1494 }
1495 }
1497 oldcaps = GST_PAD_CAPS (trans->srcpad);
1499 if (bclass->prepare_output_buffer) {
1500 GST_DEBUG_OBJECT (trans,
1501 "calling prepare buffer with caps %p %" GST_PTR_FORMAT, oldcaps,
1502 oldcaps);
1503 ret =
1504 bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1505 out_buf);
1507 /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1508 * update the pad caps if it wants */
1509 oldcaps = GST_PAD_CAPS (trans->srcpad);
1511 /* FIXME 0.11:
1512 * decrease refcount again if vmethod returned refcounted in_buf. This
1513 * is because we need to make sure that the buffer is writable for the
1514 * in_place transform. The docs of the vmethod say that you should return
1515 * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1516 if (in_buf == *out_buf)
1517 gst_buffer_unref (in_buf);
1519 /* never discard the buffer from the prepare_buffer method */
1520 if (*out_buf != NULL)
1521 discard = FALSE;
1522 }
1524 if (ret != GST_FLOW_OK)
1525 goto alloc_failed;
1527 if (*out_buf == NULL) {
1528 if (trans->passthrough && !trans->priv->force_alloc) {
1529 GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
1530 *out_buf = gst_buffer_ref (in_buf);
1531 } else {
1532 GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
1533 oldcaps);
1535 ret = gst_pad_alloc_buffer (trans->srcpad,
1536 GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1537 if (ret != GST_FLOW_OK)
1538 goto alloc_failed;
1539 }
1540 }
1542 /* must always have a buffer by now */
1543 if (*out_buf == NULL)
1544 goto no_buffer;
1546 /* check if we got different caps on this new output buffer */
1547 newcaps = GST_BUFFER_CAPS (*out_buf);
1548 newsize = GST_BUFFER_SIZE (*out_buf);
1550 if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1551 GstCaps *othercaps;
1552 gboolean can_convert;
1554 GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1556 incaps = GST_PAD_CAPS (trans->sinkpad);
1558 /* check if we can convert the current incaps to the new target caps */
1559 can_convert =
1560 gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1561 newcaps);
1563 if (!can_convert) {
1564 GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1566 gst_base_transform_transform_size (trans,
1567 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1569 compute_upstream_suggestion (trans, expsize, newcaps);
1571 /* we got a suggested caps but we can't transform to it. See if there is
1572 * another downstream format that we can transform to */
1573 othercaps =
1574 gst_base_transform_find_transform (trans, trans->sinkpad, incaps);
1576 if (othercaps && !gst_caps_is_empty (othercaps)) {
1577 GST_DEBUG_OBJECT (trans, "we found target caps %" GST_PTR_FORMAT,
1578 othercaps);
1579 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1580 gst_buffer_set_caps (*out_buf, othercaps);
1581 gst_caps_unref (othercaps);
1582 newcaps = GST_BUFFER_CAPS (*out_buf);
1583 can_convert = TRUE;
1584 } else if (othercaps)
1585 gst_caps_unref (othercaps);
1586 }
1588 /* it's possible that the buffer we got is of the wrong size, get the
1589 * expected size here, we will check the size if we are going to use the
1590 * buffer later on. */
1591 gst_base_transform_transform_size (trans,
1592 GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1594 if (can_convert) {
1595 GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1597 /* subclass might want to add fields to the caps */
1598 if (bclass->fixate_caps != NULL) {
1599 newcaps = gst_caps_copy (newcaps);
1601 GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1602 " using caps %" GST_PTR_FORMAT
1603 " on pad %s:%s using fixate_caps vmethod", newcaps, incaps,
1604 GST_DEBUG_PAD_NAME (trans->srcpad));
1605 bclass->fixate_caps (trans, GST_PAD_SINK, incaps, newcaps);
1607 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1608 gst_buffer_set_caps (*out_buf, newcaps);
1609 gst_caps_unref (newcaps);
1610 newcaps = GST_BUFFER_CAPS (*out_buf);
1611 }
1613 /* caps not empty, try to renegotiate to the new format */
1614 if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1615 /* not sure we need to fail hard here, we can simply continue our
1616 * conversion with what we negotiated before */
1617 goto failed_configure;
1618 }
1619 /* new format configure, and use the new output buffer */
1620 gst_pad_set_caps (trans->srcpad, newcaps);
1621 discard = FALSE;
1622 /* clear previous cached sink-pad caps, so buffer_alloc knows that
1623 * it needs to revisit the decision about whether to proxy or not: */
1624 gst_caps_replace (&priv->sink_alloc, NULL);
1625 /* if we got a buffer of the wrong size, discard it now and make sure we
1626 * allocate a properly sized buffer later. */
1627 if (newsize != expsize) {
1628 if (in_buf != *out_buf)
1629 gst_buffer_unref (*out_buf);
1630 *out_buf = NULL;
1631 }
1632 outsize = expsize;
1633 } else {
1634 compute_upstream_suggestion (trans, expsize, newcaps);
1636 if (in_buf != *out_buf)
1637 gst_buffer_unref (*out_buf);
1638 *out_buf = NULL;
1639 }
1640 } else if (outsize != newsize) {
1641 GST_WARNING_OBJECT (trans, "Caps did not change but allocated size does "
1642 "not match expected size (%d != %d)", newsize, outsize);
1643 if (in_buf != *out_buf)
1644 gst_buffer_unref (*out_buf);
1645 *out_buf = NULL;
1646 }
1648 /* these are the final output caps */
1649 outcaps = GST_PAD_CAPS (trans->srcpad);
1651 copymeta = FALSE;
1652 if (*out_buf == NULL) {
1653 if (!discard) {
1654 GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1655 outsize);
1656 /* no valid buffer yet, make one, metadata is writable */
1657 *out_buf = gst_buffer_new_and_alloc (outsize);
1658 gst_buffer_copy_metadata (*out_buf, in_buf,
1659 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1660 } else {
1661 GST_DEBUG_OBJECT (trans, "reuse input buffer");
1662 *out_buf = in_buf;
1663 }
1664 } else {
1665 if (trans->passthrough && in_buf != *out_buf) {
1666 /* we are asked to perform a passthrough transform but the input and
1667 * output buffers are different. We have to discard the output buffer and
1668 * reuse the input buffer. */
1669 GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1670 discard = TRUE;
1671 }
1672 if (discard) {
1673 GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1674 gst_buffer_unref (*out_buf);
1675 *out_buf = in_buf;
1676 } else {
1677 GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", in_buf,
1678 *out_buf);
1679 /* if we have different buffers, check if the metadata is ok */
1680 if (*out_buf != in_buf) {
1681 guint mask;
1683 mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
1684 GST_BUFFER_FLAG_DELTA_UNIT | GST_BUFFER_FLAG_DISCONT |
1685 GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_MEDIA1 |
1686 GST_BUFFER_FLAG_MEDIA2 | GST_BUFFER_FLAG_MEDIA3;
1687 /* see if the flags and timestamps match */
1688 copymeta =
1689 (GST_MINI_OBJECT_FLAGS (*out_buf) & mask) ==
1690 (GST_MINI_OBJECT_FLAGS (in_buf) & mask);
1691 copymeta |=
1692 GST_BUFFER_TIMESTAMP (*out_buf) != GST_BUFFER_TIMESTAMP (in_buf) ||
1693 GST_BUFFER_DURATION (*out_buf) != GST_BUFFER_DURATION (in_buf) ||
1694 GST_BUFFER_OFFSET (*out_buf) != GST_BUFFER_OFFSET (in_buf) ||
1695 GST_BUFFER_OFFSET_END (*out_buf) != GST_BUFFER_OFFSET_END (in_buf);
1696 }
1697 }
1698 }
1700 /* check if we need to make things writable. We need this when we need to
1701 * update the caps or the metadata on the output buffer. */
1702 newcaps = GST_BUFFER_CAPS (*out_buf);
1703 /* we check the pointers as a quick check and then go to the more involved
1704 * check. This is needed when we receive different pointers on the sinkpad
1705 * that mean the same caps. What we then want to do is prefer those caps over
1706 * the ones on the srcpad and set the srcpad caps to the buffer caps */
1707 setcaps = !newcaps || ((newcaps != outcaps)
1708 && (!gst_caps_is_equal (newcaps, outcaps)));
1709 /* we need to modify the metadata when the element is not gap aware,
1710 * passthrough is not used and the gap flag is set */
1711 copymeta |= !trans->priv->gap_aware && !trans->passthrough
1712 && (GST_MINI_OBJECT_FLAGS (*out_buf) & GST_BUFFER_FLAG_GAP);
1714 if (setcaps || copymeta) {
1715 GST_DEBUG_OBJECT (trans, "setcaps %d, copymeta %d", setcaps, copymeta);
1716 if (!gst_buffer_is_metadata_writable (*out_buf)) {
1717 GST_DEBUG_OBJECT (trans, "buffer metadata %p not writable", *out_buf);
1718 if (in_buf == *out_buf)
1719 *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
1720 else
1721 *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1722 }
1723 /* when we get here, the metadata should be writable */
1724 if (setcaps)
1725 gst_buffer_set_caps (*out_buf, outcaps);
1726 if (copymeta)
1727 gst_buffer_copy_metadata (*out_buf, in_buf,
1728 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1729 /* clear the GAP flag when the subclass does not understand it */
1730 if (!trans->priv->gap_aware)
1731 GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1732 }
1734 return ret;
1736 /* ERRORS */
1737 alloc_failed:
1738 {
1739 GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1740 return ret;
1741 }
1742 no_buffer:
1743 {
1744 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1745 ("Sub-class failed to provide an output buffer"), (NULL));
1746 return GST_FLOW_ERROR;
1747 }
1748 unknown_size:
1749 {
1750 GST_ERROR_OBJECT (trans, "unknown output size");
1751 return GST_FLOW_ERROR;
1752 }
1753 failed_configure:
1754 {
1755 GST_WARNING_OBJECT (trans, "failed to configure caps");
1756 return GST_FLOW_NOT_NEGOTIATED;
1757 }
1758 }
1760 /* Given @caps calcultate the size of one unit.
1761 *
1762 * For video caps, this is the size of one frame (and thus one buffer).
1763 * For audio caps, this is the size of one sample.
1764 *
1765 * These values are cached since they do not change and the calculation
1766 * potentially involves parsing caps and other expensive stuff.
1767 *
1768 * We have two cache locations to store the size, one for the source caps
1769 * and one for the sink caps.
1770 *
1771 * this function returns FALSE if no size could be calculated.
1772 */
1773 static gboolean
1774 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1775 guint * size)
1776 {
1777 gboolean res = FALSE;
1778 GstBaseTransformClass *bclass;
1780 /* see if we have the result cached */
1781 if (trans->cache_caps1 == caps) {
1782 *size = trans->cache_caps1_size;
1783 GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1784 return TRUE;
1785 }
1786 if (trans->cache_caps2 == caps) {
1787 *size = trans->cache_caps2_size;
1788 GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1789 return TRUE;
1790 }
1792 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1793 if (bclass->get_unit_size) {
1794 res = bclass->get_unit_size (trans, caps, size);
1795 GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1796 ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1798 if (res) {
1799 /* and cache the values */
1800 if (trans->cache_caps1 == NULL) {
1801 gst_caps_replace (&trans->cache_caps1, caps);
1802 trans->cache_caps1_size = *size;
1803 GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1804 } else if (trans->cache_caps2 == NULL) {
1805 gst_caps_replace (&trans->cache_caps2, caps);
1806 trans->cache_caps2_size = *size;
1807 GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1808 } else {
1809 GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1810 }
1811 }
1812 } else {
1813 GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1814 }
1815 return res;
1816 }
1818 /* your upstream peer wants to send you a buffer
1819 * that buffer has the given offset, size and caps
1820 * you're requested to allocate a buffer
1821 */
1822 static GstFlowReturn
1823 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1824 GstCaps * caps, GstBuffer ** buf)
1825 {
1826 GstBaseTransform *trans;
1827 GstBaseTransformPrivate *priv;
1828 GstFlowReturn res;
1829 gboolean alloced = FALSE;
1830 gboolean proxy, suggest, new_caps;
1831 GstCaps *sink_suggest = NULL;
1832 guint size_suggest;
1834 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1835 if (G_UNLIKELY (trans == NULL))
1836 return GST_FLOW_WRONG_STATE;
1837 priv = trans->priv;
1839 GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1840 caps, caps, size);
1842 /* if the code below does not come up with a better buffer, we will return _OK
1843 * and an empty buffer. This will trigger the core to allocate a buffer with
1844 * given input size and caps. */
1845 *buf = NULL;
1846 res = GST_FLOW_OK;
1848 /* we remember our previous alloc request to quickly see if we can proxy or
1849 * not. We skip this check if we have a pending suggestion. */
1850 GST_OBJECT_LOCK (pad);
1851 suggest = priv->suggest_pending;
1852 GST_OBJECT_UNLOCK (pad);
1854 if (!suggest) {
1855 /* we have no suggestion, see below if we need to proxy */
1856 gst_caps_replace (&sink_suggest, caps);
1857 size_suggest = size;
1858 suggest = FALSE;
1859 new_caps = sink_suggest
1860 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1862 if (new_caps)
1863 GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1864 else
1865 GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1866 } else {
1867 /* if we have a suggestion, pretend we got these as input */
1868 GST_OBJECT_LOCK (pad);
1869 if (priv->sink_suggest &&
1870 !gst_caps_can_intersect (caps, priv->sink_suggest)) {
1871 sink_suggest = gst_caps_ref (priv->sink_suggest);
1872 size_suggest = priv->size_suggest;
1873 GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1874 sink_suggest, sink_suggest, priv->size_suggest);
1875 } else {
1876 GST_DEBUG_OBJECT (trans,
1877 "have suggestion equal to upstream caps %p %" GST_PTR_FORMAT, caps,
1878 caps);
1879 gst_caps_replace (&sink_suggest, caps);
1880 size_suggest = size;
1881 suggest = FALSE;
1882 }
1883 priv->suggest_pending = FALSE;
1884 GST_OBJECT_UNLOCK (pad);
1886 /* check if we actually handle this format on the sinkpad */
1887 if (suggest) {
1888 GstCaps *peercaps;
1890 /* Always intersect with the peer caps to get correct
1891 * and complete caps. The suggested caps could be incomplete,
1892 * for example video/x-raw-yuv without any fields at all.
1893 */
1894 peercaps =
1895 gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1897 if (peercaps) {
1898 GstCaps *intersect;
1900 intersect =
1901 gst_caps_intersect_full (sink_suggest, peercaps,
1902 GST_CAPS_INTERSECT_FIRST);
1903 gst_caps_unref (peercaps);
1905 /* If intersected caps is empty then just keep them empty. The
1906 * code below will try to come up with possible caps if there
1907 * are any */
1908 gst_caps_unref (sink_suggest);
1909 sink_suggest = intersect;
1910 }
1912 /* If the suggested caps are not empty and not fixed, try to fixate them */
1913 if (!gst_caps_is_fixed (sink_suggest)
1914 && !gst_caps_is_empty (sink_suggest)) {
1915 GST_DEBUG_OBJECT (trans,
1916 "Suggested caps is not fixed: %" GST_PTR_FORMAT, sink_suggest);
1918 /* try the alloc caps if it is still not fixed */
1919 if (!gst_caps_is_fixed (sink_suggest)) {
1920 GstCaps *intersect;
1922 GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1923 "with the non-fixed caps suggestion");
1924 intersect =
1925 gst_caps_intersect_full (sink_suggest, caps,
1926 GST_CAPS_INTERSECT_FIRST);
1927 if (!gst_caps_is_empty (intersect)) {
1928 GST_DEBUG_OBJECT (trans, "It is, using it");
1929 gst_caps_replace (&sink_suggest, caps);
1930 }
1931 gst_caps_unref (intersect);
1932 }
1934 /* be safe and call default fixate */
1935 sink_suggest = gst_caps_make_writable (sink_suggest);
1936 gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1938 if (!gst_caps_is_fixed (sink_suggest)) {
1939 GST_DEBUG_OBJECT (trans,
1940 "Impossible to fixate caps, using upstream caps");
1941 gst_caps_replace (&sink_suggest, caps);
1942 size_suggest = size;
1943 suggest = FALSE;
1944 }
1946 GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1947 sink_suggest);
1948 }
1949 }
1951 new_caps = sink_suggest
1952 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1953 }
1955 /* Check if the new caps are compatible with our
1956 * sinkpad template caps and if they're not
1957 * we try to come up with any supported caps
1958 */
1959 if (new_caps) {
1960 const GstCaps *templ;
1962 templ = gst_pad_get_pad_template_caps (pad);
1964 /* Fall back to the upstream caps if the suggested caps
1965 * are not actually supported. Shouldn't really happen
1966 */
1967 if (suggest && !gst_caps_can_intersect (sink_suggest, templ)) {
1968 GST_DEBUG_OBJECT (trans,
1969 "Suggested caps not supported by sinkpad, using upstream caps");
1970 gst_caps_replace (&sink_suggest, caps);
1971 size_suggest = size;
1972 suggest = FALSE;
1973 new_caps = sink_suggest
1974 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1975 }
1977 if (new_caps && (suggest || !gst_caps_can_intersect (sink_suggest, templ))) {
1978 GstCaps *allowed, *peercaps;
1980 GST_DEBUG_OBJECT (trans,
1981 "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1982 sink_suggest);
1983 /* the requested pad alloc caps are not supported, so let's try
1984 * picking something allowed between the pads (they are linked,
1985 * there must be something) */
1986 allowed = gst_pad_get_allowed_caps (pad);
1987 if (allowed && !gst_caps_is_empty (allowed)) {
1988 GST_DEBUG_OBJECT (trans,
1989 "pads could agree on one of the following caps: " "%"
1990 GST_PTR_FORMAT, allowed);
1992 /* Check which caps would be possible with downstream */
1993 peercaps =
1994 gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1995 if (peercaps) {
1996 GstCaps *tmp, *intersect;
1998 tmp =
1999 gst_base_transform_transform_caps (trans, GST_PAD_SRC, peercaps);
2000 gst_caps_unref (peercaps);
2001 intersect = gst_caps_intersect (allowed, tmp);
2002 gst_caps_unref (tmp);
2003 gst_caps_unref (allowed);
2005 if (gst_caps_is_empty (intersect)) {
2006 gst_caps_unref (intersect);
2007 goto not_supported;
2008 }
2010 allowed = intersect;
2011 }
2013 allowed = gst_caps_make_writable (allowed);
2015 /* Fixate them to be safe if the subclass didn't do it */
2016 gst_caps_truncate (allowed);
2017 gst_pad_fixate_caps (pad, allowed);
2019 if (!gst_caps_is_fixed (allowed)) {
2020 GST_ERROR_OBJECT (trans, "Impossible to fixate any caps");
2021 gst_caps_unref (allowed);
2022 goto not_supported;
2023 }
2025 gst_caps_replace (&sink_suggest, allowed);
2026 gst_caps_unref (allowed);
2028 suggest = TRUE;
2029 new_caps = !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
2031 GST_DEBUG_OBJECT (trans, "Calculated new suggestion caps %"
2032 GST_PTR_FORMAT, sink_suggest);
2033 } else {
2034 if (allowed)
2035 gst_caps_unref (allowed);
2036 goto not_supported;
2037 }
2038 }
2039 }
2041 /* find the best format for the other side here we decide if we will proxy
2042 * the caps or not. */
2043 if (sink_suggest == NULL) {
2044 /* always proxy when the caps are NULL. When this is a new format, see if
2045 * we can proxy it downstream */
2046 GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
2047 priv->proxy_alloc = TRUE;
2048 } else if (new_caps) {
2049 GstCaps *othercaps;
2051 /* we have a new format, see what we need to proxy to */
2052 othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
2053 if (!othercaps || gst_caps_is_empty (othercaps)) {
2054 /* no transform possible, we certainly can't proxy */
2055 GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
2056 priv->proxy_alloc = FALSE;
2057 } else {
2058 /* we transformed into something */
2059 if (gst_caps_is_equal (sink_suggest, othercaps)) {
2060 GST_DEBUG_OBJECT (trans, "best caps same as input, marking for proxy");
2061 priv->proxy_alloc = TRUE;
2062 } else {
2063 GST_DEBUG_OBJECT (trans,
2064 "best caps different from input, disable proxy");
2065 priv->proxy_alloc = FALSE;
2066 }
2067 }
2068 if (othercaps)
2069 gst_caps_unref (othercaps);
2070 }
2072 /* remember the new caps */
2073 GST_OBJECT_LOCK (pad);
2074 gst_caps_replace (&priv->sink_alloc, sink_suggest);
2075 GST_OBJECT_UNLOCK (pad);
2077 proxy = priv->proxy_alloc;
2078 GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
2079 suggest);
2081 /* we only want to proxy if we have no suggestion pending, FIXME */
2082 if (proxy && !suggest) {
2083 GstCaps *newcaps;
2085 GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
2086 ", size %u", caps, caps, size);
2088 /* we always proxy the input caps, never the suggestion. The reason is that
2089 * We don't yet handle the caps of renegotiation in here. FIXME */
2090 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
2091 if (res != GST_FLOW_OK)
2092 goto alloc_failed;
2093 alloced = TRUE;
2095 /* check if the caps changed */
2096 newcaps = GST_BUFFER_CAPS (*buf);
2098 GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
2100 if (!gst_caps_is_equal (newcaps, caps)) {
2101 GST_DEBUG_OBJECT (trans, "caps are new");
2102 /* we have new caps, see if we can proxy downstream */
2103 if (gst_pad_peer_accept_caps (pad, newcaps)) {
2104 /* peer accepts the caps, return a buffer in this format */
2105 GST_DEBUG_OBJECT (trans, "peer accepted new caps");
2106 /* remember the format */
2107 GST_OBJECT_LOCK (pad);
2108 gst_caps_replace (&priv->sink_alloc, newcaps);
2109 GST_OBJECT_UNLOCK (pad);
2110 } else {
2111 GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
2112 /* peer does not accept the caps, disable proxy_alloc, free the
2113 * buffer we received and create a buffer of the requested format
2114 * by the default handler. */
2115 GST_DEBUG_OBJECT (trans, "disabling proxy");
2116 priv->proxy_alloc = FALSE;
2117 gst_buffer_unref (*buf);
2118 *buf = NULL;
2119 }
2120 } else {
2121 GST_DEBUG_OBJECT (trans, "received required caps from peer");
2122 }
2123 } else if (suggest) {
2124 /* there was a custom suggestion, create a buffer of this format and return
2125 * it. Note that this format */
2126 *buf = gst_buffer_new_and_alloc (size_suggest);
2127 GST_DEBUG_OBJECT (trans,
2128 "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2129 sink_suggest, sink_suggest);
2130 GST_BUFFER_CAPS (*buf) = sink_suggest;
2131 sink_suggest = NULL;
2132 } else {
2133 /* fallback buffer allocation by gst_pad_alloc_buffer() with the
2134 * caps and size provided by the caller */
2135 }
2137 if (sink_suggest)
2138 gst_caps_unref (sink_suggest);
2140 if (res == GST_FLOW_OK && alloced) {
2141 /* just alloc'ed a buffer, so we only want to do this again if we
2142 * received a buffer */
2143 GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2144 trans->priv->force_alloc = FALSE;
2145 }
2147 gst_object_unref (trans);
2148 return res;
2150 /* ERRORS */
2151 alloc_failed:
2152 {
2153 GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2154 if (sink_suggest)
2155 gst_caps_unref (sink_suggest);
2156 gst_object_unref (trans);
2157 return res;
2158 }
2159 not_supported:
2160 {
2161 GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2162 if (sink_suggest)
2163 gst_caps_unref (sink_suggest);
2164 gst_object_unref (trans);
2165 return GST_FLOW_NOT_NEGOTIATED;
2166 }
2167 }
2169 static void
2170 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2171 {
2172 GList *list, *tmp;
2174 GST_OBJECT_LOCK (trans);
2175 list = trans->priv->delayed_events;
2176 trans->priv->delayed_events = NULL;
2177 GST_OBJECT_UNLOCK (trans);
2178 if (!list)
2179 return;
2181 for (tmp = list; tmp; tmp = tmp->next) {
2182 GstEvent *ev = tmp->data;
2184 GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2185 GST_EVENT_TYPE_NAME (ev));
2186 gst_pad_push_event (trans->srcpad, ev);
2187 }
2188 g_list_free (list);
2189 }
2191 static gboolean
2192 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2193 {
2194 GstBaseTransform *trans;
2195 GstBaseTransformClass *bclass;
2196 gboolean ret = TRUE;
2197 gboolean forward = TRUE;
2199 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2200 if (G_UNLIKELY (trans == NULL)) {
2201 gst_event_unref (event);
2202 return FALSE;
2203 }
2204 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2206 if (bclass->event)
2207 forward = bclass->event (trans, event);
2209 /* FIXME, do this in the default event handler so the subclass can do
2210 * something different. */
2211 if (forward) {
2212 gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2214 /* src caps may not yet be set, so we delay any serialized events
2215 that we receive before (in particular newsegment events), except
2216 EOS and flush stops, since those'll obsolete previous events */
2217 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2218 gst_base_transform_drop_delayed_events (trans);
2219 delay = FALSE;
2220 } else {
2221 delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2222 && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2223 }
2225 if (delay) {
2226 GST_OBJECT_LOCK (trans);
2227 trans->priv->delayed_events =
2228 g_list_append (trans->priv->delayed_events, event);
2229 GST_OBJECT_UNLOCK (trans);
2230 } else {
2231 if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2232 gst_base_transform_send_delayed_events (trans);
2233 ret = gst_pad_push_event (trans->srcpad, event);
2234 }
2235 } else
2236 gst_event_unref (event);
2238 gst_object_unref (trans);
2240 return ret;
2241 }
2243 static gboolean
2244 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2245 {
2246 switch (GST_EVENT_TYPE (event)) {
2247 case GST_EVENT_FLUSH_START:
2248 break;
2249 case GST_EVENT_FLUSH_STOP:
2250 GST_OBJECT_LOCK (trans);
2251 /* reset QoS parameters */
2252 trans->priv->proportion = 1.0;
2253 trans->priv->earliest_time = -1;
2254 trans->priv->discont = FALSE;
2255 trans->priv->processed = 0;
2256 trans->priv->dropped = 0;
2257 GST_OBJECT_UNLOCK (trans);
2258 /* we need new segment info after the flush. */
2259 trans->have_newsegment = FALSE;
2260 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2261 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2262 break;
2263 case GST_EVENT_EOS:
2264 break;
2265 case GST_EVENT_TAG:
2266 break;
2267 case GST_EVENT_NEWSEGMENT:
2268 {
2269 GstFormat format;
2270 gdouble rate, arate;
2271 gint64 start, stop, time;
2272 gboolean update;
2274 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2275 &start, &stop, &time);
2277 trans->have_newsegment = TRUE;
2279 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2280 format, start, stop, time);
2282 if (format == GST_FORMAT_TIME) {
2283 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2284 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2285 ", accum %" GST_TIME_FORMAT,
2286 GST_TIME_ARGS (trans->segment.start),
2287 GST_TIME_ARGS (trans->segment.stop),
2288 GST_TIME_ARGS (trans->segment.time),
2289 GST_TIME_ARGS (trans->segment.accum));
2290 } else {
2291 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2292 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2293 ", accum %" G_GINT64_FORMAT,
2294 trans->segment.start, trans->segment.stop,
2295 trans->segment.time, trans->segment.accum);
2296 }
2297 break;
2298 }
2299 default:
2300 break;
2301 }
2303 return TRUE;
2304 }
2306 static gboolean
2307 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2308 {
2309 GstBaseTransform *trans;
2310 GstBaseTransformClass *bclass;
2311 gboolean ret = TRUE;
2313 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2314 if (G_UNLIKELY (trans == NULL)) {
2315 gst_event_unref (event);
2316 return FALSE;
2317 }
2319 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2321 if (bclass->src_event)
2322 ret = bclass->src_event (trans, event);
2323 else
2324 gst_event_unref (event);
2326 gst_object_unref (trans);
2328 return ret;
2329 }
2331 static gboolean
2332 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2333 {
2334 gboolean ret;
2336 GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2338 switch (GST_EVENT_TYPE (event)) {
2339 case GST_EVENT_SEEK:
2340 break;
2341 case GST_EVENT_NAVIGATION:
2342 break;
2343 case GST_EVENT_QOS:
2344 {
2345 gdouble proportion;
2346 GstClockTimeDiff diff;
2347 GstClockTime timestamp;
2349 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2350 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2351 break;
2352 }
2353 default:
2354 break;
2355 }
2357 ret = gst_pad_push_event (trans->sinkpad, event);
2359 return ret;
2360 }
2362 /* perform a transform on @inbuf and put the result in @outbuf.
2363 *
2364 * This function is common to the push and pull-based operations.
2365 *
2366 * This function takes ownership of @inbuf */
2367 static GstFlowReturn
2368 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2369 GstBuffer ** outbuf)
2370 {
2371 GstBaseTransformClass *bclass;
2372 GstFlowReturn ret = GST_FLOW_OK;
2373 gboolean want_in_place, reconfigure;
2374 GstClockTime running_time;
2375 GstClockTime timestamp;
2376 GstCaps *incaps;
2378 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2380 if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2381 GST_OBJECT_LOCK (trans);
2382 reconfigure = trans->priv->reconfigure;
2383 trans->priv->reconfigure = FALSE;
2384 GST_OBJECT_UNLOCK (trans);
2386 if (G_UNLIKELY (reconfigure)) {
2387 GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2388 /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2389 * will reconfigure the transform with the new output format. We can only
2390 * do this if the buffer actually has caps. */
2391 if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2392 goto not_negotiated;
2393 }
2394 }
2396 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2397 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2398 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2399 GST_BUFFER_OFFSET (inbuf));
2400 else
2401 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2402 inbuf, GST_BUFFER_SIZE (inbuf));
2404 /* Don't allow buffer handling before negotiation, except in passthrough mode
2405 * or if the class doesn't implement a set_caps function (in which case it doesn't
2406 * care about caps)
2407 */
2408 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2409 goto not_negotiated;
2411 /* Set discont flag so we can mark the outgoing buffer */
2412 if (GST_BUFFER_IS_DISCONT (inbuf)) {
2413 GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2414 trans->priv->discont = TRUE;
2415 }
2417 /* can only do QoS if the segment is in TIME */
2418 if (trans->segment.format != GST_FORMAT_TIME)
2419 goto no_qos;
2421 /* QOS is done on the running time of the buffer, get it now */
2422 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2423 running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2424 timestamp);
2426 if (running_time != -1) {
2427 gboolean need_skip;
2428 GstClockTime earliest_time;
2429 gdouble proportion;
2431 /* lock for getting the QoS parameters that are set (in a different thread)
2432 * with the QOS events */
2433 GST_OBJECT_LOCK (trans);
2434 earliest_time = trans->priv->earliest_time;
2435 proportion = trans->priv->proportion;
2436 /* check for QoS, don't perform conversion for buffers
2437 * that are known to be late. */
2438 need_skip = trans->priv->qos_enabled &&
2439 earliest_time != -1 && running_time <= earliest_time;
2440 GST_OBJECT_UNLOCK (trans);
2442 if (need_skip) {
2443 GstMessage *qos_msg;
2444 GstClockTime duration;
2445 guint64 stream_time;
2446 gint64 jitter;
2448 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2449 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2450 GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2452 trans->priv->dropped++;
2454 duration = GST_BUFFER_DURATION (inbuf);
2455 stream_time =
2456 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2457 timestamp);
2458 jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2460 qos_msg =
2461 gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2462 stream_time, timestamp, duration);
2463 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2464 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2465 trans->priv->processed, trans->priv->dropped);
2466 gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2468 /* mark discont for next buffer */
2469 trans->priv->discont = TRUE;
2470 goto skip;
2471 }
2472 }
2474 no_qos:
2476 /* first try to allocate an output buffer based on the currently negotiated
2477 * format. While we call pad-alloc we could renegotiate the srcpad format or
2478 * have a new suggestion for upstream buffer-alloc.
2479 * In any case, outbuf will contain a buffer suitable for doing the configured
2480 * transform after this function. */
2481 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2482 if (G_UNLIKELY (ret != GST_FLOW_OK))
2483 goto no_buffer;
2485 /* now perform the needed transform */
2486 if (trans->passthrough) {
2487 /* In passthrough mode, give transform_ip a look at the
2488 * buffer, without making it writable, or just push the
2489 * data through */
2490 if (bclass->transform_ip) {
2491 GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2492 ret = bclass->transform_ip (trans, *outbuf);
2493 } else {
2494 GST_DEBUG_OBJECT (trans, "element is in passthrough");
2495 }
2496 } else {
2497 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2499 if (want_in_place) {
2500 GST_DEBUG_OBJECT (trans, "doing inplace transform");
2502 if (inbuf != *outbuf) {
2503 guint8 *indata, *outdata;
2505 /* Different buffer. The data can still be the same when we are dealing
2506 * with subbuffers of the same buffer. Note that because of the FIXME in
2507 * prepare_output_buffer() we have decreased the refcounts of inbuf and
2508 * outbuf to keep them writable */
2509 indata = GST_BUFFER_DATA (inbuf);
2510 outdata = GST_BUFFER_DATA (*outbuf);
2512 if (indata != outdata)
2513 memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2514 }
2515 ret = bclass->transform_ip (trans, *outbuf);
2516 } else {
2517 GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2519 if (bclass->transform)
2520 ret = bclass->transform (trans, inbuf, *outbuf);
2521 else
2522 ret = GST_FLOW_NOT_SUPPORTED;
2523 }
2524 }
2526 skip:
2527 /* only unref input buffer if we allocated a new outbuf buffer */
2528 if (*outbuf != inbuf)
2529 gst_buffer_unref (inbuf);
2531 /* pushed a buffer, we can now try an alloc */
2532 GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2533 trans->priv->force_alloc = TRUE;
2534 return ret;
2536 /* ERRORS */
2537 not_negotiated:
2538 {
2539 gst_buffer_unref (inbuf);
2540 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2541 ("not negotiated"), ("not negotiated"));
2542 return GST_FLOW_NOT_NEGOTIATED;
2543 }
2544 no_buffer:
2545 {
2546 gst_buffer_unref (inbuf);
2547 GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2548 gst_flow_get_name (ret));
2549 return ret;
2550 }
2551 }
2553 static gboolean
2554 gst_base_transform_check_get_range (GstPad * pad)
2555 {
2556 GstBaseTransform *trans;
2557 gboolean ret;
2559 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2561 ret = gst_pad_check_pull_range (trans->sinkpad);
2563 gst_object_unref (trans);
2565 return ret;
2566 }
2568 /* FIXME, getrange is broken, need to pull range from the other
2569 * end based on the transform_size result.
2570 */
2571 static GstFlowReturn
2572 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2573 guint length, GstBuffer ** buffer)
2574 {
2575 GstBaseTransform *trans;
2576 GstBaseTransformClass *klass;
2577 GstFlowReturn ret;
2578 GstBuffer *inbuf;
2580 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2582 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2583 if (G_UNLIKELY (ret != GST_FLOW_OK))
2584 goto pull_error;
2586 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2587 if (klass->before_transform)
2588 klass->before_transform (trans, inbuf);
2590 GST_BASE_TRANSFORM_LOCK (trans);
2591 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2592 GST_BASE_TRANSFORM_UNLOCK (trans);
2594 done:
2595 gst_object_unref (trans);
2597 return ret;
2599 /* ERRORS */
2600 pull_error:
2601 {
2602 GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2603 gst_flow_get_name (ret));
2604 goto done;
2605 }
2606 }
2608 static GstFlowReturn
2609 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2610 {
2611 GstBaseTransform *trans;
2612 GstBaseTransformClass *klass;
2613 GstFlowReturn ret;
2614 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2615 GstClockTime timestamp, duration;
2616 GstBuffer *outbuf = NULL;
2618 trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2620 timestamp = GST_BUFFER_TIMESTAMP (buffer);
2621 duration = GST_BUFFER_DURATION (buffer);
2623 /* calculate end position of the incoming buffer */
2624 if (timestamp != GST_CLOCK_TIME_NONE) {
2625 if (duration != GST_CLOCK_TIME_NONE)
2626 last_stop = timestamp + duration;
2627 else
2628 last_stop = timestamp;
2629 }
2631 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2632 if (klass->before_transform)
2633 klass->before_transform (trans, buffer);
2635 gst_base_transform_send_delayed_events (trans);
2637 /* protect transform method and concurrent buffer alloc */
2638 GST_BASE_TRANSFORM_LOCK (trans);
2639 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2640 GST_BASE_TRANSFORM_UNLOCK (trans);
2642 /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2643 * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2644 if (outbuf != NULL) {
2645 if ((ret == GST_FLOW_OK)) {
2646 GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2648 /* Remember last stop position */
2649 if (last_stop != GST_CLOCK_TIME_NONE &&
2650 trans->segment.format == GST_FORMAT_TIME)
2651 gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2653 if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2654 last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2655 if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2656 last_stop_out += GST_BUFFER_DURATION (outbuf);
2657 } else if (last_stop != GST_CLOCK_TIME_NONE) {
2658 last_stop_out = last_stop;
2659 }
2660 if (last_stop_out != GST_CLOCK_TIME_NONE
2661 && trans->segment.format == GST_FORMAT_TIME)
2662 trans->priv->last_stop_out = last_stop_out;
2664 /* apply DISCONT flag if the buffer is not yet marked as such */
2665 if (trans->priv->discont) {
2666 if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2667 outbuf = gst_buffer_make_metadata_writable (outbuf);
2668 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2669 }
2670 trans->priv->discont = FALSE;
2671 }
2672 trans->priv->processed++;
2674 ret = gst_pad_push (trans->srcpad, outbuf);
2675 } else {
2676 gst_buffer_unref (outbuf);
2677 }
2678 }
2680 /* convert internal flow to OK and mark discont for the next buffer. */
2681 if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2682 trans->priv->discont = TRUE;
2683 ret = GST_FLOW_OK;
2684 }
2686 return ret;
2687 }
2689 static void
2690 gst_base_transform_set_property (GObject * object, guint prop_id,
2691 const GValue * value, GParamSpec * pspec)
2692 {
2693 GstBaseTransform *trans;
2695 trans = GST_BASE_TRANSFORM (object);
2697 switch (prop_id) {
2698 case PROP_QOS:
2699 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2700 break;
2701 default:
2702 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2703 break;
2704 }
2705 }
2707 static void
2708 gst_base_transform_get_property (GObject * object, guint prop_id,
2709 GValue * value, GParamSpec * pspec)
2710 {
2711 GstBaseTransform *trans;
2713 trans = GST_BASE_TRANSFORM (object);
2715 switch (prop_id) {
2716 case PROP_QOS:
2717 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2718 break;
2719 default:
2720 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2721 break;
2722 }
2723 }
2725 /* not a vmethod of anything, just an internal method */
2726 static gboolean
2727 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2728 {
2729 GstBaseTransformClass *bclass;
2730 gboolean result = TRUE;
2732 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2734 GST_OBJECT_LOCK (trans);
2735 gst_base_transform_clear_transformed_caps_cache (trans);
2736 GST_OBJECT_UNLOCK (trans);
2738 if (active) {
2739 if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2740 result &= bclass->start (trans);
2742 GST_OBJECT_LOCK (trans);
2744 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2745 trans->have_same_caps =
2746 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2747 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2748 else
2749 trans->have_same_caps = trans->passthrough;
2750 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2751 trans->negotiated = FALSE;
2752 trans->have_newsegment = FALSE;
2753 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2754 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2755 trans->priv->proportion = 1.0;
2756 trans->priv->earliest_time = -1;
2757 trans->priv->discont = FALSE;
2758 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2759 trans->priv->processed = 0;
2760 trans->priv->dropped = 0;
2761 trans->priv->force_alloc = TRUE;
2763 GST_OBJECT_UNLOCK (trans);
2764 } else {
2765 /* We must make sure streaming has finished before resetting things
2766 * and calling the ::stop vfunc */
2767 GST_PAD_STREAM_LOCK (trans->sinkpad);
2768 GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2770 gst_base_transform_drop_delayed_events (trans);
2772 trans->have_same_caps = FALSE;
2773 /* We can only reset the passthrough mode if the instance told us to
2774 handle it in configure_caps */
2775 if (bclass->passthrough_on_same_caps) {
2776 gst_base_transform_set_passthrough (trans, FALSE);
2777 }
2778 gst_caps_replace (&trans->cache_caps1, NULL);
2779 gst_caps_replace (&trans->cache_caps2, NULL);
2780 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2781 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2783 if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2784 result &= bclass->stop (trans);
2785 }
2787 return result;
2788 }
2790 static gboolean
2791 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2792 {
2793 gboolean result = TRUE;
2794 GstBaseTransform *trans;
2796 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2798 result = gst_base_transform_activate (trans, active);
2800 if (result)
2801 trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2803 gst_object_unref (trans);
2805 return result;
2806 }
2808 static gboolean
2809 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2810 {
2811 gboolean result = FALSE;
2812 GstBaseTransform *trans;
2814 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2816 result = gst_pad_activate_pull (trans->sinkpad, active);
2818 if (result)
2819 result &= gst_base_transform_activate (trans, active);
2821 if (result)
2822 trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2824 gst_object_unref (trans);
2826 return result;
2827 }
2829 /**
2830 * gst_base_transform_set_passthrough:
2831 * @trans: the #GstBaseTransform to set
2832 * @passthrough: boolean indicating passthrough mode.
2833 *
2834 * Set passthrough mode for this filter by default. This is mostly
2835 * useful for filters that do not care about negotiation.
2836 *
2837 * Always TRUE for filters which don't implement either a transform
2838 * or transform_ip method.
2839 *
2840 * MT safe.
2841 */
2842 void
2843 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2844 gboolean passthrough)
2845 {
2846 GstBaseTransformClass *bclass;
2848 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2850 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2852 GST_OBJECT_LOCK (trans);
2853 if (passthrough == FALSE) {
2854 if (bclass->transform_ip || bclass->transform)
2855 trans->passthrough = FALSE;
2856 } else {
2857 trans->passthrough = TRUE;
2858 }
2860 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2861 GST_OBJECT_UNLOCK (trans);
2862 }
2864 /**
2865 * gst_base_transform_is_passthrough:
2866 * @trans: the #GstBaseTransform to query
2867 *
2868 * See if @trans is configured as a passthrough transform.
2869 *
2870 * Returns: TRUE is the transform is configured in passthrough mode.
2871 *
2872 * MT safe.
2873 */
2874 gboolean
2875 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2876 {
2877 gboolean result;
2879 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2881 GST_OBJECT_LOCK (trans);
2882 result = trans->passthrough;
2883 GST_OBJECT_UNLOCK (trans);
2885 return result;
2886 }
2888 /**
2889 * gst_base_transform_set_in_place:
2890 * @trans: the #GstBaseTransform to modify
2891 * @in_place: Boolean value indicating that we would like to operate
2892 * on in_place buffers.
2893 *
2894 * Determines whether a non-writable buffer will be copied before passing
2895 * to the transform_ip function.
2896 * <itemizedlist>
2897 * <listitem>Always TRUE if no transform function is implemented.</listitem>
2898 * <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2899 * </itemizedlist>
2900 *
2901 * MT safe.
2902 */
2903 void
2904 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2905 {
2906 GstBaseTransformClass *bclass;
2908 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2910 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2912 GST_OBJECT_LOCK (trans);
2914 if (in_place) {
2915 if (bclass->transform_ip) {
2916 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2917 trans->always_in_place = TRUE;
2918 }
2919 } else {
2920 if (bclass->transform) {
2921 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2922 trans->always_in_place = FALSE;
2923 }
2924 }
2926 GST_OBJECT_UNLOCK (trans);
2927 }
2929 /**
2930 * gst_base_transform_is_in_place:
2931 * @trans: the #GstBaseTransform to query
2932 *
2933 * See if @trans is configured as a in_place transform.
2934 *
2935 * Returns: TRUE is the transform is configured in in_place mode.
2936 *
2937 * MT safe.
2938 */
2939 gboolean
2940 gst_base_transform_is_in_place (GstBaseTransform * trans)
2941 {
2942 gboolean result;
2944 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2946 GST_OBJECT_LOCK (trans);
2947 result = trans->always_in_place;
2948 GST_OBJECT_UNLOCK (trans);
2950 return result;
2951 }
2953 /**
2954 * gst_base_transform_update_qos:
2955 * @trans: a #GstBaseTransform
2956 * @proportion: the proportion
2957 * @diff: the diff against the clock
2958 * @timestamp: the timestamp of the buffer generating the QoS expressed in
2959 * running_time.
2960 *
2961 * Set the QoS parameters in the transform. This function is called internally
2962 * when a QOS event is received but subclasses can provide custom information
2963 * when needed.
2964 *
2965 * MT safe.
2966 *
2967 * Since: 0.10.5
2968 */
2969 void
2970 gst_base_transform_update_qos (GstBaseTransform * trans,
2971 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2972 {
2974 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2976 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2977 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2978 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2980 GST_OBJECT_LOCK (trans);
2981 trans->priv->proportion = proportion;
2982 trans->priv->earliest_time = timestamp + diff;
2983 GST_OBJECT_UNLOCK (trans);
2984 }
2986 /**
2987 * gst_base_transform_set_qos_enabled:
2988 * @trans: a #GstBaseTransform
2989 * @enabled: new state
2990 *
2991 * Enable or disable QoS handling in the transform.
2992 *
2993 * MT safe.
2994 *
2995 * Since: 0.10.5
2996 */
2997 void
2998 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2999 {
3000 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3002 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
3004 GST_OBJECT_LOCK (trans);
3005 trans->priv->qos_enabled = enabled;
3006 GST_OBJECT_UNLOCK (trans);
3007 }
3009 /**
3010 * gst_base_transform_is_qos_enabled:
3011 * @trans: a #GstBaseTransform
3012 *
3013 * Queries if the transform will handle QoS.
3014 *
3015 * Returns: TRUE if QoS is enabled.
3016 *
3017 * MT safe.
3018 *
3019 * Since: 0.10.5
3020 */
3021 gboolean
3022 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
3023 {
3024 gboolean result;
3026 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
3028 GST_OBJECT_LOCK (trans);
3029 result = trans->priv->qos_enabled;
3030 GST_OBJECT_UNLOCK (trans);
3032 return result;
3033 }
3035 /**
3036 * gst_base_transform_set_gap_aware:
3037 * @trans: a #GstBaseTransform
3038 * @gap_aware: New state
3039 *
3040 * If @gap_aware is %FALSE (the default), output buffers will have the
3041 * %GST_BUFFER_FLAG_GAP flag unset.
3042 *
3043 * If set to %TRUE, the element must handle output buffers with this flag set
3044 * correctly, i.e. it can assume that the buffer contains neutral data but must
3045 * unset the flag if the output is no neutral data.
3046 *
3047 * MT safe.
3048 *
3049 * Since: 0.10.16
3050 */
3051 void
3052 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
3053 {
3054 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3056 GST_OBJECT_LOCK (trans);
3057 trans->priv->gap_aware = gap_aware;
3058 GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
3059 GST_OBJECT_UNLOCK (trans);
3060 }
3062 /**
3063 * gst_base_transform_suggest:
3064 * @trans: a #GstBaseTransform
3065 * @caps: (transfer none): caps to suggest
3066 * @size: buffer size to suggest
3067 *
3068 * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
3069 * taken.
3070 *
3071 * Since: 0.10.21
3072 */
3073 void
3074 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
3075 guint size)
3076 {
3077 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3079 GST_OBJECT_LOCK (trans->sinkpad);
3080 if (trans->priv->sink_suggest)
3081 gst_caps_unref (trans->priv->sink_suggest);
3082 if (caps)
3083 caps = gst_caps_copy (caps);
3084 trans->priv->sink_suggest = caps;
3085 trans->priv->size_suggest = size;
3086 trans->priv->suggest_pending = TRUE;
3087 gst_base_transform_clear_transformed_caps_cache (trans);
3088 GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
3089 GST_OBJECT_UNLOCK (trans->sinkpad);
3090 }
3092 /**
3093 * gst_base_transform_reconfigure:
3094 * @trans: a #GstBaseTransform
3095 *
3096 * Instructs @trans to renegotiate a new downstream transform on the next
3097 * buffer. This function is typically called after properties on the transform
3098 * were set that influence the output format.
3099 *
3100 * Since: 0.10.21
3101 */
3102 void
3103 gst_base_transform_reconfigure (GstBaseTransform * trans)
3104 {
3105 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3107 GST_OBJECT_LOCK (trans);
3108 GST_DEBUG_OBJECT (trans, "marking reconfigure");
3109 trans->priv->reconfigure = TRUE;
3110 gst_base_transform_clear_transformed_caps_cache (trans);
3111 gst_caps_replace (&trans->priv->sink_alloc, NULL);
3112 GST_OBJECT_UNLOCK (trans);
3113 }