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