basetransform: Fix 'equality comparison with extraneous parentheses' compiler warning
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasetransform.c
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  */
23
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  */
200
201 #ifdef HAVE_CONFIG_H
202 #  include "config.h"
203 #endif
204
205 #include <stdlib.h>
206 #include <string.h>
207
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>
216
217 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
218 #define GST_CAT_DEFAULT gst_base_transform_debug
219
220 /* BaseTransform signals and args */
221 enum
222 {
223   /* FILL ME */
224   LAST_SIGNAL
225 };
226
227 #define DEFAULT_PROP_QOS        FALSE
228
229 enum
230 {
231   PROP_0,
232   PROP_QOS
233 };
234
235 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
236     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
237
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;
246
247   GstActivateMode pad_mode;
248
249   gboolean gap_aware;
250
251   /* caps used for allocating buffers */
252   gboolean proxy_alloc;
253   GstCaps *sink_alloc;
254   GstCaps *src_alloc;
255
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;
275
276   /* upstream caps and size suggestions */
277   GstCaps *sink_suggest;
278   guint size_suggest;
279   gboolean suggest_pending;
280
281   gboolean reconfigure;
282
283   /* QoS stats */
284   guint64 processed;
285   guint64 dropped;
286
287   GstClockTime last_stop_out;
288   GList *delayed_events;
289
290   GstCaps *cached_peer_caps[2];
291   GstCaps *cached_transformed_caps[2];
292 };
293
294 static GstElementClass *parent_class = NULL;
295
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);
301
302 GType
303 gst_base_transform_get_type (void)
304 {
305   static volatile gsize base_transform_type = 0;
306
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     };
320
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 }
327
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);
341
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);
364
365 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
366
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 }
378
379 static void
380 gst_base_transform_clear_transformed_caps_cache (GstBaseTransform * trans)
381 {
382   struct _GstBaseTransformPrivate *priv = trans->priv;
383   int n;
384
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 }
396
397 static void
398 gst_base_transform_finalize (GObject * object)
399 {
400   GstBaseTransform *trans;
401
402   trans = GST_BASE_TRANSFORM (object);
403
404   gst_base_transform_drop_delayed_events (trans);
405   gst_caps_replace (&trans->priv->sink_suggest, NULL);
406   g_mutex_free (trans->transform_lock);
407
408   gst_base_transform_clear_transformed_caps_cache (trans);
409
410   G_OBJECT_CLASS (parent_class)->finalize (object);
411 }
412
413 static void
414 gst_base_transform_class_init (GstBaseTransformClass * klass)
415 {
416   GObjectClass *gobject_class;
417
418   gobject_class = G_OBJECT_CLASS (klass);
419
420   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
421       "basetransform element");
422
423   GST_DEBUG ("gst_base_transform_class_init");
424
425   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
426
427   parent_class = g_type_class_peek_parent (klass);
428
429   gobject_class->set_property = gst_base_transform_set_property;
430   gobject_class->get_property = gst_base_transform_get_property;
431
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));
435
436   gobject_class->finalize = gst_base_transform_finalize;
437
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 }
445
446 static void
447 gst_base_transform_init (GstBaseTransform * trans,
448     GstBaseTransformClass * bclass)
449 {
450   GstPadTemplate *pad_template;
451
452   GST_DEBUG ("gst_base_transform_init");
453
454   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
455
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);
479
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);
501
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;
510
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;
516
517     if (bclass->transform_ip == NULL) {
518       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
519       trans->passthrough = TRUE;
520     }
521   }
522
523   trans->priv->processed = 0;
524   trans->priv->dropped = 0;
525   trans->priv->force_alloc = TRUE;
526 }
527
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;
539
540   if (caps == NULL)
541     return NULL;
542
543   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
544
545   /* if there is a custom transform function, use this */
546   if (klass->transform_caps) {
547     GstCaps *temp;
548     gint i;
549
550     /* start with empty caps */
551     ret = gst_caps_new_empty ();
552     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
553
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);
559
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;
568
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);
574
575         temp = gst_caps_make_writable (temp);
576
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);
580
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   }
595
596   GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
597       ret);
598
599   return ret;
600 }
601
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;
619
620   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
621
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");
625
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;
641
642     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
643         inunitsize);
644
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;
648
649     /* get the amount of units */
650     units = size / inunitsize;
651
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;
655
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);
660
661     ret = TRUE;
662   }
663   return ret;
664
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 }
687
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;
706
707   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
708
709   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
710   cache_index = (pad == trans->srcpad) ? 0 : 1;
711
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);
734
735   if (peercaps) {
736     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
737
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   }
748
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;
756
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;
765
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   }
776
777 done_update_cache:
778   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
779
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   }
787
788 done:
789   GST_OBJECT_UNLOCK (trans);
790
791   if (peercaps)
792     gst_caps_unref (peercaps);
793
794   gst_object_unref (trans);
795
796   return caps;
797 }
798
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;
807
808   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
809
810   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
811   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
812
813   /* clear the cache */
814   gst_caps_replace (&trans->cache_caps1, NULL);
815   gst_caps_replace (&trans->cache_caps2, NULL);
816
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);
820
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);
826
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);
831
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   }
837
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;
845
846   return ret;
847 }
848
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;
858
859   /* convert the in caps to all possible out caps */
860   othercaps =
861       gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
862
863   /* check if transform is empty */
864   if (!othercaps || gst_caps_is_empty (othercaps))
865     goto no_transform;
866
867   /* check if the out caps is a subset of the othercaps */
868   if (!gst_caps_can_intersect (out, othercaps))
869     goto no_subset;
870
871   if (othercaps)
872     gst_caps_unref (othercaps);
873
874   GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
875   GST_DEBUG_OBJECT (trans, "to   %" GST_PTR_FORMAT, out);
876
877   return TRUE;
878
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 }
896
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;
922
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);
925
926   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
927
928   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
929   otherpeer = gst_pad_get_peer (otherpad);
930
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);
936
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;
942
943     templ_caps = gst_pad_get_pad_template_caps (otherpad);
944     GST_DEBUG_OBJECT (trans,
945         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
946
947     intersect =
948         gst_caps_intersect_full (othercaps, templ_caps,
949         GST_CAPS_INTERSECT_FIRST);
950
951     gst_caps_unref (othercaps);
952     othercaps = intersect;
953   }
954
955   /* check if transform is empty */
956   if (!othercaps || gst_caps_is_empty (othercaps))
957     goto no_transform;
958
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);
967
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   }
997
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;
1004
1005     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
1006
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;
1013
1014     is_fixed = gst_caps_is_fixed (othercaps);
1015
1016     GST_DEBUG_OBJECT (trans,
1017         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
1018   }
1019
1020   if (gst_caps_is_empty (othercaps))
1021     goto no_transform_possible;
1022
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));
1029
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 */
1032
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;
1037
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);
1061
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));
1066
1067       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1068       is_fixed = gst_caps_is_fixed (othercaps);
1069     }
1070   }
1071
1072   /* caps should be fixed now, if not we have to fail. */
1073   if (!is_fixed)
1074     goto could_not_fixate;
1075
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;
1080
1081   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1082       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1083
1084   if (otherpeer)
1085     gst_object_unref (otherpeer);
1086
1087   return othercaps;
1088
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 }
1123
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;
1133
1134 #if 0
1135   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1136
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;
1143
1144     GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1145
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);
1151
1152     if (!allowed) {
1153       GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1154       goto no_transform_possible;
1155     }
1156
1157     GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1158
1159     /* intersect with the requested format */
1160     ret = gst_caps_can_intersect (allowed, caps);
1161     gst_caps_unref (allowed);
1162
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);
1169
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;
1175
1176     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1177   }
1178 #endif
1179
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
1186
1187   return ret;
1188
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 }
1199
1200 static gboolean
1201 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1202 {
1203   gboolean ret = TRUE;
1204   GstBaseTransform *trans;
1205   GstBaseTransformClass *bclass;
1206
1207   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1208   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1209
1210   if (bclass->accept_caps)
1211     ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1212
1213   gst_object_unref (trans);
1214
1215   return ret;
1216 }
1217
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;
1234
1235   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1236
1237   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1238   otherpeer = gst_pad_get_peer (otherpad);
1239
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;
1244
1245   GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1246
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;
1251
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   }
1261
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   }
1268
1269   /* call configure now */
1270   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1271     goto failed_configure;
1272
1273   /* we know this will work, we implement the setcaps */
1274   gst_pad_set_caps (otherpad, othercaps);
1275
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   }
1284
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);
1292
1293   trans->negotiated = ret;
1294
1295   gst_object_unref (trans);
1296
1297   return ret;
1298
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 }
1316
1317 static gboolean
1318 gst_base_transform_default_query (GstBaseTransform * trans,
1319     GstPadDirection direction, GstQuery * query)
1320 {
1321   gboolean ret = FALSE;
1322   GstPad *otherpad;
1323
1324   otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1325
1326   switch (GST_QUERY_TYPE (query)) {
1327     case GST_QUERY_POSITION:{
1328       GstFormat format;
1329
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;
1334
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   }
1354
1355   return ret;
1356 }
1357
1358 static gboolean
1359 gst_base_transform_query (GstPad * pad, GstQuery * query)
1360 {
1361   GstBaseTransform *trans;
1362   GstBaseTransformClass *bclass;
1363   gboolean ret;
1364
1365   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1366   if (G_UNLIKELY (trans == NULL))
1367     return FALSE;
1368
1369   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1370
1371   if (bclass->query)
1372     ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1373   else
1374     ret = gst_pad_query_default (pad, query);
1375
1376   gst_object_unref (trans);
1377
1378   return ret;
1379 }
1380
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   };
1388
1389   return types;
1390 }
1391
1392 static void
1393 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1394     GstCaps * caps)
1395 {
1396   GstCaps *othercaps;
1397   GstBaseTransformPrivate *priv = trans->priv;
1398
1399   GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1400
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);
1404
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;
1412
1413     GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1414
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)) {
1419
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);
1424
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 }
1436
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;
1455
1456   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1457
1458   priv = trans->priv;
1459
1460   *out_buf = NULL;
1461
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;
1474
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   }
1496
1497   oldcaps = GST_PAD_CAPS (trans->srcpad);
1498
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);
1506
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);
1510
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);
1518
1519     /* never discard the buffer from the prepare_buffer method */
1520     if (*out_buf != NULL)
1521       discard = FALSE;
1522   }
1523
1524   if (ret != GST_FLOW_OK)
1525     goto alloc_failed;
1526
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);
1534
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   }
1541
1542   /* must always have a buffer by now */
1543   if (*out_buf == NULL)
1544     goto no_buffer;
1545
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);
1549
1550   if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1551     GstCaps *othercaps;
1552     gboolean can_convert;
1553
1554     GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1555
1556     incaps = GST_PAD_CAPS (trans->sinkpad);
1557
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);
1562
1563     if (!can_convert) {
1564       GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1565
1566       gst_base_transform_transform_size (trans,
1567           GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1568
1569       compute_upstream_suggestion (trans, expsize, newcaps);
1570
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);
1575
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     }
1587
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);
1593
1594     if (can_convert) {
1595       GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1596
1597       /* subclass might want to add fields to the caps */
1598       if (bclass->fixate_caps != NULL) {
1599         newcaps = gst_caps_copy (newcaps);
1600
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);
1606
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       }
1612
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);
1635
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   }
1647
1648   /* these are the final output caps */
1649   outcaps = GST_PAD_CAPS (trans->srcpad);
1650
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;
1682
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   }
1699
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);
1713
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   }
1733
1734   return ret;
1735
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 }
1759
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;
1779
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   }
1791
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");
1797
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 }
1817
1818 /* your upstream peer wants to send you a buffer
1819  * that buffer has the given offset, size and caps
1820  * you're requested to allocate a buffer
1821  */
1822 static GstFlowReturn
1823 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1824     GstCaps * caps, GstBuffer ** buf)
1825 {
1826   GstBaseTransform *trans;
1827   GstBaseTransformPrivate *priv;
1828   GstFlowReturn res;
1829   gboolean alloced = FALSE;
1830   gboolean proxy, suggest, new_caps;
1831   GstCaps *sink_suggest = NULL;
1832   guint size_suggest;
1833
1834   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1835   if (G_UNLIKELY (trans == NULL))
1836     return GST_FLOW_WRONG_STATE;
1837   priv = trans->priv;
1838
1839   GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1840       caps, caps, size);
1841
1842   /* if the code below does not come up with a better buffer, we will return _OK
1843    * and an empty buffer. This will trigger the core to allocate a buffer with
1844    * given input size and caps. */
1845   *buf = NULL;
1846   res = GST_FLOW_OK;
1847
1848   /* we remember our previous alloc request to quickly see if we can proxy or
1849    * not. We skip this check if we have a pending suggestion. */
1850   GST_OBJECT_LOCK (pad);
1851   suggest = priv->suggest_pending;
1852   GST_OBJECT_UNLOCK (pad);
1853
1854   if (!suggest) {
1855     /* we have no suggestion, see below if we need to proxy */
1856     gst_caps_replace (&sink_suggest, caps);
1857     size_suggest = size;
1858     suggest = FALSE;
1859     new_caps = sink_suggest
1860         && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1861
1862     if (new_caps)
1863       GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1864     else
1865       GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1866   } else {
1867     /* if we have a suggestion, pretend we got these as input */
1868     GST_OBJECT_LOCK (pad);
1869     if (priv->sink_suggest &&
1870         !gst_caps_can_intersect (caps, priv->sink_suggest)) {
1871       sink_suggest = gst_caps_ref (priv->sink_suggest);
1872       size_suggest = priv->size_suggest;
1873       GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1874           sink_suggest, sink_suggest, priv->size_suggest);
1875     } else {
1876       GST_DEBUG_OBJECT (trans,
1877           "have suggestion equal to upstream caps %p %" GST_PTR_FORMAT, caps,
1878           caps);
1879       gst_caps_replace (&sink_suggest, caps);
1880       size_suggest = size;
1881       suggest = FALSE;
1882     }
1883     priv->suggest_pending = FALSE;
1884     GST_OBJECT_UNLOCK (pad);
1885
1886     /* check if we actually handle this format on the sinkpad */
1887     if (suggest) {
1888       GstCaps *peercaps;
1889
1890       /* Always intersect with the peer caps to get correct
1891        * and complete caps. The suggested caps could be incomplete,
1892        * for example video/x-raw-yuv without any fields at all.
1893        */
1894       peercaps =
1895           gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1896
1897       if (peercaps) {
1898         GstCaps *intersect;
1899
1900         intersect =
1901             gst_caps_intersect_full (sink_suggest, peercaps,
1902             GST_CAPS_INTERSECT_FIRST);
1903         gst_caps_unref (peercaps);
1904
1905         /* If intersected caps is empty then just keep them empty. The
1906          * code below will try to come up with possible caps if there
1907          * are any */
1908         gst_caps_unref (sink_suggest);
1909         sink_suggest = intersect;
1910       }
1911
1912       /* If the suggested caps are not empty and not fixed, try to fixate them */
1913       if (!gst_caps_is_fixed (sink_suggest)
1914           && !gst_caps_is_empty (sink_suggest)) {
1915         GST_DEBUG_OBJECT (trans,
1916             "Suggested caps is not fixed: %" GST_PTR_FORMAT, sink_suggest);
1917
1918         /* try the alloc caps if it is still not fixed */
1919         if (!gst_caps_is_fixed (sink_suggest)) {
1920           GstCaps *intersect;
1921
1922           GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1923               "with the non-fixed caps suggestion");
1924           intersect =
1925               gst_caps_intersect_full (sink_suggest, caps,
1926               GST_CAPS_INTERSECT_FIRST);
1927           if (!gst_caps_is_empty (intersect)) {
1928             GST_DEBUG_OBJECT (trans, "It is, using it");
1929             gst_caps_replace (&sink_suggest, caps);
1930           }
1931           gst_caps_unref (intersect);
1932         }
1933
1934         /* be safe and call default fixate */
1935         sink_suggest = gst_caps_make_writable (sink_suggest);
1936         gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1937
1938         if (!gst_caps_is_fixed (sink_suggest)) {
1939           GST_DEBUG_OBJECT (trans,
1940               "Impossible to fixate caps, using upstream caps");
1941           gst_caps_replace (&sink_suggest, caps);
1942           size_suggest = size;
1943           suggest = FALSE;
1944         }
1945
1946         GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1947             sink_suggest);
1948       }
1949     }
1950
1951     new_caps = sink_suggest
1952         && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1953   }
1954
1955   /* Check if the new caps are compatible with our
1956    * sinkpad template caps and if they're not
1957    * we try to come up with any supported caps
1958    */
1959   if (new_caps) {
1960     const GstCaps *templ;
1961
1962     templ = gst_pad_get_pad_template_caps (pad);
1963
1964     /* Fall back to the upstream caps if the suggested caps
1965      * are not actually supported. Shouldn't really happen
1966      */
1967     if (suggest && !gst_caps_can_intersect (sink_suggest, templ)) {
1968       GST_DEBUG_OBJECT (trans,
1969           "Suggested caps not supported by sinkpad, using upstream caps");
1970       gst_caps_replace (&sink_suggest, caps);
1971       size_suggest = size;
1972       suggest = FALSE;
1973       new_caps = sink_suggest
1974           && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1975     }
1976
1977     if (new_caps && (suggest || !gst_caps_can_intersect (sink_suggest, templ))) {
1978       GstCaps *allowed, *peercaps;
1979
1980       GST_DEBUG_OBJECT (trans,
1981           "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1982           sink_suggest);
1983       /* the requested pad alloc caps are not supported, so let's try
1984        * picking something allowed between the pads (they are linked,
1985        * there must be something) */
1986       allowed = gst_pad_get_allowed_caps (pad);
1987       if (allowed && !gst_caps_is_empty (allowed)) {
1988         GST_DEBUG_OBJECT (trans,
1989             "pads could agree on one of the following caps: " "%"
1990             GST_PTR_FORMAT, allowed);
1991
1992         /* Check which caps would be possible with downstream */
1993         peercaps =
1994             gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1995         if (peercaps) {
1996           GstCaps *tmp, *intersect;
1997
1998           tmp =
1999               gst_base_transform_transform_caps (trans, GST_PAD_SRC, peercaps);
2000           gst_caps_unref (peercaps);
2001           intersect = gst_caps_intersect (allowed, tmp);
2002           gst_caps_unref (tmp);
2003           gst_caps_unref (allowed);
2004
2005           if (gst_caps_is_empty (intersect)) {
2006             gst_caps_unref (intersect);
2007             goto not_supported;
2008           }
2009
2010           allowed = intersect;
2011         }
2012
2013         allowed = gst_caps_make_writable (allowed);
2014
2015         /* Fixate them to be safe if the subclass didn't do it */
2016         gst_caps_truncate (allowed);
2017         gst_pad_fixate_caps (pad, allowed);
2018
2019         if (!gst_caps_is_fixed (allowed)) {
2020           GST_ERROR_OBJECT (trans, "Impossible to fixate any caps");
2021           gst_caps_unref (allowed);
2022           goto not_supported;
2023         }
2024
2025         gst_caps_replace (&sink_suggest, allowed);
2026         gst_caps_unref (allowed);
2027
2028         suggest = TRUE;
2029         new_caps = !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
2030
2031         GST_DEBUG_OBJECT (trans, "Calculated new suggestion caps %"
2032             GST_PTR_FORMAT, sink_suggest);
2033       } else {
2034         if (allowed)
2035           gst_caps_unref (allowed);
2036         goto not_supported;
2037       }
2038     }
2039   }
2040
2041   /* find the best format for the other side here we decide if we will proxy
2042    * the caps or not. */
2043   if (sink_suggest == NULL) {
2044     /* always proxy when the caps are NULL. When this is a new format, see if
2045      * we can proxy it downstream */
2046     GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
2047     priv->proxy_alloc = TRUE;
2048   } else if (new_caps) {
2049     GstCaps *othercaps;
2050
2051     /* we have a new format, see what we need to proxy to */
2052     othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
2053     if (!othercaps || gst_caps_is_empty (othercaps)) {
2054       /* no transform possible, we certainly can't proxy */
2055       GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
2056       priv->proxy_alloc = FALSE;
2057     } else {
2058       /* we transformed into something */
2059       if (gst_caps_is_equal (sink_suggest, othercaps)) {
2060         GST_DEBUG_OBJECT (trans, "best caps same as input, marking for proxy");
2061         priv->proxy_alloc = TRUE;
2062       } else {
2063         GST_DEBUG_OBJECT (trans,
2064             "best caps different from input, disable proxy");
2065         priv->proxy_alloc = FALSE;
2066       }
2067     }
2068     if (othercaps)
2069       gst_caps_unref (othercaps);
2070   }
2071
2072   /* remember the new caps */
2073   GST_OBJECT_LOCK (pad);
2074   gst_caps_replace (&priv->sink_alloc, sink_suggest);
2075   GST_OBJECT_UNLOCK (pad);
2076
2077   proxy = priv->proxy_alloc;
2078   GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
2079       suggest);
2080
2081   /* we only want to proxy if we have no suggestion pending, FIXME */
2082   if (proxy && !suggest) {
2083     GstCaps *newcaps;
2084
2085     GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
2086         ", size %u", caps, caps, size);
2087
2088     /* we always proxy the input caps, never the suggestion. The reason is that
2089      * We don't yet handle the caps of renegotiation in here. FIXME */
2090     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
2091     if (res != GST_FLOW_OK)
2092       goto alloc_failed;
2093     alloced = TRUE;
2094
2095     /* check if the caps changed */
2096     newcaps = GST_BUFFER_CAPS (*buf);
2097
2098     GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
2099
2100     if (!gst_caps_is_equal (newcaps, caps)) {
2101       GST_DEBUG_OBJECT (trans, "caps are new");
2102       /* we have new caps, see if we can proxy downstream */
2103       if (gst_pad_peer_accept_caps (pad, newcaps)) {
2104         /* peer accepts the caps, return a buffer in this format */
2105         GST_DEBUG_OBJECT (trans, "peer accepted new caps");
2106         /* remember the format */
2107         GST_OBJECT_LOCK (pad);
2108         gst_caps_replace (&priv->sink_alloc, newcaps);
2109         GST_OBJECT_UNLOCK (pad);
2110       } else {
2111         GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
2112         /* peer does not accept the caps, disable proxy_alloc, free the
2113          * buffer we received and create a buffer of the requested format
2114          * by the default handler. */
2115         GST_DEBUG_OBJECT (trans, "disabling proxy");
2116         priv->proxy_alloc = FALSE;
2117         gst_buffer_unref (*buf);
2118         *buf = NULL;
2119       }
2120     } else {
2121       GST_DEBUG_OBJECT (trans, "received required caps from peer");
2122     }
2123   } else if (suggest) {
2124     /* there was a custom suggestion, create a buffer of this format and return
2125      * it. Note that this format  */
2126     *buf = gst_buffer_new_and_alloc (size_suggest);
2127     GST_DEBUG_OBJECT (trans,
2128         "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2129         sink_suggest, sink_suggest);
2130     GST_BUFFER_CAPS (*buf) = sink_suggest;
2131     sink_suggest = NULL;
2132   } else {
2133     /* fallback buffer allocation by gst_pad_alloc_buffer() with the
2134      * caps and size provided by the caller */
2135   }
2136
2137   if (sink_suggest)
2138     gst_caps_unref (sink_suggest);
2139
2140   if (res == GST_FLOW_OK && alloced) {
2141     /* just alloc'ed a buffer, so we only want to do this again if we
2142      * received a buffer */
2143     GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2144     trans->priv->force_alloc = FALSE;
2145   }
2146
2147   gst_object_unref (trans);
2148   return res;
2149
2150   /* ERRORS */
2151 alloc_failed:
2152   {
2153     GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2154     if (sink_suggest)
2155       gst_caps_unref (sink_suggest);
2156     gst_object_unref (trans);
2157     return res;
2158   }
2159 not_supported:
2160   {
2161     GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2162     if (sink_suggest)
2163       gst_caps_unref (sink_suggest);
2164     gst_object_unref (trans);
2165     return GST_FLOW_NOT_NEGOTIATED;
2166   }
2167 }
2168
2169 static void
2170 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2171 {
2172   GList *list, *tmp;
2173
2174   GST_OBJECT_LOCK (trans);
2175   list = trans->priv->delayed_events;
2176   trans->priv->delayed_events = NULL;
2177   GST_OBJECT_UNLOCK (trans);
2178   if (!list)
2179     return;
2180
2181   for (tmp = list; tmp; tmp = tmp->next) {
2182     GstEvent *ev = tmp->data;
2183
2184     GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2185         GST_EVENT_TYPE_NAME (ev));
2186     gst_pad_push_event (trans->srcpad, ev);
2187   }
2188   g_list_free (list);
2189 }
2190
2191 static gboolean
2192 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2193 {
2194   GstBaseTransform *trans;
2195   GstBaseTransformClass *bclass;
2196   gboolean ret = TRUE;
2197   gboolean forward = TRUE;
2198
2199   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2200   if (G_UNLIKELY (trans == NULL)) {
2201     gst_event_unref (event);
2202     return FALSE;
2203   }
2204   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2205
2206   if (bclass->event)
2207     forward = bclass->event (trans, event);
2208
2209   /* FIXME, do this in the default event handler so the subclass can do
2210    * something different. */
2211   if (forward) {
2212     gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2213
2214     /* src caps may not yet be set, so we delay any serialized events
2215        that we receive before (in particular newsegment events), except
2216        EOS and flush stops, since those'll obsolete previous events */
2217     if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2218       gst_base_transform_drop_delayed_events (trans);
2219       delay = FALSE;
2220     } else {
2221       delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2222           && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2223
2224       /* do not stall sparse stream update newsegment events */
2225       if (delay && (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)) {
2226         gboolean update;
2227
2228         gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL,
2229             NULL, NULL, NULL);
2230         if (update) {
2231           GST_DEBUG_OBJECT (trans, "update segment; triggering delayed events");
2232           delay = FALSE;
2233           caps_set = TRUE;
2234         }
2235       }
2236     }
2237
2238     if (delay) {
2239       GST_OBJECT_LOCK (trans);
2240       trans->priv->delayed_events =
2241           g_list_append (trans->priv->delayed_events, event);
2242       GST_OBJECT_UNLOCK (trans);
2243     } else {
2244       if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2245         gst_base_transform_send_delayed_events (trans);
2246       ret = gst_pad_push_event (trans->srcpad, event);
2247     }
2248   } else
2249     gst_event_unref (event);
2250
2251   gst_object_unref (trans);
2252
2253   return ret;
2254 }
2255
2256 static gboolean
2257 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2258 {
2259   switch (GST_EVENT_TYPE (event)) {
2260     case GST_EVENT_FLUSH_START:
2261       break;
2262     case GST_EVENT_FLUSH_STOP:
2263       GST_OBJECT_LOCK (trans);
2264       /* reset QoS parameters */
2265       trans->priv->proportion = 1.0;
2266       trans->priv->earliest_time = -1;
2267       trans->priv->discont = FALSE;
2268       trans->priv->processed = 0;
2269       trans->priv->dropped = 0;
2270       GST_OBJECT_UNLOCK (trans);
2271       /* we need new segment info after the flush. */
2272       trans->have_newsegment = FALSE;
2273       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2274       trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2275       break;
2276     case GST_EVENT_EOS:
2277       break;
2278     case GST_EVENT_TAG:
2279       break;
2280     case GST_EVENT_NEWSEGMENT:
2281     {
2282       GstFormat format;
2283       gdouble rate, arate;
2284       gint64 start, stop, time;
2285       gboolean update;
2286
2287       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2288           &start, &stop, &time);
2289
2290       trans->have_newsegment = TRUE;
2291
2292       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2293           format, start, stop, time);
2294
2295       if (format == GST_FORMAT_TIME) {
2296         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2297             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2298             ", accum %" GST_TIME_FORMAT,
2299             GST_TIME_ARGS (trans->segment.start),
2300             GST_TIME_ARGS (trans->segment.stop),
2301             GST_TIME_ARGS (trans->segment.time),
2302             GST_TIME_ARGS (trans->segment.accum));
2303       } else {
2304         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2305             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2306             ", accum %" G_GINT64_FORMAT,
2307             trans->segment.start, trans->segment.stop,
2308             trans->segment.time, trans->segment.accum);
2309       }
2310       break;
2311     }
2312     default:
2313       break;
2314   }
2315
2316   return TRUE;
2317 }
2318
2319 static gboolean
2320 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2321 {
2322   GstBaseTransform *trans;
2323   GstBaseTransformClass *bclass;
2324   gboolean ret = TRUE;
2325
2326   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2327   if (G_UNLIKELY (trans == NULL)) {
2328     gst_event_unref (event);
2329     return FALSE;
2330   }
2331
2332   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2333
2334   if (bclass->src_event)
2335     ret = bclass->src_event (trans, event);
2336   else
2337     gst_event_unref (event);
2338
2339   gst_object_unref (trans);
2340
2341   return ret;
2342 }
2343
2344 static gboolean
2345 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2346 {
2347   gboolean ret;
2348
2349   GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2350
2351   switch (GST_EVENT_TYPE (event)) {
2352     case GST_EVENT_SEEK:
2353       break;
2354     case GST_EVENT_NAVIGATION:
2355       break;
2356     case GST_EVENT_QOS:
2357     {
2358       gdouble proportion;
2359       GstClockTimeDiff diff;
2360       GstClockTime timestamp;
2361
2362       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
2363       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2364       break;
2365     }
2366     default:
2367       break;
2368   }
2369
2370   ret = gst_pad_push_event (trans->sinkpad, event);
2371
2372   return ret;
2373 }
2374
2375 /* perform a transform on @inbuf and put the result in @outbuf.
2376  *
2377  * This function is common to the push and pull-based operations.
2378  *
2379  * This function takes ownership of @inbuf */
2380 static GstFlowReturn
2381 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2382     GstBuffer ** outbuf)
2383 {
2384   GstBaseTransformClass *bclass;
2385   GstFlowReturn ret = GST_FLOW_OK;
2386   gboolean want_in_place, reconfigure;
2387   GstClockTime running_time;
2388   GstClockTime timestamp;
2389   GstCaps *incaps;
2390
2391   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2392
2393   if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2394     GST_OBJECT_LOCK (trans);
2395     reconfigure = trans->priv->reconfigure;
2396     trans->priv->reconfigure = FALSE;
2397     GST_OBJECT_UNLOCK (trans);
2398
2399     if (G_UNLIKELY (reconfigure)) {
2400       GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2401       /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2402        * will reconfigure the transform with the new output format. We can only
2403        * do this if the buffer actually has caps. */
2404       if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2405         goto not_negotiated;
2406     }
2407   }
2408
2409   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2410     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2411         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2412         GST_BUFFER_OFFSET (inbuf));
2413   else
2414     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2415         inbuf, GST_BUFFER_SIZE (inbuf));
2416
2417   /* Don't allow buffer handling before negotiation, except in passthrough mode
2418    * or if the class doesn't implement a set_caps function (in which case it doesn't
2419    * care about caps)
2420    */
2421   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2422     goto not_negotiated;
2423
2424   /* Set discont flag so we can mark the outgoing buffer */
2425   if (GST_BUFFER_IS_DISCONT (inbuf)) {
2426     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2427     trans->priv->discont = TRUE;
2428   }
2429
2430   /* can only do QoS if the segment is in TIME */
2431   if (trans->segment.format != GST_FORMAT_TIME)
2432     goto no_qos;
2433
2434   /* QOS is done on the running time of the buffer, get it now */
2435   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2436   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2437       timestamp);
2438
2439   if (running_time != -1) {
2440     gboolean need_skip;
2441     GstClockTime earliest_time;
2442     gdouble proportion;
2443
2444     /* lock for getting the QoS parameters that are set (in a different thread)
2445      * with the QOS events */
2446     GST_OBJECT_LOCK (trans);
2447     earliest_time = trans->priv->earliest_time;
2448     proportion = trans->priv->proportion;
2449     /* check for QoS, don't perform conversion for buffers
2450      * that are known to be late. */
2451     need_skip = trans->priv->qos_enabled &&
2452         earliest_time != -1 && running_time <= earliest_time;
2453     GST_OBJECT_UNLOCK (trans);
2454
2455     if (need_skip) {
2456       GstMessage *qos_msg;
2457       GstClockTime duration;
2458       guint64 stream_time;
2459       gint64 jitter;
2460
2461       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2462           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2463           GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2464
2465       trans->priv->dropped++;
2466
2467       duration = GST_BUFFER_DURATION (inbuf);
2468       stream_time =
2469           gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2470           timestamp);
2471       jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2472
2473       qos_msg =
2474           gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2475           stream_time, timestamp, duration);
2476       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2477       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2478           trans->priv->processed, trans->priv->dropped);
2479       gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2480
2481       /* mark discont for next buffer */
2482       trans->priv->discont = TRUE;
2483       goto skip;
2484     }
2485   }
2486
2487 no_qos:
2488
2489   /* first try to allocate an output buffer based on the currently negotiated
2490    * format. While we call pad-alloc we could renegotiate the srcpad format or
2491    * have a new suggestion for upstream buffer-alloc.
2492    * In any case, outbuf will contain a buffer suitable for doing the configured
2493    * transform after this function. */
2494   ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2495   if (G_UNLIKELY (ret != GST_FLOW_OK))
2496     goto no_buffer;
2497
2498   /* now perform the needed transform */
2499   if (trans->passthrough) {
2500     /* In passthrough mode, give transform_ip a look at the
2501      * buffer, without making it writable, or just push the
2502      * data through */
2503     if (bclass->transform_ip) {
2504       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2505       ret = bclass->transform_ip (trans, *outbuf);
2506     } else {
2507       GST_DEBUG_OBJECT (trans, "element is in passthrough");
2508     }
2509   } else {
2510     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2511
2512     if (want_in_place) {
2513       GST_DEBUG_OBJECT (trans, "doing inplace transform");
2514
2515       if (inbuf != *outbuf) {
2516         guint8 *indata, *outdata;
2517
2518         /* Different buffer. The data can still be the same when we are dealing
2519          * with subbuffers of the same buffer. Note that because of the FIXME in
2520          * prepare_output_buffer() we have decreased the refcounts of inbuf and
2521          * outbuf to keep them writable */
2522         indata = GST_BUFFER_DATA (inbuf);
2523         outdata = GST_BUFFER_DATA (*outbuf);
2524
2525         if (indata != outdata)
2526           memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2527       }
2528       ret = bclass->transform_ip (trans, *outbuf);
2529     } else {
2530       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2531
2532       if (bclass->transform)
2533         ret = bclass->transform (trans, inbuf, *outbuf);
2534       else
2535         ret = GST_FLOW_NOT_SUPPORTED;
2536     }
2537   }
2538
2539 skip:
2540   /* only unref input buffer if we allocated a new outbuf buffer */
2541   if (*outbuf != inbuf)
2542     gst_buffer_unref (inbuf);
2543
2544   /* pushed a buffer, we can now try an alloc */
2545   GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2546   trans->priv->force_alloc = TRUE;
2547   return ret;
2548
2549   /* ERRORS */
2550 not_negotiated:
2551   {
2552     gst_buffer_unref (inbuf);
2553     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2554         ("not negotiated"), ("not negotiated"));
2555     return GST_FLOW_NOT_NEGOTIATED;
2556   }
2557 no_buffer:
2558   {
2559     gst_buffer_unref (inbuf);
2560     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2561         gst_flow_get_name (ret));
2562     return ret;
2563   }
2564 }
2565
2566 static gboolean
2567 gst_base_transform_check_get_range (GstPad * pad)
2568 {
2569   GstBaseTransform *trans;
2570   gboolean ret;
2571
2572   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2573
2574   ret = gst_pad_check_pull_range (trans->sinkpad);
2575
2576   gst_object_unref (trans);
2577
2578   return ret;
2579 }
2580
2581 /* FIXME, getrange is broken, need to pull range from the other
2582  * end based on the transform_size result.
2583  */
2584 static GstFlowReturn
2585 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2586     guint length, GstBuffer ** buffer)
2587 {
2588   GstBaseTransform *trans;
2589   GstBaseTransformClass *klass;
2590   GstFlowReturn ret;
2591   GstBuffer *inbuf;
2592
2593   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2594
2595   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2596   if (G_UNLIKELY (ret != GST_FLOW_OK))
2597     goto pull_error;
2598
2599   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2600   if (klass->before_transform)
2601     klass->before_transform (trans, inbuf);
2602
2603   GST_BASE_TRANSFORM_LOCK (trans);
2604   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2605   GST_BASE_TRANSFORM_UNLOCK (trans);
2606
2607 done:
2608   gst_object_unref (trans);
2609
2610   return ret;
2611
2612   /* ERRORS */
2613 pull_error:
2614   {
2615     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2616         gst_flow_get_name (ret));
2617     goto done;
2618   }
2619 }
2620
2621 static GstFlowReturn
2622 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2623 {
2624   GstBaseTransform *trans;
2625   GstBaseTransformClass *klass;
2626   GstFlowReturn ret;
2627   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2628   GstClockTime timestamp, duration;
2629   GstBuffer *outbuf = NULL;
2630
2631   trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2632
2633   timestamp = GST_BUFFER_TIMESTAMP (buffer);
2634   duration = GST_BUFFER_DURATION (buffer);
2635
2636   /* calculate end position of the incoming buffer */
2637   if (timestamp != GST_CLOCK_TIME_NONE) {
2638     if (duration != GST_CLOCK_TIME_NONE)
2639       last_stop = timestamp + duration;
2640     else
2641       last_stop = timestamp;
2642   }
2643
2644   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2645   if (klass->before_transform)
2646     klass->before_transform (trans, buffer);
2647
2648   gst_base_transform_send_delayed_events (trans);
2649
2650   /* protect transform method and concurrent buffer alloc */
2651   GST_BASE_TRANSFORM_LOCK (trans);
2652   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2653   GST_BASE_TRANSFORM_UNLOCK (trans);
2654
2655   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2656    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2657   if (outbuf != NULL) {
2658     if (ret == GST_FLOW_OK) {
2659       GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2660
2661       /* Remember last stop position */
2662       if (last_stop != GST_CLOCK_TIME_NONE &&
2663           trans->segment.format == GST_FORMAT_TIME)
2664         gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2665
2666       if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2667         last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2668         if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2669           last_stop_out += GST_BUFFER_DURATION (outbuf);
2670       } else if (last_stop != GST_CLOCK_TIME_NONE) {
2671         last_stop_out = last_stop;
2672       }
2673       if (last_stop_out != GST_CLOCK_TIME_NONE
2674           && trans->segment.format == GST_FORMAT_TIME)
2675         trans->priv->last_stop_out = last_stop_out;
2676
2677       /* apply DISCONT flag if the buffer is not yet marked as such */
2678       if (trans->priv->discont) {
2679         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2680           outbuf = gst_buffer_make_metadata_writable (outbuf);
2681           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2682         }
2683         trans->priv->discont = FALSE;
2684       }
2685       trans->priv->processed++;
2686
2687       ret = gst_pad_push (trans->srcpad, outbuf);
2688     } else {
2689       gst_buffer_unref (outbuf);
2690     }
2691   }
2692
2693   /* convert internal flow to OK and mark discont for the next buffer. */
2694   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2695     trans->priv->discont = TRUE;
2696     ret = GST_FLOW_OK;
2697   }
2698
2699   return ret;
2700 }
2701
2702 static void
2703 gst_base_transform_set_property (GObject * object, guint prop_id,
2704     const GValue * value, GParamSpec * pspec)
2705 {
2706   GstBaseTransform *trans;
2707
2708   trans = GST_BASE_TRANSFORM (object);
2709
2710   switch (prop_id) {
2711     case PROP_QOS:
2712       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2713       break;
2714     default:
2715       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2716       break;
2717   }
2718 }
2719
2720 static void
2721 gst_base_transform_get_property (GObject * object, guint prop_id,
2722     GValue * value, GParamSpec * pspec)
2723 {
2724   GstBaseTransform *trans;
2725
2726   trans = GST_BASE_TRANSFORM (object);
2727
2728   switch (prop_id) {
2729     case PROP_QOS:
2730       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2731       break;
2732     default:
2733       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2734       break;
2735   }
2736 }
2737
2738 /* not a vmethod of anything, just an internal method */
2739 static gboolean
2740 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2741 {
2742   GstBaseTransformClass *bclass;
2743   gboolean result = TRUE;
2744
2745   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2746
2747   GST_OBJECT_LOCK (trans);
2748   gst_base_transform_clear_transformed_caps_cache (trans);
2749   GST_OBJECT_UNLOCK (trans);
2750
2751   if (active) {
2752     if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2753       result &= bclass->start (trans);
2754
2755     GST_OBJECT_LOCK (trans);
2756
2757     if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2758       trans->have_same_caps =
2759           gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2760           GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2761     else
2762       trans->have_same_caps = trans->passthrough;
2763     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2764     trans->negotiated = FALSE;
2765     trans->have_newsegment = FALSE;
2766     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2767     trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2768     trans->priv->proportion = 1.0;
2769     trans->priv->earliest_time = -1;
2770     trans->priv->discont = FALSE;
2771     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2772     trans->priv->processed = 0;
2773     trans->priv->dropped = 0;
2774     trans->priv->force_alloc = TRUE;
2775
2776     GST_OBJECT_UNLOCK (trans);
2777   } else {
2778     /* We must make sure streaming has finished before resetting things
2779      * and calling the ::stop vfunc */
2780     GST_PAD_STREAM_LOCK (trans->sinkpad);
2781     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2782
2783     gst_base_transform_drop_delayed_events (trans);
2784
2785     trans->have_same_caps = FALSE;
2786     /* We can only reset the passthrough mode if the instance told us to
2787        handle it in configure_caps */
2788     if (bclass->passthrough_on_same_caps) {
2789       gst_base_transform_set_passthrough (trans, FALSE);
2790     }
2791     gst_caps_replace (&trans->cache_caps1, NULL);
2792     gst_caps_replace (&trans->cache_caps2, NULL);
2793     gst_caps_replace (&trans->priv->sink_alloc, NULL);
2794     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2795
2796     if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2797       result &= bclass->stop (trans);
2798   }
2799
2800   return result;
2801 }
2802
2803 static gboolean
2804 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2805 {
2806   gboolean result = TRUE;
2807   GstBaseTransform *trans;
2808
2809   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2810
2811   result = gst_base_transform_activate (trans, active);
2812
2813   if (result)
2814     trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2815
2816   gst_object_unref (trans);
2817
2818   return result;
2819 }
2820
2821 static gboolean
2822 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2823 {
2824   gboolean result = FALSE;
2825   GstBaseTransform *trans;
2826
2827   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2828
2829   result = gst_pad_activate_pull (trans->sinkpad, active);
2830
2831   if (result)
2832     result &= gst_base_transform_activate (trans, active);
2833
2834   if (result)
2835     trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2836
2837   gst_object_unref (trans);
2838
2839   return result;
2840 }
2841
2842 /**
2843  * gst_base_transform_set_passthrough:
2844  * @trans: the #GstBaseTransform to set
2845  * @passthrough: boolean indicating passthrough mode.
2846  *
2847  * Set passthrough mode for this filter by default. This is mostly
2848  * useful for filters that do not care about negotiation.
2849  *
2850  * Always TRUE for filters which don't implement either a transform
2851  * or transform_ip method.
2852  *
2853  * MT safe.
2854  */
2855 void
2856 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2857     gboolean passthrough)
2858 {
2859   GstBaseTransformClass *bclass;
2860
2861   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2862
2863   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2864
2865   GST_OBJECT_LOCK (trans);
2866   if (passthrough == FALSE) {
2867     if (bclass->transform_ip || bclass->transform)
2868       trans->passthrough = FALSE;
2869   } else {
2870     trans->passthrough = TRUE;
2871   }
2872
2873   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2874   GST_OBJECT_UNLOCK (trans);
2875 }
2876
2877 /**
2878  * gst_base_transform_is_passthrough:
2879  * @trans: the #GstBaseTransform to query
2880  *
2881  * See if @trans is configured as a passthrough transform.
2882  *
2883  * Returns: TRUE is the transform is configured in passthrough mode.
2884  *
2885  * MT safe.
2886  */
2887 gboolean
2888 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2889 {
2890   gboolean result;
2891
2892   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2893
2894   GST_OBJECT_LOCK (trans);
2895   result = trans->passthrough;
2896   GST_OBJECT_UNLOCK (trans);
2897
2898   return result;
2899 }
2900
2901 /**
2902  * gst_base_transform_set_in_place:
2903  * @trans: the #GstBaseTransform to modify
2904  * @in_place: Boolean value indicating that we would like to operate
2905  * on in_place buffers.
2906  *
2907  * Determines whether a non-writable buffer will be copied before passing
2908  * to the transform_ip function.
2909  * <itemizedlist>
2910  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2911  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2912  * </itemizedlist>
2913  *
2914  * MT safe.
2915  */
2916 void
2917 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2918 {
2919   GstBaseTransformClass *bclass;
2920
2921   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2922
2923   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2924
2925   GST_OBJECT_LOCK (trans);
2926
2927   if (in_place) {
2928     if (bclass->transform_ip) {
2929       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2930       trans->always_in_place = TRUE;
2931     }
2932   } else {
2933     if (bclass->transform) {
2934       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2935       trans->always_in_place = FALSE;
2936     }
2937   }
2938
2939   GST_OBJECT_UNLOCK (trans);
2940 }
2941
2942 /**
2943  * gst_base_transform_is_in_place:
2944  * @trans: the #GstBaseTransform to query
2945  *
2946  * See if @trans is configured as a in_place transform.
2947  *
2948  * Returns: TRUE is the transform is configured in in_place mode.
2949  *
2950  * MT safe.
2951  */
2952 gboolean
2953 gst_base_transform_is_in_place (GstBaseTransform * trans)
2954 {
2955   gboolean result;
2956
2957   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2958
2959   GST_OBJECT_LOCK (trans);
2960   result = trans->always_in_place;
2961   GST_OBJECT_UNLOCK (trans);
2962
2963   return result;
2964 }
2965
2966 /**
2967  * gst_base_transform_update_qos:
2968  * @trans: a #GstBaseTransform
2969  * @proportion: the proportion
2970  * @diff: the diff against the clock
2971  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2972  * running_time.
2973  *
2974  * Set the QoS parameters in the transform. This function is called internally
2975  * when a QOS event is received but subclasses can provide custom information
2976  * when needed.
2977  *
2978  * MT safe.
2979  *
2980  * Since: 0.10.5
2981  */
2982 void
2983 gst_base_transform_update_qos (GstBaseTransform * trans,
2984     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2985 {
2986
2987   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2988
2989   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2990       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2991       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2992
2993   GST_OBJECT_LOCK (trans);
2994   trans->priv->proportion = proportion;
2995   trans->priv->earliest_time = timestamp + diff;
2996   GST_OBJECT_UNLOCK (trans);
2997 }
2998
2999 /**
3000  * gst_base_transform_set_qos_enabled:
3001  * @trans: a #GstBaseTransform
3002  * @enabled: new state
3003  *
3004  * Enable or disable QoS handling in the transform.
3005  *
3006  * MT safe.
3007  *
3008  * Since: 0.10.5
3009  */
3010 void
3011 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
3012 {
3013   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3014
3015   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
3016
3017   GST_OBJECT_LOCK (trans);
3018   trans->priv->qos_enabled = enabled;
3019   GST_OBJECT_UNLOCK (trans);
3020 }
3021
3022 /**
3023  * gst_base_transform_is_qos_enabled:
3024  * @trans: a #GstBaseTransform
3025  *
3026  * Queries if the transform will handle QoS.
3027  *
3028  * Returns: TRUE if QoS is enabled.
3029  *
3030  * MT safe.
3031  *
3032  * Since: 0.10.5
3033  */
3034 gboolean
3035 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
3036 {
3037   gboolean result;
3038
3039   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
3040
3041   GST_OBJECT_LOCK (trans);
3042   result = trans->priv->qos_enabled;
3043   GST_OBJECT_UNLOCK (trans);
3044
3045   return result;
3046 }
3047
3048 /**
3049  * gst_base_transform_set_gap_aware:
3050  * @trans: a #GstBaseTransform
3051  * @gap_aware: New state
3052  *
3053  * If @gap_aware is %FALSE (the default), output buffers will have the
3054  * %GST_BUFFER_FLAG_GAP flag unset.
3055  *
3056  * If set to %TRUE, the element must handle output buffers with this flag set
3057  * correctly, i.e. it can assume that the buffer contains neutral data but must
3058  * unset the flag if the output is no neutral data.
3059  *
3060  * MT safe.
3061  *
3062  * Since: 0.10.16
3063  */
3064 void
3065 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
3066 {
3067   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3068
3069   GST_OBJECT_LOCK (trans);
3070   trans->priv->gap_aware = gap_aware;
3071   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
3072   GST_OBJECT_UNLOCK (trans);
3073 }
3074
3075 /**
3076  * gst_base_transform_suggest:
3077  * @trans: a #GstBaseTransform
3078  * @caps: (transfer none): caps to suggest
3079  * @size: buffer size to suggest
3080  *
3081  * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
3082  * taken.
3083  *
3084  * Since: 0.10.21
3085  */
3086 void
3087 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
3088     guint size)
3089 {
3090   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3091
3092   GST_OBJECT_LOCK (trans->sinkpad);
3093   if (trans->priv->sink_suggest)
3094     gst_caps_unref (trans->priv->sink_suggest);
3095   if (caps)
3096     caps = gst_caps_copy (caps);
3097   trans->priv->sink_suggest = caps;
3098   trans->priv->size_suggest = size;
3099   trans->priv->suggest_pending = TRUE;
3100   gst_base_transform_clear_transformed_caps_cache (trans);
3101   GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
3102   GST_OBJECT_UNLOCK (trans->sinkpad);
3103 }
3104
3105 /**
3106  * gst_base_transform_reconfigure:
3107  * @trans: a #GstBaseTransform
3108  *
3109  * Instructs @trans to renegotiate a new downstream transform on the next
3110  * buffer. This function is typically called after properties on the transform
3111  * were set that influence the output format.
3112  *
3113  * Since: 0.10.21
3114  */
3115 void
3116 gst_base_transform_reconfigure (GstBaseTransform * trans)
3117 {
3118   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3119
3120   GST_OBJECT_LOCK (trans);
3121   GST_DEBUG_OBJECT (trans, "marking reconfigure");
3122   trans->priv->reconfigure = TRUE;
3123   gst_base_transform_clear_transformed_caps_cache (trans);
3124   gst_caps_replace (&trans->priv->sink_alloc, NULL);
3125   GST_OBJECT_UNLOCK (trans);
3126 }