409b9991019b3aef7204afc7db9a8c5099ad4f17
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 GstBaseTransformClass *klass;
1828 GstBaseTransformPrivate *priv;
1829 GstFlowReturn res;
1830 gboolean alloced = FALSE;
1831 gboolean proxy, suggest, new_caps;
1832 GstCaps *sink_suggest = NULL;
1833 guint size_suggest;
1835 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1836 if (G_UNLIKELY (trans == NULL))
1837 return GST_FLOW_WRONG_STATE;
1838 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1839 priv = trans->priv;
1841 GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1842 caps, caps, size);
1844 /* if the code below does not come up with a better buffer, we will return _OK
1845 * and an empty buffer. This will trigger the core to allocate a buffer with
1846 * given input size and caps. */
1847 *buf = NULL;
1848 res = GST_FLOW_OK;
1850 /* we remember our previous alloc request to quickly see if we can proxy or
1851 * not. We skip this check if we have a pending suggestion. */
1852 GST_OBJECT_LOCK (pad);
1853 suggest = priv->suggest_pending;
1854 GST_OBJECT_UNLOCK (pad);
1856 if (!suggest) {
1857 /* we have no suggestion, see below if we need to proxy */
1858 gst_caps_replace (&sink_suggest, caps);
1859 size_suggest = size;
1860 suggest = FALSE;
1861 new_caps = sink_suggest
1862 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1864 if (new_caps)
1865 GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1866 else
1867 GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1868 } else {
1869 /* if we have a suggestion, pretend we got these as input */
1870 GST_OBJECT_LOCK (pad);
1871 if (priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest)) {
1872 sink_suggest = gst_caps_ref (priv->sink_suggest);
1873 size_suggest = priv->size_suggest;
1874 GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1875 sink_suggest, sink_suggest, priv->size_suggest);
1876 } else {
1877 GST_DEBUG_OBJECT (trans,
1878 "have suggestion equal to upstream caps %p %" GST_PTR_FORMAT, caps,
1879 caps);
1880 gst_caps_replace (&sink_suggest, caps);
1881 size_suggest = size;
1882 suggest = FALSE;
1883 }
1884 priv->suggest_pending = FALSE;
1885 GST_OBJECT_UNLOCK (pad);
1887 /* check if we actually handle this format on the sinkpad */
1888 if (suggest) {
1889 GstCaps *peercaps;
1891 /* Always intersect with the peer caps to get correct
1892 * and complete caps. The suggested caps could be incomplete,
1893 * for example video/x-raw-yuv without any fields at all.
1894 */
1895 peercaps =
1896 gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1898 if (peercaps) {
1899 GstCaps *intersect;
1901 intersect =
1902 gst_caps_intersect_full (sink_suggest, peercaps,
1903 GST_CAPS_INTERSECT_FIRST);
1904 gst_caps_unref (peercaps);
1906 /* If intersected caps is empty then just keep them empty. The
1907 * code below will try to come up with possible caps if there
1908 * are any */
1909 gst_caps_unref (sink_suggest);
1910 sink_suggest = intersect;
1911 }
1913 /* If the suggested caps are not empty and not fixed, try to fixate them */
1914 if (!gst_caps_is_fixed (sink_suggest)
1915 && !gst_caps_is_empty (sink_suggest)) {
1916 GST_DEBUG_OBJECT (trans,
1917 "Suggested caps is not fixed: %" GST_PTR_FORMAT, sink_suggest);
1919 /* try the alloc caps if it is still not fixed */
1920 if (!gst_caps_is_fixed (sink_suggest)) {
1921 GstCaps *intersect;
1923 GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1924 "with the non-fixed caps suggestion");
1925 intersect =
1926 gst_caps_intersect_full (sink_suggest, caps,
1927 GST_CAPS_INTERSECT_FIRST);
1928 if (!gst_caps_is_empty (intersect)) {
1929 GST_DEBUG_OBJECT (trans, "It is, using it");
1930 gst_caps_replace (&sink_suggest, caps);
1931 }
1932 gst_caps_unref (intersect);
1933 }
1935 /* be safe and call default fixate */
1936 sink_suggest = gst_caps_make_writable (sink_suggest);
1937 gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1939 if (!gst_caps_is_fixed (sink_suggest)) {
1940 gst_caps_unref (sink_suggest);
1941 sink_suggest = NULL;
1942 }
1944 GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1945 sink_suggest);
1946 }
1947 }
1949 new_caps = sink_suggest
1950 && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1951 }
1953 /* Check if the new caps are compatible with our
1954 * sinkpad template caps and if they're not
1955 * we try to come up with any supported caps
1956 */
1957 if (new_caps) {
1958 const GstCaps *templ;
1960 templ = gst_pad_get_pad_template_caps (pad);
1962 if (!gst_caps_can_intersect (sink_suggest, templ)) {
1963 GstCaps *allowed;
1964 GstCaps *peercaps;
1966 GST_DEBUG_OBJECT (trans,
1967 "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1968 sink_suggest);
1969 /* the requested pad alloc caps are not supported, so let's try
1970 * picking something allowed between the pads (they are linked,
1971 * there must be something) */
1972 allowed = gst_pad_get_allowed_caps (pad);
1973 if (allowed && !gst_caps_is_empty (allowed)) {
1974 GST_DEBUG_OBJECT (trans,
1975 "pads could agree on one of the following caps: " "%"
1976 GST_PTR_FORMAT, allowed);
1977 allowed = gst_caps_make_writable (allowed);
1979 if (klass->fixate_caps) {
1980 peercaps =
1981 gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1982 klass->fixate_caps (trans, GST_PAD_SRC, peercaps, allowed);
1983 gst_caps_unref (peercaps);
1984 }
1986 /* Fixate them to be safe if the subclass didn't do it */
1987 gst_caps_truncate (allowed);
1988 gst_pad_fixate_caps (pad, allowed);
1989 gst_caps_replace (&sink_suggest, allowed);
1990 gst_caps_unref (allowed);
1992 suggest = TRUE;
1993 new_caps = !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1995 GST_DEBUG_OBJECT (trans, "Fixated suggestion caps to %"
1996 GST_PTR_FORMAT, sink_suggest);
1997 } else {
1998 if (allowed)
1999 gst_caps_unref (allowed);
2000 goto not_supported;
2001 }
2002 }
2003 }
2005 /* find the best format for the other side here we decide if we will proxy
2006 * the caps or not. */
2007 if (sink_suggest == NULL) {
2008 /* always proxy when the caps are NULL. When this is a new format, see if
2009 * we can proxy it downstream */
2010 GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
2011 priv->proxy_alloc = TRUE;
2012 } else if (new_caps) {
2013 GstCaps *othercaps;
2015 /* we have a new format, see what we need to proxy to */
2016 othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
2017 if (!othercaps || gst_caps_is_empty (othercaps)) {
2018 /* no transform possible, we certainly can't proxy */
2019 GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
2020 priv->proxy_alloc = FALSE;
2021 } else {
2022 /* we transformed into something */
2023 if (gst_caps_is_equal (sink_suggest, othercaps)) {
2024 GST_DEBUG_OBJECT (trans, "best caps same as input, marking for proxy");
2025 priv->proxy_alloc = TRUE;
2026 } else {
2027 GST_DEBUG_OBJECT (trans,
2028 "best caps different from input, disable proxy");
2029 priv->proxy_alloc = FALSE;
2030 }
2031 }
2032 if (othercaps)
2033 gst_caps_unref (othercaps);
2034 }
2036 /* remember the new caps */
2037 GST_OBJECT_LOCK (pad);
2038 gst_caps_replace (&priv->sink_alloc, sink_suggest);
2039 GST_OBJECT_UNLOCK (pad);
2041 proxy = priv->proxy_alloc;
2042 GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
2043 suggest);
2045 /* we only want to proxy if we have no suggestion pending, FIXME */
2046 if (proxy && !suggest) {
2047 GstCaps *newcaps;
2049 GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
2050 ", size %u", caps, caps, size);
2052 /* we always proxy the input caps, never the suggestion. The reason is that
2053 * We don't yet handle the caps of renegotiation in here. FIXME */
2054 res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
2055 if (res != GST_FLOW_OK)
2056 goto alloc_failed;
2057 alloced = TRUE;
2059 /* check if the caps changed */
2060 newcaps = GST_BUFFER_CAPS (*buf);
2062 GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
2064 if (!gst_caps_is_equal (newcaps, caps)) {
2065 GST_DEBUG_OBJECT (trans, "caps are new");
2066 /* we have new caps, see if we can proxy downstream */
2067 if (gst_pad_peer_accept_caps (pad, newcaps)) {
2068 /* peer accepts the caps, return a buffer in this format */
2069 GST_DEBUG_OBJECT (trans, "peer accepted new caps");
2070 /* remember the format */
2071 GST_OBJECT_LOCK (pad);
2072 gst_caps_replace (&priv->sink_alloc, newcaps);
2073 GST_OBJECT_UNLOCK (pad);
2074 } else {
2075 GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
2076 /* peer does not accept the caps, disable proxy_alloc, free the
2077 * buffer we received and create a buffer of the requested format
2078 * by the default handler. */
2079 GST_DEBUG_OBJECT (trans, "disabling proxy");
2080 priv->proxy_alloc = FALSE;
2081 gst_buffer_unref (*buf);
2082 *buf = NULL;
2083 }
2084 } else {
2085 GST_DEBUG_OBJECT (trans, "received required caps from peer");
2086 }
2087 } else if (suggest) {
2088 /* there was a custom suggestion, create a buffer of this format and return
2089 * it. Note that this format */
2090 *buf = gst_buffer_new_and_alloc (size_suggest);
2091 GST_DEBUG_OBJECT (trans,
2092 "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2093 sink_suggest, sink_suggest);
2094 GST_BUFFER_CAPS (*buf) = sink_suggest;
2095 sink_suggest = NULL;
2096 } else {
2097 /* fallback buffer allocation by gst_pad_alloc_buffer() with the
2098 * caps and size provided by the caller */
2099 }
2101 if (sink_suggest)
2102 gst_caps_unref (sink_suggest);
2104 if (res == GST_FLOW_OK && alloced) {
2105 /* just alloc'ed a buffer, so we only want to do this again if we
2106 * received a buffer */
2107 GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2108 trans->priv->force_alloc = FALSE;
2109 }
2111 gst_object_unref (trans);
2112 return res;
2114 /* ERRORS */
2115 alloc_failed:
2116 {
2117 GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2118 if (sink_suggest)
2119 gst_caps_unref (sink_suggest);
2120 gst_object_unref (trans);
2121 return res;
2122 }
2123 not_supported:
2124 {
2125 GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2126 if (sink_suggest)
2127 gst_caps_unref (sink_suggest);
2128 gst_object_unref (trans);
2129 return GST_FLOW_NOT_NEGOTIATED;
2130 }
2131 }
2133 static void
2134 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2135 {
2136 GList *list, *tmp;
2138 GST_OBJECT_LOCK (trans);
2139 list = trans->priv->delayed_events;
2140 trans->priv->delayed_events = NULL;
2141 GST_OBJECT_UNLOCK (trans);
2142 if (!list)
2143 return;
2145 for (tmp = list; tmp; tmp = tmp->next) {
2146 GstEvent *ev = tmp->data;
2148 GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2149 GST_EVENT_TYPE_NAME (ev));
2150 gst_pad_push_event (trans->srcpad, ev);
2151 }
2152 g_list_free (list);
2153 }
2155 static gboolean
2156 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2157 {
2158 GstBaseTransform *trans;
2159 GstBaseTransformClass *bclass;
2160 gboolean ret = TRUE;
2161 gboolean forward = TRUE;
2163 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2164 if (G_UNLIKELY (trans == NULL)) {
2165 gst_event_unref (event);
2166 return FALSE;
2167 }
2168 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2170 if (bclass->event)
2171 forward = bclass->event (trans, event);
2173 /* FIXME, do this in the default event handler so the subclass can do
2174 * something different. */
2175 if (forward) {
2176 gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2178 /* src caps may not yet be set, so we delay any serialized events
2179 that we receive before (in particular newsegment events), except
2180 EOS and flush stops, since those'll obsolete previous events */
2181 if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2182 gst_base_transform_drop_delayed_events (trans);
2183 delay = FALSE;
2184 } else {
2185 delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2186 && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2187 }
2189 if (delay) {
2190 GST_OBJECT_LOCK (trans);
2191 trans->priv->delayed_events =
2192 g_list_append (trans->priv->delayed_events, event);
2193 GST_OBJECT_UNLOCK (trans);
2194 } else {
2195 if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2196 gst_base_transform_send_delayed_events (trans);
2197 ret = gst_pad_push_event (trans->srcpad, event);
2198 }
2199 } else
2200 gst_event_unref (event);
2202 gst_object_unref (trans);
2204 return ret;
2205 }
2207 static gboolean
2208 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2209 {
2210 switch (GST_EVENT_TYPE (event)) {
2211 case GST_EVENT_FLUSH_START:
2212 break;
2213 case GST_EVENT_FLUSH_STOP:
2214 GST_OBJECT_LOCK (trans);
2215 /* reset QoS parameters */
2216 trans->priv->proportion = 1.0;
2217 trans->priv->earliest_time = -1;
2218 trans->priv->discont = FALSE;
2219 trans->priv->processed = 0;
2220 trans->priv->dropped = 0;
2221 GST_OBJECT_UNLOCK (trans);
2222 /* we need new segment info after the flush. */
2223 trans->have_newsegment = FALSE;
2224 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2225 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2226 break;
2227 case GST_EVENT_EOS:
2228 break;
2229 case GST_EVENT_TAG:
2230 break;
2231 case GST_EVENT_NEWSEGMENT:
2232 {
2233 GstFormat format;
2234 gdouble rate, arate;
2235 gint64 start, stop, time;
2236 gboolean update;
2238 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2239 &start, &stop, &time);
2241 trans->have_newsegment = TRUE;
2243 gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2244 format, start, stop, time);
2246 if (format == GST_FORMAT_TIME) {
2247 GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2248 " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2249 ", accum %" GST_TIME_FORMAT,
2250 GST_TIME_ARGS (trans->segment.start),
2251 GST_TIME_ARGS (trans->segment.stop),
2252 GST_TIME_ARGS (trans->segment.time),
2253 GST_TIME_ARGS (trans->segment.accum));
2254 } else {
2255 GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2256 " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2257 ", accum %" G_GINT64_FORMAT,
2258 trans->segment.start, trans->segment.stop,
2259 trans->segment.time, trans->segment.accum);
2260 }
2261 break;
2262 }
2263 default:
2264 break;
2265 }
2267 return TRUE;
2268 }
2270 static gboolean
2271 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2272 {
2273 GstBaseTransform *trans;
2274 GstBaseTransformClass *bclass;
2275 gboolean ret = TRUE;
2277 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2278 if (G_UNLIKELY (trans == NULL)) {
2279 gst_event_unref (event);
2280 return FALSE;
2281 }
2283 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2285 if (bclass->src_event)
2286 ret = bclass->src_event (trans, event);
2287 else
2288 gst_event_unref (event);
2290 gst_object_unref (trans);
2292 return ret;
2293 }
2295 static gboolean
2296 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2297 {
2298 gboolean ret;
2300 GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2302 switch (GST_EVENT_TYPE (event)) {
2303 case GST_EVENT_SEEK:
2304 break;
2305 case GST_EVENT_NAVIGATION:
2306 break;
2307 case GST_EVENT_QOS:
2308 {
2309 gdouble proportion;
2310 GstClockTimeDiff diff;
2311 GstClockTime timestamp;
2313 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
2314 gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2315 break;
2316 }
2317 default:
2318 break;
2319 }
2321 ret = gst_pad_push_event (trans->sinkpad, event);
2323 return ret;
2324 }
2326 /* perform a transform on @inbuf and put the result in @outbuf.
2327 *
2328 * This function is common to the push and pull-based operations.
2329 *
2330 * This function takes ownership of @inbuf */
2331 static GstFlowReturn
2332 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2333 GstBuffer ** outbuf)
2334 {
2335 GstBaseTransformClass *bclass;
2336 GstFlowReturn ret = GST_FLOW_OK;
2337 gboolean want_in_place, reconfigure;
2338 GstClockTime running_time;
2339 GstClockTime timestamp;
2340 GstCaps *incaps;
2342 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2344 if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2345 GST_OBJECT_LOCK (trans);
2346 reconfigure = trans->priv->reconfigure;
2347 trans->priv->reconfigure = FALSE;
2348 GST_OBJECT_UNLOCK (trans);
2350 if (G_UNLIKELY (reconfigure)) {
2351 GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2352 /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2353 * will reconfigure the transform with the new output format. We can only
2354 * do this if the buffer actually has caps. */
2355 if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2356 goto not_negotiated;
2357 }
2358 }
2360 if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2361 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2362 G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2363 GST_BUFFER_OFFSET (inbuf));
2364 else
2365 GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2366 inbuf, GST_BUFFER_SIZE (inbuf));
2368 /* Don't allow buffer handling before negotiation, except in passthrough mode
2369 * or if the class doesn't implement a set_caps function (in which case it doesn't
2370 * care about caps)
2371 */
2372 if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2373 goto not_negotiated;
2375 /* Set discont flag so we can mark the outgoing buffer */
2376 if (GST_BUFFER_IS_DISCONT (inbuf)) {
2377 GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2378 trans->priv->discont = TRUE;
2379 }
2381 /* can only do QoS if the segment is in TIME */
2382 if (trans->segment.format != GST_FORMAT_TIME)
2383 goto no_qos;
2385 /* QOS is done on the running time of the buffer, get it now */
2386 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2387 running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2388 timestamp);
2390 if (running_time != -1) {
2391 gboolean need_skip;
2392 GstClockTime earliest_time;
2393 gdouble proportion;
2395 /* lock for getting the QoS parameters that are set (in a different thread)
2396 * with the QOS events */
2397 GST_OBJECT_LOCK (trans);
2398 earliest_time = trans->priv->earliest_time;
2399 proportion = trans->priv->proportion;
2400 /* check for QoS, don't perform conversion for buffers
2401 * that are known to be late. */
2402 need_skip = trans->priv->qos_enabled &&
2403 earliest_time != -1 && running_time <= earliest_time;
2404 GST_OBJECT_UNLOCK (trans);
2406 if (need_skip) {
2407 GstMessage *qos_msg;
2408 GstClockTime duration;
2409 guint64 stream_time;
2410 gint64 jitter;
2412 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2413 GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2414 GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2416 trans->priv->dropped++;
2418 duration = GST_BUFFER_DURATION (inbuf);
2419 stream_time =
2420 gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2421 timestamp);
2422 jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2424 qos_msg =
2425 gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2426 stream_time, timestamp, duration);
2427 gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2428 gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2429 trans->priv->processed, trans->priv->dropped);
2430 gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2432 /* mark discont for next buffer */
2433 trans->priv->discont = TRUE;
2434 goto skip;
2435 }
2436 }
2438 no_qos:
2440 /* first try to allocate an output buffer based on the currently negotiated
2441 * format. While we call pad-alloc we could renegotiate the srcpad format or
2442 * have a new suggestion for upstream buffer-alloc.
2443 * In any case, outbuf will contain a buffer suitable for doing the configured
2444 * transform after this function. */
2445 ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2446 if (G_UNLIKELY (ret != GST_FLOW_OK))
2447 goto no_buffer;
2449 /* now perform the needed transform */
2450 if (trans->passthrough) {
2451 /* In passthrough mode, give transform_ip a look at the
2452 * buffer, without making it writable, or just push the
2453 * data through */
2454 if (bclass->transform_ip) {
2455 GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2456 ret = bclass->transform_ip (trans, *outbuf);
2457 } else {
2458 GST_DEBUG_OBJECT (trans, "element is in passthrough");
2459 }
2460 } else {
2461 want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2463 if (want_in_place) {
2464 GST_DEBUG_OBJECT (trans, "doing inplace transform");
2466 if (inbuf != *outbuf) {
2467 guint8 *indata, *outdata;
2469 /* Different buffer. The data can still be the same when we are dealing
2470 * with subbuffers of the same buffer. Note that because of the FIXME in
2471 * prepare_output_buffer() we have decreased the refcounts of inbuf and
2472 * outbuf to keep them writable */
2473 indata = GST_BUFFER_DATA (inbuf);
2474 outdata = GST_BUFFER_DATA (*outbuf);
2476 if (indata != outdata)
2477 memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2478 }
2479 ret = bclass->transform_ip (trans, *outbuf);
2480 } else {
2481 GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2483 if (bclass->transform)
2484 ret = bclass->transform (trans, inbuf, *outbuf);
2485 else
2486 ret = GST_FLOW_NOT_SUPPORTED;
2487 }
2488 }
2490 skip:
2491 /* only unref input buffer if we allocated a new outbuf buffer */
2492 if (*outbuf != inbuf)
2493 gst_buffer_unref (inbuf);
2495 /* pushed a buffer, we can now try an alloc */
2496 GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2497 trans->priv->force_alloc = TRUE;
2498 return ret;
2500 /* ERRORS */
2501 not_negotiated:
2502 {
2503 gst_buffer_unref (inbuf);
2504 GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2505 ("not negotiated"), ("not negotiated"));
2506 return GST_FLOW_NOT_NEGOTIATED;
2507 }
2508 no_buffer:
2509 {
2510 gst_buffer_unref (inbuf);
2511 GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2512 gst_flow_get_name (ret));
2513 return ret;
2514 }
2515 }
2517 static gboolean
2518 gst_base_transform_check_get_range (GstPad * pad)
2519 {
2520 GstBaseTransform *trans;
2521 gboolean ret;
2523 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2525 ret = gst_pad_check_pull_range (trans->sinkpad);
2527 gst_object_unref (trans);
2529 return ret;
2530 }
2532 /* FIXME, getrange is broken, need to pull range from the other
2533 * end based on the transform_size result.
2534 */
2535 static GstFlowReturn
2536 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2537 guint length, GstBuffer ** buffer)
2538 {
2539 GstBaseTransform *trans;
2540 GstBaseTransformClass *klass;
2541 GstFlowReturn ret;
2542 GstBuffer *inbuf;
2544 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2546 ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2547 if (G_UNLIKELY (ret != GST_FLOW_OK))
2548 goto pull_error;
2550 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2551 if (klass->before_transform)
2552 klass->before_transform (trans, inbuf);
2554 GST_BASE_TRANSFORM_LOCK (trans);
2555 ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2556 GST_BASE_TRANSFORM_UNLOCK (trans);
2558 done:
2559 gst_object_unref (trans);
2561 return ret;
2563 /* ERRORS */
2564 pull_error:
2565 {
2566 GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2567 gst_flow_get_name (ret));
2568 goto done;
2569 }
2570 }
2572 static GstFlowReturn
2573 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2574 {
2575 GstBaseTransform *trans;
2576 GstBaseTransformClass *klass;
2577 GstFlowReturn ret;
2578 GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2579 GstClockTime timestamp, duration;
2580 GstBuffer *outbuf = NULL;
2582 trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2584 timestamp = GST_BUFFER_TIMESTAMP (buffer);
2585 duration = GST_BUFFER_DURATION (buffer);
2587 /* calculate end position of the incoming buffer */
2588 if (timestamp != GST_CLOCK_TIME_NONE) {
2589 if (duration != GST_CLOCK_TIME_NONE)
2590 last_stop = timestamp + duration;
2591 else
2592 last_stop = timestamp;
2593 }
2595 klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2596 if (klass->before_transform)
2597 klass->before_transform (trans, buffer);
2599 gst_base_transform_send_delayed_events (trans);
2601 /* protect transform method and concurrent buffer alloc */
2602 GST_BASE_TRANSFORM_LOCK (trans);
2603 ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2604 GST_BASE_TRANSFORM_UNLOCK (trans);
2606 /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2607 * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2608 if (outbuf != NULL) {
2609 if ((ret == GST_FLOW_OK)) {
2610 GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2612 /* Remember last stop position */
2613 if (last_stop != GST_CLOCK_TIME_NONE &&
2614 trans->segment.format == GST_FORMAT_TIME)
2615 gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2617 if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2618 last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2619 if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2620 last_stop_out += GST_BUFFER_DURATION (outbuf);
2621 } else if (last_stop != GST_CLOCK_TIME_NONE) {
2622 last_stop_out = last_stop;
2623 }
2624 if (last_stop_out != GST_CLOCK_TIME_NONE
2625 && trans->segment.format == GST_FORMAT_TIME)
2626 trans->priv->last_stop_out = last_stop_out;
2628 /* apply DISCONT flag if the buffer is not yet marked as such */
2629 if (trans->priv->discont) {
2630 if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2631 outbuf = gst_buffer_make_metadata_writable (outbuf);
2632 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2633 }
2634 trans->priv->discont = FALSE;
2635 }
2636 trans->priv->processed++;
2638 ret = gst_pad_push (trans->srcpad, outbuf);
2639 } else {
2640 gst_buffer_unref (outbuf);
2641 }
2642 }
2644 /* convert internal flow to OK and mark discont for the next buffer. */
2645 if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2646 trans->priv->discont = TRUE;
2647 ret = GST_FLOW_OK;
2648 }
2650 return ret;
2651 }
2653 static void
2654 gst_base_transform_set_property (GObject * object, guint prop_id,
2655 const GValue * value, GParamSpec * pspec)
2656 {
2657 GstBaseTransform *trans;
2659 trans = GST_BASE_TRANSFORM (object);
2661 switch (prop_id) {
2662 case PROP_QOS:
2663 gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2664 break;
2665 default:
2666 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2667 break;
2668 }
2669 }
2671 static void
2672 gst_base_transform_get_property (GObject * object, guint prop_id,
2673 GValue * value, GParamSpec * pspec)
2674 {
2675 GstBaseTransform *trans;
2677 trans = GST_BASE_TRANSFORM (object);
2679 switch (prop_id) {
2680 case PROP_QOS:
2681 g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2682 break;
2683 default:
2684 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2685 break;
2686 }
2687 }
2689 /* not a vmethod of anything, just an internal method */
2690 static gboolean
2691 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2692 {
2693 GstBaseTransformClass *bclass;
2694 gboolean result = TRUE;
2696 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2698 GST_OBJECT_LOCK (trans);
2699 gst_base_transform_clear_transformed_caps_cache (trans);
2700 GST_OBJECT_UNLOCK (trans);
2702 if (active) {
2703 if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2704 result &= bclass->start (trans);
2706 GST_OBJECT_LOCK (trans);
2708 if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2709 trans->have_same_caps =
2710 gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2711 GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2712 else
2713 trans->have_same_caps = trans->passthrough;
2714 GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2715 trans->negotiated = FALSE;
2716 trans->have_newsegment = FALSE;
2717 gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2718 trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2719 trans->priv->proportion = 1.0;
2720 trans->priv->earliest_time = -1;
2721 trans->priv->discont = FALSE;
2722 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2723 trans->priv->processed = 0;
2724 trans->priv->dropped = 0;
2725 trans->priv->force_alloc = TRUE;
2727 GST_OBJECT_UNLOCK (trans);
2728 } else {
2729 /* We must make sure streaming has finished before resetting things
2730 * and calling the ::stop vfunc */
2731 GST_PAD_STREAM_LOCK (trans->sinkpad);
2732 GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2734 gst_base_transform_drop_delayed_events (trans);
2736 trans->have_same_caps = FALSE;
2737 /* We can only reset the passthrough mode if the instance told us to
2738 handle it in configure_caps */
2739 if (bclass->passthrough_on_same_caps) {
2740 gst_base_transform_set_passthrough (trans, FALSE);
2741 }
2742 gst_caps_replace (&trans->cache_caps1, NULL);
2743 gst_caps_replace (&trans->cache_caps2, NULL);
2744 gst_caps_replace (&trans->priv->sink_alloc, NULL);
2745 gst_caps_replace (&trans->priv->sink_suggest, NULL);
2747 if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2748 result &= bclass->stop (trans);
2749 }
2751 return result;
2752 }
2754 static gboolean
2755 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2756 {
2757 gboolean result = TRUE;
2758 GstBaseTransform *trans;
2760 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2762 result = gst_base_transform_activate (trans, active);
2764 if (result)
2765 trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2767 gst_object_unref (trans);
2769 return result;
2770 }
2772 static gboolean
2773 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2774 {
2775 gboolean result = FALSE;
2776 GstBaseTransform *trans;
2778 trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2780 result = gst_pad_activate_pull (trans->sinkpad, active);
2782 if (result)
2783 result &= gst_base_transform_activate (trans, active);
2785 if (result)
2786 trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2788 gst_object_unref (trans);
2790 return result;
2791 }
2793 /**
2794 * gst_base_transform_set_passthrough:
2795 * @trans: the #GstBaseTransform to set
2796 * @passthrough: boolean indicating passthrough mode.
2797 *
2798 * Set passthrough mode for this filter by default. This is mostly
2799 * useful for filters that do not care about negotiation.
2800 *
2801 * Always TRUE for filters which don't implement either a transform
2802 * or transform_ip method.
2803 *
2804 * MT safe.
2805 */
2806 void
2807 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2808 gboolean passthrough)
2809 {
2810 GstBaseTransformClass *bclass;
2812 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2814 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2816 GST_OBJECT_LOCK (trans);
2817 if (passthrough == FALSE) {
2818 if (bclass->transform_ip || bclass->transform)
2819 trans->passthrough = FALSE;
2820 } else {
2821 trans->passthrough = TRUE;
2822 }
2824 GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2825 GST_OBJECT_UNLOCK (trans);
2826 }
2828 /**
2829 * gst_base_transform_is_passthrough:
2830 * @trans: the #GstBaseTransform to query
2831 *
2832 * See if @trans is configured as a passthrough transform.
2833 *
2834 * Returns: TRUE is the transform is configured in passthrough mode.
2835 *
2836 * MT safe.
2837 */
2838 gboolean
2839 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2840 {
2841 gboolean result;
2843 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2845 GST_OBJECT_LOCK (trans);
2846 result = trans->passthrough;
2847 GST_OBJECT_UNLOCK (trans);
2849 return result;
2850 }
2852 /**
2853 * gst_base_transform_set_in_place:
2854 * @trans: the #GstBaseTransform to modify
2855 * @in_place: Boolean value indicating that we would like to operate
2856 * on in_place buffers.
2857 *
2858 * Determines whether a non-writable buffer will be copied before passing
2859 * to the transform_ip function.
2860 * <itemizedlist>
2861 * <listitem>Always TRUE if no transform function is implemented.</listitem>
2862 * <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2863 * </itemizedlist>
2864 *
2865 * MT safe.
2866 */
2867 void
2868 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2869 {
2870 GstBaseTransformClass *bclass;
2872 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2874 bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2876 GST_OBJECT_LOCK (trans);
2878 if (in_place) {
2879 if (bclass->transform_ip) {
2880 GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2881 trans->always_in_place = TRUE;
2882 }
2883 } else {
2884 if (bclass->transform) {
2885 GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2886 trans->always_in_place = FALSE;
2887 }
2888 }
2890 GST_OBJECT_UNLOCK (trans);
2891 }
2893 /**
2894 * gst_base_transform_is_in_place:
2895 * @trans: the #GstBaseTransform to query
2896 *
2897 * See if @trans is configured as a in_place transform.
2898 *
2899 * Returns: TRUE is the transform is configured in in_place mode.
2900 *
2901 * MT safe.
2902 */
2903 gboolean
2904 gst_base_transform_is_in_place (GstBaseTransform * trans)
2905 {
2906 gboolean result;
2908 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2910 GST_OBJECT_LOCK (trans);
2911 result = trans->always_in_place;
2912 GST_OBJECT_UNLOCK (trans);
2914 return result;
2915 }
2917 /**
2918 * gst_base_transform_update_qos:
2919 * @trans: a #GstBaseTransform
2920 * @proportion: the proportion
2921 * @diff: the diff against the clock
2922 * @timestamp: the timestamp of the buffer generating the QoS expressed in
2923 * running_time.
2924 *
2925 * Set the QoS parameters in the transform. This function is called internally
2926 * when a QOS event is received but subclasses can provide custom information
2927 * when needed.
2928 *
2929 * MT safe.
2930 *
2931 * Since: 0.10.5
2932 */
2933 void
2934 gst_base_transform_update_qos (GstBaseTransform * trans,
2935 gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2936 {
2938 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2940 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2941 "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2942 GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2944 GST_OBJECT_LOCK (trans);
2945 trans->priv->proportion = proportion;
2946 trans->priv->earliest_time = timestamp + diff;
2947 GST_OBJECT_UNLOCK (trans);
2948 }
2950 /**
2951 * gst_base_transform_set_qos_enabled:
2952 * @trans: a #GstBaseTransform
2953 * @enabled: new state
2954 *
2955 * Enable or disable QoS handling in the transform.
2956 *
2957 * MT safe.
2958 *
2959 * Since: 0.10.5
2960 */
2961 void
2962 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2963 {
2964 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2966 GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2968 GST_OBJECT_LOCK (trans);
2969 trans->priv->qos_enabled = enabled;
2970 GST_OBJECT_UNLOCK (trans);
2971 }
2973 /**
2974 * gst_base_transform_is_qos_enabled:
2975 * @trans: a #GstBaseTransform
2976 *
2977 * Queries if the transform will handle QoS.
2978 *
2979 * Returns: TRUE if QoS is enabled.
2980 *
2981 * MT safe.
2982 *
2983 * Since: 0.10.5
2984 */
2985 gboolean
2986 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2987 {
2988 gboolean result;
2990 g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2992 GST_OBJECT_LOCK (trans);
2993 result = trans->priv->qos_enabled;
2994 GST_OBJECT_UNLOCK (trans);
2996 return result;
2997 }
2999 /**
3000 * gst_base_transform_set_gap_aware:
3001 * @trans: a #GstBaseTransform
3002 * @gap_aware: New state
3003 *
3004 * If @gap_aware is %FALSE (the default), output buffers will have the
3005 * %GST_BUFFER_FLAG_GAP flag unset.
3006 *
3007 * If set to %TRUE, the element must handle output buffers with this flag set
3008 * correctly, i.e. it can assume that the buffer contains neutral data but must
3009 * unset the flag if the output is no neutral data.
3010 *
3011 * MT safe.
3012 *
3013 * Since: 0.10.16
3014 */
3015 void
3016 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
3017 {
3018 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3020 GST_OBJECT_LOCK (trans);
3021 trans->priv->gap_aware = gap_aware;
3022 GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
3023 GST_OBJECT_UNLOCK (trans);
3024 }
3026 /**
3027 * gst_base_transform_suggest:
3028 * @trans: a #GstBaseTransform
3029 * @caps: (transfer none): caps to suggest
3030 * @size: buffer size to suggest
3031 *
3032 * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
3033 * taken.
3034 *
3035 * Since: 0.10.21
3036 */
3037 void
3038 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
3039 guint size)
3040 {
3041 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3043 GST_OBJECT_LOCK (trans->sinkpad);
3044 if (trans->priv->sink_suggest)
3045 gst_caps_unref (trans->priv->sink_suggest);
3046 if (caps)
3047 caps = gst_caps_copy (caps);
3048 trans->priv->sink_suggest = caps;
3049 trans->priv->size_suggest = size;
3050 trans->priv->suggest_pending = TRUE;
3051 gst_base_transform_clear_transformed_caps_cache (trans);
3052 GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
3053 GST_OBJECT_UNLOCK (trans->sinkpad);
3054 }
3056 /**
3057 * gst_base_transform_reconfigure:
3058 * @trans: a #GstBaseTransform
3059 *
3060 * Instructs @trans to renegotiate a new downstream transform on the next
3061 * buffer. This function is typically called after properties on the transform
3062 * were set that influence the output format.
3063 *
3064 * Since: 0.10.21
3065 */
3066 void
3067 gst_base_transform_reconfigure (GstBaseTransform * trans)
3068 {
3069 g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3071 GST_OBJECT_LOCK (trans);
3072 GST_DEBUG_OBJECT (trans, "marking reconfigure");
3073 trans->priv->reconfigure = TRUE;
3074 gst_base_transform_clear_transformed_caps_cache (trans);
3075 gst_caps_replace (&trans->priv->sink_alloc, NULL);
3076 GST_OBJECT_UNLOCK (trans);
3077 }