docs/libs/gstreamer-libs-sections.txt: Add new function:
[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  * Use Cases:
48  * <orderedlist>
49  * <listitem>
50  *   <itemizedlist><title>Passthrough mode</title>
51  *   <listitem><para>
52  *     Element has no interest in modifying the buffer. It may want to inspect it,
53  *     in which case the element should have a transform_ip function. If there
54  *     is no transform_ip function in passthrough mode, the buffer is pushed
55  *     intact.
56  *   </para></listitem>
57  *   <listitem><para>
58  *     On the GstBaseTransformClass is the passthrough_on_same_caps variable
59  *     which will automatically set/unset passthrough based on whether the
60  *     element negotiates the same caps on both pads.
61  *   </para></listitem>
62  *   <listitem><para>
63  *     passthrough_on_same_caps on an element that doesn't implement a
64  *     transform_caps function is useful for elements that only inspect data
65  *     (such as level)
66  *   </para></listitem>
67  *   </itemizedlist>
68  *   <itemizedlist>
69  *   <title>Example elements</title>
70  *     <listitem>Level</listitem>
71  *     <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
72  *     certain modes.</listitem>
73  *   </itemizedlist>
74  * </listitem>
75  * <listitem>
76  *   <itemizedlist>
77  *     <title>Modifications in-place - input buffer and output buffer are the
78  *     same thing.</title>
79  *   <listitem><para>
80  *     The element must implement a transform_ip function.
81  *   </para></listitem>
82  *   <listitem><para>
83  *     Output buffer size must <= input buffer size
84  *   </para></listitem>
85  *   <listitem><para>
86  *     If the always_in_place flag is set, non-writable buffers will be copied
87  *     and passed to the transform_ip function, otherwise a new buffer will be
88  *     created and the transform function called.
89  *   </para></listitem>
90  *   <listitem><para>
91  *     Incoming writable buffers will be passed to the transform_ip function
92  *     immediately.  </para></listitem>
93  *   <listitem><para>
94  *     only implementing transform_ip and not transform implies always_in_place
95  *     = TRUE
96  *   </para></listitem>
97  *   </itemizedlist>
98  *   <itemizedlist>
99  *   <title>Example elements</title>
100  *     <listitem>Volume</listitem>
101  *     <listitem>Audioconvert in certain modes (signed/unsigned
102  *     conversion)</listitem>
103  *     <listitem>ffmpegcolorspace in certain modes (endianness
104  *     swapping)</listitem>
105  *   </itemizedlist>
106  *  </listitem>
107  * <listitem>
108  *   <itemizedlist>
109  *   <title>Modifications only to the caps/metadata of a buffer</title>
110  *   <listitem><para>
111  *     The element does not require writable data, but non-writable buffers
112  *     should be subbuffered so that the meta-information can be replaced.
113  *   </para></listitem>
114  *   <listitem><para>
115  *     Elements wishing to operate in this mode should replace the
116  *     prepare_output_buffer method to create subbuffers of the input buffer
117  *     and set always_in_place to TRUE
118  *   </para></listitem>
119  *   </itemizedlist>
120  *   <itemizedlist>
121  *   <title>Example elements</title>
122  *     <listitem>Capsfilter when setting caps on outgoing buffers that have
123  *     none.</listitem>
124  *     <listitem>identity when it is going to re-timestamp buffers by
125  *     datarate.</listitem>
126  *   </itemizedlist>
127  * </listitem>
128  * <listitem>
129  *   <itemizedlist><title>Normal mode</title>
130  *   <listitem><para>
131  *     always_in_place flag is not set, or there is no transform_ip function
132  *   </para></listitem>
133  *   <listitem><para>
134  *     Element will receive an input buffer and output buffer to operate on.
135  *   </para></listitem>
136  *   <listitem><para>
137  *     Output buffer is allocated by calling the prepare_output_buffer function.
138  *   </para></listitem>
139  *   </itemizedlist>
140  *   <itemizedlist>
141  *   <title>Example elements</title>
142  *     <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
143  *     scaling/conversions</listitem>
144  *   </itemizedlist>
145  * </listitem>
146  * <listitem>
147  *   <itemizedlist><title>Special output buffer allocations</title>
148  *   <listitem><para>
149  *     Elements which need to do special allocation of their output buffers
150  *     other than what gst_buffer_pad_alloc allows should implement a
151  *     prepare_output_buffer method, which calls the parent implementation and
152  *     passes the newly allocated buffer.
153  *   </para></listitem>
154  *   </itemizedlist>
155  *   <itemizedlist>
156  *   <title>Example elements</title>
157  *     <listitem>efence</listitem>
158  *   </itemizedlist>
159  * </listitem>
160  * </orderedlist>
161  *
162  * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
163  * <listitem><para>
164  *   <itemizedlist><title>passthrough</title>
165  *     <listitem><para>
166  *       Implies that in the current configuration, the sub-class is not
167  *       interested in modifying the buffers.
168  *     </para></listitem>
169  *     <listitem><para>
170  *       Elements which are always in passthrough mode whenever the same caps
171  *       has been negotiated on both pads can set the class variable
172  *       passthrough_on_same_caps to have this behaviour automatically.
173  *     </para></listitem>
174  *   </itemizedlist>
175  * </para></listitem>
176  * <listitem><para>
177  *   <itemizedlist><title>always_in_place</title>
178  *     <listitem><para>
179  *       Determines whether a non-writable buffer will be copied before passing
180  *       to the transform_ip function.
181  *     </para></listitem>
182  *     <listitem><para>
183  *       Implied TRUE if no transform function is implemented.
184  *     </para></listitem>
185  *     <listitem><para>
186  *       Implied FALSE if ONLY transform function is implemented.
187  *     </para></listitem>
188  *   </itemizedlist>
189  * </para></listitem>
190  * </itemizedlist>
191  *
192 */
193
194 #ifdef HAVE_CONFIG_H
195 #  include "config.h"
196 #endif
197
198 #include <stdlib.h>
199 #include <string.h>
200
201 #include "../../../gst/gst_private.h"
202 #include "../../../gst/gst-i18n-lib.h"
203 #include "gstbasetransform.h"
204 #include <gst/gstmarshal.h>
205
206 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
207 #define GST_CAT_DEFAULT gst_base_transform_debug
208
209 /* BaseTransform signals and args */
210 enum
211 {
212   /* FILL ME */
213   LAST_SIGNAL
214 };
215
216 #define DEFAULT_PROP_QOS        FALSE
217
218 enum
219 {
220   PROP_0,
221   PROP_QOS
222 };
223
224 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
225     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
226
227 struct _GstBaseTransformPrivate
228 {
229   /* QoS *//* with LOCK */
230   gboolean qos_enabled;
231   gdouble proportion;
232   GstClockTime earliest_time;
233   /* previous buffer had a discont */
234   gboolean discont;
235
236   GstActivateMode pad_mode;
237
238   gboolean gap_aware;
239
240   /* caps used for allocating buffers */
241   gboolean proxy_alloc;
242   GstCaps *sink_alloc;
243   GstCaps *src_alloc;
244   /* upstream caps and size suggestions */
245   GstCaps *sink_suggest;
246   guint size_suggest;
247 };
248
249 static GstElementClass *parent_class = NULL;
250
251 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
252 static void gst_base_transform_init (GstBaseTransform * trans,
253     GstBaseTransformClass * klass);
254 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
255     * trans, GstBuffer * input, GstBuffer ** buf);
256
257 GType
258 gst_base_transform_get_type (void)
259 {
260   static GType base_transform_type = 0;
261
262   if (!base_transform_type) {
263     static const GTypeInfo base_transform_info = {
264       sizeof (GstBaseTransformClass),
265       NULL,
266       NULL,
267       (GClassInitFunc) gst_base_transform_class_init,
268       NULL,
269       NULL,
270       sizeof (GstBaseTransform),
271       0,
272       (GInstanceInitFunc) gst_base_transform_init,
273     };
274
275     base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
276         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
277   }
278   return base_transform_type;
279 }
280
281 static void gst_base_transform_finalize (GObject * object);
282 static void gst_base_transform_set_property (GObject * object, guint prop_id,
283     const GValue * value, GParamSpec * pspec);
284 static void gst_base_transform_get_property (GObject * object, guint prop_id,
285     GValue * value, GParamSpec * pspec);
286 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
287     gboolean active);
288 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
289     gboolean active);
290 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
291     gboolean active);
292 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
293     GstCaps * caps, guint * size);
294
295 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
296 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
297     GstEvent * event);
298 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
299 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
300     GstEvent * event);
301 static gboolean gst_base_transform_check_get_range (GstPad * pad);
302 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
303     guint length, GstBuffer ** buffer);
304 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
305     GstBuffer * buffer);
306 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
307 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
308 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
309     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
310
311 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
312
313 static void
314 gst_base_transform_finalize (GObject * object)
315 {
316   GstBaseTransform *trans;
317
318   trans = GST_BASE_TRANSFORM (object);
319
320   gst_caps_replace (&trans->priv->sink_suggest, NULL);
321   g_mutex_free (trans->transform_lock);
322
323   G_OBJECT_CLASS (parent_class)->finalize (object);
324 }
325
326 static void
327 gst_base_transform_class_init (GstBaseTransformClass * klass)
328 {
329   GObjectClass *gobject_class;
330
331   gobject_class = G_OBJECT_CLASS (klass);
332
333   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
334       "basetransform element");
335
336   GST_DEBUG ("gst_base_transform_class_init");
337
338   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
339
340   parent_class = g_type_class_peek_parent (klass);
341
342   gobject_class->set_property =
343       GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
344   gobject_class->get_property =
345       GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
346
347   g_object_class_install_property (gobject_class, PROP_QOS,
348       g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
349           DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
350
351   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
352
353   klass->passthrough_on_same_caps = FALSE;
354   klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
355   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
356 }
357
358 static void
359 gst_base_transform_init (GstBaseTransform * trans,
360     GstBaseTransformClass * bclass)
361 {
362   GstPadTemplate *pad_template;
363
364   GST_DEBUG ("gst_base_transform_init");
365
366   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
367
368   pad_template =
369       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
370   g_return_if_fail (pad_template != NULL);
371   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
372   gst_pad_set_getcaps_function (trans->sinkpad,
373       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
374   gst_pad_set_setcaps_function (trans->sinkpad,
375       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
376   gst_pad_set_event_function (trans->sinkpad,
377       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
378   gst_pad_set_chain_function (trans->sinkpad,
379       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
380   gst_pad_set_activatepush_function (trans->sinkpad,
381       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
382   gst_pad_set_bufferalloc_function (trans->sinkpad,
383       GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
384   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
385
386   pad_template =
387       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
388   g_return_if_fail (pad_template != NULL);
389   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
390   gst_pad_set_getcaps_function (trans->srcpad,
391       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
392   gst_pad_set_event_function (trans->srcpad,
393       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
394   gst_pad_set_checkgetrange_function (trans->srcpad,
395       GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
396   gst_pad_set_getrange_function (trans->srcpad,
397       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
398   gst_pad_set_activatepull_function (trans->srcpad,
399       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
400   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
401
402   trans->transform_lock = g_mutex_new ();
403   trans->pending_configure = FALSE;
404   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
405   trans->cache_caps1 = NULL;
406   trans->cache_caps2 = NULL;
407   trans->priv->pad_mode = GST_ACTIVATE_NONE;
408   trans->priv->gap_aware = FALSE;
409
410   trans->passthrough = FALSE;
411   if (bclass->transform == NULL) {
412     /* If no transform function, always_in_place is TRUE */
413     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
414     trans->always_in_place = TRUE;
415
416     if (bclass->transform_ip == NULL) {
417       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
418       trans->passthrough = TRUE;
419     }
420   }
421 }
422
423 /* given @caps on the src or sink pad (given by @direction)
424  * calculate the possible caps on the other pad.
425  *
426  * Returns new caps, unref after usage.
427  */
428 static GstCaps *
429 gst_base_transform_transform_caps (GstBaseTransform * trans,
430     GstPadDirection direction, GstCaps * caps)
431 {
432   GstCaps *ret;
433   GstBaseTransformClass *klass;
434
435   if (caps == NULL)
436     return NULL;
437
438   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
439
440   /* if there is a custom transform function, use this */
441   if (klass->transform_caps) {
442     GstCaps *temp;
443     gint i;
444
445     /* start with empty caps */
446     ret = gst_caps_new_empty ();
447     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
448
449     if (gst_caps_is_any (caps)) {
450       /* for any caps we still have to call the transform function */
451       GST_DEBUG_OBJECT (trans, "from: ANY");
452       temp = klass->transform_caps (trans, direction, caps);
453       GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);
454
455       temp = gst_caps_make_writable (temp);
456       gst_caps_append (ret, temp);
457     } else {
458       /* we send caps with just one structure to the transform
459        * function as this is easier for the element */
460       for (i = 0; i < gst_caps_get_size (caps); i++) {
461         GstCaps *nth;
462
463         nth = gst_caps_copy_nth (caps, i);
464         GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
465         temp = klass->transform_caps (trans, direction, nth);
466         gst_caps_unref (nth);
467         GST_LOG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
468
469         temp = gst_caps_make_writable (temp);
470         /* here we need to only append those structures, that are not yet
471          * in there, we use the merge function for this */
472         gst_caps_merge (ret, temp);
473
474         GST_LOG_OBJECT (trans, "  merged[%d]: %" GST_PTR_FORMAT, i, ret);
475       }
476       GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
477       /* we can't do much simplification here because we don't really want to
478        * change the caps order */
479     }
480   } else {
481     GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
482     /* no transform function, use the identity transform */
483     ret = gst_caps_ref (caps);
484   }
485
486   GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
487       ret);
488
489   return ret;
490 }
491
492 /* transform a buffer of @size with @caps on the pad with @direction to
493  * the size of a buffer with @othercaps and store the result in @othersize
494  *
495  * We have two ways of doing this:
496  *  1) use a custom transform size function, this is for complicated custom
497  *     cases with no fixed unit_size.
498  *  2) use the unit_size functions where there is a relationship between the
499  *     caps and the size of a buffer.
500  */
501 static gboolean
502 gst_base_transform_transform_size (GstBaseTransform * trans,
503     GstPadDirection direction, GstCaps * caps,
504     guint size, GstCaps * othercaps, guint * othersize)
505 {
506   guint inunitsize, outunitsize, units;
507   GstBaseTransformClass *klass;
508   gboolean ret;
509
510   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
511
512   GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
513       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
514       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
515
516   if (klass->transform_size) {
517     /* if there is a custom transform function, use this */
518     ret = klass->transform_size (trans, direction, caps, size, othercaps,
519         othersize);
520   } else {
521     /* there is no transform_size function, we have to use the unit_size
522      * functions. This method assumes there is a fixed unit_size associated with
523      * each caps. We provide the same amount of units on both sides. */
524     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
525       goto no_in_size;
526
527     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
528         inunitsize);
529
530     /* input size must be a multiple of the unit_size of the input caps */
531     if (inunitsize == 0 || (size % inunitsize != 0))
532       goto no_multiple;
533
534     /* get the amount of units */
535     units = size / inunitsize;
536
537     /* now get the unit size of the output */
538     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
539       goto no_out_size;
540
541     /* the output size is the unit_size times the amount of units on the
542      * input */
543     *othersize = units * outunitsize;
544     GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
545
546     ret = TRUE;
547   }
548   return ret;
549
550   /* ERRORS */
551 no_in_size:
552   {
553     GST_DEBUG_OBJECT (trans, "could not get in_size");
554     g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
555     return FALSE;
556   }
557 no_multiple:
558   {
559     GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
560         inunitsize);
561     g_warning ("%s: size %u is not a multiple of unit size %u",
562         GST_ELEMENT_NAME (trans), size, inunitsize);
563     return FALSE;
564   }
565 no_out_size:
566   {
567     GST_DEBUG_OBJECT (trans, "could not get out_size");
568     g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
569     return FALSE;
570   }
571 }
572
573 /* get the caps that can be handled by @pad. We perforn:
574  *
575  *  - take the caps of peer of otherpad,
576  *  - filter against the padtemplate of otherpad, 
577  *  - calculate all transforms of remaining caps
578  *  - filter against template of @pad
579  *
580  * If there is no peer, we simply return the caps of the padtemplate of pad.
581  */
582 static GstCaps *
583 gst_base_transform_getcaps (GstPad * pad)
584 {
585   GstBaseTransform *trans;
586   GstPad *otherpad;
587   GstCaps *caps;
588
589   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
590
591   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
592
593   /* we can do what the peer can */
594   caps = gst_pad_peer_get_caps (otherpad);
595   if (caps) {
596     GstCaps *temp;
597     const GstCaps *templ;
598
599     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, caps);
600
601     /* filtered against our padtemplate */
602     templ = gst_pad_get_pad_template_caps (otherpad);
603     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
604     temp = gst_caps_intersect (caps, templ);
605     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
606     gst_caps_unref (caps);
607     /* then see what we can transform this to */
608     caps = gst_base_transform_transform_caps (trans,
609         GST_PAD_DIRECTION (otherpad), temp);
610     GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
611     gst_caps_unref (temp);
612     if (caps == NULL)
613       goto done;
614
615     /* and filter against the template again */
616     templ = gst_pad_get_pad_template_caps (pad);
617     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
618     temp = gst_caps_intersect (caps, templ);
619     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
620     gst_caps_unref (caps);
621     /* this is what we can do */
622     caps = temp;
623   } else {
624     /* no peer, our padtemplate is enough then */
625     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
626   }
627
628 done:
629   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
630
631   gst_object_unref (trans);
632
633   return caps;
634 }
635
636 /* function triggered when the in and out caps are negotiated and need
637  * to be configured in the subclass. */
638 static gboolean
639 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
640     GstCaps * out)
641 {
642   gboolean ret = TRUE;
643   GstBaseTransformClass *klass;
644
645   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
646
647   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
648   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
649
650   /* clear the cache */
651   gst_caps_replace (&trans->cache_caps1, NULL);
652   gst_caps_replace (&trans->cache_caps2, NULL);
653
654   /* figure out same caps state */
655   trans->have_same_caps = gst_caps_is_equal (in, out);
656   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
657
658   /* If we've a transform_ip method and same input/output caps, set in_place
659    * by default. If for some reason the sub-class prefers using a transform
660    * function, it can clear the in place flag in the set_caps */
661   gst_base_transform_set_in_place (trans,
662       klass->transform_ip && trans->have_same_caps);
663
664   /* Set the passthrough if the class wants passthrough_on_same_caps
665    * and we have the same caps on each pad */
666   if (klass->passthrough_on_same_caps)
667     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
668
669   /* now configure the element with the caps */
670   if (klass->set_caps) {
671     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
672     ret = klass->set_caps (trans, in, out);
673   }
674
675   trans->negotiated = ret;
676
677   return ret;
678 }
679
680 /* check if caps @in on @pad can be transformed to @out on the other pad.
681  * We don't have a vmethod to test this yet so we have to do a somewhat less
682  * efficient check for this.
683  */
684 static gboolean
685 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
686     GstCaps * in, GstCaps * out)
687 {
688   GstCaps *othercaps;
689
690   /* convert the in caps to all possible out caps */
691   othercaps =
692       gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
693
694   /* check if transform is empty */
695   if (!othercaps || gst_caps_is_empty (othercaps))
696     goto no_transform;
697
698   /* check if the out caps is a subset of the othercaps */
699   if (!gst_caps_is_subset (out, othercaps))
700     goto no_subset;
701
702   if (othercaps)
703     gst_caps_unref (othercaps);
704
705   GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
706   GST_DEBUG_OBJECT (trans, "to   %" GST_PTR_FORMAT, out);
707
708   return TRUE;
709
710   /* ERRORS */
711 no_transform:
712   {
713     GST_DEBUG_OBJECT (trans,
714         "transform returned useless %" GST_PTR_FORMAT, othercaps);
715     if (othercaps)
716       gst_caps_unref (othercaps);
717     return FALSE;
718   }
719 no_subset:
720   {
721     GST_DEBUG_OBJECT (trans, "no subset");
722     if (othercaps)
723       gst_caps_unref (othercaps);
724     return FALSE;
725   }
726 }
727
728 /* given a fixed @caps on @pad, create the best possible caps for the
729  * other pad.
730  * @caps must be fixed when calling this function.
731  *
732  * This function calls the transform caps vmethod of the basetransform to figure
733  * out the possible target formats. It then tries to select the best format from
734  * this list by:
735  *
736  * - attempt passthrough if the target caps is a superset of the input caps
737  * - fixating by using peer caps
738  * - fixating with transform fixate function
739  * - fixating with pad fixate functions.
740  *
741  * this function returns a caps that can be transformed into and is accepted by
742  * the peer element.
743  */
744 static GstCaps *
745 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
746     GstCaps * caps)
747 {
748   GstBaseTransformClass *klass;
749   GstPad *otherpad, *otherpeer;
750   GstCaps *othercaps;
751   gboolean peer_checked = FALSE;
752
753   /* caps must be fixed here, this is a programming error if it's not */
754   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
755
756   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
757
758   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
759   otherpeer = gst_pad_get_peer (otherpad);
760
761   /* see how we can transform the input caps. We need to do this even for
762    * passthrough because it might be possible that this element cannot support
763    * passthrough at all. */
764   othercaps = gst_base_transform_transform_caps (trans,
765       GST_PAD_DIRECTION (pad), caps);
766
767   /* The caps we can actually output is the intersection of the transformed
768    * caps with the pad template for the pad */
769   if (othercaps) {
770     GstCaps *intersect;
771     const GstCaps *templ_caps;
772
773     templ_caps = gst_pad_get_pad_template_caps (otherpad);
774     GST_DEBUG_OBJECT (trans,
775         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
776
777     intersect = gst_caps_intersect (othercaps, templ_caps);
778
779     gst_caps_unref (othercaps);
780     othercaps = intersect;
781   }
782
783   /* check if transform is empty */
784   if (!othercaps || gst_caps_is_empty (othercaps))
785     goto no_transform;
786
787   /* if the othercaps are not fixed, we need to fixate them, first attempt
788    * is by attempting passthrough if the othercaps are a superset of caps. */
789   /* FIXME. maybe the caps is not fixed because it has multiple structures of
790    * fixed caps */
791   if (!gst_caps_is_fixed (othercaps)) {
792     GstCaps *temp;
793
794     GST_DEBUG_OBJECT (trans,
795         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
796
797     /* see if the target caps are a superset of the source caps, in this
798      * case we can try to perform passthrough */
799     temp = gst_caps_intersect (othercaps, caps);
800     GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
801     if (temp) {
802       if (!gst_caps_is_empty (temp)) {
803         GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
804         if (otherpeer) {
805           /* try passthrough. we know it's fixed, because caps is fixed */
806           if (gst_pad_accept_caps (otherpeer, caps)) {
807             GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
808             /* peer accepted unmodified caps, we free the original non-fixed
809              * caps and work with the passthrough caps */
810             gst_caps_unref (othercaps);
811             othercaps = gst_caps_ref (caps);
812             /* mark that we checked othercaps with the peer, this
813              * makes sure we don't call accept_caps again with these same
814              * caps */
815             peer_checked = TRUE;
816           } else {
817             GST_DEBUG_OBJECT (trans,
818                 "peer did not accept %" GST_PTR_FORMAT, caps);
819           }
820         } else {
821           GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
822           gst_caps_unref (othercaps);
823           othercaps = gst_caps_ref (caps);
824         }
825       }
826       gst_caps_unref (temp);
827     }
828   }
829
830   /* second attempt at fixation is done by intersecting with
831    * the peer caps */
832   if (!gst_caps_is_fixed (othercaps) && otherpeer) {
833     /* intersect against what the peer can do */
834     GstCaps *peercaps;
835     GstCaps *intersect;
836
837     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
838
839     peercaps = gst_pad_get_caps (otherpeer);
840     intersect = gst_caps_intersect (peercaps, othercaps);
841     gst_caps_unref (peercaps);
842     gst_caps_unref (othercaps);
843     othercaps = intersect;
844     peer_checked = FALSE;
845
846     GST_DEBUG_OBJECT (trans,
847         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
848   }
849
850   if (gst_caps_is_empty (othercaps))
851     goto no_transform_possible;
852
853   /* third attempt at fixation, call the fixate vmethod and
854    * ultimately call the pad fixate function. */
855   if (!gst_caps_is_fixed (othercaps)) {
856     GstCaps *temp;
857
858     GST_DEBUG_OBJECT (trans,
859         "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
860         othercaps, GST_DEBUG_PAD_NAME (otherpad));
861
862     /* since we have no other way to fixate left, we might as well just take
863      * the first of the caps list and fixate that */
864
865     /* FIXME: when fixating using the vmethod, it might make sense to fixate
866      * each of the caps; but Wim doesn't see a use case for that yet */
867     temp = gst_caps_copy_nth (othercaps, 0);
868     gst_caps_unref (othercaps);
869     othercaps = temp;
870     peer_checked = FALSE;
871
872     if (klass->fixate_caps) {
873       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
874           " using caps %" GST_PTR_FORMAT
875           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
876           GST_DEBUG_PAD_NAME (otherpad));
877       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
878     }
879     /* if still not fixed, no other option but to let the default pad fixate
880      * function do its job */
881     if (!gst_caps_is_fixed (othercaps)) {
882       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
883           " on pad %s:%s using gst_pad_fixate_caps", othercaps,
884           GST_DEBUG_PAD_NAME (otherpad));
885       gst_pad_fixate_caps (otherpad, othercaps);
886     }
887     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
888   }
889
890   /* caps should be fixed now, if not we have to fail. */
891   if (!gst_caps_is_fixed (othercaps))
892     goto could_not_fixate;
893
894   /* and peer should accept, don't check again if we already checked the
895    * othercaps against the peer. */
896   if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
897     goto peer_no_accept;
898
899   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
900       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
901
902   if (otherpeer)
903     gst_object_unref (otherpeer);
904
905   return othercaps;
906
907   /* ERRORS */
908 no_transform:
909   {
910     GST_DEBUG_OBJECT (trans,
911         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
912     goto error_cleanup;
913   }
914 no_transform_possible:
915   {
916     GST_DEBUG_OBJECT (trans,
917         "transform could not transform %" GST_PTR_FORMAT
918         " in anything we support", caps);
919     goto error_cleanup;
920   }
921 could_not_fixate:
922   {
923     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
924     goto error_cleanup;
925   }
926 peer_no_accept:
927   {
928     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
929         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
930     goto error_cleanup;
931   }
932 error_cleanup:
933   {
934     if (otherpeer)
935       gst_object_unref (otherpeer);
936     if (othercaps)
937       gst_caps_unref (othercaps);
938     return NULL;
939   }
940 }
941
942 /* called when new caps arrive on the sink or source pad,
943  * We try to find the best caps for the other side using our _find_transform()
944  * function. If there are caps, we configure the transform for this new
945  * transformation.
946  *
947  * FIXME, this function is currently commutative but this should not really be
948  * because we never set caps starting from the srcpad.
949  */
950 static gboolean
951 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
952 {
953   GstBaseTransform *trans;
954   GstBaseTransformClass *klass;
955   GstPad *otherpad, *otherpeer;
956   GstCaps *othercaps = NULL;
957   gboolean ret = TRUE;
958   GstCaps *incaps, *outcaps;
959
960   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
961   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
962
963   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
964   otherpeer = gst_pad_get_peer (otherpad);
965
966   /* if we get called recursively, we bail out now to avoid an
967    * infinite loop. */
968   if (GST_PAD_IS_IN_SETCAPS (otherpad))
969     goto done;
970
971   GST_DEBUG_OBJECT (pad, "have new caps %" GST_PTR_FORMAT, caps);
972
973   /* find best possible caps for the other pad */
974   othercaps = gst_base_transform_find_transform (trans, pad, caps);
975   if (!othercaps || gst_caps_is_empty (othercaps))
976     goto no_transform_possible;
977
978   /* configure the element now */
979   /* make sure in and out caps are correct */
980   if (pad == trans->sinkpad) {
981     incaps = caps;
982     outcaps = othercaps;
983   } else {
984     incaps = othercaps;
985     outcaps = caps;
986   }
987
988 #if 0
989   /* if we have the same caps, we can optimize and reuse the input caps */
990   if (gst_caps_is_equal (incaps, outcaps)) {
991     GST_INFO_OBJECT (trans, "reuse caps");
992     gst_caps_unref (outcaps);
993     outcaps = gst_caps_ref (incaps);
994   }
995 #endif
996
997   /* call configure now */
998   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
999     goto failed_configure;
1000
1001   /* we know this will work, we implement the setcaps */
1002   gst_pad_set_caps (otherpad, othercaps);
1003
1004   if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1005     /* FIXME hm? */
1006     ret &= gst_pad_set_caps (otherpeer, othercaps);
1007     if (!ret) {
1008       GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1009           othercaps);
1010     }
1011   }
1012
1013 done:
1014   if (otherpeer)
1015     gst_object_unref (otherpeer);
1016   if (othercaps)
1017     gst_caps_unref (othercaps);
1018
1019   trans->negotiated = ret;
1020
1021   gst_object_unref (trans);
1022
1023   return ret;
1024
1025   /* ERRORS */
1026 no_transform_possible:
1027   {
1028     GST_WARNING_OBJECT (trans,
1029         "transform could not transform %" GST_PTR_FORMAT
1030         " in anything we support", caps);
1031     ret = FALSE;
1032     goto done;
1033   }
1034 failed_configure:
1035   {
1036     GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1037         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1038     ret = FALSE;
1039     goto done;
1040   }
1041 }
1042
1043 /* Allocate a buffer using gst_pad_alloc_buffer
1044  *
1045  * This function can do renegotiation on the source pad
1046  *
1047  * The output buffer is always writable. outbuf can be equal to
1048  * inbuf, the caller should be prepared for this and perform 
1049  * appropriate refcounting.
1050  */
1051 static GstFlowReturn
1052 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1053     GstBuffer * in_buf, GstBuffer ** out_buf)
1054 {
1055   GstBaseTransformClass *bclass;
1056   GstBaseTransformPrivate *priv;
1057   GstFlowReturn ret = GST_FLOW_OK;
1058   guint outsize, newsize;
1059   gboolean discard;
1060   GstCaps *incaps, *oldcaps, *newcaps;
1061
1062   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1063
1064   priv = trans->priv;
1065
1066   /* figure out how to allocate a buffer based on the current configuration */
1067   if (trans->passthrough) {
1068     GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1069     /* passthrough, we don't really need to call pad alloc but we still need to
1070      * in order to get upstream negotiation. The output size is the same as the
1071      * input size. */
1072     outsize = GST_BUFFER_SIZE (in_buf);
1073     /* we always alloc and discard here */
1074     discard = TRUE;
1075   } else {
1076     gboolean want_in_place = (bclass->transform_ip != NULL)
1077         && trans->always_in_place;
1078
1079     if (want_in_place) {
1080       GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1081       /* we alloc a buffer of the same size as the input */
1082       outsize = GST_BUFFER_SIZE (in_buf);
1083       /* only discard it when the input was not writable, otherwise, we reuse
1084        * the input buffer. */
1085       discard = gst_buffer_is_writable (in_buf);
1086     } else {
1087       GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1088       /* copy transform, figure out the output size */
1089       if (!gst_base_transform_transform_size (trans,
1090               GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1091               GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1092               &outsize)) {
1093         goto unknown_size;
1094       }
1095       /* never discard this buffer, we need it for storing the output */
1096       discard = FALSE;
1097     }
1098   }
1099
1100   oldcaps = GST_PAD_CAPS (trans->srcpad);
1101
1102   if (bclass->prepare_output_buffer) {
1103     GST_DEBUG_OBJECT (trans,
1104         "calling prepare buffer with caps %" GST_PTR_FORMAT, oldcaps);
1105     ret =
1106         bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1107         out_buf);
1108
1109     /* FIXME 0.11:
1110      * decrease refcount again if vmethod returned refcounted in_buf. This
1111      * is because we need to make sure that the buffer is writable for the
1112      * in_place transform. The docs of the vmethod say that you should return
1113      * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1114     if (in_buf == *out_buf)
1115       gst_buffer_unref (in_buf);
1116
1117     /* never discard the buffer from the prepare_buffer method */
1118     discard = FALSE;
1119   } else {
1120     GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT, oldcaps);
1121
1122     ret = gst_pad_alloc_buffer (trans->srcpad,
1123         GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1124   }
1125
1126   if (ret != GST_FLOW_OK)
1127     goto alloc_failed;
1128
1129   /* must always return a buffer */
1130   g_assert (*out_buf != NULL);
1131
1132   /* check if we got different caps on this new output buffer */
1133   newcaps = GST_BUFFER_CAPS (*out_buf);
1134   newsize = GST_BUFFER_SIZE (*out_buf);
1135   if (!gst_caps_is_equal (newcaps, oldcaps)) {
1136     GstCaps *othercaps;
1137     gboolean can_convert;
1138
1139     GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1140
1141     incaps = GST_PAD_CAPS (trans->sinkpad);
1142
1143     /* it's possible that the buffer we got is of the wrong size, get the
1144      * expected size here */
1145     gst_base_transform_transform_size (trans,
1146         GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &outsize);
1147
1148     /* check if we can convert the current incaps to the new target caps */
1149     can_convert =
1150         gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1151         newcaps);
1152
1153     if (can_convert) {
1154       GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1155       /* caps not empty, try to renegotiate to the new format */
1156       if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1157         /* not sure we need to fail hard here, we can simply continue our
1158          * conversion with what we negotiated before */
1159         goto failed_configure;
1160       }
1161       /* new format configure, and use the new output buffer */
1162       gst_pad_set_caps (trans->srcpad, newcaps);
1163       discard = FALSE;
1164     } else {
1165       GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1166
1167       /* we cannot convert the current buffer but we might be able to suggest a
1168        * new format upstream, try to find what the best format is. */
1169       othercaps =
1170           gst_base_transform_find_transform (trans, trans->srcpad, newcaps);
1171
1172       if (!othercaps) {
1173         GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1174         /* we received caps that we cannot transform. Upstream is behaving badly
1175          * because it should have checked if we could handle these caps. We can
1176          * simply ignore these caps and produce a buffer with our original caps. */
1177       } else {
1178         guint size_suggest;
1179
1180         GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1181
1182         /* not a subset, we have a new upstream suggestion, remember it and
1183          * allocate a default buffer. First we try to convert the size */
1184         if (gst_base_transform_transform_size (trans,
1185                 GST_PAD_SRC, newcaps, outsize, othercaps, &size_suggest)) {
1186
1187           /* ok, remember the suggestions now */
1188           GST_DEBUG_OBJECT (trans,
1189               "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1190               size_suggest, othercaps);
1191
1192           GST_OBJECT_LOCK (trans->sinkpad);
1193           if (priv->sink_suggest)
1194             gst_caps_unref (priv->sink_suggest);
1195           priv->sink_suggest = gst_caps_ref (othercaps);
1196           priv->size_suggest = size_suggest;
1197           GST_OBJECT_UNLOCK (trans->sinkpad);
1198         }
1199         gst_caps_unref (othercaps);
1200       }
1201       if (in_buf != *out_buf)
1202         gst_buffer_unref (*out_buf);
1203       *out_buf = NULL;
1204     }
1205
1206     /* if we got a buffer of the wrong size, discard it now */
1207     if (newsize != outsize) {
1208       if (in_buf != *out_buf)
1209         gst_buffer_unref (*out_buf);
1210       *out_buf = NULL;
1211       discard = FALSE;
1212     }
1213   }
1214
1215   if (*out_buf == NULL) {
1216     if (!discard) {
1217       GST_DEBUG_OBJECT (trans, "make default output buffer");
1218       /* no valid buffer yet, make one */
1219       *out_buf = gst_buffer_new_and_alloc (outsize);
1220       gst_buffer_copy_metadata (*out_buf, in_buf,
1221           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1222     } else {
1223       GST_DEBUG_OBJECT (trans, "reuse input buffer");
1224       *out_buf = in_buf;
1225     }
1226   } else {
1227     if (discard) {
1228       GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1229       gst_buffer_unref (*out_buf);
1230       *out_buf = in_buf;
1231     } else {
1232       GST_DEBUG_OBJECT (trans, "using pad-alloc buffer");
1233       gst_buffer_copy_metadata (*out_buf, in_buf,
1234           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1235     }
1236   }
1237   gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (trans->srcpad));
1238
1239   /* clear the GAP flag when the subclass does not understand it */
1240   if (!trans->priv->gap_aware)
1241     GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1242
1243   return ret;
1244
1245   /* ERRORS */
1246 alloc_failed:
1247   {
1248     GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1249     return ret;
1250   }
1251 unknown_size:
1252   {
1253     GST_ERROR_OBJECT (trans, "unknown output size");
1254     return GST_FLOW_ERROR;
1255   }
1256 failed_configure:
1257   {
1258     GST_WARNING_OBJECT (trans, "failed to configure caps");
1259     return GST_FLOW_NOT_NEGOTIATED;
1260   }
1261 }
1262
1263 /* Given @caps calcultate the size of one unit.
1264  *
1265  * For video caps, this is the size of one frame (and thus one buffer).
1266  * For audio caps, this is the size of one sample.
1267  *
1268  * These values are cached since they do not change and the calculation
1269  * potentially involves parsing caps and other expensive stuff.
1270  *
1271  * We have two cache locations to store the size, one for the source caps
1272  * and one for the sink caps.
1273  *
1274  * this function returns FALSE if no size could be calculated.
1275  */
1276 static gboolean
1277 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1278     guint * size)
1279 {
1280   gboolean res = FALSE;
1281   GstBaseTransformClass *bclass;
1282
1283   /* see if we have the result cached */
1284   if (trans->cache_caps1 == caps) {
1285     *size = trans->cache_caps1_size;
1286     GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1287     return TRUE;
1288   }
1289   if (trans->cache_caps2 == caps) {
1290     *size = trans->cache_caps2_size;
1291     GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1292     return TRUE;
1293   }
1294
1295   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1296   if (bclass->get_unit_size) {
1297     res = bclass->get_unit_size (trans, caps, size);
1298     GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1299         ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1300
1301     if (res) {
1302       /* and cache the values */
1303       if (trans->cache_caps1 == NULL) {
1304         gst_caps_replace (&trans->cache_caps1, caps);
1305         trans->cache_caps1_size = *size;
1306         GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1307       } else if (trans->cache_caps2 == NULL) {
1308         gst_caps_replace (&trans->cache_caps2, caps);
1309         trans->cache_caps2_size = *size;
1310         GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1311       } else {
1312         GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1313       }
1314     }
1315   } else {
1316     GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1317   }
1318   return res;
1319 }
1320
1321 /* your upstream peer wants to send you a buffer
1322  * that buffer has the given offset, size and caps
1323  * you're requested to allocate a buffer
1324  */
1325 static GstFlowReturn
1326 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1327     GstCaps * caps, GstBuffer ** buf)
1328 {
1329   GstBaseTransform *trans;
1330   GstBaseTransformPrivate *priv;
1331   GstFlowReturn res;
1332   gboolean proxy = FALSE, suggest = FALSE;
1333   GstCaps *sink_suggest;
1334   guint size_suggest = 0;
1335
1336   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1337   priv = trans->priv;
1338
1339   GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1340       size);
1341
1342   *buf = NULL;
1343
1344   /* we remember our previous alloc request to quickly see if we can proxy or
1345    * not. */
1346   if (caps && gst_caps_is_equal (priv->sink_alloc, caps)) {
1347     /* we have seen this before, see if we need to proxy */
1348     GST_DEBUG_OBJECT (trans, "have old caps");
1349     sink_suggest = caps;
1350     suggest = FALSE;
1351     res = GST_FLOW_OK;
1352   } else {
1353     GstCaps *temp, *othercaps;
1354     const GstCaps *templ;
1355     gboolean empty;
1356
1357     GST_DEBUG_OBJECT (trans, "new format %" GST_PTR_FORMAT, caps);
1358
1359     /* if we have a suggestion, pretend we got these as input */
1360     GST_OBJECT_LOCK (pad);
1361     if ((priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest))) {
1362       sink_suggest = gst_caps_ref (priv->sink_suggest);
1363       size_suggest = priv->size_suggest;
1364       GST_DEBUG_OBJECT (trans, "have suggestion %" GST_PTR_FORMAT,
1365           sink_suggest);
1366       suggest = TRUE;
1367     } else {
1368       GST_DEBUG_OBJECT (trans, "using caps %" GST_PTR_FORMAT, caps);
1369       sink_suggest = caps;
1370       suggest = FALSE;
1371     }
1372     GST_OBJECT_UNLOCK (pad);
1373
1374     /* check if we actually handle this format on the sinkpad */
1375     if (sink_suggest) {
1376       templ = gst_pad_get_pad_template_caps (pad);
1377       temp = gst_caps_intersect (sink_suggest, templ);
1378
1379       empty = gst_caps_is_empty (temp);
1380       gst_caps_unref (temp);
1381
1382       if (empty)
1383         goto not_supported;
1384     }
1385
1386     /* find the best format for the other side */
1387     if (sink_suggest == NULL) {
1388       /* always proxy when the caps are NULL. When this is a new format, see if
1389        * we can proxy it downstream */
1390       GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
1391       priv->proxy_alloc = TRUE;
1392     } else {
1393       othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
1394       if (!othercaps || gst_caps_is_empty (othercaps)) {
1395         /* no transform, can't proxy */
1396         GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
1397         priv->proxy_alloc = FALSE;
1398       } else {
1399         if (gst_caps_is_equal (caps, othercaps)) {
1400           GST_DEBUG_OBJECT (trans,
1401               "best caps same as input, marking for proxy");
1402           priv->proxy_alloc = TRUE;
1403         } else {
1404           GST_DEBUG_OBJECT (trans,
1405               "best caps different from input, disable proxy");
1406           priv->proxy_alloc = FALSE;
1407         }
1408       }
1409       if (othercaps)
1410         gst_caps_unref (othercaps);
1411     }
1412   }
1413   /* remember the new caps */
1414   gst_caps_replace (&priv->sink_alloc, sink_suggest);
1415   proxy = priv->proxy_alloc;
1416   GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d", proxy);
1417
1418   if (proxy) {
1419     GstCaps *newcaps;
1420
1421     GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %" GST_PTR_FORMAT
1422         ", size %u", caps, size);
1423
1424     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
1425     if (res != GST_FLOW_OK)
1426       goto alloc_failed;
1427
1428     /* check if the caps changed */
1429     newcaps = GST_BUFFER_CAPS (*buf);
1430
1431     GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
1432
1433     if (newcaps != caps) {
1434       GST_DEBUG_OBJECT (trans, "got new caps %" GST_PTR_FORMAT, newcaps);
1435       if (!suggest) {
1436         /* we have new caps, see if we can proxy downstream */
1437         if (gst_pad_peer_accept_caps (trans->sinkpad, newcaps)) {
1438           /* peer accepts the caps, return a buffer in this format */
1439           GST_DEBUG_OBJECT (trans, "peer accepted new caps");
1440           /* remember the format */
1441           gst_caps_replace (&priv->sink_alloc, newcaps);
1442         } else {
1443           GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
1444           /* peer does not accept the caps, create a buffer of the requested
1445            * format. */
1446           gst_buffer_unref (*buf);
1447           *buf = NULL;
1448         }
1449       }
1450     }
1451   }
1452   if (suggest) {
1453     *buf = gst_buffer_new_and_alloc (size_suggest);
1454     GST_DEBUG_OBJECT (trans,
1455         "doing suggestion of size %u, caps %" GST_PTR_FORMAT, size_suggest,
1456         sink_suggest);
1457     GST_BUFFER_CAPS (*buf) = sink_suggest;
1458     res = GST_FLOW_OK;
1459   }
1460
1461   gst_object_unref (trans);
1462
1463   return res;
1464
1465   /* ERRORS */
1466 alloc_failed:
1467   {
1468     GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
1469     if (suggest)
1470       gst_caps_unref (sink_suggest);
1471     gst_object_unref (trans);
1472     return res;
1473   }
1474 not_supported:
1475   {
1476     GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
1477     if (suggest)
1478       gst_caps_unref (sink_suggest);
1479     gst_object_unref (trans);
1480     return GST_FLOW_NOT_NEGOTIATED;
1481   }
1482 }
1483
1484 static gboolean
1485 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
1486 {
1487   GstBaseTransform *trans;
1488   GstBaseTransformClass *bclass;
1489   gboolean ret = TRUE;
1490   gboolean forward = TRUE;
1491
1492   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1493   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1494
1495   if (bclass->event)
1496     forward = bclass->event (trans, event);
1497
1498   /* FIXME, do this in the default event handler so the subclass can do
1499    * something different. */
1500   if (forward)
1501     ret = gst_pad_push_event (trans->srcpad, event);
1502   else
1503     gst_event_unref (event);
1504
1505   gst_object_unref (trans);
1506
1507   return ret;
1508 }
1509
1510 static gboolean
1511 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1512 {
1513   switch (GST_EVENT_TYPE (event)) {
1514     case GST_EVENT_FLUSH_START:
1515       break;
1516     case GST_EVENT_FLUSH_STOP:
1517       GST_OBJECT_LOCK (trans);
1518       /* reset QoS parameters */
1519       trans->priv->proportion = 1.0;
1520       trans->priv->earliest_time = -1;
1521       trans->priv->discont = FALSE;
1522       GST_OBJECT_UNLOCK (trans);
1523       /* we need new segment info after the flush. */
1524       trans->have_newsegment = FALSE;
1525       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1526       break;
1527     case GST_EVENT_EOS:
1528       break;
1529     case GST_EVENT_TAG:
1530       break;
1531     case GST_EVENT_NEWSEGMENT:
1532     {
1533       GstFormat format;
1534       gdouble rate, arate;
1535       gint64 start, stop, time;
1536       gboolean update;
1537
1538       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1539           &start, &stop, &time);
1540
1541       trans->have_newsegment = TRUE;
1542
1543       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
1544           format, start, stop, time);
1545
1546       if (format == GST_FORMAT_TIME) {
1547         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1548             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1549             ", accum %" GST_TIME_FORMAT,
1550             GST_TIME_ARGS (trans->segment.start),
1551             GST_TIME_ARGS (trans->segment.stop),
1552             GST_TIME_ARGS (trans->segment.time),
1553             GST_TIME_ARGS (trans->segment.accum));
1554       } else {
1555         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1556             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1557             ", accum %" G_GINT64_FORMAT,
1558             trans->segment.start, trans->segment.stop,
1559             trans->segment.time, trans->segment.accum);
1560       }
1561       break;
1562     }
1563     default:
1564       break;
1565   }
1566
1567   return TRUE;
1568 }
1569
1570 static gboolean
1571 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
1572 {
1573   GstBaseTransform *trans;
1574   GstBaseTransformClass *bclass;
1575   gboolean ret = TRUE;
1576
1577   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1578   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1579
1580   if (bclass->src_event)
1581     ret = bclass->src_event (trans, event);
1582
1583   gst_object_unref (trans);
1584
1585   return ret;
1586 }
1587
1588 static gboolean
1589 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1590 {
1591   gboolean ret;
1592
1593   switch (GST_EVENT_TYPE (event)) {
1594     case GST_EVENT_SEEK:
1595       break;
1596     case GST_EVENT_NAVIGATION:
1597       break;
1598     case GST_EVENT_QOS:
1599     {
1600       gdouble proportion;
1601       GstClockTimeDiff diff;
1602       GstClockTime timestamp;
1603
1604       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1605       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1606       break;
1607     }
1608     default:
1609       break;
1610   }
1611
1612   ret = gst_pad_push_event (trans->sinkpad, event);
1613
1614   return ret;
1615 }
1616
1617 /* perform a transform on @inbuf and put the result in @outbuf.
1618  *
1619  * This function is common to the push and pull-based operations.
1620  *
1621  * This function takes ownership of @inbuf */
1622 static GstFlowReturn
1623 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1624     GstBuffer ** outbuf)
1625 {
1626   GstBaseTransformClass *bclass;
1627   GstFlowReturn ret = GST_FLOW_OK;
1628   gboolean want_in_place;
1629   GstClockTime qostime;
1630
1631   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1632
1633   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1634     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1635         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1636         GST_BUFFER_OFFSET (inbuf));
1637   else
1638     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1639         inbuf, GST_BUFFER_SIZE (inbuf));
1640
1641   /* Don't allow buffer handling before negotiation, except in passthrough mode
1642    * or if the class doesn't implement a set_caps function (in which case it doesn't
1643    * care about caps)
1644    */
1645   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1646     goto not_negotiated;
1647
1648   /* Set discont flag so we can mark the outgoing buffer */
1649   if (GST_BUFFER_IS_DISCONT (inbuf)) {
1650     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
1651     trans->priv->discont = TRUE;
1652   }
1653
1654   /* can only do QoS if the segment is in TIME */
1655   if (trans->segment.format != GST_FORMAT_TIME)
1656     goto no_qos;
1657
1658   /* QOS is done on the running time of the buffer, get it now */
1659   qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1660       GST_BUFFER_TIMESTAMP (inbuf));
1661
1662   if (qostime != -1) {
1663     gboolean need_skip;
1664     GstClockTime earliest_time;
1665
1666     /* lock for getting the QoS parameters that are set (in a different thread)
1667      * with the QOS events */
1668     GST_OBJECT_LOCK (trans);
1669     earliest_time = trans->priv->earliest_time;
1670     /* check for QoS, don't perform conversion for buffers
1671      * that are known to be late. */
1672     need_skip = trans->priv->qos_enabled &&
1673         earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
1674     GST_OBJECT_UNLOCK (trans);
1675
1676     if (need_skip) {
1677       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1678           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1679           GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1680       /* mark discont for next buffer */
1681       trans->priv->discont = TRUE;
1682       goto skip;
1683     }
1684   }
1685
1686 no_qos:
1687
1688   /* first try to allocate an output buffer based on the currently negotiated
1689    * format. While we call pad-alloc we could renegotiate the srcpad format or
1690    * have a new suggestion for upstream buffer-alloc. 
1691    * In any case, outbuf will contain a buffer suitable for doing the configured
1692    * transform after this function. */
1693   ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
1694   if (G_UNLIKELY (ret != GST_FLOW_OK))
1695     goto no_buffer;
1696
1697   /* now perform the needed transform */
1698   if (trans->passthrough) {
1699     /* In passthrough mode, give transform_ip a look at the
1700      * buffer, without making it writable, or just push the
1701      * data through */
1702     if (bclass->transform_ip) {
1703       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
1704       ret = bclass->transform_ip (trans, *outbuf);
1705     } else {
1706       GST_DEBUG_OBJECT (trans, "element is in passthrough");
1707     }
1708   } else {
1709     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1710
1711     if (want_in_place) {
1712       GST_DEBUG_OBJECT (trans, "doing inplace transform");
1713
1714       if (inbuf != *outbuf) {
1715         /* different buffers, copy the input to the output first, we then do an
1716          * in-place transform on the output buffer. */
1717         memcpy (GST_BUFFER_DATA (*outbuf), GST_BUFFER_DATA (inbuf),
1718             GST_BUFFER_SIZE (inbuf));
1719       }
1720       ret = bclass->transform_ip (trans, *outbuf);
1721     } else {
1722       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
1723
1724       if (bclass->transform)
1725         ret = bclass->transform (trans, inbuf, *outbuf);
1726       else
1727         ret = GST_FLOW_NOT_SUPPORTED;
1728     }
1729   }
1730
1731 skip:
1732   /* only unref input buffer if we allocated a new outbuf buffer */
1733   if (*outbuf != inbuf)
1734     gst_buffer_unref (inbuf);
1735
1736   return ret;
1737
1738   /* ERRORS */
1739 not_negotiated:
1740   {
1741     gst_buffer_unref (inbuf);
1742     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1743         ("not negotiated"), ("not negotiated"));
1744     return GST_FLOW_NOT_NEGOTIATED;
1745   }
1746 no_buffer:
1747   {
1748     gst_buffer_unref (inbuf);
1749     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
1750         gst_flow_get_name (ret));
1751     return ret;
1752   }
1753 }
1754
1755 static gboolean
1756 gst_base_transform_check_get_range (GstPad * pad)
1757 {
1758   GstBaseTransform *trans;
1759   gboolean ret;
1760
1761   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1762
1763   ret = gst_pad_check_pull_range (trans->sinkpad);
1764
1765   gst_object_unref (trans);
1766
1767   return ret;
1768 }
1769
1770 /* FIXME, getrange is broken, need to pull range from the other
1771  * end based on the transform_size result.
1772  */
1773 static GstFlowReturn
1774 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1775     guint length, GstBuffer ** buffer)
1776 {
1777   GstBaseTransform *trans;
1778   GstFlowReturn ret;
1779   GstBuffer *inbuf;
1780
1781   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1782
1783   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1784   if (ret == GST_FLOW_OK) {
1785     ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1786   }
1787
1788   gst_object_unref (trans);
1789
1790   return ret;
1791 }
1792
1793 static GstFlowReturn
1794 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1795 {
1796   GstBaseTransform *trans;
1797   GstFlowReturn ret;
1798   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
1799   GstBuffer *outbuf = NULL;
1800
1801   trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
1802
1803   /* calculate end position of the incoming buffer */
1804   if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) {
1805     if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
1806       last_stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1807     else
1808       last_stop = GST_BUFFER_TIMESTAMP (buffer);
1809   }
1810
1811   /* protect transform method and concurrent buffer alloc */
1812   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1813
1814   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
1815    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
1816   if (outbuf != NULL) {
1817     if ((ret == GST_FLOW_OK)) {
1818       /* Remember last stop position */
1819       if ((last_stop != GST_CLOCK_TIME_NONE) &&
1820           (trans->segment.format == GST_FORMAT_TIME))
1821         gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
1822
1823       /* apply DISCONT flag if the buffer is not yet marked as such */
1824       if (trans->priv->discont) {
1825         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
1826           outbuf = gst_buffer_make_metadata_writable (outbuf);
1827           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1828         }
1829         trans->priv->discont = FALSE;
1830       }
1831       ret = gst_pad_push (trans->srcpad, outbuf);
1832     } else
1833       gst_buffer_unref (outbuf);
1834   }
1835
1836   /* convert internal flow to OK and mark discont for the next buffer. */
1837   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
1838     trans->priv->discont = TRUE;
1839     ret = GST_FLOW_OK;
1840   }
1841
1842   return ret;
1843 }
1844
1845 static void
1846 gst_base_transform_set_property (GObject * object, guint prop_id,
1847     const GValue * value, GParamSpec * pspec)
1848 {
1849   GstBaseTransform *trans;
1850
1851   trans = GST_BASE_TRANSFORM (object);
1852
1853   switch (prop_id) {
1854     case PROP_QOS:
1855       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
1856       break;
1857     default:
1858       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1859       break;
1860   }
1861 }
1862
1863 static void
1864 gst_base_transform_get_property (GObject * object, guint prop_id,
1865     GValue * value, GParamSpec * pspec)
1866 {
1867   GstBaseTransform *trans;
1868
1869   trans = GST_BASE_TRANSFORM (object);
1870
1871   switch (prop_id) {
1872     case PROP_QOS:
1873       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
1874       break;
1875     default:
1876       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1877       break;
1878   }
1879 }
1880
1881 /* not a vmethod of anything, just an internal method */
1882 static gboolean
1883 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
1884 {
1885   GstBaseTransformClass *bclass;
1886   gboolean result = TRUE;
1887
1888   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1889
1890   if (active) {
1891     if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
1892       result &= bclass->start (trans);
1893
1894     GST_OBJECT_LOCK (trans);
1895
1896     if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1897       trans->have_same_caps =
1898           gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1899           GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1900     else
1901       trans->have_same_caps = trans->passthrough;
1902     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1903     trans->negotiated = FALSE;
1904     trans->have_newsegment = FALSE;
1905     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1906     trans->priv->proportion = 1.0;
1907     trans->priv->earliest_time = -1;
1908     trans->priv->discont = FALSE;
1909     gst_caps_replace (&trans->priv->sink_suggest, NULL);
1910
1911     GST_OBJECT_UNLOCK (trans);
1912   } else {
1913     /* We must make sure streaming has finished before resetting things
1914      * and calling the ::stop vfunc */
1915     GST_PAD_STREAM_LOCK (trans->sinkpad);
1916     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
1917
1918     trans->have_same_caps = FALSE;
1919     /* We can only reset the passthrough mode if the instance told us to 
1920        handle it in configure_caps */
1921     if (bclass->passthrough_on_same_caps) {
1922       gst_base_transform_set_passthrough (trans, FALSE);
1923     }
1924     gst_caps_replace (&trans->cache_caps1, NULL);
1925     gst_caps_replace (&trans->cache_caps2, NULL);
1926     gst_caps_replace (&trans->priv->sink_alloc, NULL);
1927     gst_caps_replace (&trans->priv->sink_suggest, NULL);
1928
1929     if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
1930       result &= bclass->stop (trans);
1931   }
1932
1933   return result;
1934 }
1935
1936 static gboolean
1937 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1938 {
1939   gboolean result = TRUE;
1940   GstBaseTransform *trans;
1941
1942   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1943
1944   result = gst_base_transform_activate (trans, active);
1945
1946   if (result)
1947     trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
1948
1949   gst_object_unref (trans);
1950
1951   return result;
1952 }
1953
1954 static gboolean
1955 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1956 {
1957   gboolean result = FALSE;
1958   GstBaseTransform *trans;
1959
1960   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1961
1962   result = gst_pad_activate_pull (trans->sinkpad, active);
1963
1964   if (result)
1965     result &= gst_base_transform_activate (trans, active);
1966
1967   if (result)
1968     trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
1969
1970   gst_object_unref (trans);
1971
1972   return result;
1973 }
1974
1975 /**
1976  * gst_base_transform_set_passthrough:
1977  * @trans: the #GstBaseTransform to set
1978  * @passthrough: boolean indicating passthrough mode.
1979  *
1980  * Set passthrough mode for this filter by default. This is mostly
1981  * useful for filters that do not care about negotiation.
1982  *
1983  * Always TRUE for filters which don't implement either a transform
1984  * or transform_ip method.
1985  *
1986  * MT safe.
1987  */
1988 void
1989 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1990     gboolean passthrough)
1991 {
1992   GstBaseTransformClass *bclass;
1993
1994   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
1995
1996   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1997
1998   GST_OBJECT_LOCK (trans);
1999   if (passthrough == FALSE) {
2000     if (bclass->transform_ip || bclass->transform)
2001       trans->passthrough = FALSE;
2002   } else {
2003     trans->passthrough = TRUE;
2004   }
2005
2006   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2007   GST_OBJECT_UNLOCK (trans);
2008 }
2009
2010 /**
2011  * gst_base_transform_is_passthrough:
2012  * @trans: the #GstBaseTransform to query
2013  *
2014  * See if @trans is configured as a passthrough transform.
2015  *
2016  * Returns: TRUE is the transform is configured in passthrough mode.
2017  *
2018  * MT safe.
2019  */
2020 gboolean
2021 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2022 {
2023   gboolean result;
2024
2025   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2026
2027   GST_OBJECT_LOCK (trans);
2028   result = trans->passthrough;
2029   GST_OBJECT_UNLOCK (trans);
2030
2031   return result;
2032 }
2033
2034 /**
2035  * gst_base_transform_set_in_place:
2036  * @trans: the #GstBaseTransform to modify
2037  * @in_place: Boolean value indicating that we would like to operate
2038  * on in_place buffers.
2039  *
2040  * Determines whether a non-writable buffer will be copied before passing
2041  * to the transform_ip function.
2042  * <itemizedlist>
2043  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2044  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2045  * </itemizedlist>
2046  *
2047  * MT safe.
2048  */
2049 void
2050 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2051 {
2052   GstBaseTransformClass *bclass;
2053
2054   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2055
2056   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2057
2058   GST_OBJECT_LOCK (trans);
2059
2060   if (in_place) {
2061     if (bclass->transform_ip) {
2062       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2063       trans->always_in_place = TRUE;
2064     }
2065   } else {
2066     if (bclass->transform) {
2067       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2068       trans->always_in_place = FALSE;
2069     }
2070   }
2071
2072   GST_OBJECT_UNLOCK (trans);
2073 }
2074
2075 /**
2076  * gst_base_transform_is_in_place:
2077  * @trans: the #GstBaseTransform to query
2078  *
2079  * See if @trans is configured as a in_place transform.
2080  *
2081  * Returns: TRUE is the transform is configured in in_place mode.
2082  *
2083  * MT safe.
2084  */
2085 gboolean
2086 gst_base_transform_is_in_place (GstBaseTransform * trans)
2087 {
2088   gboolean result;
2089
2090   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2091
2092   GST_OBJECT_LOCK (trans);
2093   result = trans->always_in_place;
2094   GST_OBJECT_UNLOCK (trans);
2095
2096   return result;
2097 }
2098
2099 /**
2100  * gst_base_transform_update_qos:
2101  * @trans: a #GstBaseTransform
2102  * @proportion: the proportion
2103  * @diff: the diff against the clock
2104  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2105  * running_time.
2106  *
2107  * Set the QoS parameters in the transform. This function is called internally
2108  * when a QOS event is received but subclasses can provide custom information
2109  * when needed.
2110  *
2111  * Since: 0.10.5
2112  *
2113  * MT safe.
2114  */
2115 void
2116 gst_base_transform_update_qos (GstBaseTransform * trans,
2117     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2118 {
2119
2120   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2121
2122   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2123       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2124       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2125
2126   GST_OBJECT_LOCK (trans);
2127   trans->priv->proportion = proportion;
2128   trans->priv->earliest_time = timestamp + diff;
2129   GST_OBJECT_UNLOCK (trans);
2130 }
2131
2132 /**
2133  * gst_base_transform_set_qos_enabled:
2134  * @trans: a #GstBaseTransform
2135  * @enabled: new state
2136  *
2137  * Enable or disable QoS handling in the transform.
2138  *
2139  * Since: 0.10.5
2140  *
2141  * MT safe.
2142  */
2143 void
2144 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2145 {
2146   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2147
2148   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2149
2150   GST_OBJECT_LOCK (trans);
2151   trans->priv->qos_enabled = enabled;
2152   GST_OBJECT_UNLOCK (trans);
2153 }
2154
2155 /**
2156  * gst_base_transform_is_qos_enabled:
2157  * @trans: a #GstBaseTransform
2158  *
2159  * Queries if the transform will handle QoS.
2160  *
2161  * Returns: TRUE if QoS is enabled.
2162  *
2163  * Since: 0.10.5
2164  *
2165  * MT safe.
2166  */
2167 gboolean
2168 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2169 {
2170   gboolean result;
2171
2172   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2173
2174   GST_OBJECT_LOCK (trans);
2175   result = trans->priv->qos_enabled;
2176   GST_OBJECT_UNLOCK (trans);
2177
2178   return result;
2179 }
2180
2181 /**
2182  * gst_base_transform_set_gap_aware:
2183  * @trans: a #GstBaseTransform
2184  * @gap_aware: New state
2185  *
2186  * If @gap_aware is %FALSE (the default), output buffers will have the
2187  * %GST_BUFFER_FLAG_GAP flag unset.
2188  *
2189  * If set to %TRUE, the element must handle output buffers with this flag set
2190  * correctly, i.e. it can assume that the buffer contains neutral data but must
2191  * unset the flag if the output is no neutral data.
2192  *
2193  * Since: 0.10.16
2194  *
2195  * MT safe.
2196  */
2197 void
2198 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2199 {
2200   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2201
2202   GST_OBJECT_LOCK (trans);
2203   trans->priv->gap_aware = gap_aware;
2204   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2205   GST_OBJECT_UNLOCK (trans);
2206 }
2207
2208 /**
2209  * gst_base_transform_suggest:
2210  * @trans: a #GstBaseTransform
2211  * @gcaps: caps to suggest
2212  *
2213  * Instructs @trans to suggest new @caps upstream.
2214  *
2215  * Since: 0.10.21
2216  */
2217 void
2218 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
2219     guint size)
2220 {
2221   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2222
2223   GST_OBJECT_LOCK (trans->sinkpad);
2224   if (trans->priv->sink_suggest)
2225     gst_caps_unref (trans->priv->sink_suggest);
2226   trans->priv->sink_suggest = gst_caps_copy (caps);
2227   trans->priv->size_suggest = size;
2228   gst_caps_replace (&trans->priv->sink_alloc, NULL);
2229   GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
2230   GST_OBJECT_UNLOCK (trans->sinkpad);
2231 }
2232
2233 #if 0
2234 /**
2235  * gst_base_transform_reconfigure:
2236  * @trans: a #GstBaseTransform
2237  *
2238  * Instructs @trans to renegotiate a new downstream transform on the next
2239  * buffer.
2240  *
2241  * Note: Not yet implemented.
2242  *
2243  * Since: 0.10.21
2244  */
2245 void
2246 gst_base_transform_reconfigure (GstBaseTransform * trans)
2247 {
2248 }
2249 #endif