basetransform: fix reconfigure methods
[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 #include "../../../gst/gst_private.h"
209 #include "../../../gst/gst-i18n-lib.h"
210 #include "../../../gst/glib-compat-private.h"
211 #include "gstbasetransform.h"
212 #include <gst/gstmarshal.h>
213
214 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
215 #define GST_CAT_DEFAULT gst_base_transform_debug
216
217 /* BaseTransform signals and args */
218 enum
219 {
220   /* FILL ME */
221   LAST_SIGNAL
222 };
223
224 #define DEFAULT_PROP_QOS        FALSE
225
226 enum
227 {
228   PROP_0,
229   PROP_QOS
230 };
231
232 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
233     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
234
235 struct _GstBaseTransformPrivate
236 {
237   /* QoS *//* with LOCK */
238   gboolean qos_enabled;
239   gdouble proportion;
240   GstClockTime earliest_time;
241   /* previous buffer had a discont */
242   gboolean discont;
243
244   GstPadMode pad_mode;
245
246   gboolean gap_aware;
247
248   gboolean reconfigure;
249
250   /* QoS stats */
251   guint64 processed;
252   guint64 dropped;
253
254   GstClockTime position_out;
255
256   GstBufferPool *pool;
257   GstAllocator *allocator;
258   guint prefix;
259   guint alignment;
260 };
261
262
263 static GstElementClass *parent_class = NULL;
264
265 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
266 static void gst_base_transform_init (GstBaseTransform * trans,
267     GstBaseTransformClass * klass);
268
269 /* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
270  * method to get to the padtemplates */
271 GType
272 gst_base_transform_get_type (void)
273 {
274   static volatile gsize base_transform_type = 0;
275
276   if (g_once_init_enter (&base_transform_type)) {
277     GType _type;
278     static const GTypeInfo base_transform_info = {
279       sizeof (GstBaseTransformClass),
280       NULL,
281       NULL,
282       (GClassInitFunc) gst_base_transform_class_init,
283       NULL,
284       NULL,
285       sizeof (GstBaseTransform),
286       0,
287       (GInstanceInitFunc) gst_base_transform_init,
288     };
289
290     _type = g_type_register_static (GST_TYPE_ELEMENT,
291         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
292     g_once_init_leave (&base_transform_type, _type);
293   }
294   return base_transform_type;
295 }
296
297 static void gst_base_transform_finalize (GObject * object);
298 static void gst_base_transform_set_property (GObject * object, guint prop_id,
299     const GValue * value, GParamSpec * pspec);
300 static void gst_base_transform_get_property (GObject * object, guint prop_id,
301     GValue * value, GParamSpec * pspec);
302 static gboolean gst_base_transform_src_activate_mode (GstPad * pad,
303     GstObject * parent, GstPadMode mode, gboolean active);
304 static gboolean gst_base_transform_sink_activate_mode (GstPad * pad,
305     GstObject * parent, GstPadMode mode, gboolean active);
306 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
307     gboolean active);
308 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
309     GstCaps * caps, gsize * size);
310
311 static gboolean gst_base_transform_src_event (GstPad * pad, GstObject * parent,
312     GstEvent * event);
313 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
314     GstEvent * event);
315 static gboolean gst_base_transform_sink_event (GstPad * pad, GstObject * parent,
316     GstEvent * event);
317 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
318     GstEvent * event);
319 static GstFlowReturn gst_base_transform_getrange (GstPad * pad,
320     GstObject * parent, guint64 offset, guint length, GstBuffer ** buffer);
321 static GstFlowReturn gst_base_transform_chain (GstPad * pad, GstObject * parent,
322     GstBuffer * buffer);
323 static GstCaps *gst_base_transform_default_transform_caps (GstBaseTransform *
324     trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter);
325 static GstCaps *gst_base_transform_default_fixate_caps (GstBaseTransform *
326     trans, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
327 static GstCaps *gst_base_transform_query_caps (GstBaseTransform * trans,
328     GstPad * pad, GstCaps * filter);
329 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
330     GstPadDirection direction, GstCaps * caps);
331 static gboolean gst_base_transform_setcaps (GstBaseTransform * trans,
332     GstPad * pad, GstCaps * caps);
333 static gboolean gst_base_transform_default_propose_allocation (GstBaseTransform
334     * trans, gboolean passthrough, GstQuery * query);
335 static gboolean gst_base_transform_query (GstPad * pad, GstObject * parent,
336     GstQuery * query);
337 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
338     GstPadDirection direction, GstQuery * query);
339 static gboolean gst_base_transform_default_transform_size (GstBaseTransform *
340     trans, GstPadDirection direction, GstCaps * caps, gsize size,
341     GstCaps * othercaps, gsize * othersize);
342
343 static GstFlowReturn default_prepare_output_buffer (GstBaseTransform * trans,
344     GstBuffer * inbuf, GstBuffer ** outbuf);
345 static gboolean default_copy_metadata (GstBaseTransform * trans,
346     GstBuffer * inbuf, GstBuffer * outbuf);
347
348 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
349
350
351 static void
352 gst_base_transform_finalize (GObject * object)
353 {
354   G_OBJECT_CLASS (parent_class)->finalize (object);
355 }
356
357 static void
358 gst_base_transform_class_init (GstBaseTransformClass * klass)
359 {
360   GObjectClass *gobject_class;
361
362   gobject_class = G_OBJECT_CLASS (klass);
363
364   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
365       "basetransform element");
366
367   GST_DEBUG ("gst_base_transform_class_init");
368
369   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
370
371   parent_class = g_type_class_peek_parent (klass);
372
373   gobject_class->set_property = gst_base_transform_set_property;
374   gobject_class->get_property = gst_base_transform_get_property;
375
376   g_object_class_install_property (gobject_class, PROP_QOS,
377       g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
378           DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
379
380   gobject_class->finalize = gst_base_transform_finalize;
381
382   klass->passthrough_on_same_caps = FALSE;
383
384   klass->transform_caps =
385       GST_DEBUG_FUNCPTR (gst_base_transform_default_transform_caps);
386   klass->fixate_caps =
387       GST_DEBUG_FUNCPTR (gst_base_transform_default_fixate_caps);
388   klass->accept_caps =
389       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
390   klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
391   klass->propose_allocation =
392       GST_DEBUG_FUNCPTR (gst_base_transform_default_propose_allocation);
393   klass->transform_size =
394       GST_DEBUG_FUNCPTR (gst_base_transform_default_transform_size);
395
396   klass->sink_event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
397   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
398   klass->prepare_output_buffer =
399       GST_DEBUG_FUNCPTR (default_prepare_output_buffer);
400   klass->copy_metadata = GST_DEBUG_FUNCPTR (default_copy_metadata);
401 }
402
403 static void
404 gst_base_transform_init (GstBaseTransform * trans,
405     GstBaseTransformClass * bclass)
406 {
407   GstPadTemplate *pad_template;
408
409   GST_DEBUG ("gst_base_transform_init");
410
411   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
412
413   pad_template =
414       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
415   g_return_if_fail (pad_template != NULL);
416   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
417   gst_pad_set_event_function (trans->sinkpad,
418       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
419   gst_pad_set_chain_function (trans->sinkpad,
420       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
421   gst_pad_set_activatemode_function (trans->sinkpad,
422       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_mode));
423   gst_pad_set_query_function (trans->sinkpad,
424       GST_DEBUG_FUNCPTR (gst_base_transform_query));
425   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
426
427   pad_template =
428       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
429   g_return_if_fail (pad_template != NULL);
430   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
431   gst_pad_set_event_function (trans->srcpad,
432       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
433   gst_pad_set_getrange_function (trans->srcpad,
434       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
435   gst_pad_set_activatemode_function (trans->srcpad,
436       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_mode));
437   gst_pad_set_query_function (trans->srcpad,
438       GST_DEBUG_FUNCPTR (gst_base_transform_query));
439   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
440
441   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
442   trans->cache_caps1 = NULL;
443   trans->cache_caps2 = NULL;
444   trans->priv->pad_mode = GST_PAD_MODE_NONE;
445   trans->priv->gap_aware = FALSE;
446
447   trans->passthrough = FALSE;
448   if (bclass->transform == NULL) {
449     /* If no transform function, always_in_place is TRUE */
450     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
451     trans->always_in_place = TRUE;
452
453     if (bclass->transform_ip == NULL) {
454       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
455       trans->passthrough = TRUE;
456     }
457   }
458
459   trans->priv->processed = 0;
460   trans->priv->dropped = 0;
461 }
462
463 static GstCaps *
464 gst_base_transform_default_transform_caps (GstBaseTransform * trans,
465     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
466 {
467   GstCaps *ret;
468
469   GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
470   /* no transform function, use the identity transform */
471   if (filter) {
472     ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
473   } else {
474     ret = gst_caps_ref (caps);
475   }
476   return ret;
477 }
478
479 /* given @caps on the src or sink pad (given by @direction)
480  * calculate the possible caps on the other pad.
481  *
482  * Returns new caps, unref after usage.
483  */
484 static GstCaps *
485 gst_base_transform_transform_caps (GstBaseTransform * trans,
486     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
487 {
488   GstCaps *ret = NULL;
489   GstBaseTransformClass *klass;
490
491   if (caps == NULL)
492     return NULL;
493
494   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
495
496   /* if there is a custom transform function, use this */
497   if (klass->transform_caps) {
498     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
499
500     GST_LOG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
501     ret = klass->transform_caps (trans, direction, caps, filter);
502     GST_LOG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, ret);
503
504 #ifndef G_DISABLE_ASSERT
505     if (filter) {
506       if (!gst_caps_is_subset (ret, filter)) {
507         GstCaps *intersection;
508
509         GST_ERROR_OBJECT (trans,
510             "transform_caps returned caps %" GST_PTR_FORMAT
511             " which are not a real subset of the filter caps %"
512             GST_PTR_FORMAT, ret, filter);
513         g_warning ("%s: transform_caps returned caps which are not a real "
514             "subset of the filter caps", GST_ELEMENT_NAME (trans));
515
516         intersection =
517             gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
518         gst_caps_unref (ret);
519         ret = intersection;
520       }
521     }
522 #endif
523   }
524
525   GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
526
527   return ret;
528 }
529
530 static gboolean
531 gst_base_transform_default_transform_size (GstBaseTransform * trans,
532     GstPadDirection direction, GstCaps * caps, gsize size,
533     GstCaps * othercaps, gsize * othersize)
534 {
535   gsize inunitsize, outunitsize, units;
536   GstBaseTransformClass *klass;
537
538   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
539
540   if (klass->get_unit_size == NULL) {
541     /* if there is no transform_size and no unit_size, it means the
542      * element does not modify the size of a buffer */
543     *othersize = size;
544   } else {
545     /* there is no transform_size function, we have to use the unit_size
546      * functions. This method assumes there is a fixed unit_size associated with
547      * each caps. We provide the same amount of units on both sides. */
548     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
549       goto no_in_size;
550
551     GST_DEBUG_OBJECT (trans,
552         "input size %" G_GSIZE_FORMAT ", input unit size %" G_GSIZE_FORMAT,
553         size, inunitsize);
554
555     /* input size must be a multiple of the unit_size of the input caps */
556     if (inunitsize == 0 || (size % inunitsize != 0))
557       goto no_multiple;
558
559     /* get the amount of units */
560     units = size / inunitsize;
561
562     /* now get the unit size of the output */
563     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
564       goto no_out_size;
565
566     /* the output size is the unit_size times the amount of units on the
567      * input */
568     *othersize = units * outunitsize;
569     GST_DEBUG_OBJECT (trans, "transformed size to %" G_GSIZE_FORMAT,
570         *othersize);
571   }
572   return TRUE;
573
574   /* ERRORS */
575 no_in_size:
576   {
577     GST_DEBUG_OBJECT (trans, "could not get in_size");
578     g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
579     return FALSE;
580   }
581 no_multiple:
582   {
583     GST_DEBUG_OBJECT (trans, "Size %" G_GSIZE_FORMAT " is not a multiple of"
584         "unit size %" G_GSIZE_FORMAT, size, inunitsize);
585     g_warning ("%s: size %" G_GSIZE_FORMAT " is not a multiple of unit size %"
586         G_GSIZE_FORMAT, GST_ELEMENT_NAME (trans), size, inunitsize);
587     return FALSE;
588   }
589 no_out_size:
590   {
591     GST_DEBUG_OBJECT (trans, "could not get out_size");
592     g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
593     return FALSE;
594   }
595 }
596
597 /* transform a buffer of @size with @caps on the pad with @direction to
598  * the size of a buffer with @othercaps and store the result in @othersize
599  *
600  * We have two ways of doing this:
601  *  1) use a custom transform size function, this is for complicated custom
602  *     cases with no fixed unit_size.
603  *  2) use the unit_size functions where there is a relationship between the
604  *     caps and the size of a buffer.
605  */
606 static gboolean
607 gst_base_transform_transform_size (GstBaseTransform * trans,
608     GstPadDirection direction, GstCaps * caps,
609     gsize size, GstCaps * othercaps, gsize * othersize)
610 {
611   GstBaseTransformClass *klass;
612   gboolean ret = FALSE;
613
614   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
615
616   GST_DEBUG_OBJECT (trans,
617       "asked to transform size %" G_GSIZE_FORMAT " for caps %"
618       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
619       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
620
621   if (klass->transform_size) {
622     /* if there is a custom transform function, use this */
623     ret = klass->transform_size (trans, direction, caps, size, othercaps,
624         othersize);
625   }
626   return ret;
627 }
628
629 /* get the caps that can be handled by @pad. We perform:
630  *
631  *  - take the caps of peer of otherpad,
632  *  - filter against the padtemplate of otherpad, 
633  *  - calculate all transforms of remaining caps
634  *  - filter against template of @pad
635  *
636  * If there is no peer, we simply return the caps of the padtemplate of pad.
637  */
638 static GstCaps *
639 gst_base_transform_query_caps (GstBaseTransform * trans, GstPad * pad,
640     GstCaps * filter)
641 {
642   GstPad *otherpad;
643   GstCaps *peercaps, *caps, *temp, *peerfilter = NULL;
644   GstCaps *templ;
645
646   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
647
648   /* we can do what the peer can */
649   if (filter) {
650
651     GST_DEBUG_OBJECT (pad, "filter caps  %" GST_PTR_FORMAT, filter);
652
653     /* filtered against our padtemplate on the other side */
654     templ = gst_pad_get_pad_template_caps (pad);
655     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
656     temp = gst_caps_intersect_full (filter, templ, GST_CAPS_INTERSECT_FIRST);
657     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
658     gst_caps_unref (templ);
659
660     /* then see what we can transform this to */
661     peerfilter = gst_base_transform_transform_caps (trans,
662         GST_PAD_DIRECTION (pad), temp, NULL);
663     GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, peerfilter);
664     gst_caps_unref (temp);
665
666     /* and filter against the template of this pad */
667     templ = gst_pad_get_pad_template_caps (otherpad);
668     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
669     /* We keep the caps sorted like the returned caps */
670     temp =
671         gst_caps_intersect_full (peerfilter, templ, GST_CAPS_INTERSECT_FIRST);
672     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
673     gst_caps_unref (peerfilter);
674     gst_caps_unref (templ);
675     peerfilter = temp;
676   }
677
678   peercaps = gst_pad_peer_query_caps (otherpad, peerfilter);
679
680   if (peerfilter)
681     gst_caps_unref (peerfilter);
682
683   if (peercaps) {
684     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
685
686     /* filtered against our padtemplate on the other side */
687     templ = gst_pad_get_pad_template_caps (otherpad);
688     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
689     temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
690     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
691     gst_caps_unref (templ);
692   } else {
693     temp = gst_pad_get_pad_template_caps (otherpad);
694   }
695
696   /* then see what we can transform this to */
697   caps = gst_base_transform_transform_caps (trans,
698       GST_PAD_DIRECTION (otherpad), temp, filter);
699   GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
700   gst_caps_unref (temp);
701   if (caps == NULL)
702     goto done;
703
704   if (peercaps) {
705     /* and filter against the template of this pad */
706     templ = gst_pad_get_pad_template_caps (pad);
707     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
708     /* We keep the caps sorted like the returned caps */
709     temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
710     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
711     gst_caps_unref (caps);
712     gst_caps_unref (templ);
713     caps = temp;
714
715     /* Now try if we can put the untransformed downstream caps first */
716     temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
717     if (!gst_caps_is_empty (temp)) {
718       gst_caps_merge (temp, caps);
719       caps = temp;
720     } else {
721       gst_caps_unref (temp);
722     }
723   } else {
724     gst_caps_unref (caps);
725     /* no peer or the peer can do anything, our padtemplate is enough then */
726     caps = gst_pad_get_pad_template_caps (pad);
727
728     if (filter) {
729       GstCaps *temp;
730
731       temp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
732       gst_caps_unref (caps);
733       caps = temp;
734     }
735   }
736
737 done:
738   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
739
740   if (peercaps)
741     gst_caps_unref (peercaps);
742
743   return caps;
744 }
745
746 /* takes ownership of the pool and allocator */
747 static gboolean
748 gst_base_transform_set_allocation (GstBaseTransform * trans,
749     GstBufferPool * pool, GstAllocator * allocator, guint prefix,
750     guint alignment)
751 {
752   GstAllocator *oldalloc;
753   GstBufferPool *oldpool;
754   GstBaseTransformPrivate *priv = trans->priv;
755
756   /* activate */
757   if (pool) {
758     GST_DEBUG_OBJECT (trans, "setting pool %p active", pool);
759     if (!gst_buffer_pool_set_active (pool, TRUE))
760       goto activate_failed;
761   }
762
763   GST_OBJECT_LOCK (trans);
764   oldpool = priv->pool;
765   priv->pool = pool;
766   oldalloc = priv->allocator;
767   priv->allocator = allocator;
768   priv->prefix = prefix;
769   priv->alignment = alignment;
770   GST_OBJECT_UNLOCK (trans);
771
772   if (oldpool) {
773     GST_DEBUG_OBJECT (trans, "deactivating old pool %p", oldpool);
774     gst_buffer_pool_set_active (oldpool, FALSE);
775     gst_object_unref (oldpool);
776   }
777   if (oldalloc) {
778     gst_allocator_unref (oldalloc);
779   }
780   return TRUE;
781
782   /* ERRORS */
783 activate_failed:
784   {
785     GST_ERROR_OBJECT (trans, "failed to activate bufferpool.");
786     return FALSE;
787   }
788 }
789
790 static gboolean
791 gst_base_transform_do_bufferpool (GstBaseTransform * trans, GstCaps * outcaps)
792 {
793   GstQuery *query;
794   gboolean result = TRUE;
795   GstBufferPool *pool = NULL, *oldpool;
796   guint size, min, max, prefix, alignment;
797   GstBaseTransformClass *klass;
798   GstAllocator *allocator = NULL;
799
800   /* there are these possibilities:
801    *
802    * 1) we negotiated passthrough, we can proxy the bufferpool directly and we
803    *    will do that whenever some upstream does an allocation query.
804    * 2) we need to do a transform, we need to get a bufferpool from downstream
805    *    and configure it. When upstream does the ALLOCATION query, the
806    *    propose_allocation vmethod will be called and we will configure the
807    *    upstream allocator with our proposed values then.
808    */
809
810   /* clear old pool */
811   oldpool = trans->priv->pool;
812   if (oldpool) {
813     GST_DEBUG_OBJECT (trans, "unreffing old pool");
814     gst_buffer_pool_set_active (oldpool, FALSE);
815     gst_object_unref (oldpool);
816     trans->priv->pool = oldpool = NULL;
817   }
818
819   if (trans->passthrough || trans->always_in_place) {
820     /* we are in passthrough, the input buffer is never copied and always passed
821      * along. We never allocate an output buffer on the srcpad. What we do is
822      * let the upstream element decide if it wants to use a bufferpool and
823      * then we will proxy the downstream pool */
824     GST_DEBUG_OBJECT (trans, "we're passthough, delay bufferpool");
825     return TRUE;
826   }
827
828   /* not passthrough, we need to allocate */
829   /* find a pool for the negotiated caps now */
830   GST_DEBUG_OBJECT (trans, "doing allocation query");
831   query = gst_query_new_allocation (outcaps, TRUE);
832   if (!gst_pad_peer_query (trans->srcpad, query)) {
833     /* not a problem, just debug a little */
834     GST_DEBUG_OBJECT (trans, "peer ALLOCATION query failed");
835   }
836
837   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
838
839   GST_DEBUG_OBJECT (trans, "calling decide_allocation");
840   if (G_LIKELY (klass->decide_allocation))
841     if ((result = klass->decide_allocation (trans, query)) == FALSE)
842       goto no_decide_allocation;
843
844   /* we got configuration from our peer, parse them */
845   gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
846       &alignment, &pool);
847
848   if (size == 0) {
849     /* no size, we have variable size buffers */
850     if (gst_query_get_n_allocation_memories (query) > 0) {
851       if ((allocator = gst_query_parse_nth_allocation_memory (query, 0)))
852         gst_allocator_ref (allocator);
853     }
854     GST_DEBUG_OBJECT (trans, "no size, using allocator %p", allocator);
855   } else if (pool == NULL) {
856     GstStructure *config;
857
858     /* we did not get a pool, make one ourselves then */
859     pool = gst_buffer_pool_new ();
860
861     GST_DEBUG_OBJECT (trans, "no pool, making one");
862     config = gst_buffer_pool_get_config (pool);
863     gst_buffer_pool_config_set (config, outcaps, size, min, max, prefix,
864         alignment);
865     gst_buffer_pool_set_config (pool, config);
866   }
867
868   gst_query_unref (query);
869
870   /* and store */
871   result =
872       gst_base_transform_set_allocation (trans, pool, allocator, prefix,
873       alignment);
874
875   return result;
876
877   /* Errors */
878 no_decide_allocation:
879   {
880     GST_WARNING_OBJECT (trans, "Subclass failed to decide allocation");
881     gst_query_unref (query);
882
883     return result;
884   }
885 }
886
887 /* function triggered when the in and out caps are negotiated and need
888  * to be configured in the subclass. */
889 static gboolean
890 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
891     GstCaps * out)
892 {
893   gboolean ret = TRUE;
894   GstBaseTransformClass *klass;
895
896   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
897
898   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
899   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
900
901   /* clear the cache */
902   gst_caps_replace (&trans->cache_caps1, NULL);
903   gst_caps_replace (&trans->cache_caps2, NULL);
904
905   /* figure out same caps state */
906   trans->have_same_caps = gst_caps_is_equal (in, out);
907   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
908
909   /* If we've a transform_ip method and same input/output caps, set in_place
910    * by default. If for some reason the sub-class prefers using a transform
911    * function, it can clear the in place flag in the set_caps */
912   gst_base_transform_set_in_place (trans,
913       klass->transform_ip && trans->have_same_caps);
914
915   /* Set the passthrough if the class wants passthrough_on_same_caps
916    * and we have the same caps on each pad */
917   if (klass->passthrough_on_same_caps)
918     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
919
920   /* now configure the element with the caps */
921   if (klass->set_caps) {
922     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
923     ret = klass->set_caps (trans, in, out);
924   }
925
926   trans->negotiated = ret;
927
928   return ret;
929 }
930
931 static GstCaps *
932 gst_base_transform_default_fixate_caps (GstBaseTransform * trans,
933     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
934 {
935   othercaps = gst_caps_make_writable (othercaps);
936   gst_caps_fixate (othercaps);
937   GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, othercaps);
938
939   return othercaps;
940 }
941
942 /* given a fixed @caps on @pad, create the best possible caps for the
943  * other pad.
944  * @caps must be fixed when calling this function.
945  *
946  * This function calls the transform caps vmethod of the basetransform to figure
947  * out the possible target formats. It then tries to select the best format from
948  * this list by:
949  *
950  * - attempt passthrough if the target caps is a superset of the input caps
951  * - fixating by using peer caps
952  * - fixating with transform fixate function
953  * - fixating with pad fixate functions.
954  *
955  * this function returns a caps that can be transformed into and is accepted by
956  * the peer element.
957  */
958 static GstCaps *
959 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
960     GstCaps * caps)
961 {
962   GstBaseTransformClass *klass;
963   GstPad *otherpad, *otherpeer;
964   GstCaps *othercaps;
965   gboolean is_fixed;
966
967   /* caps must be fixed here, this is a programming error if it's not */
968   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
969
970   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
971
972   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
973   otherpeer = gst_pad_get_peer (otherpad);
974
975   /* see how we can transform the input caps. We need to do this even for
976    * passthrough because it might be possible that this element cannot support
977    * passthrough at all. */
978   othercaps = gst_base_transform_transform_caps (trans,
979       GST_PAD_DIRECTION (pad), caps, NULL);
980
981   /* The caps we can actually output is the intersection of the transformed
982    * caps with the pad template for the pad */
983   if (othercaps) {
984     GstCaps *intersect, *templ_caps;
985
986     templ_caps = gst_pad_get_pad_template_caps (otherpad);
987     GST_DEBUG_OBJECT (trans,
988         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
989
990     intersect =
991         gst_caps_intersect_full (othercaps, templ_caps,
992         GST_CAPS_INTERSECT_FIRST);
993
994     gst_caps_unref (othercaps);
995     gst_caps_unref (templ_caps);
996     othercaps = intersect;
997   }
998
999   /* check if transform is empty */
1000   if (!othercaps || gst_caps_is_empty (othercaps))
1001     goto no_transform;
1002
1003   /* if the othercaps are not fixed, we need to fixate them, first attempt
1004    * is by attempting passthrough if the othercaps are a superset of caps. */
1005   /* FIXME. maybe the caps is not fixed because it has multiple structures of
1006    * fixed caps */
1007   is_fixed = gst_caps_is_fixed (othercaps);
1008   if (!is_fixed) {
1009     GST_DEBUG_OBJECT (trans,
1010         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
1011
1012     /* Now let's see what the peer suggests based on our transformed caps */
1013     if (otherpeer) {
1014       GstCaps *peercaps, *intersection, *templ_caps;
1015
1016       GST_DEBUG_OBJECT (trans,
1017           "Checking peer caps with filter %" GST_PTR_FORMAT, othercaps);
1018
1019       peercaps = gst_pad_query_caps (otherpeer, othercaps);
1020       GST_DEBUG_OBJECT (trans, "Resulted in %" GST_PTR_FORMAT, peercaps);
1021       if (!gst_caps_is_empty (peercaps)) {
1022         templ_caps = gst_pad_get_pad_template_caps (otherpad);
1023
1024         GST_DEBUG_OBJECT (trans,
1025             "Intersecting with template caps %" GST_PTR_FORMAT, templ_caps);
1026
1027         intersection =
1028             gst_caps_intersect_full (peercaps, templ_caps,
1029             GST_CAPS_INTERSECT_FIRST);
1030         GST_DEBUG_OBJECT (trans, "Intersection: %" GST_PTR_FORMAT,
1031             intersection);
1032         gst_caps_unref (peercaps);
1033         gst_caps_unref (templ_caps);
1034         peercaps = intersection;
1035
1036         GST_DEBUG_OBJECT (trans,
1037             "Intersecting with transformed caps %" GST_PTR_FORMAT, othercaps);
1038         intersection =
1039             gst_caps_intersect_full (peercaps, othercaps,
1040             GST_CAPS_INTERSECT_FIRST);
1041         GST_DEBUG_OBJECT (trans, "Intersection: %" GST_PTR_FORMAT,
1042             intersection);
1043         gst_caps_unref (peercaps);
1044         gst_caps_unref (othercaps);
1045         othercaps = intersection;
1046       } else {
1047         othercaps = peercaps;
1048       }
1049
1050       is_fixed = gst_caps_is_fixed (othercaps);
1051     } else {
1052       GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
1053       gst_caps_unref (othercaps);
1054       othercaps = gst_caps_ref (caps);
1055       is_fixed = TRUE;
1056     }
1057   }
1058   if (gst_caps_is_empty (othercaps))
1059     goto no_transform_possible;
1060
1061   GST_DEBUG ("have %sfixed caps %" GST_PTR_FORMAT, (is_fixed ? "" : "non-"),
1062       othercaps);
1063
1064   /* second attempt at fixation, call the fixate vmethod */
1065   /* caps could be fixed but the subclass may want to add fields */
1066   if (klass->fixate_caps) {
1067     GST_DEBUG_OBJECT (trans, "calling fixate_caps for %" GST_PTR_FORMAT
1068         " using caps %" GST_PTR_FORMAT " on pad %s:%s", othercaps, caps,
1069         GST_DEBUG_PAD_NAME (otherpad));
1070     /* note that we pass the complete array of structures to the fixate
1071      * function, it needs to truncate itself */
1072     othercaps =
1073         klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1074     is_fixed = gst_caps_is_fixed (othercaps);
1075     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
1076   }
1077
1078   /* caps should be fixed now, if not we have to fail. */
1079   if (!is_fixed)
1080     goto could_not_fixate;
1081
1082   /* and peer should accept */
1083   if (otherpeer && !gst_pad_query_accept_caps (otherpeer, othercaps))
1084     goto peer_no_accept;
1085
1086   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1087       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1088
1089   if (otherpeer)
1090     gst_object_unref (otherpeer);
1091
1092   return othercaps;
1093
1094   /* ERRORS */
1095 no_transform:
1096   {
1097     GST_DEBUG_OBJECT (trans,
1098         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
1099     goto error_cleanup;
1100   }
1101 no_transform_possible:
1102   {
1103     GST_DEBUG_OBJECT (trans,
1104         "transform could not transform %" GST_PTR_FORMAT
1105         " in anything we support", caps);
1106     goto error_cleanup;
1107   }
1108 could_not_fixate:
1109   {
1110     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1111     goto error_cleanup;
1112   }
1113 peer_no_accept:
1114   {
1115     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1116         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1117     goto error_cleanup;
1118   }
1119 error_cleanup:
1120   {
1121     if (otherpeer)
1122       gst_object_unref (otherpeer);
1123     if (othercaps)
1124       gst_caps_unref (othercaps);
1125     return NULL;
1126   }
1127 }
1128
1129 static gboolean
1130 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1131     GstPadDirection direction, GstCaps * caps)
1132 {
1133 #if 0
1134   GstPad *otherpad;
1135   GstCaps *othercaps = NULL;
1136 #endif
1137   gboolean ret = TRUE;
1138
1139 #if 0
1140   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1141
1142   /* we need fixed caps for the check, fall back to the default implementation
1143    * if we don't */
1144   if (!gst_caps_is_fixed (caps))
1145 #endif
1146   {
1147     GstCaps *allowed;
1148
1149     GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1150
1151     /* get all the formats we can handle on this pad */
1152     if (direction == GST_PAD_SRC)
1153       allowed = gst_pad_query_caps (trans->srcpad, NULL);
1154     else
1155       allowed = gst_pad_query_caps (trans->sinkpad, NULL);
1156
1157     if (!allowed) {
1158       GST_DEBUG_OBJECT (trans, "gst_pad_query_caps() failed");
1159       goto no_transform_possible;
1160     }
1161
1162     GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1163
1164     /* intersect with the requested format */
1165     ret = gst_caps_is_subset (caps, allowed);
1166     gst_caps_unref (allowed);
1167
1168     if (!ret)
1169       goto no_transform_possible;
1170   }
1171 #if 0
1172   else {
1173     GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1174
1175     /* find best possible caps for the other pad as a way to see if we can
1176      * transform this caps. */
1177     othercaps = gst_base_transform_find_transform (trans, pad, caps, FALSE);
1178     if (!othercaps || gst_caps_is_empty (othercaps))
1179       goto no_transform_possible;
1180
1181     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1182   }
1183 #endif
1184
1185 done:
1186 #if 0
1187   /* We know it's always NULL since we never use it */
1188   if (othercaps)
1189     gst_caps_unref (othercaps);
1190 #endif
1191
1192   return ret;
1193
1194   /* ERRORS */
1195 no_transform_possible:
1196   {
1197     GST_DEBUG_OBJECT (trans,
1198         "transform could not transform %" GST_PTR_FORMAT
1199         " in anything we support", caps);
1200     ret = FALSE;
1201     goto done;
1202   }
1203 }
1204
1205 /* called when new caps arrive on the sink pad,
1206  * We try to find the best caps for the other side using our _find_transform()
1207  * function. If there are caps, we configure the transform for this new
1208  * transformation.
1209  */
1210 static gboolean
1211 gst_base_transform_setcaps (GstBaseTransform * trans, GstPad * pad,
1212     GstCaps * incaps)
1213 {
1214   GstCaps *outcaps;
1215   gboolean ret = TRUE;
1216
1217   GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, incaps, incaps);
1218
1219   /* find best possible caps for the other pad */
1220   outcaps = gst_base_transform_find_transform (trans, pad, incaps);
1221   if (!outcaps || gst_caps_is_empty (outcaps))
1222     goto no_transform_possible;
1223
1224   /* configure the element now */
1225
1226   /* if we have the same caps, we can optimize and reuse the input caps */
1227   if (gst_caps_is_equal (incaps, outcaps)) {
1228     GST_INFO_OBJECT (trans, "reuse caps");
1229     gst_caps_unref (outcaps);
1230     outcaps = gst_caps_ref (incaps);
1231   }
1232
1233   /* call configure now */
1234   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1235     goto failed_configure;
1236
1237   GST_OBJECT_LOCK (trans->sinkpad);
1238   GST_OBJECT_FLAG_UNSET (trans->srcpad, GST_PAD_FLAG_NEED_RECONFIGURE);
1239   trans->priv->reconfigure = FALSE;
1240   GST_OBJECT_UNLOCK (trans->sinkpad);
1241
1242   /* we know this will work, we implement the setcaps */
1243   gst_pad_push_event (trans->srcpad, gst_event_new_caps (outcaps));
1244
1245   if (ret) {
1246     /* try to get a pool when needed */
1247     ret = gst_base_transform_do_bufferpool (trans, outcaps);
1248   }
1249
1250 done:
1251   if (outcaps)
1252     gst_caps_unref (outcaps);
1253
1254   trans->negotiated = ret;
1255
1256   return ret;
1257
1258   /* ERRORS */
1259 no_transform_possible:
1260   {
1261     GST_WARNING_OBJECT (trans,
1262         "transform could not transform %" GST_PTR_FORMAT
1263         " in anything we support", incaps);
1264     ret = FALSE;
1265     goto done;
1266   }
1267 failed_configure:
1268   {
1269     GST_WARNING_OBJECT (trans, "FAILED to configure incaps %" GST_PTR_FORMAT
1270         " and outcaps %" GST_PTR_FORMAT, incaps, outcaps);
1271     ret = FALSE;
1272     goto done;
1273   }
1274 }
1275
1276 static gboolean
1277 gst_base_transform_default_propose_allocation (GstBaseTransform * trans,
1278     gboolean passthrough, GstQuery * query)
1279 {
1280   gboolean ret;
1281
1282   if (passthrough) {
1283     GST_DEBUG_OBJECT (trans, "doing passthrough query");
1284     ret = gst_pad_peer_query (trans->srcpad, query);
1285   } else {
1286     ret = FALSE;
1287   }
1288   return ret;
1289 }
1290
1291 static gboolean
1292 gst_base_transform_default_query (GstBaseTransform * trans,
1293     GstPadDirection direction, GstQuery * query)
1294 {
1295   gboolean ret = FALSE;
1296   GstPad *pad, *otherpad;
1297   GstBaseTransformClass *klass;
1298
1299   if (direction == GST_PAD_SRC) {
1300     pad = trans->srcpad;
1301     otherpad = trans->sinkpad;
1302   } else {
1303     pad = trans->sinkpad;
1304     otherpad = trans->srcpad;
1305   }
1306
1307   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1308
1309   switch (GST_QUERY_TYPE (query)) {
1310     case GST_QUERY_ALLOCATION:
1311     {
1312       gboolean passthrough;
1313
1314       /* can only be done on the sinkpad */
1315       if (direction != GST_PAD_SINK)
1316         goto done;
1317
1318       passthrough = gst_base_transform_is_passthrough (trans);
1319
1320       GST_DEBUG_OBJECT (trans, "propose %spassthrough allocation values",
1321           (passthrough ? "" : "non-"));
1322
1323       /* pass the query to the propose_allocation vmethod if any */
1324       if (G_LIKELY (klass->propose_allocation))
1325         ret = klass->propose_allocation (trans, passthrough, query);
1326       else
1327         ret = FALSE;
1328
1329       GST_DEBUG_OBJECT (trans, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret,
1330           query);
1331       break;
1332     }
1333     case GST_QUERY_POSITION:
1334     {
1335       GstFormat format;
1336
1337       gst_query_parse_position (query, &format, NULL);
1338       if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1339         gint64 pos;
1340         ret = TRUE;
1341
1342         if ((direction == GST_PAD_SINK)
1343             || (trans->priv->position_out == GST_CLOCK_TIME_NONE)) {
1344           pos =
1345               gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1346               trans->segment.position);
1347         } else {
1348           pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1349               trans->priv->position_out);
1350         }
1351         gst_query_set_position (query, format, pos);
1352       } else {
1353         ret = gst_pad_peer_query (otherpad, query);
1354       }
1355       break;
1356     }
1357     case GST_QUERY_ACCEPT_CAPS:
1358     {
1359       GstCaps *caps;
1360
1361       gst_query_parse_accept_caps (query, &caps);
1362       if (klass->accept_caps) {
1363         ret = klass->accept_caps (trans, direction, caps);
1364         gst_query_set_accept_caps_result (query, ret);
1365         /* return TRUE, we answered the query */
1366         ret = TRUE;
1367       }
1368       break;
1369     }
1370     case GST_QUERY_CAPS:
1371     {
1372       GstCaps *filter, *caps;
1373
1374       gst_query_parse_caps (query, &filter);
1375       caps = gst_base_transform_query_caps (trans, pad, filter);
1376       gst_query_set_caps_result (query, caps);
1377       gst_caps_unref (caps);
1378       ret = TRUE;
1379       break;
1380     }
1381     default:
1382       ret = gst_pad_peer_query (otherpad, query);
1383       break;
1384   }
1385
1386 done:
1387   return ret;
1388 }
1389
1390 static gboolean
1391 gst_base_transform_query (GstPad * pad, GstObject * parent, GstQuery * query)
1392 {
1393   GstBaseTransform *trans;
1394   GstBaseTransformClass *bclass;
1395   gboolean ret = FALSE;
1396
1397   trans = GST_BASE_TRANSFORM (parent);
1398   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1399
1400   if (bclass->query)
1401     ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1402
1403   return ret;
1404 }
1405
1406 /* this function either returns the input buffer without incrementing the
1407  * refcount or it allocates a new (writable) buffer */
1408 static GstFlowReturn
1409 default_prepare_output_buffer (GstBaseTransform * trans,
1410     GstBuffer * inbuf, GstBuffer ** outbuf)
1411 {
1412   GstBaseTransformPrivate *priv;
1413   GstFlowReturn ret = GST_FLOW_OK;
1414   GstBaseTransformClass *bclass;
1415   GstCaps *incaps, *outcaps;
1416   gsize insize, outsize;
1417   gboolean res;
1418
1419   priv = trans->priv;
1420   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1421
1422   /* figure out how to allocate an output buffer */
1423   if (trans->passthrough) {
1424     /* passthrough, we will not modify the incomming buffer so we can just
1425      * reuse it */
1426     GST_DEBUG_OBJECT (trans, "passthrough: reusing input buffer");
1427     *outbuf = inbuf;
1428     goto done;
1429   }
1430
1431   /* we can't reuse the input buffer */
1432   if (priv->pool) {
1433     GST_DEBUG_OBJECT (trans, "using pool alloc");
1434     ret = gst_buffer_pool_acquire_buffer (priv->pool, outbuf, NULL);
1435     goto copy_meta;
1436   }
1437
1438   /* no pool, we need to figure out the size of the output buffer first */
1439   if ((bclass->transform_ip != NULL) && trans->always_in_place) {
1440     /* we want to do an in-place alloc */
1441     if (gst_buffer_is_writable (inbuf)) {
1442       GST_DEBUG_OBJECT (trans, "inplace reuse writable input buffer");
1443       *outbuf = inbuf;
1444     } else {
1445       GST_DEBUG_OBJECT (trans, "making writable buffer copy");
1446       /* we make a copy of the input buffer */
1447       *outbuf = gst_buffer_copy (inbuf);
1448     }
1449     goto done;
1450   }
1451
1452   /* else use the transform function to get the size */
1453   incaps = gst_pad_get_current_caps (trans->sinkpad);
1454   outcaps = gst_pad_get_current_caps (trans->srcpad);
1455
1456   GST_DEBUG_OBJECT (trans, "getting output size for alloc");
1457   /* copy transform, figure out the output size */
1458   insize = gst_buffer_get_size (inbuf);
1459   res = gst_base_transform_transform_size (trans,
1460       GST_PAD_SINK, incaps, insize, outcaps, &outsize);
1461
1462   gst_caps_unref (incaps);
1463   gst_caps_unref (outcaps);
1464
1465   if (!res)
1466     goto unknown_size;
1467
1468   GST_DEBUG_OBJECT (trans, "doing alloc of size %" G_GSIZE_FORMAT, outsize);
1469   *outbuf = gst_buffer_new_allocate (priv->allocator, outsize, priv->alignment);
1470
1471 copy_meta:
1472   /* copy the metadata */
1473   if (bclass->copy_metadata)
1474     if (!bclass->copy_metadata (trans, inbuf, *outbuf)) {
1475       /* something failed, post a warning */
1476       GST_ELEMENT_WARNING (trans, STREAM, NOT_IMPLEMENTED,
1477           ("could not copy metadata"), (NULL));
1478     }
1479
1480 done:
1481   return ret;
1482
1483   /* ERRORS */
1484 unknown_size:
1485   {
1486     GST_ERROR_OBJECT (trans, "unknown output size");
1487     return GST_FLOW_ERROR;
1488   }
1489 }
1490
1491 static gboolean
1492 default_copy_metadata (GstBaseTransform * trans,
1493     GstBuffer * inbuf, GstBuffer * outbuf)
1494 {
1495   GstBaseTransformPrivate *priv = trans->priv;
1496
1497   /* now copy the metadata */
1498   GST_DEBUG_OBJECT (trans, "copying metadata");
1499
1500   /* this should not happen, buffers allocated from a pool or with
1501    * new_allocate should always be writable. */
1502   if (!gst_buffer_is_writable (outbuf))
1503     goto not_writable;
1504
1505   /* when we get here, the metadata should be writable */
1506   gst_buffer_copy_into (outbuf, inbuf,
1507       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
1508
1509   /* clear the GAP flag when the subclass does not understand it */
1510   if (!priv->gap_aware)
1511     GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP);
1512
1513   return TRUE;
1514
1515   /* ERRORS */
1516 not_writable:
1517   {
1518     GST_WARNING_OBJECT (trans, "buffer %p not writable", outbuf);
1519     return FALSE;
1520   }
1521 }
1522
1523 /* Given @caps calcultate the size of one unit.
1524  *
1525  * For video caps, this is the size of one frame (and thus one buffer).
1526  * For audio caps, this is the size of one sample.
1527  *
1528  * These values are cached since they do not change and the calculation
1529  * potentially involves parsing caps and other expensive stuff.
1530  *
1531  * We have two cache locations to store the size, one for the source caps
1532  * and one for the sink caps.
1533  *
1534  * this function returns FALSE if no size could be calculated.
1535  */
1536 static gboolean
1537 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1538     gsize * size)
1539 {
1540   gboolean res = FALSE;
1541   GstBaseTransformClass *bclass;
1542
1543   /* see if we have the result cached */
1544   if (trans->cache_caps1 == caps) {
1545     *size = trans->cache_caps1_size;
1546     GST_DEBUG_OBJECT (trans,
1547         "returned %" G_GSIZE_FORMAT " from first cache", *size);
1548     return TRUE;
1549   }
1550   if (trans->cache_caps2 == caps) {
1551     *size = trans->cache_caps2_size;
1552     GST_DEBUG_OBJECT (trans,
1553         "returned %" G_GSIZE_FORMAT " from second cached", *size);
1554     return TRUE;
1555   }
1556
1557   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1558   res = bclass->get_unit_size (trans, caps, size);
1559   GST_DEBUG_OBJECT (trans,
1560       "caps %" GST_PTR_FORMAT ") has unit size %" G_GSIZE_FORMAT ", res %s",
1561       caps, *size, res ? "TRUE" : "FALSE");
1562
1563   if (res) {
1564     /* and cache the values */
1565     if (trans->cache_caps1 == NULL) {
1566       gst_caps_replace (&trans->cache_caps1, caps);
1567       trans->cache_caps1_size = *size;
1568       GST_DEBUG_OBJECT (trans,
1569           "caching %" G_GSIZE_FORMAT " in first cache", *size);
1570     } else if (trans->cache_caps2 == NULL) {
1571       gst_caps_replace (&trans->cache_caps2, caps);
1572       trans->cache_caps2_size = *size;
1573       GST_DEBUG_OBJECT (trans,
1574           "caching %" G_GSIZE_FORMAT " in second cache", *size);
1575     } else {
1576       GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1577     }
1578   }
1579   return res;
1580 }
1581
1582 static gboolean
1583 gst_base_transform_sink_event (GstPad * pad, GstObject * parent,
1584     GstEvent * event)
1585 {
1586   GstBaseTransform *trans;
1587   GstBaseTransformClass *bclass;
1588   gboolean ret = TRUE;
1589
1590   trans = GST_BASE_TRANSFORM (parent);
1591   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1592
1593   if (bclass->sink_event)
1594     ret = bclass->sink_event (trans, event);
1595   else
1596     gst_event_unref (event);
1597
1598   return ret;
1599 }
1600
1601 static gboolean
1602 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1603 {
1604   gboolean ret = TRUE, forward = TRUE;
1605
1606   switch (GST_EVENT_TYPE (event)) {
1607     case GST_EVENT_FLUSH_START:
1608       break;
1609     case GST_EVENT_FLUSH_STOP:
1610       GST_OBJECT_LOCK (trans);
1611       /* reset QoS parameters */
1612       trans->priv->proportion = 1.0;
1613       trans->priv->earliest_time = -1;
1614       trans->priv->discont = FALSE;
1615       trans->priv->processed = 0;
1616       trans->priv->dropped = 0;
1617       GST_OBJECT_UNLOCK (trans);
1618       /* we need new segment info after the flush. */
1619       trans->have_segment = FALSE;
1620       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1621       trans->priv->position_out = GST_CLOCK_TIME_NONE;
1622       break;
1623     case GST_EVENT_EOS:
1624       break;
1625     case GST_EVENT_TAG:
1626       break;
1627     case GST_EVENT_CAPS:
1628     {
1629       GstCaps *caps;
1630
1631       gst_event_parse_caps (event, &caps);
1632       ret = gst_base_transform_setcaps (trans, trans->sinkpad, caps);
1633
1634       forward = FALSE;
1635       break;
1636     }
1637     case GST_EVENT_SEGMENT:
1638     {
1639       gst_event_copy_segment (event, &trans->segment);
1640       trans->have_segment = TRUE;
1641
1642       GST_DEBUG_OBJECT (trans, "received SEGMENT %" GST_SEGMENT_FORMAT,
1643           &trans->segment);
1644       break;
1645     }
1646     default:
1647       break;
1648   }
1649
1650   if (ret && forward)
1651     ret = gst_pad_push_event (trans->srcpad, event);
1652   else
1653     gst_event_unref (event);
1654
1655   return ret;
1656 }
1657
1658 static gboolean
1659 gst_base_transform_src_event (GstPad * pad, GstObject * parent,
1660     GstEvent * event)
1661 {
1662   GstBaseTransform *trans;
1663   GstBaseTransformClass *bclass;
1664   gboolean ret = TRUE;
1665
1666   trans = GST_BASE_TRANSFORM (parent);
1667   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1668
1669   if (bclass->src_event)
1670     ret = bclass->src_event (trans, event);
1671   else
1672     gst_event_unref (event);
1673
1674   return ret;
1675 }
1676
1677 static gboolean
1678 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1679 {
1680   gboolean ret;
1681
1682   GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
1683
1684   switch (GST_EVENT_TYPE (event)) {
1685     case GST_EVENT_SEEK:
1686       break;
1687     case GST_EVENT_NAVIGATION:
1688       break;
1689     case GST_EVENT_QOS:
1690     {
1691       gdouble proportion;
1692       GstClockTimeDiff diff;
1693       GstClockTime timestamp;
1694
1695       gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
1696       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1697       break;
1698     }
1699     default:
1700       break;
1701   }
1702
1703   ret = gst_pad_push_event (trans->sinkpad, event);
1704
1705   return ret;
1706 }
1707
1708 /* perform a transform on @inbuf and put the result in @outbuf.
1709  *
1710  * This function is common to the push and pull-based operations.
1711  *
1712  * This function takes ownership of @inbuf */
1713 static GstFlowReturn
1714 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1715     GstBuffer ** outbuf)
1716 {
1717   GstBaseTransformClass *bclass;
1718   GstFlowReturn ret = GST_FLOW_OK;
1719   gboolean want_in_place;
1720   GstClockTime running_time;
1721   GstClockTime timestamp;
1722   gboolean reconfigure;
1723
1724   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1725
1726   GST_OBJECT_LOCK (trans->sinkpad);
1727   reconfigure = GST_PAD_NEEDS_RECONFIGURE (trans->srcpad)
1728       || trans->priv->reconfigure;
1729   GST_OBJECT_FLAG_UNSET (trans->srcpad, GST_PAD_FLAG_NEED_RECONFIGURE);
1730   trans->priv->reconfigure = FALSE;
1731   GST_OBJECT_UNLOCK (trans->sinkpad);
1732
1733   if (G_UNLIKELY (reconfigure)) {
1734     GstCaps *incaps;
1735
1736     GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
1737
1738     incaps = gst_pad_get_current_caps (trans->sinkpad);
1739     if (incaps == NULL)
1740       goto no_reconfigure;
1741
1742     /* if we need to reconfigure we pretend new caps arrived. This
1743      * will reconfigure the transform with the new output format. */
1744     if (!gst_base_transform_setcaps (trans, trans->sinkpad, incaps)) {
1745       gst_caps_unref (incaps);
1746       goto not_negotiated;
1747     }
1748     gst_caps_unref (incaps);
1749   }
1750
1751 no_reconfigure:
1752   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1753     GST_DEBUG_OBJECT (trans,
1754         "handling buffer %p of size %" G_GSIZE_FORMAT " and offset %"
1755         G_GUINT64_FORMAT, inbuf, gst_buffer_get_size (inbuf),
1756         GST_BUFFER_OFFSET (inbuf));
1757   else
1758     GST_DEBUG_OBJECT (trans,
1759         "handling buffer %p of size %" G_GSIZE_FORMAT " and offset NONE", inbuf,
1760         gst_buffer_get_size (inbuf));
1761
1762   /* Don't allow buffer handling before negotiation, except in passthrough mode
1763    * or if the class doesn't implement a set_caps function (in which case it doesn't
1764    * care about caps)
1765    */
1766   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1767     goto not_negotiated;
1768
1769   /* Set discont flag so we can mark the outgoing buffer */
1770   if (GST_BUFFER_IS_DISCONT (inbuf)) {
1771     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
1772     trans->priv->discont = TRUE;
1773   }
1774
1775   /* can only do QoS if the segment is in TIME */
1776   if (trans->segment.format != GST_FORMAT_TIME)
1777     goto no_qos;
1778
1779   /* QOS is done on the running time of the buffer, get it now */
1780   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
1781   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1782       timestamp);
1783
1784   if (running_time != -1) {
1785     gboolean need_skip;
1786     GstClockTime earliest_time;
1787     gdouble proportion;
1788
1789     /* lock for getting the QoS parameters that are set (in a different thread)
1790      * with the QOS events */
1791     GST_OBJECT_LOCK (trans);
1792     earliest_time = trans->priv->earliest_time;
1793     proportion = trans->priv->proportion;
1794     /* check for QoS, don't perform conversion for buffers
1795      * that are known to be late. */
1796     need_skip = trans->priv->qos_enabled &&
1797         earliest_time != -1 && running_time <= earliest_time;
1798     GST_OBJECT_UNLOCK (trans);
1799
1800     if (need_skip) {
1801       GstMessage *qos_msg;
1802       GstClockTime duration;
1803       guint64 stream_time;
1804       gint64 jitter;
1805
1806       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1807           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1808           GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
1809
1810       trans->priv->dropped++;
1811
1812       duration = GST_BUFFER_DURATION (inbuf);
1813       stream_time =
1814           gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1815           timestamp);
1816       jitter = GST_CLOCK_DIFF (running_time, earliest_time);
1817
1818       qos_msg =
1819           gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
1820           stream_time, timestamp, duration);
1821       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1822       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1823           trans->priv->processed, trans->priv->dropped);
1824       gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
1825
1826       /* mark discont for next buffer */
1827       trans->priv->discont = TRUE;
1828       goto skip;
1829     }
1830   }
1831
1832 no_qos:
1833
1834   /* first try to allocate an output buffer based on the currently negotiated
1835    * format. outbuf will contain a buffer suitable for doing the configured
1836    * transform after this function. */
1837   if (bclass->prepare_output_buffer == NULL)
1838     goto no_prepare;
1839
1840   GST_DEBUG_OBJECT (trans, "calling prepare buffer");
1841   ret = bclass->prepare_output_buffer (trans, inbuf, outbuf);
1842
1843   if (ret != GST_FLOW_OK || *outbuf == NULL)
1844     goto no_buffer;
1845
1846   GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", inbuf,
1847       *outbuf);
1848
1849   /* now perform the needed transform */
1850   if (trans->passthrough) {
1851     /* In passthrough mode, give transform_ip a look at the
1852      * buffer, without making it writable, or just push the
1853      * data through */
1854     if (bclass->transform_ip) {
1855       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
1856       ret = bclass->transform_ip (trans, *outbuf);
1857     } else {
1858       GST_DEBUG_OBJECT (trans, "element is in passthrough");
1859     }
1860   } else {
1861     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1862
1863     if (want_in_place) {
1864       GST_DEBUG_OBJECT (trans, "doing inplace transform");
1865       ret = bclass->transform_ip (trans, *outbuf);
1866     } else {
1867       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
1868
1869       if (bclass->transform)
1870         ret = bclass->transform (trans, inbuf, *outbuf);
1871       else
1872         ret = GST_FLOW_NOT_SUPPORTED;
1873     }
1874   }
1875
1876 skip:
1877   /* only unref input buffer if we allocated a new outbuf buffer. If we reused
1878    * the input buffer, no refcount is changed to keep the input buffer writable
1879    * when needed. */
1880   if (*outbuf != inbuf)
1881     gst_buffer_unref (inbuf);
1882
1883   return ret;
1884
1885   /* ERRORS */
1886 not_negotiated:
1887   {
1888     gst_buffer_unref (inbuf);
1889     *outbuf = NULL;
1890     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1891         ("not negotiated"), ("not negotiated"));
1892     return GST_FLOW_NOT_NEGOTIATED;
1893   }
1894 no_prepare:
1895   {
1896     gst_buffer_unref (inbuf);
1897     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1898         ("Sub-class has no prepare_output_buffer implementation"), (NULL));
1899     return GST_FLOW_NOT_SUPPORTED;
1900   }
1901 no_buffer:
1902   {
1903     gst_buffer_unref (inbuf);
1904     *outbuf = NULL;
1905     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
1906         gst_flow_get_name (ret));
1907     return ret;
1908   }
1909 }
1910
1911 /* FIXME, getrange is broken, need to pull range from the other
1912  * end based on the transform_size result.
1913  */
1914 static GstFlowReturn
1915 gst_base_transform_getrange (GstPad * pad, GstObject * parent, guint64 offset,
1916     guint length, GstBuffer ** buffer)
1917 {
1918   GstBaseTransform *trans;
1919   GstBaseTransformClass *klass;
1920   GstFlowReturn ret;
1921   GstBuffer *inbuf;
1922
1923   trans = GST_BASE_TRANSFORM (parent);
1924
1925   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1926   if (G_UNLIKELY (ret != GST_FLOW_OK))
1927     goto pull_error;
1928
1929   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1930   if (klass->before_transform)
1931     klass->before_transform (trans, inbuf);
1932
1933   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1934
1935 done:
1936   return ret;
1937
1938   /* ERRORS */
1939 pull_error:
1940   {
1941     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
1942         gst_flow_get_name (ret));
1943     goto done;
1944   }
1945 }
1946
1947 static GstFlowReturn
1948 gst_base_transform_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1949 {
1950   GstBaseTransform *trans;
1951   GstBaseTransformClass *klass;
1952   GstFlowReturn ret;
1953   GstClockTime position = GST_CLOCK_TIME_NONE;
1954   GstClockTime timestamp, duration;
1955   GstBuffer *outbuf = NULL;
1956
1957   trans = GST_BASE_TRANSFORM (parent);
1958
1959   timestamp = GST_BUFFER_TIMESTAMP (buffer);
1960   duration = GST_BUFFER_DURATION (buffer);
1961
1962   /* calculate end position of the incoming buffer */
1963   if (timestamp != GST_CLOCK_TIME_NONE) {
1964     if (duration != GST_CLOCK_TIME_NONE)
1965       position = timestamp + duration;
1966     else
1967       position = timestamp;
1968   }
1969
1970   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1971   if (klass->before_transform)
1972     klass->before_transform (trans, buffer);
1973
1974   /* protect transform method and concurrent buffer alloc */
1975   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1976
1977   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
1978    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
1979   if (outbuf != NULL) {
1980     if (ret == GST_FLOW_OK) {
1981       GstClockTime position_out = GST_CLOCK_TIME_NONE;
1982
1983       /* Remember last stop position */
1984       if (position != GST_CLOCK_TIME_NONE &&
1985           trans->segment.format == GST_FORMAT_TIME)
1986         trans->segment.position = position;
1987
1988       if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
1989         position_out = GST_BUFFER_TIMESTAMP (outbuf);
1990         if (GST_BUFFER_DURATION_IS_VALID (outbuf))
1991           position_out += GST_BUFFER_DURATION (outbuf);
1992       } else if (position != GST_CLOCK_TIME_NONE) {
1993         position_out = position;
1994       }
1995       if (position_out != GST_CLOCK_TIME_NONE
1996           && trans->segment.format == GST_FORMAT_TIME)
1997         trans->priv->position_out = position_out;
1998
1999       /* apply DISCONT flag if the buffer is not yet marked as such */
2000       if (trans->priv->discont) {
2001         GST_DEBUG_OBJECT (trans, "we have a pending DISCONT");
2002         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2003           GST_DEBUG_OBJECT (trans, "marking DISCONT on output buffer");
2004           outbuf = gst_buffer_make_writable (outbuf);
2005           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2006         }
2007         trans->priv->discont = FALSE;
2008       }
2009       trans->priv->processed++;
2010
2011       ret = gst_pad_push (trans->srcpad, outbuf);
2012     } else {
2013       GST_DEBUG_OBJECT (trans, "we got return %s", gst_flow_get_name (ret));
2014       gst_buffer_unref (outbuf);
2015     }
2016   }
2017
2018   /* convert internal flow to OK and mark discont for the next buffer. */
2019   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2020     GST_DEBUG_OBJECT (trans, "dropped a buffer, marking DISCONT");
2021     trans->priv->discont = TRUE;
2022     ret = GST_FLOW_OK;
2023   }
2024
2025   return ret;
2026 }
2027
2028 static void
2029 gst_base_transform_set_property (GObject * object, guint prop_id,
2030     const GValue * value, GParamSpec * pspec)
2031 {
2032   GstBaseTransform *trans;
2033
2034   trans = GST_BASE_TRANSFORM (object);
2035
2036   switch (prop_id) {
2037     case PROP_QOS:
2038       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2039       break;
2040     default:
2041       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2042       break;
2043   }
2044 }
2045
2046 static void
2047 gst_base_transform_get_property (GObject * object, guint prop_id,
2048     GValue * value, GParamSpec * pspec)
2049 {
2050   GstBaseTransform *trans;
2051
2052   trans = GST_BASE_TRANSFORM (object);
2053
2054   switch (prop_id) {
2055     case PROP_QOS:
2056       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2057       break;
2058     default:
2059       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2060       break;
2061   }
2062 }
2063
2064 /* not a vmethod of anything, just an internal method */
2065 static gboolean
2066 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2067 {
2068   GstBaseTransformClass *bclass;
2069   gboolean result = TRUE;
2070
2071   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2072
2073   if (active) {
2074     GstCaps *incaps, *outcaps;
2075
2076     if (trans->priv->pad_mode == GST_PAD_MODE_NONE && bclass->start)
2077       result &= bclass->start (trans);
2078
2079     incaps = gst_pad_get_current_caps (trans->sinkpad);
2080     outcaps = gst_pad_get_current_caps (trans->srcpad);
2081
2082     GST_OBJECT_LOCK (trans);
2083     if (incaps && outcaps)
2084       trans->have_same_caps =
2085           gst_caps_is_equal (incaps, outcaps) || trans->passthrough;
2086     else
2087       trans->have_same_caps = trans->passthrough;
2088     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2089     trans->negotiated = FALSE;
2090     trans->have_segment = FALSE;
2091     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2092     trans->priv->position_out = GST_CLOCK_TIME_NONE;
2093     trans->priv->proportion = 1.0;
2094     trans->priv->earliest_time = -1;
2095     trans->priv->discont = FALSE;
2096     trans->priv->processed = 0;
2097     trans->priv->dropped = 0;
2098     GST_OBJECT_UNLOCK (trans);
2099
2100     if (incaps)
2101       gst_caps_unref (incaps);
2102     if (outcaps)
2103       gst_caps_unref (outcaps);
2104   } else {
2105     /* We must make sure streaming has finished before resetting things
2106      * and calling the ::stop vfunc */
2107     GST_PAD_STREAM_LOCK (trans->sinkpad);
2108     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2109
2110     trans->have_same_caps = FALSE;
2111     /* We can only reset the passthrough mode if the instance told us to 
2112        handle it in configure_caps */
2113     if (bclass->passthrough_on_same_caps) {
2114       gst_base_transform_set_passthrough (trans, FALSE);
2115     }
2116     gst_caps_replace (&trans->cache_caps1, NULL);
2117     gst_caps_replace (&trans->cache_caps2, NULL);
2118
2119     if (trans->priv->pad_mode != GST_PAD_MODE_NONE && bclass->stop)
2120       result &= bclass->stop (trans);
2121
2122     gst_base_transform_set_allocation (trans, NULL, NULL, 0, 0);
2123   }
2124
2125   return result;
2126 }
2127
2128 static gboolean
2129 gst_base_transform_sink_activate_mode (GstPad * pad, GstObject * parent,
2130     GstPadMode mode, gboolean active)
2131 {
2132   gboolean result = FALSE;
2133   GstBaseTransform *trans;
2134
2135   trans = GST_BASE_TRANSFORM (parent);
2136
2137   switch (mode) {
2138     case GST_PAD_MODE_PUSH:
2139     {
2140       result = gst_base_transform_activate (trans, active);
2141
2142       if (result)
2143         trans->priv->pad_mode = active ? GST_PAD_MODE_PUSH : GST_PAD_MODE_NONE;
2144
2145       break;
2146     }
2147     default:
2148       result = TRUE;
2149       break;
2150   }
2151   return result;
2152 }
2153
2154 static gboolean
2155 gst_base_transform_src_activate_mode (GstPad * pad, GstObject * parent,
2156     GstPadMode mode, gboolean active)
2157 {
2158   gboolean result = FALSE;
2159   GstBaseTransform *trans;
2160
2161   trans = GST_BASE_TRANSFORM (parent);
2162
2163   switch (mode) {
2164     case GST_PAD_MODE_PULL:
2165     {
2166       result =
2167           gst_pad_activate_mode (trans->sinkpad, GST_PAD_MODE_PULL, active);
2168
2169       if (result)
2170         result &= gst_base_transform_activate (trans, active);
2171
2172       if (result)
2173         trans->priv->pad_mode = active ? mode : GST_PAD_MODE_NONE;
2174       break;
2175     }
2176     default:
2177       result = TRUE;
2178       break;
2179   }
2180
2181   return result;
2182 }
2183
2184 /**
2185  * gst_base_transform_set_passthrough:
2186  * @trans: the #GstBaseTransform to set
2187  * @passthrough: boolean indicating passthrough mode.
2188  *
2189  * Set passthrough mode for this filter by default. This is mostly
2190  * useful for filters that do not care about negotiation.
2191  *
2192  * Always TRUE for filters which don't implement either a transform
2193  * or transform_ip method.
2194  *
2195  * MT safe.
2196  */
2197 void
2198 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2199     gboolean passthrough)
2200 {
2201   GstBaseTransformClass *bclass;
2202
2203   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2204
2205   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2206
2207   GST_OBJECT_LOCK (trans);
2208   if (passthrough == FALSE) {
2209     if (bclass->transform_ip || bclass->transform)
2210       trans->passthrough = FALSE;
2211   } else {
2212     trans->passthrough = TRUE;
2213   }
2214
2215   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2216   GST_OBJECT_UNLOCK (trans);
2217 }
2218
2219 /**
2220  * gst_base_transform_is_passthrough:
2221  * @trans: the #GstBaseTransform to query
2222  *
2223  * See if @trans is configured as a passthrough transform.
2224  *
2225  * Returns: TRUE is the transform is configured in passthrough mode.
2226  *
2227  * MT safe.
2228  */
2229 gboolean
2230 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2231 {
2232   gboolean result;
2233
2234   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2235
2236   GST_OBJECT_LOCK (trans);
2237   result = trans->passthrough;
2238   GST_OBJECT_UNLOCK (trans);
2239
2240   return result;
2241 }
2242
2243 /**
2244  * gst_base_transform_set_in_place:
2245  * @trans: the #GstBaseTransform to modify
2246  * @in_place: Boolean value indicating that we would like to operate
2247  * on in_place buffers.
2248  *
2249  * Determines whether a non-writable buffer will be copied before passing
2250  * to the transform_ip function.
2251  * <itemizedlist>
2252  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2253  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2254  * </itemizedlist>
2255  *
2256  * MT safe.
2257  */
2258 void
2259 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2260 {
2261   GstBaseTransformClass *bclass;
2262
2263   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2264
2265   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2266
2267   GST_OBJECT_LOCK (trans);
2268
2269   if (in_place) {
2270     if (bclass->transform_ip) {
2271       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2272       trans->always_in_place = TRUE;
2273     }
2274   } else {
2275     if (bclass->transform) {
2276       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2277       trans->always_in_place = FALSE;
2278     }
2279   }
2280
2281   GST_OBJECT_UNLOCK (trans);
2282 }
2283
2284 /**
2285  * gst_base_transform_is_in_place:
2286  * @trans: the #GstBaseTransform to query
2287  *
2288  * See if @trans is configured as a in_place transform.
2289  *
2290  * Returns: TRUE is the transform is configured in in_place mode.
2291  *
2292  * MT safe.
2293  */
2294 gboolean
2295 gst_base_transform_is_in_place (GstBaseTransform * trans)
2296 {
2297   gboolean result;
2298
2299   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2300
2301   GST_OBJECT_LOCK (trans);
2302   result = trans->always_in_place;
2303   GST_OBJECT_UNLOCK (trans);
2304
2305   return result;
2306 }
2307
2308 /**
2309  * gst_base_transform_update_qos:
2310  * @trans: a #GstBaseTransform
2311  * @proportion: the proportion
2312  * @diff: the diff against the clock
2313  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2314  * running_time.
2315  *
2316  * Set the QoS parameters in the transform. This function is called internally
2317  * when a QOS event is received but subclasses can provide custom information
2318  * when needed.
2319  *
2320  * MT safe.
2321  *
2322  * Since: 0.10.5
2323  */
2324 void
2325 gst_base_transform_update_qos (GstBaseTransform * trans,
2326     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2327 {
2328
2329   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2330
2331   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2332       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2333       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2334
2335   GST_OBJECT_LOCK (trans);
2336   trans->priv->proportion = proportion;
2337   trans->priv->earliest_time = timestamp + diff;
2338   GST_OBJECT_UNLOCK (trans);
2339 }
2340
2341 /**
2342  * gst_base_transform_set_qos_enabled:
2343  * @trans: a #GstBaseTransform
2344  * @enabled: new state
2345  *
2346  * Enable or disable QoS handling in the transform.
2347  *
2348  * MT safe.
2349  *
2350  * Since: 0.10.5
2351  */
2352 void
2353 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2354 {
2355   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2356
2357   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2358
2359   GST_OBJECT_LOCK (trans);
2360   trans->priv->qos_enabled = enabled;
2361   GST_OBJECT_UNLOCK (trans);
2362 }
2363
2364 /**
2365  * gst_base_transform_is_qos_enabled:
2366  * @trans: a #GstBaseTransform
2367  *
2368  * Queries if the transform will handle QoS.
2369  *
2370  * Returns: TRUE if QoS is enabled.
2371  *
2372  * MT safe.
2373  *
2374  * Since: 0.10.5
2375  */
2376 gboolean
2377 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2378 {
2379   gboolean result;
2380
2381   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2382
2383   GST_OBJECT_LOCK (trans);
2384   result = trans->priv->qos_enabled;
2385   GST_OBJECT_UNLOCK (trans);
2386
2387   return result;
2388 }
2389
2390 /**
2391  * gst_base_transform_set_gap_aware:
2392  * @trans: a #GstBaseTransform
2393  * @gap_aware: New state
2394  *
2395  * If @gap_aware is %FALSE (the default), output buffers will have the
2396  * %GST_BUFFER_FLAG_GAP flag unset.
2397  *
2398  * If set to %TRUE, the element must handle output buffers with this flag set
2399  * correctly, i.e. it can assume that the buffer contains neutral data but must
2400  * unset the flag if the output is no neutral data.
2401  *
2402  * MT safe.
2403  *
2404  * Since: 0.10.16
2405  */
2406 void
2407 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2408 {
2409   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2410
2411   GST_OBJECT_LOCK (trans);
2412   trans->priv->gap_aware = gap_aware;
2413   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2414   GST_OBJECT_UNLOCK (trans);
2415 }
2416
2417 /**
2418  * gst_base_transform_reconfigure_sink:
2419  * @trans: a #GstBaseTransform
2420  *
2421  * Instructs @trans to request renegotiation upstream. This function is
2422  * typically called after properties on the transform were set that
2423  * influence the input format.
2424  */
2425 void
2426 gst_base_transform_reconfigure_sink (GstBaseTransform * trans)
2427 {
2428   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2429
2430   /* push the renegotiate event */
2431   if (!gst_pad_push_event (GST_BASE_TRANSFORM_SINK_PAD (trans),
2432           gst_event_new_reconfigure ()))
2433     GST_DEBUG_OBJECT (trans, "Renegotiate event wasn't handled");
2434 }
2435
2436 /**
2437  * gst_base_transform_reconfigure_src:
2438  * @trans: a #GstBaseTransform
2439  *
2440  * Instructs @trans to renegotiate a new downstream transform on the next
2441  * buffer. This function is typically called after properties on the transform
2442  * were set that influence the output format.
2443  *
2444  * Since: 0.10.21
2445  */
2446 void
2447 gst_base_transform_reconfigure_src (GstBaseTransform * trans)
2448 {
2449   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2450
2451   GST_OBJECT_LOCK (trans);
2452   GST_DEBUG_OBJECT (trans, "marking reconfigure");
2453   trans->priv->reconfigure = TRUE;
2454   GST_OBJECT_UNLOCK (trans);
2455 }