5c368255793272c3977d42d4862da6657b01745b
[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 "gstbasetransform.h"
211 #include <gst/gstmarshal.h>
212
213 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
214 #define GST_CAT_DEFAULT gst_base_transform_debug
215
216 /* BaseTransform signals and args */
217 enum
218 {
219   /* FILL ME */
220   LAST_SIGNAL
221 };
222
223 #define DEFAULT_PROP_QOS        FALSE
224
225 enum
226 {
227   PROP_0,
228   PROP_QOS
229 };
230
231 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
232     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
233
234 struct _GstBaseTransformPrivate
235 {
236   /* QoS *//* with LOCK */
237   gboolean qos_enabled;
238   gdouble proportion;
239   GstClockTime earliest_time;
240   /* previous buffer had a discont */
241   gboolean discont;
242
243   GstActivateMode pad_mode;
244
245   gboolean gap_aware;
246
247   /* caps used for allocating buffers */
248   gboolean proxy_alloc;
249   GstCaps *sink_alloc;
250   GstCaps *src_alloc;
251
252   /*
253    * This flag controls if basetransform should explicitly
254    * do a pad alloc when it receives a buffer even if it operates on
255    * passthrough, this is needed to check for downstream caps suggestions
256    * and this newly alloc'ed buffer is discarded.
257    *
258    * Without this flag basetransform would try a pad alloc whenever it
259    * gets a new buffer and pipelines like:
260    * "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
261    * Would have a 3 pad allocs for each buffer pushed downstream from the src.
262    *
263    * This flag is set to TRUE on start up, on setcaps and when a buffer is
264    * pushed downstream. It is set to FALSE after a pad alloc has been requested
265    * downstream.
266    * The rationale is that when a pad alloc flows through the pipeline, all
267    * basetransform elements on passthrough will avoid pad alloc'ing when they
268    * get the buffer.
269    */
270   gboolean force_alloc;
271
272   /* upstream caps and size suggestions */
273   GstCaps *sink_suggest;
274   guint size_suggest;
275   gboolean suggest_pending;
276
277   gboolean reconfigure;
278
279   /* QoS stats */
280   guint64 processed;
281   guint64 dropped;
282
283   GstClockTime last_stop_out;
284 };
285
286 static GstElementClass *parent_class = NULL;
287
288 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
289 static void gst_base_transform_init (GstBaseTransform * trans,
290     GstBaseTransformClass * klass);
291 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
292     * trans, GstBuffer * input, GstBuffer ** buf);
293
294 GType
295 gst_base_transform_get_type (void)
296 {
297   static volatile gsize base_transform_type = 0;
298
299   if (g_once_init_enter (&base_transform_type)) {
300     GType _type;
301     static const GTypeInfo base_transform_info = {
302       sizeof (GstBaseTransformClass),
303       NULL,
304       NULL,
305       (GClassInitFunc) gst_base_transform_class_init,
306       NULL,
307       NULL,
308       sizeof (GstBaseTransform),
309       0,
310       (GInstanceInitFunc) gst_base_transform_init,
311     };
312
313     _type = g_type_register_static (GST_TYPE_ELEMENT,
314         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
315     g_once_init_leave (&base_transform_type, _type);
316   }
317   return base_transform_type;
318 }
319
320 static void gst_base_transform_finalize (GObject * object);
321 static void gst_base_transform_set_property (GObject * object, guint prop_id,
322     const GValue * value, GParamSpec * pspec);
323 static void gst_base_transform_get_property (GObject * object, guint prop_id,
324     GValue * value, GParamSpec * pspec);
325 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
326     gboolean active);
327 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
328     gboolean active);
329 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
330     gboolean active);
331 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
332     GstCaps * caps, guint * size);
333
334 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
335 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
336     GstEvent * event);
337 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
338 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
339     GstEvent * event);
340 static gboolean gst_base_transform_check_get_range (GstPad * pad);
341 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
342     guint length, GstBuffer ** buffer);
343 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
344     GstBuffer * buffer);
345 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
346 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
347 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
348     GstPadDirection direction, GstCaps * caps);
349 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
350 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
351     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
352 static gboolean gst_base_transform_query (GstPad * pad, GstQuery * query);
353 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
354     GstPadDirection direction, GstQuery * query);
355 static const GstQueryType *gst_base_transform_query_type (GstPad * pad);
356
357 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
358
359 static void
360 gst_base_transform_finalize (GObject * object)
361 {
362   GstBaseTransform *trans;
363
364   trans = GST_BASE_TRANSFORM (object);
365
366   gst_caps_replace (&trans->priv->sink_suggest, NULL);
367   g_mutex_free (trans->transform_lock);
368
369   G_OBJECT_CLASS (parent_class)->finalize (object);
370 }
371
372 static void
373 gst_base_transform_class_init (GstBaseTransformClass * klass)
374 {
375   GObjectClass *gobject_class;
376
377   gobject_class = G_OBJECT_CLASS (klass);
378
379   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
380       "basetransform element");
381
382   GST_DEBUG ("gst_base_transform_class_init");
383
384   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
385
386   parent_class = g_type_class_peek_parent (klass);
387
388   gobject_class->set_property = gst_base_transform_set_property;
389   gobject_class->get_property = gst_base_transform_get_property;
390
391   g_object_class_install_property (gobject_class, PROP_QOS,
392       g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
393           DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
394
395   gobject_class->finalize = gst_base_transform_finalize;
396
397   klass->passthrough_on_same_caps = FALSE;
398   klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
399   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
400   klass->accept_caps =
401       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
402   klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
403 }
404
405 static void
406 gst_base_transform_init (GstBaseTransform * trans,
407     GstBaseTransformClass * bclass)
408 {
409   GstPadTemplate *pad_template;
410
411   GST_DEBUG ("gst_base_transform_init");
412
413   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
414
415   pad_template =
416       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
417   g_return_if_fail (pad_template != NULL);
418   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
419   gst_pad_set_getcaps_function (trans->sinkpad,
420       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
421   gst_pad_set_acceptcaps_function (trans->sinkpad,
422       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
423   gst_pad_set_setcaps_function (trans->sinkpad,
424       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
425   gst_pad_set_event_function (trans->sinkpad,
426       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
427   gst_pad_set_chain_function (trans->sinkpad,
428       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
429   gst_pad_set_activatepush_function (trans->sinkpad,
430       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
431   gst_pad_set_bufferalloc_function (trans->sinkpad,
432       GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
433   gst_pad_set_query_function (trans->sinkpad,
434       GST_DEBUG_FUNCPTR (gst_base_transform_query));
435   gst_pad_set_query_type_function (trans->sinkpad,
436       GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
437   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
438
439   pad_template =
440       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
441   g_return_if_fail (pad_template != NULL);
442   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
443   gst_pad_set_getcaps_function (trans->srcpad,
444       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
445   gst_pad_set_acceptcaps_function (trans->srcpad,
446       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
447   gst_pad_set_event_function (trans->srcpad,
448       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
449   gst_pad_set_checkgetrange_function (trans->srcpad,
450       GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
451   gst_pad_set_getrange_function (trans->srcpad,
452       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
453   gst_pad_set_activatepull_function (trans->srcpad,
454       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
455   gst_pad_set_query_function (trans->srcpad,
456       GST_DEBUG_FUNCPTR (gst_base_transform_query));
457   gst_pad_set_query_type_function (trans->srcpad,
458       GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
459   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
460
461   trans->transform_lock = g_mutex_new ();
462   trans->pending_configure = FALSE;
463   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
464   trans->cache_caps1 = NULL;
465   trans->cache_caps2 = NULL;
466   trans->priv->pad_mode = GST_ACTIVATE_NONE;
467   trans->priv->gap_aware = FALSE;
468
469   trans->passthrough = FALSE;
470   if (bclass->transform == NULL) {
471     /* If no transform function, always_in_place is TRUE */
472     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
473     trans->always_in_place = TRUE;
474
475     if (bclass->transform_ip == NULL) {
476       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
477       trans->passthrough = TRUE;
478     }
479   }
480
481   trans->priv->processed = 0;
482   trans->priv->dropped = 0;
483   trans->priv->force_alloc = TRUE;
484 }
485
486 /* given @caps on the src or sink pad (given by @direction)
487  * calculate the possible caps on the other pad.
488  *
489  * Returns new caps, unref after usage.
490  */
491 static GstCaps *
492 gst_base_transform_transform_caps (GstBaseTransform * trans,
493     GstPadDirection direction, GstCaps * caps)
494 {
495   GstCaps *ret;
496   GstBaseTransformClass *klass;
497
498   if (caps == NULL)
499     return NULL;
500
501   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
502
503   /* if there is a custom transform function, use this */
504   if (klass->transform_caps) {
505     GstCaps *temp;
506     gint i;
507
508     /* start with empty caps */
509     ret = gst_caps_new_empty ();
510     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
511
512     if (gst_caps_is_any (caps)) {
513       /* for any caps we still have to call the transform function */
514       GST_DEBUG_OBJECT (trans, "from: ANY");
515       temp = klass->transform_caps (trans, direction, caps);
516       GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);
517
518       temp = gst_caps_make_writable (temp);
519       gst_caps_append (ret, temp);
520     } else {
521       gint n = gst_caps_get_size (caps);
522       /* we send caps with just one structure to the transform
523        * function as this is easier for the element */
524       for (i = 0; i < n; i++) {
525         GstCaps *nth;
526
527         nth = gst_caps_copy_nth (caps, i);
528         GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
529         temp = klass->transform_caps (trans, direction, nth);
530         gst_caps_unref (nth);
531         GST_LOG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
532
533         temp = gst_caps_make_writable (temp);
534
535         /* here we need to only append those structures, that are not yet
536          * in there, we use the merge function for this */
537         gst_caps_merge (ret, temp);
538
539         GST_LOG_OBJECT (trans, "  merged[%d]: %" GST_PTR_FORMAT, i, ret);
540       }
541       GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
542       /* FIXME: we can't do much simplification here because we don't really want to
543        * change the caps order
544        gst_caps_do_simplify (ret);
545        GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
546        */
547     }
548   } else {
549     GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
550     /* no transform function, use the identity transform */
551     ret = gst_caps_ref (caps);
552   }
553
554   GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
555       ret);
556
557   return ret;
558 }
559
560 /* transform a buffer of @size with @caps on the pad with @direction to
561  * the size of a buffer with @othercaps and store the result in @othersize
562  *
563  * We have two ways of doing this:
564  *  1) use a custom transform size function, this is for complicated custom
565  *     cases with no fixed unit_size.
566  *  2) use the unit_size functions where there is a relationship between the
567  *     caps and the size of a buffer.
568  */
569 static gboolean
570 gst_base_transform_transform_size (GstBaseTransform * trans,
571     GstPadDirection direction, GstCaps * caps,
572     guint size, GstCaps * othercaps, guint * othersize)
573 {
574   guint inunitsize, outunitsize, units;
575   GstBaseTransformClass *klass;
576   gboolean ret;
577
578   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
579
580   GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
581       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
582       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
583
584   if (klass->transform_size) {
585     /* if there is a custom transform function, use this */
586     ret = klass->transform_size (trans, direction, caps, size, othercaps,
587         othersize);
588   } else if (klass->get_unit_size == NULL) {
589     /* if there is no transform_size and no unit_size, it means the
590      * element does not modify the size of a buffer */
591     *othersize = size;
592     ret = TRUE;
593   } else {
594     /* there is no transform_size function, we have to use the unit_size
595      * functions. This method assumes there is a fixed unit_size associated with
596      * each caps. We provide the same amount of units on both sides. */
597     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
598       goto no_in_size;
599
600     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
601         inunitsize);
602
603     /* input size must be a multiple of the unit_size of the input caps */
604     if (inunitsize == 0 || (size % inunitsize != 0))
605       goto no_multiple;
606
607     /* get the amount of units */
608     units = size / inunitsize;
609
610     /* now get the unit size of the output */
611     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
612       goto no_out_size;
613
614     /* the output size is the unit_size times the amount of units on the
615      * input */
616     *othersize = units * outunitsize;
617     GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
618
619     ret = TRUE;
620   }
621   return ret;
622
623   /* ERRORS */
624 no_in_size:
625   {
626     GST_DEBUG_OBJECT (trans, "could not get in_size");
627     g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
628     return FALSE;
629   }
630 no_multiple:
631   {
632     GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
633         inunitsize);
634     g_warning ("%s: size %u is not a multiple of unit size %u",
635         GST_ELEMENT_NAME (trans), size, inunitsize);
636     return FALSE;
637   }
638 no_out_size:
639   {
640     GST_DEBUG_OBJECT (trans, "could not get out_size");
641     g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
642     return FALSE;
643   }
644 }
645
646 /* get the caps that can be handled by @pad. We perform:
647  *
648  *  - take the caps of peer of otherpad,
649  *  - filter against the padtemplate of otherpad, 
650  *  - calculate all transforms of remaining caps
651  *  - filter against template of @pad
652  *
653  * If there is no peer, we simply return the caps of the padtemplate of pad.
654  */
655 static GstCaps *
656 gst_base_transform_getcaps (GstPad * pad)
657 {
658   GstBaseTransform *trans;
659   GstPad *otherpad;
660   const GstCaps *templ;
661   GstCaps *peercaps, *caps, *temp;
662
663   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
664
665   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
666
667   /* we can do what the peer can */
668   peercaps = gst_pad_peer_get_caps_reffed (otherpad);
669   if (peercaps) {
670     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
671
672     /* filtered against our padtemplate on the other side */
673     templ = gst_pad_get_pad_template_caps (otherpad);
674     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
675     temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
676     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
677   } else {
678     temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
679     GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
680         temp);
681   }
682
683   /* then see what we can transform this to */
684   caps = gst_base_transform_transform_caps (trans,
685       GST_PAD_DIRECTION (otherpad), temp);
686   GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
687   gst_caps_unref (temp);
688   if (caps == NULL)
689     goto done;
690
691   /* and filter against the template of this pad */
692   templ = gst_pad_get_pad_template_caps (pad);
693   GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
694   /* We keep the caps sorted like the returned caps */
695   temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
696   GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
697   gst_caps_unref (caps);
698   caps = temp;
699
700   if (peercaps) {
701     /* Now try if we can put the untransformed downstream caps first */
702     temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
703     if (!gst_caps_is_empty (temp)) {
704       gst_caps_merge (temp, caps);
705       caps = temp;
706     } else {
707       gst_caps_unref (temp);
708     }
709   }
710
711 done:
712   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
713
714   if (peercaps)
715     gst_caps_unref (peercaps);
716
717   gst_object_unref (trans);
718
719   return caps;
720 }
721
722 /* function triggered when the in and out caps are negotiated and need
723  * to be configured in the subclass. */
724 static gboolean
725 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
726     GstCaps * out)
727 {
728   gboolean ret = TRUE;
729   GstBaseTransformClass *klass;
730
731   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
732
733   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
734   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
735
736   /* clear the cache */
737   gst_caps_replace (&trans->cache_caps1, NULL);
738   gst_caps_replace (&trans->cache_caps2, NULL);
739
740   /* figure out same caps state */
741   trans->have_same_caps = gst_caps_is_equal (in, out);
742   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
743
744   /* If we've a transform_ip method and same input/output caps, set in_place
745    * by default. If for some reason the sub-class prefers using a transform
746    * function, it can clear the in place flag in the set_caps */
747   gst_base_transform_set_in_place (trans,
748       klass->transform_ip && trans->have_same_caps);
749
750   /* Set the passthrough if the class wants passthrough_on_same_caps
751    * and we have the same caps on each pad */
752   if (klass->passthrough_on_same_caps)
753     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
754
755   /* now configure the element with the caps */
756   if (klass->set_caps) {
757     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
758     ret = klass->set_caps (trans, in, out);
759   }
760
761   GST_OBJECT_LOCK (trans);
762   /* make sure we reevaluate how the buffer_alloc works wrt to proxy allocating
763    * the buffer. FIXME, this triggers some quite heavy codepaths that don't need
764    * to be taken.. */
765   trans->priv->suggest_pending = TRUE;
766   GST_OBJECT_UNLOCK (trans);
767   trans->negotiated = ret;
768
769   return ret;
770 }
771
772 /* check if caps @in on @pad can be transformed to @out on the other pad.
773  * We don't have a vmethod to test this yet so we have to do a somewhat less
774  * efficient check for this.
775  */
776 static gboolean
777 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
778     GstCaps * in, GstCaps * out)
779 {
780   GstCaps *othercaps;
781
782   /* convert the in caps to all possible out caps */
783   othercaps =
784       gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
785
786   /* check if transform is empty */
787   if (!othercaps || gst_caps_is_empty (othercaps))
788     goto no_transform;
789
790   /* check if the out caps is a subset of the othercaps */
791   if (!gst_caps_can_intersect (out, othercaps))
792     goto no_subset;
793
794   if (othercaps)
795     gst_caps_unref (othercaps);
796
797   GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
798   GST_DEBUG_OBJECT (trans, "to   %" GST_PTR_FORMAT, out);
799
800   return TRUE;
801
802   /* ERRORS */
803 no_transform:
804   {
805     GST_DEBUG_OBJECT (trans,
806         "transform returned useless %" GST_PTR_FORMAT, othercaps);
807     if (othercaps)
808       gst_caps_unref (othercaps);
809     return FALSE;
810   }
811 no_subset:
812   {
813     GST_DEBUG_OBJECT (trans, "no subset");
814     if (othercaps)
815       gst_caps_unref (othercaps);
816     return FALSE;
817   }
818 }
819
820 /* given a fixed @caps on @pad, create the best possible caps for the
821  * other pad.
822  * @caps must be fixed when calling this function.
823  *
824  * This function calls the transform caps vmethod of the basetransform to figure
825  * out the possible target formats. It then tries to select the best format from
826  * this list by:
827  *
828  * - attempt passthrough if the target caps is a superset of the input caps
829  * - fixating by using peer caps
830  * - fixating with transform fixate function
831  * - fixating with pad fixate functions.
832  *
833  * this function returns a caps that can be transformed into and is accepted by
834  * the peer element.
835  */
836 static GstCaps *
837 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
838     GstCaps * caps)
839 {
840   GstBaseTransformClass *klass;
841   GstPad *otherpad, *otherpeer;
842   GstCaps *othercaps;
843   gboolean peer_checked = FALSE;
844   gboolean is_fixed;
845
846   /* caps must be fixed here, this is a programming error if it's not */
847   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
848
849   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
850
851   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
852   otherpeer = gst_pad_get_peer (otherpad);
853
854   /* see how we can transform the input caps. We need to do this even for
855    * passthrough because it might be possible that this element cannot support
856    * passthrough at all. */
857   othercaps = gst_base_transform_transform_caps (trans,
858       GST_PAD_DIRECTION (pad), caps);
859
860   /* The caps we can actually output is the intersection of the transformed
861    * caps with the pad template for the pad */
862   if (othercaps) {
863     GstCaps *intersect;
864     const GstCaps *templ_caps;
865
866     templ_caps = gst_pad_get_pad_template_caps (otherpad);
867     GST_DEBUG_OBJECT (trans,
868         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
869
870     intersect =
871         gst_caps_intersect_full (othercaps, templ_caps,
872         GST_CAPS_INTERSECT_FIRST);
873
874     gst_caps_unref (othercaps);
875     othercaps = intersect;
876   }
877
878   /* check if transform is empty */
879   if (!othercaps || gst_caps_is_empty (othercaps))
880     goto no_transform;
881
882   /* if the othercaps are not fixed, we need to fixate them, first attempt
883    * is by attempting passthrough if the othercaps are a superset of caps. */
884   /* FIXME. maybe the caps is not fixed because it has multiple structures of
885    * fixed caps */
886   is_fixed = gst_caps_is_fixed (othercaps);
887   if (!is_fixed) {
888     GST_DEBUG_OBJECT (trans,
889         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
890
891     /* see if the target caps are a superset of the source caps, in this
892      * case we can try to perform passthrough */
893     if (gst_caps_can_intersect (othercaps, caps)) {
894       GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
895       if (otherpeer) {
896         /* try passthrough. we know it's fixed, because caps is fixed */
897         if (gst_pad_accept_caps (otherpeer, caps)) {
898           GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
899           /* peer accepted unmodified caps, we free the original non-fixed
900            * caps and work with the passthrough caps */
901           gst_caps_unref (othercaps);
902           othercaps = gst_caps_ref (caps);
903           is_fixed = TRUE;
904           /* mark that we checked othercaps with the peer, this
905            * makes sure we don't call accept_caps again with these same
906            * caps */
907           peer_checked = TRUE;
908         } else {
909           GST_DEBUG_OBJECT (trans,
910               "peer did not accept %" GST_PTR_FORMAT, caps);
911         }
912       } else {
913         GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
914         gst_caps_unref (othercaps);
915         othercaps = gst_caps_ref (caps);
916         is_fixed = TRUE;
917       }
918     }
919   }
920
921   /* second attempt at fixation is done by intersecting with
922    * the peer caps */
923   if (!is_fixed && otherpeer) {
924     /* intersect against what the peer can do */
925     GstCaps *peercaps;
926     GstCaps *intersect;
927
928     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
929
930     peercaps = gst_pad_get_caps_reffed (otherpeer);
931     intersect = gst_caps_intersect (peercaps, othercaps);
932     gst_caps_unref (peercaps);
933     gst_caps_unref (othercaps);
934     othercaps = intersect;
935     peer_checked = FALSE;
936
937     is_fixed = gst_caps_is_fixed (othercaps);
938
939     GST_DEBUG_OBJECT (trans,
940         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
941   }
942
943   if (gst_caps_is_empty (othercaps))
944     goto no_transform_possible;
945
946   /* third attempt at fixation, call the fixate vmethod and
947    * ultimately call the pad fixate function. */
948   if (!is_fixed) {
949     GST_DEBUG_OBJECT (trans,
950         "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
951         othercaps, GST_DEBUG_PAD_NAME (otherpad));
952
953     /* since we have no other way to fixate left, we might as well just take
954      * the first of the caps list and fixate that */
955
956     /* FIXME: when fixating using the vmethod, it might make sense to fixate
957      * each of the caps; but Wim doesn't see a use case for that yet */
958     gst_caps_truncate (othercaps);
959     peer_checked = FALSE;
960
961     if (klass->fixate_caps) {
962       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
963           " using caps %" GST_PTR_FORMAT
964           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
965           GST_DEBUG_PAD_NAME (otherpad));
966       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
967       is_fixed = gst_caps_is_fixed (othercaps);
968     }
969     /* if still not fixed, no other option but to let the default pad fixate
970      * function do its job */
971     if (!is_fixed) {
972       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
973           " on pad %s:%s using gst_pad_fixate_caps", othercaps,
974           GST_DEBUG_PAD_NAME (otherpad));
975       gst_pad_fixate_caps (otherpad, othercaps);
976       is_fixed = gst_caps_is_fixed (othercaps);
977     }
978     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
979   } else {
980     GST_DEBUG ("caps are fixed");
981     /* else caps are fixed but the subclass may want to add fields */
982     if (klass->fixate_caps) {
983       othercaps = gst_caps_make_writable (othercaps);
984
985       GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
986           " using caps %" GST_PTR_FORMAT
987           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
988           GST_DEBUG_PAD_NAME (otherpad));
989
990       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
991       is_fixed = gst_caps_is_fixed (othercaps);
992     }
993   }
994
995   /* caps should be fixed now, if not we have to fail. */
996   if (!is_fixed)
997     goto could_not_fixate;
998
999   /* and peer should accept, don't check again if we already checked the
1000    * othercaps against the peer. */
1001   if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
1002     goto peer_no_accept;
1003
1004   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1005       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1006
1007   if (otherpeer)
1008     gst_object_unref (otherpeer);
1009
1010   return othercaps;
1011
1012   /* ERRORS */
1013 no_transform:
1014   {
1015     GST_DEBUG_OBJECT (trans,
1016         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
1017     goto error_cleanup;
1018   }
1019 no_transform_possible:
1020   {
1021     GST_DEBUG_OBJECT (trans,
1022         "transform could not transform %" GST_PTR_FORMAT
1023         " in anything we support", caps);
1024     goto error_cleanup;
1025   }
1026 could_not_fixate:
1027   {
1028     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1029     goto error_cleanup;
1030   }
1031 peer_no_accept:
1032   {
1033     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1034         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1035     goto error_cleanup;
1036   }
1037 error_cleanup:
1038   {
1039     if (otherpeer)
1040       gst_object_unref (otherpeer);
1041     if (othercaps)
1042       gst_caps_unref (othercaps);
1043     return NULL;
1044   }
1045 }
1046
1047 static gboolean
1048 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1049     GstPadDirection direction, GstCaps * caps)
1050 {
1051 #if 0
1052   GstPad *otherpad;
1053   GstCaps *othercaps = NULL;
1054 #endif
1055   gboolean ret = TRUE;
1056
1057 #if 0
1058   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1059
1060   /* we need fixed caps for the check, fall back to the default implementation
1061    * if we don't */
1062   if (!gst_caps_is_fixed (caps))
1063 #endif
1064   {
1065     GstCaps *allowed;
1066
1067     GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1068
1069     /* get all the formats we can handle on this pad */
1070     if (direction == GST_PAD_SRC)
1071       allowed = gst_pad_get_caps_reffed (trans->srcpad);
1072     else
1073       allowed = gst_pad_get_caps_reffed (trans->sinkpad);
1074
1075     if (!allowed) {
1076       GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1077       goto no_transform_possible;
1078     }
1079
1080     GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1081
1082     /* intersect with the requested format */
1083     ret = gst_caps_can_intersect (allowed, caps);
1084     gst_caps_unref (allowed);
1085
1086     if (!ret)
1087       goto no_transform_possible;
1088   }
1089 #if 0
1090   else {
1091     GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1092
1093     /* find best possible caps for the other pad as a way to see if we can
1094      * transform this caps. */
1095     othercaps = gst_base_transform_find_transform (trans, pad, caps);
1096     if (!othercaps || gst_caps_is_empty (othercaps))
1097       goto no_transform_possible;
1098
1099     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1100   }
1101 #endif
1102
1103 done:
1104 #if 0
1105   /* We know it's always NULL since we never use it */
1106   if (othercaps)
1107     gst_caps_unref (othercaps);
1108 #endif
1109
1110   return ret;
1111
1112   /* ERRORS */
1113 no_transform_possible:
1114   {
1115     GST_DEBUG_OBJECT (trans,
1116         "transform could not transform %" GST_PTR_FORMAT
1117         " in anything we support", caps);
1118     ret = FALSE;
1119     goto done;
1120   }
1121 }
1122
1123 static gboolean
1124 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1125 {
1126   gboolean ret = TRUE;
1127   GstBaseTransform *trans;
1128   GstBaseTransformClass *bclass;
1129
1130   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1131   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1132
1133   if (bclass->accept_caps)
1134     ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1135
1136   gst_object_unref (trans);
1137
1138   return ret;
1139 }
1140
1141 /* called when new caps arrive on the sink or source pad,
1142  * We try to find the best caps for the other side using our _find_transform()
1143  * function. If there are caps, we configure the transform for this new
1144  * transformation.
1145  *
1146  * FIXME, this function is currently commutative but this should not really be
1147  * because we never set caps starting from the srcpad.
1148  */
1149 static gboolean
1150 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1151 {
1152   GstBaseTransform *trans;
1153   GstPad *otherpad, *otherpeer;
1154   GstCaps *othercaps = NULL;
1155   gboolean ret = TRUE;
1156   GstCaps *incaps, *outcaps;
1157
1158   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1159
1160   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1161   otherpeer = gst_pad_get_peer (otherpad);
1162
1163   /* if we get called recursively, we bail out now to avoid an
1164    * infinite loop. */
1165   if (GST_PAD_IS_IN_SETCAPS (otherpad))
1166     goto done;
1167
1168   GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1169
1170   /* find best possible caps for the other pad */
1171   othercaps = gst_base_transform_find_transform (trans, pad, caps);
1172   if (!othercaps || gst_caps_is_empty (othercaps))
1173     goto no_transform_possible;
1174
1175   /* configure the element now */
1176   /* make sure in and out caps are correct */
1177   if (pad == trans->sinkpad) {
1178     incaps = caps;
1179     outcaps = othercaps;
1180   } else {
1181     incaps = othercaps;
1182     outcaps = caps;
1183   }
1184
1185   /* if we have the same caps, we can optimize and reuse the input caps */
1186   if (gst_caps_is_equal (incaps, outcaps)) {
1187     GST_INFO_OBJECT (trans, "reuse caps");
1188     gst_caps_unref (othercaps);
1189     outcaps = othercaps = gst_caps_ref (incaps);
1190   }
1191
1192   /* call configure now */
1193   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1194     goto failed_configure;
1195
1196   /* we know this will work, we implement the setcaps */
1197   gst_pad_set_caps (otherpad, othercaps);
1198
1199   if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1200     /* FIXME hm? */
1201     ret &= gst_pad_set_caps (otherpeer, othercaps);
1202     if (!ret) {
1203       GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1204           othercaps);
1205     }
1206   }
1207
1208 done:
1209   /* new caps, force alloc on next buffer on the chain */
1210   trans->priv->force_alloc = TRUE;
1211   if (otherpeer)
1212     gst_object_unref (otherpeer);
1213   if (othercaps)
1214     gst_caps_unref (othercaps);
1215
1216   trans->negotiated = ret;
1217
1218   gst_object_unref (trans);
1219
1220   return ret;
1221
1222   /* ERRORS */
1223 no_transform_possible:
1224   {
1225     GST_WARNING_OBJECT (trans,
1226         "transform could not transform %" GST_PTR_FORMAT
1227         " in anything we support", caps);
1228     ret = FALSE;
1229     goto done;
1230   }
1231 failed_configure:
1232   {
1233     GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1234         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1235     ret = FALSE;
1236     goto done;
1237   }
1238 }
1239
1240 static gboolean
1241 gst_base_transform_default_query (GstBaseTransform * trans,
1242     GstPadDirection direction, GstQuery * query)
1243 {
1244   gboolean ret = FALSE;
1245   GstPad *otherpad;
1246
1247   otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1248
1249   switch (GST_QUERY_TYPE (query)) {
1250     case GST_QUERY_POSITION:{
1251       GstFormat format;
1252
1253       gst_query_parse_position (query, &format, NULL);
1254       if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1255         gint64 pos;
1256         ret = TRUE;
1257
1258         if ((direction == GST_PAD_SINK)
1259             || (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
1260           pos =
1261               gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1262               trans->segment.last_stop);
1263         } else {
1264           pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1265               trans->priv->last_stop_out);
1266         }
1267         gst_query_set_position (query, format, pos);
1268       } else {
1269         ret = gst_pad_peer_query (otherpad, query);
1270       }
1271       break;
1272     }
1273     default:
1274       ret = gst_pad_peer_query (otherpad, query);
1275       break;
1276   }
1277
1278   return ret;
1279 }
1280
1281 static gboolean
1282 gst_base_transform_query (GstPad * pad, GstQuery * query)
1283 {
1284   GstBaseTransform *trans;
1285   GstBaseTransformClass *bclass;
1286   gboolean ret;
1287
1288   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1289   if (G_UNLIKELY (trans == NULL))
1290     return FALSE;
1291
1292   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1293
1294   if (bclass->query)
1295     ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1296   else
1297     ret = gst_pad_query_default (pad, query);
1298
1299   gst_object_unref (trans);
1300
1301   return ret;
1302 }
1303
1304 static const GstQueryType *
1305 gst_base_transform_query_type (GstPad * pad)
1306 {
1307   static const GstQueryType types[] = {
1308     GST_QUERY_POSITION,
1309     GST_QUERY_NONE
1310   };
1311
1312   return types;
1313 }
1314
1315 static void
1316 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1317     GstCaps * caps)
1318 {
1319   GstCaps *othercaps;
1320   GstBaseTransformPrivate *priv = trans->priv;
1321
1322   GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1323
1324   /* we cannot convert the current buffer but we might be able to suggest a
1325    * new format upstream, try to find what the best format is. */
1326   othercaps = gst_base_transform_find_transform (trans, trans->srcpad, caps);
1327
1328   if (!othercaps) {
1329     GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1330     /* we received caps that we cannot transform. Upstream is behaving badly
1331      * because it should have checked if we could handle these caps. We can
1332      * simply ignore these caps and produce a buffer with our original caps. */
1333   } else {
1334     guint size_suggest;
1335
1336     GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1337
1338     /* not a subset, we have a new upstream suggestion, remember it and
1339      * allocate a default buffer. First we try to convert the size */
1340     if (gst_base_transform_transform_size (trans,
1341             GST_PAD_SRC, caps, expsize, othercaps, &size_suggest)) {
1342
1343       /* ok, remember the suggestions now */
1344       GST_DEBUG_OBJECT (trans,
1345           "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1346           size_suggest, othercaps);
1347
1348       GST_OBJECT_LOCK (trans->sinkpad);
1349       if (priv->sink_suggest)
1350         gst_caps_unref (priv->sink_suggest);
1351       priv->sink_suggest = gst_caps_ref (othercaps);
1352       priv->size_suggest = size_suggest;
1353       trans->priv->suggest_pending = TRUE;
1354       GST_OBJECT_UNLOCK (trans->sinkpad);
1355     }
1356     gst_caps_unref (othercaps);
1357   }
1358 }
1359
1360 /* Allocate a buffer using gst_pad_alloc_buffer
1361  *
1362  * This function can do renegotiation on the source pad
1363  *
1364  * The output buffer is always writable. outbuf can be equal to
1365  * inbuf, the caller should be prepared for this and perform 
1366  * appropriate refcounting.
1367  */
1368 static GstFlowReturn
1369 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1370     GstBuffer * in_buf, GstBuffer ** out_buf)
1371 {
1372   GstBaseTransformClass *bclass;
1373   GstBaseTransformPrivate *priv;
1374   GstFlowReturn ret = GST_FLOW_OK;
1375   guint outsize, newsize, expsize;
1376   gboolean discard, setcaps, copymeta;
1377   GstCaps *incaps, *oldcaps, *newcaps, *outcaps;
1378
1379   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1380
1381   priv = trans->priv;
1382
1383   *out_buf = NULL;
1384
1385   /* figure out how to allocate a buffer based on the current configuration */
1386   if (trans->passthrough) {
1387     GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1388     /* passthrough, we don't really need to call pad alloc but we still need to
1389      * in order to get upstream negotiation. The output size is the same as the
1390      * input size. */
1391     outsize = GST_BUFFER_SIZE (in_buf);
1392     /* we always alloc and discard here */
1393     discard = TRUE;
1394   } else {
1395     gboolean want_in_place = (bclass->transform_ip != NULL)
1396         && trans->always_in_place;
1397
1398     if (want_in_place) {
1399       GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1400       /* we alloc a buffer of the same size as the input */
1401       outsize = GST_BUFFER_SIZE (in_buf);
1402       /* only discard it when the input was not writable, otherwise, we reuse
1403        * the input buffer. */
1404       discard = gst_buffer_is_writable (in_buf);
1405       GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1406     } else {
1407       GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1408       /* copy transform, figure out the output size */
1409       if (!gst_base_transform_transform_size (trans,
1410               GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1411               GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1412               &outsize)) {
1413         goto unknown_size;
1414       }
1415       /* never discard this buffer, we need it for storing the output */
1416       discard = FALSE;
1417     }
1418   }
1419
1420   oldcaps = GST_PAD_CAPS (trans->srcpad);
1421
1422   if (bclass->prepare_output_buffer) {
1423     GST_DEBUG_OBJECT (trans,
1424         "calling prepare buffer with caps %p %" GST_PTR_FORMAT, oldcaps,
1425         oldcaps);
1426     ret =
1427         bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1428         out_buf);
1429
1430     /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1431      * update the pad caps if it wants */
1432     oldcaps = GST_PAD_CAPS (trans->srcpad);
1433
1434     /* FIXME 0.11:
1435      * decrease refcount again if vmethod returned refcounted in_buf. This
1436      * is because we need to make sure that the buffer is writable for the
1437      * in_place transform. The docs of the vmethod say that you should return
1438      * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1439     if (in_buf == *out_buf)
1440       gst_buffer_unref (in_buf);
1441
1442     /* never discard the buffer from the prepare_buffer method */
1443     if (*out_buf != NULL)
1444       discard = FALSE;
1445   }
1446
1447   if (ret != GST_FLOW_OK)
1448     goto alloc_failed;
1449
1450   if (*out_buf == NULL) {
1451     if (trans->passthrough && !trans->priv->force_alloc) {
1452       GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
1453       *out_buf = gst_buffer_ref (in_buf);
1454     } else {
1455       GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
1456           oldcaps);
1457
1458       ret = gst_pad_alloc_buffer (trans->srcpad,
1459           GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1460       if (ret != GST_FLOW_OK)
1461         goto alloc_failed;
1462     }
1463   }
1464
1465   /* must always have a buffer by now */
1466   if (*out_buf == NULL)
1467     goto no_buffer;
1468
1469   /* check if we got different caps on this new output buffer */
1470   newcaps = GST_BUFFER_CAPS (*out_buf);
1471   newsize = GST_BUFFER_SIZE (*out_buf);
1472
1473   if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1474     GstCaps *othercaps;
1475     gboolean can_convert;
1476
1477     GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1478
1479     incaps = GST_PAD_CAPS (trans->sinkpad);
1480
1481     /* check if we can convert the current incaps to the new target caps */
1482     can_convert =
1483         gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1484         newcaps);
1485
1486     if (!can_convert) {
1487       GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1488
1489       gst_base_transform_transform_size (trans,
1490           GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1491
1492       compute_upstream_suggestion (trans, expsize, newcaps);
1493
1494       /* we got a suggested caps but we can't transform to it. See if there is
1495        * another downstream format that we can transform to */
1496       othercaps =
1497           gst_base_transform_find_transform (trans, trans->sinkpad, incaps);
1498
1499       if (othercaps && !gst_caps_is_empty (othercaps)) {
1500         GST_DEBUG_OBJECT (trans, "we found target caps %" GST_PTR_FORMAT,
1501             othercaps);
1502         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1503         gst_buffer_set_caps (*out_buf, othercaps);
1504         gst_caps_unref (othercaps);
1505         newcaps = GST_BUFFER_CAPS (*out_buf);
1506         can_convert = TRUE;
1507       } else if (othercaps)
1508         gst_caps_unref (othercaps);
1509     }
1510
1511     /* it's possible that the buffer we got is of the wrong size, get the
1512      * expected size here, we will check the size if we are going to use the
1513      * buffer later on. */
1514     gst_base_transform_transform_size (trans,
1515         GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1516
1517     if (can_convert) {
1518       GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1519
1520       /* subclass might want to add fields to the caps */
1521       if (bclass->fixate_caps != NULL) {
1522         newcaps = gst_caps_copy (newcaps);
1523
1524         GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1525             " using caps %" GST_PTR_FORMAT
1526             " on pad %s:%s using fixate_caps vmethod", newcaps, incaps,
1527             GST_DEBUG_PAD_NAME (trans->srcpad));
1528         bclass->fixate_caps (trans, GST_PAD_SINK, incaps, newcaps);
1529
1530         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1531         gst_buffer_set_caps (*out_buf, newcaps);
1532         gst_caps_unref (newcaps);
1533         newcaps = GST_BUFFER_CAPS (*out_buf);
1534       }
1535
1536       /* caps not empty, try to renegotiate to the new format */
1537       if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1538         /* not sure we need to fail hard here, we can simply continue our
1539          * conversion with what we negotiated before */
1540         goto failed_configure;
1541       }
1542       /* new format configure, and use the new output buffer */
1543       gst_pad_set_caps (trans->srcpad, newcaps);
1544       discard = FALSE;
1545       /* clear previous cached sink-pad caps, so buffer_alloc knows that
1546        * it needs to revisit the decision about whether to proxy or not: */
1547       gst_caps_replace (&priv->sink_alloc, NULL);
1548       /* if we got a buffer of the wrong size, discard it now and make sure we
1549        * allocate a properly sized buffer later. */
1550       if (newsize != expsize) {
1551         if (in_buf != *out_buf)
1552           gst_buffer_unref (*out_buf);
1553         *out_buf = NULL;
1554       }
1555       outsize = expsize;
1556     } else {
1557       compute_upstream_suggestion (trans, expsize, newcaps);
1558
1559       if (in_buf != *out_buf)
1560         gst_buffer_unref (*out_buf);
1561       *out_buf = NULL;
1562     }
1563   } else if (outsize != newsize) {
1564     GST_WARNING_OBJECT (trans, "Caps did not change but allocated size does "
1565         "not match expected size (%d != %d)", newsize, outsize);
1566     if (in_buf != *out_buf)
1567       gst_buffer_unref (*out_buf);
1568     *out_buf = NULL;
1569   }
1570
1571   /* these are the final output caps */
1572   outcaps = GST_PAD_CAPS (trans->srcpad);
1573
1574   copymeta = FALSE;
1575   if (*out_buf == NULL) {
1576     if (!discard) {
1577       GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1578           outsize);
1579       /* no valid buffer yet, make one, metadata is writable */
1580       *out_buf = gst_buffer_new_and_alloc (outsize);
1581       gst_buffer_copy_metadata (*out_buf, in_buf,
1582           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1583     } else {
1584       GST_DEBUG_OBJECT (trans, "reuse input buffer");
1585       *out_buf = in_buf;
1586     }
1587   } else {
1588     if (trans->passthrough && in_buf != *out_buf) {
1589       /* we are asked to perform a passthrough transform but the input and
1590        * output buffers are different. We have to discard the output buffer and
1591        * reuse the input buffer. */
1592       GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1593       discard = TRUE;
1594     }
1595     if (discard) {
1596       GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1597       gst_buffer_unref (*out_buf);
1598       *out_buf = in_buf;
1599     } else {
1600       GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", in_buf,
1601           *out_buf);
1602       /* if we have different buffers, check if the metadata is ok */
1603       if (*out_buf != in_buf) {
1604         guint mask;
1605
1606         mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
1607             GST_BUFFER_FLAG_DELTA_UNIT | GST_BUFFER_FLAG_DISCONT |
1608             GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_MEDIA1 |
1609             GST_BUFFER_FLAG_MEDIA2 | GST_BUFFER_FLAG_MEDIA3;
1610         /* see if the flags and timestamps match */
1611         copymeta =
1612             (GST_MINI_OBJECT_FLAGS (*out_buf) & mask) ==
1613             (GST_MINI_OBJECT_FLAGS (in_buf) & mask);
1614         copymeta |=
1615             GST_BUFFER_TIMESTAMP (*out_buf) != GST_BUFFER_TIMESTAMP (in_buf) ||
1616             GST_BUFFER_DURATION (*out_buf) != GST_BUFFER_DURATION (in_buf) ||
1617             GST_BUFFER_OFFSET (*out_buf) != GST_BUFFER_OFFSET (in_buf) ||
1618             GST_BUFFER_OFFSET_END (*out_buf) != GST_BUFFER_OFFSET_END (in_buf);
1619       }
1620     }
1621   }
1622
1623   /* check if we need to make things writable. We need this when we need to
1624    * update the caps or the metadata on the output buffer. */
1625   newcaps = GST_BUFFER_CAPS (*out_buf);
1626   /* we check the pointers as a quick check and then go to the more involved
1627    * check. This is needed when we receive different pointers on the sinkpad
1628    * that mean the same caps. What we then want to do is prefer those caps over
1629    * the ones on the srcpad and set the srcpad caps to the buffer caps */
1630   setcaps = !newcaps || ((newcaps != outcaps)
1631       && (!gst_caps_is_equal (newcaps, outcaps)));
1632   /* we need to modify the metadata when the element is not gap aware,
1633    * passthrough is not used and the gap flag is set */
1634   copymeta |= !trans->priv->gap_aware && !trans->passthrough
1635       && (GST_MINI_OBJECT_FLAGS (*out_buf) & GST_BUFFER_FLAG_GAP);
1636
1637   if (setcaps || copymeta) {
1638     GST_DEBUG_OBJECT (trans, "setcaps %d, copymeta %d", setcaps, copymeta);
1639     if (!gst_buffer_is_metadata_writable (*out_buf)) {
1640       GST_DEBUG_OBJECT (trans, "buffer metadata %p not writable", *out_buf);
1641       if (in_buf == *out_buf)
1642         *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
1643       else
1644         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1645     }
1646     /* when we get here, the metadata should be writable */
1647     if (setcaps)
1648       gst_buffer_set_caps (*out_buf, outcaps);
1649     if (copymeta)
1650       gst_buffer_copy_metadata (*out_buf, in_buf,
1651           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1652     /* clear the GAP flag when the subclass does not understand it */
1653     if (!trans->priv->gap_aware)
1654       GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1655   }
1656
1657   return ret;
1658
1659   /* ERRORS */
1660 alloc_failed:
1661   {
1662     GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1663     return ret;
1664   }
1665 no_buffer:
1666   {
1667     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1668         ("Sub-class failed to provide an output buffer"), (NULL));
1669     return GST_FLOW_ERROR;
1670   }
1671 unknown_size:
1672   {
1673     GST_ERROR_OBJECT (trans, "unknown output size");
1674     return GST_FLOW_ERROR;
1675   }
1676 failed_configure:
1677   {
1678     GST_WARNING_OBJECT (trans, "failed to configure caps");
1679     return GST_FLOW_NOT_NEGOTIATED;
1680   }
1681 }
1682
1683 /* Given @caps calcultate the size of one unit.
1684  *
1685  * For video caps, this is the size of one frame (and thus one buffer).
1686  * For audio caps, this is the size of one sample.
1687  *
1688  * These values are cached since they do not change and the calculation
1689  * potentially involves parsing caps and other expensive stuff.
1690  *
1691  * We have two cache locations to store the size, one for the source caps
1692  * and one for the sink caps.
1693  *
1694  * this function returns FALSE if no size could be calculated.
1695  */
1696 static gboolean
1697 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1698     guint * size)
1699 {
1700   gboolean res = FALSE;
1701   GstBaseTransformClass *bclass;
1702
1703   /* see if we have the result cached */
1704   if (trans->cache_caps1 == caps) {
1705     *size = trans->cache_caps1_size;
1706     GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1707     return TRUE;
1708   }
1709   if (trans->cache_caps2 == caps) {
1710     *size = trans->cache_caps2_size;
1711     GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1712     return TRUE;
1713   }
1714
1715   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1716   if (bclass->get_unit_size) {
1717     res = bclass->get_unit_size (trans, caps, size);
1718     GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1719         ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1720
1721     if (res) {
1722       /* and cache the values */
1723       if (trans->cache_caps1 == NULL) {
1724         gst_caps_replace (&trans->cache_caps1, caps);
1725         trans->cache_caps1_size = *size;
1726         GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1727       } else if (trans->cache_caps2 == NULL) {
1728         gst_caps_replace (&trans->cache_caps2, caps);
1729         trans->cache_caps2_size = *size;
1730         GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1731       } else {
1732         GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1733       }
1734     }
1735   } else {
1736     GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1737   }
1738   return res;
1739 }
1740
1741 /* your upstream peer wants to send you a buffer
1742  * that buffer has the given offset, size and caps
1743  * you're requested to allocate a buffer
1744  */
1745 static GstFlowReturn
1746 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1747     GstCaps * caps, GstBuffer ** buf)
1748 {
1749   GstBaseTransform *trans;
1750   GstBaseTransformClass *klass;
1751   GstBaseTransformPrivate *priv;
1752   GstFlowReturn res;
1753   gboolean alloced = FALSE;
1754   gboolean proxy, suggest, same_caps;
1755   GstCaps *sink_suggest = NULL;
1756   guint size_suggest;
1757
1758   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1759   if (G_UNLIKELY (trans == NULL))
1760     return GST_FLOW_WRONG_STATE;
1761   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1762   priv = trans->priv;
1763
1764   GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1765       caps, caps, size);
1766
1767   /* if the code below does not come up with a better buffer, we will return _OK
1768    * and an empty buffer. This will trigger the core to allocate a buffer with
1769    * given input size and caps. */
1770   *buf = NULL;
1771   res = GST_FLOW_OK;
1772
1773   /* we remember our previous alloc request to quickly see if we can proxy or
1774    * not. We skip this check if we have a pending suggestion. */
1775   GST_OBJECT_LOCK (pad);
1776   same_caps = !priv->suggest_pending && caps &&
1777       gst_caps_is_equal (priv->sink_alloc, caps);
1778   GST_OBJECT_UNLOCK (pad);
1779
1780   if (same_caps) {
1781     /* we have seen this before, see below if we need to proxy */
1782     GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1783     gst_caps_replace (&sink_suggest, caps);
1784     size_suggest = size;
1785     suggest = FALSE;
1786   } else {
1787     GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1788
1789     /* if we have a suggestion, pretend we got these as input */
1790     GST_OBJECT_LOCK (pad);
1791     if ((priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest))) {
1792       sink_suggest = gst_caps_ref (priv->sink_suggest);
1793       size_suggest = priv->size_suggest;
1794       GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1795           sink_suggest, sink_suggest, priv->size_suggest);
1796       /* suggest is TRUE when we have a custom suggestion pending that we need
1797        * to unref later. */
1798       suggest = TRUE;
1799     } else {
1800       GST_DEBUG_OBJECT (trans, "using caps %p %" GST_PTR_FORMAT " size %u",
1801           caps, caps, size);
1802       gst_caps_replace (&sink_suggest, caps);
1803       size_suggest = size;
1804       suggest = FALSE;
1805     }
1806     priv->suggest_pending = FALSE;
1807     GST_OBJECT_UNLOCK (pad);
1808
1809     /* check if we actually handle this format on the sinkpad */
1810     if (sink_suggest) {
1811       const GstCaps *templ;
1812
1813       if (!gst_caps_is_fixed (sink_suggest)) {
1814         GstCaps *peercaps;
1815
1816         GST_DEBUG_OBJECT (trans, "Suggested caps is not fixed: %"
1817             GST_PTR_FORMAT, sink_suggest);
1818
1819         peercaps =
1820             gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1821         /* try fixating by intersecting with peer caps */
1822         if (peercaps) {
1823           GstCaps *intersect;
1824
1825           intersect =
1826               gst_caps_intersect_full (sink_suggest, peercaps,
1827               GST_CAPS_INTERSECT_FIRST);
1828           gst_caps_unref (peercaps);
1829           gst_caps_unref (sink_suggest);
1830           sink_suggest = intersect;
1831         }
1832
1833         if (gst_caps_is_empty (sink_suggest))
1834           goto not_supported;
1835
1836         /* try the alloc caps if it is still not fixed */
1837         if (!gst_caps_is_fixed (sink_suggest)) {
1838           GstCaps *intersect;
1839
1840           GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1841               "with the non-fixed caps suggestion");
1842           intersect =
1843               gst_caps_intersect_full (sink_suggest, caps,
1844               GST_CAPS_INTERSECT_FIRST);
1845           if (!gst_caps_is_empty (intersect)) {
1846             GST_DEBUG_OBJECT (trans, "It is, using it");
1847             gst_caps_replace (&sink_suggest, caps);
1848           }
1849           gst_caps_unref (intersect);
1850         }
1851
1852         /* be safe and call default fixate */
1853         sink_suggest = gst_caps_make_writable (sink_suggest);
1854         gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1855
1856         if (!gst_caps_is_fixed (sink_suggest)) {
1857           gst_caps_unref (sink_suggest);
1858           sink_suggest = NULL;
1859         }
1860
1861         GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1862             sink_suggest);
1863       }
1864
1865       if (sink_suggest) {
1866         templ = gst_pad_get_pad_template_caps (pad);
1867
1868         if (!gst_caps_can_intersect (sink_suggest, templ)) {
1869           GstCaps *allowed;
1870           GstCaps *peercaps;
1871
1872           GST_DEBUG_OBJECT (trans,
1873               "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1874               sink_suggest);
1875           /* the requested pad alloc caps are not supported, so let's try
1876            * picking something allowed between the pads (they are linked,
1877            * there must be something) */
1878           allowed = gst_pad_get_allowed_caps (pad);
1879           if (allowed && !gst_caps_is_empty (allowed)) {
1880             GST_DEBUG_OBJECT (trans,
1881                 "pads could agree on one of the following caps: " "%"
1882                 GST_PTR_FORMAT, allowed);
1883             allowed = gst_caps_make_writable (allowed);
1884
1885             if (klass->fixate_caps) {
1886               peercaps =
1887                   gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1888               klass->fixate_caps (trans, GST_PAD_SRC, peercaps, allowed);
1889               gst_caps_unref (peercaps);
1890             }
1891
1892             /* Fixate them to be safe if the subclass didn't do it */
1893             gst_caps_truncate (allowed);
1894             gst_pad_fixate_caps (pad, allowed);
1895             gst_caps_replace (&sink_suggest, allowed);
1896             gst_caps_unref (allowed);
1897
1898             suggest = TRUE;
1899
1900             GST_DEBUG_OBJECT (trans, "Fixated suggestion caps to %"
1901                 GST_PTR_FORMAT, sink_suggest);
1902           } else {
1903             if (allowed)
1904               gst_caps_unref (allowed);
1905             goto not_supported;
1906           }
1907         }
1908       }
1909     }
1910
1911     /* find the best format for the other side here we decide if we will proxy
1912      * the caps or not. */
1913     if (sink_suggest == NULL) {
1914       /* always proxy when the caps are NULL. When this is a new format, see if
1915        * we can proxy it downstream */
1916       GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
1917       priv->proxy_alloc = TRUE;
1918     } else {
1919       GstCaps *othercaps;
1920
1921       /* we have a new format, see what we need to proxy to */
1922       othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
1923       if (!othercaps || gst_caps_is_empty (othercaps)) {
1924         /* no transform possible, we certainly can't proxy */
1925         GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
1926         priv->proxy_alloc = FALSE;
1927       } else {
1928         /* we transformed into something */
1929         if (gst_caps_is_equal (sink_suggest, othercaps)) {
1930           GST_DEBUG_OBJECT (trans,
1931               "best caps same as input, marking for proxy");
1932           priv->proxy_alloc = TRUE;
1933         } else {
1934           GST_DEBUG_OBJECT (trans,
1935               "best caps different from input, disable proxy");
1936           priv->proxy_alloc = FALSE;
1937         }
1938       }
1939       if (othercaps)
1940         gst_caps_unref (othercaps);
1941     }
1942   }
1943   /* remember the new caps */
1944   GST_OBJECT_LOCK (pad);
1945   gst_caps_replace (&priv->sink_alloc, sink_suggest);
1946   GST_OBJECT_UNLOCK (pad);
1947
1948   proxy = priv->proxy_alloc;
1949   GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
1950       suggest);
1951
1952   /* we only want to proxy if we have no suggestion pending, FIXME */
1953   if (proxy && !suggest) {
1954     GstCaps *newcaps;
1955
1956     GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
1957         ", size %u", caps, caps, size);
1958
1959     /* we always proxy the input caps, never the suggestion. The reason is that
1960      * We don't yet handle the caps of renegotiation in here. FIXME */
1961     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
1962     if (res != GST_FLOW_OK)
1963       goto alloc_failed;
1964     alloced = TRUE;
1965
1966     /* check if the caps changed */
1967     newcaps = GST_BUFFER_CAPS (*buf);
1968
1969     GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
1970
1971     if (!gst_caps_is_equal (newcaps, caps)) {
1972       GST_DEBUG_OBJECT (trans, "caps are new");
1973       /* we have new caps, see if we can proxy downstream */
1974       if (gst_pad_peer_accept_caps (pad, newcaps)) {
1975         /* peer accepts the caps, return a buffer in this format */
1976         GST_DEBUG_OBJECT (trans, "peer accepted new caps");
1977         /* remember the format */
1978         GST_OBJECT_LOCK (pad);
1979         gst_caps_replace (&priv->sink_alloc, newcaps);
1980         GST_OBJECT_UNLOCK (pad);
1981       } else {
1982         GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
1983         /* peer does not accept the caps, disable proxy_alloc, free the
1984          * buffer we received and create a buffer of the requested format
1985          * by the default handler. */
1986         GST_DEBUG_OBJECT (trans, "disabling proxy");
1987         priv->proxy_alloc = FALSE;
1988         gst_buffer_unref (*buf);
1989         *buf = NULL;
1990       }
1991     } else {
1992       GST_DEBUG_OBJECT (trans, "received required caps from peer");
1993     }
1994   }
1995
1996   if (suggest) {
1997     /* there was a custom suggestion, create a buffer of this format and return
1998      * it. Note that this format  */
1999     *buf = gst_buffer_new_and_alloc (size_suggest);
2000     GST_DEBUG_OBJECT (trans,
2001         "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2002         sink_suggest, sink_suggest);
2003     GST_BUFFER_CAPS (*buf) = sink_suggest;
2004     sink_suggest = NULL;
2005   }
2006
2007   if (sink_suggest)
2008     gst_caps_unref (sink_suggest);
2009
2010   if (res == GST_FLOW_OK && alloced) {
2011     /* just alloc'ed a buffer, so we only want to do this again if we
2012      * received a buffer */
2013     GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2014     trans->priv->force_alloc = FALSE;
2015   }
2016
2017   gst_object_unref (trans);
2018   return res;
2019
2020   /* ERRORS */
2021 alloc_failed:
2022   {
2023     GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2024     if (sink_suggest)
2025       gst_caps_unref (sink_suggest);
2026     gst_object_unref (trans);
2027     return res;
2028   }
2029 not_supported:
2030   {
2031     GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2032     if (sink_suggest)
2033       gst_caps_unref (sink_suggest);
2034     gst_object_unref (trans);
2035     return GST_FLOW_NOT_NEGOTIATED;
2036   }
2037 }
2038
2039 static gboolean
2040 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2041 {
2042   GstBaseTransform *trans;
2043   GstBaseTransformClass *bclass;
2044   gboolean ret = TRUE;
2045   gboolean forward = TRUE;
2046
2047   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2048   if (G_UNLIKELY (trans == NULL)) {
2049     gst_event_unref (event);
2050     return FALSE;
2051   }
2052   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2053
2054   if (bclass->event)
2055     forward = bclass->event (trans, event);
2056
2057   /* FIXME, do this in the default event handler so the subclass can do
2058    * something different. */
2059   if (forward)
2060     ret = gst_pad_push_event (trans->srcpad, event);
2061   else
2062     gst_event_unref (event);
2063
2064   gst_object_unref (trans);
2065
2066   return ret;
2067 }
2068
2069 static gboolean
2070 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2071 {
2072   switch (GST_EVENT_TYPE (event)) {
2073     case GST_EVENT_FLUSH_START:
2074       break;
2075     case GST_EVENT_FLUSH_STOP:
2076       GST_OBJECT_LOCK (trans);
2077       /* reset QoS parameters */
2078       trans->priv->proportion = 1.0;
2079       trans->priv->earliest_time = -1;
2080       trans->priv->discont = FALSE;
2081       trans->priv->processed = 0;
2082       trans->priv->dropped = 0;
2083       GST_OBJECT_UNLOCK (trans);
2084       /* we need new segment info after the flush. */
2085       trans->have_newsegment = FALSE;
2086       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2087       trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2088       break;
2089     case GST_EVENT_EOS:
2090       break;
2091     case GST_EVENT_TAG:
2092       break;
2093     case GST_EVENT_NEWSEGMENT:
2094     {
2095       GstFormat format;
2096       gdouble rate, arate;
2097       gint64 start, stop, time;
2098       gboolean update;
2099
2100       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2101           &start, &stop, &time);
2102
2103       trans->have_newsegment = TRUE;
2104
2105       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2106           format, start, stop, time);
2107
2108       if (format == GST_FORMAT_TIME) {
2109         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2110             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2111             ", accum %" GST_TIME_FORMAT,
2112             GST_TIME_ARGS (trans->segment.start),
2113             GST_TIME_ARGS (trans->segment.stop),
2114             GST_TIME_ARGS (trans->segment.time),
2115             GST_TIME_ARGS (trans->segment.accum));
2116       } else {
2117         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2118             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2119             ", accum %" G_GINT64_FORMAT,
2120             trans->segment.start, trans->segment.stop,
2121             trans->segment.time, trans->segment.accum);
2122       }
2123       break;
2124     }
2125     default:
2126       break;
2127   }
2128
2129   return TRUE;
2130 }
2131
2132 static gboolean
2133 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2134 {
2135   GstBaseTransform *trans;
2136   GstBaseTransformClass *bclass;
2137   gboolean ret = TRUE;
2138
2139   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2140   if (G_UNLIKELY (trans == NULL)) {
2141     gst_event_unref (event);
2142     return FALSE;
2143   }
2144
2145   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2146
2147   if (bclass->src_event)
2148     ret = bclass->src_event (trans, event);
2149   else
2150     gst_event_unref (event);
2151
2152   gst_object_unref (trans);
2153
2154   return ret;
2155 }
2156
2157 static gboolean
2158 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2159 {
2160   gboolean ret;
2161
2162   GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2163
2164   switch (GST_EVENT_TYPE (event)) {
2165     case GST_EVENT_SEEK:
2166       break;
2167     case GST_EVENT_NAVIGATION:
2168       break;
2169     case GST_EVENT_QOS:
2170     {
2171       gdouble proportion;
2172       GstClockTimeDiff diff;
2173       GstClockTime timestamp;
2174
2175       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
2176       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2177       break;
2178     }
2179     default:
2180       break;
2181   }
2182
2183   ret = gst_pad_push_event (trans->sinkpad, event);
2184
2185   return ret;
2186 }
2187
2188 /* perform a transform on @inbuf and put the result in @outbuf.
2189  *
2190  * This function is common to the push and pull-based operations.
2191  *
2192  * This function takes ownership of @inbuf */
2193 static GstFlowReturn
2194 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2195     GstBuffer ** outbuf)
2196 {
2197   GstBaseTransformClass *bclass;
2198   GstFlowReturn ret = GST_FLOW_OK;
2199   gboolean want_in_place, reconfigure;
2200   GstClockTime running_time;
2201   GstClockTime timestamp;
2202   GstCaps *incaps;
2203
2204   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2205
2206   if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2207     GST_OBJECT_LOCK (trans);
2208     reconfigure = trans->priv->reconfigure;
2209     trans->priv->reconfigure = FALSE;
2210     GST_OBJECT_UNLOCK (trans);
2211
2212     if (G_UNLIKELY (reconfigure)) {
2213       GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2214       /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2215        * will reconfigure the transform with the new output format. We can only
2216        * do this if the buffer actually has caps. */
2217       if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2218         goto not_negotiated;
2219     }
2220   }
2221
2222   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2223     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2224         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2225         GST_BUFFER_OFFSET (inbuf));
2226   else
2227     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2228         inbuf, GST_BUFFER_SIZE (inbuf));
2229
2230   /* Don't allow buffer handling before negotiation, except in passthrough mode
2231    * or if the class doesn't implement a set_caps function (in which case it doesn't
2232    * care about caps)
2233    */
2234   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2235     goto not_negotiated;
2236
2237   /* Set discont flag so we can mark the outgoing buffer */
2238   if (GST_BUFFER_IS_DISCONT (inbuf)) {
2239     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2240     trans->priv->discont = TRUE;
2241   }
2242
2243   /* can only do QoS if the segment is in TIME */
2244   if (trans->segment.format != GST_FORMAT_TIME)
2245     goto no_qos;
2246
2247   /* QOS is done on the running time of the buffer, get it now */
2248   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2249   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2250       timestamp);
2251
2252   if (running_time != -1) {
2253     gboolean need_skip;
2254     GstClockTime earliest_time;
2255     gdouble proportion;
2256
2257     /* lock for getting the QoS parameters that are set (in a different thread)
2258      * with the QOS events */
2259     GST_OBJECT_LOCK (trans);
2260     earliest_time = trans->priv->earliest_time;
2261     proportion = trans->priv->proportion;
2262     /* check for QoS, don't perform conversion for buffers
2263      * that are known to be late. */
2264     need_skip = trans->priv->qos_enabled &&
2265         earliest_time != -1 && running_time <= earliest_time;
2266     GST_OBJECT_UNLOCK (trans);
2267
2268     if (need_skip) {
2269       GstMessage *qos_msg;
2270       GstClockTime duration;
2271       guint64 stream_time;
2272       gint64 jitter;
2273
2274       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2275           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2276           GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2277
2278       trans->priv->dropped++;
2279
2280       duration = GST_BUFFER_DURATION (inbuf);
2281       stream_time =
2282           gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2283           timestamp);
2284       jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2285
2286       qos_msg =
2287           gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2288           stream_time, timestamp, duration);
2289       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2290       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2291           trans->priv->processed, trans->priv->dropped);
2292       gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2293
2294       /* mark discont for next buffer */
2295       trans->priv->discont = TRUE;
2296       goto skip;
2297     }
2298   }
2299
2300 no_qos:
2301
2302   /* first try to allocate an output buffer based on the currently negotiated
2303    * format. While we call pad-alloc we could renegotiate the srcpad format or
2304    * have a new suggestion for upstream buffer-alloc. 
2305    * In any case, outbuf will contain a buffer suitable for doing the configured
2306    * transform after this function. */
2307   ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2308   if (G_UNLIKELY (ret != GST_FLOW_OK))
2309     goto no_buffer;
2310
2311   /* now perform the needed transform */
2312   if (trans->passthrough) {
2313     /* In passthrough mode, give transform_ip a look at the
2314      * buffer, without making it writable, or just push the
2315      * data through */
2316     if (bclass->transform_ip) {
2317       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2318       ret = bclass->transform_ip (trans, *outbuf);
2319     } else {
2320       GST_DEBUG_OBJECT (trans, "element is in passthrough");
2321     }
2322   } else {
2323     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2324
2325     if (want_in_place) {
2326       GST_DEBUG_OBJECT (trans, "doing inplace transform");
2327
2328       if (inbuf != *outbuf) {
2329         guint8 *indata, *outdata;
2330
2331         /* Different buffer. The data can still be the same when we are dealing
2332          * with subbuffers of the same buffer. Note that because of the FIXME in
2333          * prepare_output_buffer() we have decreased the refcounts of inbuf and
2334          * outbuf to keep them writable */
2335         indata = GST_BUFFER_DATA (inbuf);
2336         outdata = GST_BUFFER_DATA (*outbuf);
2337
2338         if (indata != outdata)
2339           memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2340       }
2341       ret = bclass->transform_ip (trans, *outbuf);
2342     } else {
2343       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2344
2345       if (bclass->transform)
2346         ret = bclass->transform (trans, inbuf, *outbuf);
2347       else
2348         ret = GST_FLOW_NOT_SUPPORTED;
2349     }
2350   }
2351
2352 skip:
2353   /* only unref input buffer if we allocated a new outbuf buffer */
2354   if (*outbuf != inbuf)
2355     gst_buffer_unref (inbuf);
2356
2357   /* pushed a buffer, we can now try an alloc */
2358   GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2359   trans->priv->force_alloc = TRUE;
2360   return ret;
2361
2362   /* ERRORS */
2363 not_negotiated:
2364   {
2365     gst_buffer_unref (inbuf);
2366     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2367         ("not negotiated"), ("not negotiated"));
2368     return GST_FLOW_NOT_NEGOTIATED;
2369   }
2370 no_buffer:
2371   {
2372     gst_buffer_unref (inbuf);
2373     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2374         gst_flow_get_name (ret));
2375     return ret;
2376   }
2377 }
2378
2379 static gboolean
2380 gst_base_transform_check_get_range (GstPad * pad)
2381 {
2382   GstBaseTransform *trans;
2383   gboolean ret;
2384
2385   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2386
2387   ret = gst_pad_check_pull_range (trans->sinkpad);
2388
2389   gst_object_unref (trans);
2390
2391   return ret;
2392 }
2393
2394 /* FIXME, getrange is broken, need to pull range from the other
2395  * end based on the transform_size result.
2396  */
2397 static GstFlowReturn
2398 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2399     guint length, GstBuffer ** buffer)
2400 {
2401   GstBaseTransform *trans;
2402   GstBaseTransformClass *klass;
2403   GstFlowReturn ret;
2404   GstBuffer *inbuf;
2405
2406   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2407
2408   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2409   if (G_UNLIKELY (ret != GST_FLOW_OK))
2410     goto pull_error;
2411
2412   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2413   if (klass->before_transform)
2414     klass->before_transform (trans, inbuf);
2415
2416   GST_BASE_TRANSFORM_LOCK (trans);
2417   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2418   GST_BASE_TRANSFORM_UNLOCK (trans);
2419
2420 done:
2421   gst_object_unref (trans);
2422
2423   return ret;
2424
2425   /* ERRORS */
2426 pull_error:
2427   {
2428     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2429         gst_flow_get_name (ret));
2430     goto done;
2431   }
2432 }
2433
2434 static GstFlowReturn
2435 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2436 {
2437   GstBaseTransform *trans;
2438   GstBaseTransformClass *klass;
2439   GstFlowReturn ret;
2440   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2441   GstClockTime timestamp, duration;
2442   GstBuffer *outbuf = NULL;
2443
2444   trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2445
2446   timestamp = GST_BUFFER_TIMESTAMP (buffer);
2447   duration = GST_BUFFER_DURATION (buffer);
2448
2449   /* calculate end position of the incoming buffer */
2450   if (timestamp != GST_CLOCK_TIME_NONE) {
2451     if (duration != GST_CLOCK_TIME_NONE)
2452       last_stop = timestamp + duration;
2453     else
2454       last_stop = timestamp;
2455   }
2456
2457   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2458   if (klass->before_transform)
2459     klass->before_transform (trans, buffer);
2460
2461   /* protect transform method and concurrent buffer alloc */
2462   GST_BASE_TRANSFORM_LOCK (trans);
2463   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2464   GST_BASE_TRANSFORM_UNLOCK (trans);
2465
2466   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2467    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2468   if (outbuf != NULL) {
2469     if ((ret == GST_FLOW_OK)) {
2470       GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2471
2472       /* Remember last stop position */
2473       if (last_stop != GST_CLOCK_TIME_NONE &&
2474           trans->segment.format == GST_FORMAT_TIME)
2475         gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2476
2477       if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2478         last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2479         if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2480           last_stop_out += GST_BUFFER_DURATION (outbuf);
2481       } else if (last_stop != GST_CLOCK_TIME_NONE) {
2482         last_stop_out = last_stop;
2483       }
2484       if (last_stop_out != GST_CLOCK_TIME_NONE
2485           && trans->segment.format == GST_FORMAT_TIME)
2486         trans->priv->last_stop_out = last_stop_out;
2487
2488       /* apply DISCONT flag if the buffer is not yet marked as such */
2489       if (trans->priv->discont) {
2490         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2491           outbuf = gst_buffer_make_metadata_writable (outbuf);
2492           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2493         }
2494         trans->priv->discont = FALSE;
2495       }
2496       trans->priv->processed++;
2497       ret = gst_pad_push (trans->srcpad, outbuf);
2498     } else {
2499       gst_buffer_unref (outbuf);
2500     }
2501   }
2502
2503   /* convert internal flow to OK and mark discont for the next buffer. */
2504   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2505     trans->priv->discont = TRUE;
2506     ret = GST_FLOW_OK;
2507   }
2508
2509   return ret;
2510 }
2511
2512 static void
2513 gst_base_transform_set_property (GObject * object, guint prop_id,
2514     const GValue * value, GParamSpec * pspec)
2515 {
2516   GstBaseTransform *trans;
2517
2518   trans = GST_BASE_TRANSFORM (object);
2519
2520   switch (prop_id) {
2521     case PROP_QOS:
2522       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2523       break;
2524     default:
2525       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2526       break;
2527   }
2528 }
2529
2530 static void
2531 gst_base_transform_get_property (GObject * object, guint prop_id,
2532     GValue * value, GParamSpec * pspec)
2533 {
2534   GstBaseTransform *trans;
2535
2536   trans = GST_BASE_TRANSFORM (object);
2537
2538   switch (prop_id) {
2539     case PROP_QOS:
2540       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2541       break;
2542     default:
2543       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2544       break;
2545   }
2546 }
2547
2548 /* not a vmethod of anything, just an internal method */
2549 static gboolean
2550 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2551 {
2552   GstBaseTransformClass *bclass;
2553   gboolean result = TRUE;
2554
2555   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2556
2557   if (active) {
2558     if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2559       result &= bclass->start (trans);
2560
2561     GST_OBJECT_LOCK (trans);
2562
2563     if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2564       trans->have_same_caps =
2565           gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2566           GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2567     else
2568       trans->have_same_caps = trans->passthrough;
2569     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2570     trans->negotiated = FALSE;
2571     trans->have_newsegment = FALSE;
2572     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2573     trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2574     trans->priv->proportion = 1.0;
2575     trans->priv->earliest_time = -1;
2576     trans->priv->discont = FALSE;
2577     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2578     trans->priv->processed = 0;
2579     trans->priv->dropped = 0;
2580     trans->priv->force_alloc = TRUE;
2581
2582     GST_OBJECT_UNLOCK (trans);
2583   } else {
2584     /* We must make sure streaming has finished before resetting things
2585      * and calling the ::stop vfunc */
2586     GST_PAD_STREAM_LOCK (trans->sinkpad);
2587     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2588
2589     trans->have_same_caps = FALSE;
2590     /* We can only reset the passthrough mode if the instance told us to 
2591        handle it in configure_caps */
2592     if (bclass->passthrough_on_same_caps) {
2593       gst_base_transform_set_passthrough (trans, FALSE);
2594     }
2595     gst_caps_replace (&trans->cache_caps1, NULL);
2596     gst_caps_replace (&trans->cache_caps2, NULL);
2597     gst_caps_replace (&trans->priv->sink_alloc, NULL);
2598     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2599
2600     if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2601       result &= bclass->stop (trans);
2602   }
2603
2604   return result;
2605 }
2606
2607 static gboolean
2608 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2609 {
2610   gboolean result = TRUE;
2611   GstBaseTransform *trans;
2612
2613   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2614
2615   result = gst_base_transform_activate (trans, active);
2616
2617   if (result)
2618     trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2619
2620   gst_object_unref (trans);
2621
2622   return result;
2623 }
2624
2625 static gboolean
2626 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2627 {
2628   gboolean result = FALSE;
2629   GstBaseTransform *trans;
2630
2631   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2632
2633   result = gst_pad_activate_pull (trans->sinkpad, active);
2634
2635   if (result)
2636     result &= gst_base_transform_activate (trans, active);
2637
2638   if (result)
2639     trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2640
2641   gst_object_unref (trans);
2642
2643   return result;
2644 }
2645
2646 /**
2647  * gst_base_transform_set_passthrough:
2648  * @trans: the #GstBaseTransform to set
2649  * @passthrough: boolean indicating passthrough mode.
2650  *
2651  * Set passthrough mode for this filter by default. This is mostly
2652  * useful for filters that do not care about negotiation.
2653  *
2654  * Always TRUE for filters which don't implement either a transform
2655  * or transform_ip method.
2656  *
2657  * MT safe.
2658  */
2659 void
2660 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2661     gboolean passthrough)
2662 {
2663   GstBaseTransformClass *bclass;
2664
2665   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2666
2667   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2668
2669   GST_OBJECT_LOCK (trans);
2670   if (passthrough == FALSE) {
2671     if (bclass->transform_ip || bclass->transform)
2672       trans->passthrough = FALSE;
2673   } else {
2674     trans->passthrough = TRUE;
2675   }
2676
2677   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2678   GST_OBJECT_UNLOCK (trans);
2679 }
2680
2681 /**
2682  * gst_base_transform_is_passthrough:
2683  * @trans: the #GstBaseTransform to query
2684  *
2685  * See if @trans is configured as a passthrough transform.
2686  *
2687  * Returns: TRUE is the transform is configured in passthrough mode.
2688  *
2689  * MT safe.
2690  */
2691 gboolean
2692 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2693 {
2694   gboolean result;
2695
2696   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2697
2698   GST_OBJECT_LOCK (trans);
2699   result = trans->passthrough;
2700   GST_OBJECT_UNLOCK (trans);
2701
2702   return result;
2703 }
2704
2705 /**
2706  * gst_base_transform_set_in_place:
2707  * @trans: the #GstBaseTransform to modify
2708  * @in_place: Boolean value indicating that we would like to operate
2709  * on in_place buffers.
2710  *
2711  * Determines whether a non-writable buffer will be copied before passing
2712  * to the transform_ip function.
2713  * <itemizedlist>
2714  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2715  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2716  * </itemizedlist>
2717  *
2718  * MT safe.
2719  */
2720 void
2721 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2722 {
2723   GstBaseTransformClass *bclass;
2724
2725   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2726
2727   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2728
2729   GST_OBJECT_LOCK (trans);
2730
2731   if (in_place) {
2732     if (bclass->transform_ip) {
2733       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2734       trans->always_in_place = TRUE;
2735     }
2736   } else {
2737     if (bclass->transform) {
2738       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2739       trans->always_in_place = FALSE;
2740     }
2741   }
2742
2743   GST_OBJECT_UNLOCK (trans);
2744 }
2745
2746 /**
2747  * gst_base_transform_is_in_place:
2748  * @trans: the #GstBaseTransform to query
2749  *
2750  * See if @trans is configured as a in_place transform.
2751  *
2752  * Returns: TRUE is the transform is configured in in_place mode.
2753  *
2754  * MT safe.
2755  */
2756 gboolean
2757 gst_base_transform_is_in_place (GstBaseTransform * trans)
2758 {
2759   gboolean result;
2760
2761   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2762
2763   GST_OBJECT_LOCK (trans);
2764   result = trans->always_in_place;
2765   GST_OBJECT_UNLOCK (trans);
2766
2767   return result;
2768 }
2769
2770 /**
2771  * gst_base_transform_update_qos:
2772  * @trans: a #GstBaseTransform
2773  * @proportion: the proportion
2774  * @diff: the diff against the clock
2775  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2776  * running_time.
2777  *
2778  * Set the QoS parameters in the transform. This function is called internally
2779  * when a QOS event is received but subclasses can provide custom information
2780  * when needed.
2781  *
2782  * MT safe.
2783  *
2784  * Since: 0.10.5
2785  */
2786 void
2787 gst_base_transform_update_qos (GstBaseTransform * trans,
2788     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2789 {
2790
2791   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2792
2793   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2794       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2795       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2796
2797   GST_OBJECT_LOCK (trans);
2798   trans->priv->proportion = proportion;
2799   trans->priv->earliest_time = timestamp + diff;
2800   GST_OBJECT_UNLOCK (trans);
2801 }
2802
2803 /**
2804  * gst_base_transform_set_qos_enabled:
2805  * @trans: a #GstBaseTransform
2806  * @enabled: new state
2807  *
2808  * Enable or disable QoS handling in the transform.
2809  *
2810  * MT safe.
2811  *
2812  * Since: 0.10.5
2813  */
2814 void
2815 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2816 {
2817   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2818
2819   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2820
2821   GST_OBJECT_LOCK (trans);
2822   trans->priv->qos_enabled = enabled;
2823   GST_OBJECT_UNLOCK (trans);
2824 }
2825
2826 /**
2827  * gst_base_transform_is_qos_enabled:
2828  * @trans: a #GstBaseTransform
2829  *
2830  * Queries if the transform will handle QoS.
2831  *
2832  * Returns: TRUE if QoS is enabled.
2833  *
2834  * MT safe.
2835  *
2836  * Since: 0.10.5
2837  */
2838 gboolean
2839 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2840 {
2841   gboolean result;
2842
2843   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2844
2845   GST_OBJECT_LOCK (trans);
2846   result = trans->priv->qos_enabled;
2847   GST_OBJECT_UNLOCK (trans);
2848
2849   return result;
2850 }
2851
2852 /**
2853  * gst_base_transform_set_gap_aware:
2854  * @trans: a #GstBaseTransform
2855  * @gap_aware: New state
2856  *
2857  * If @gap_aware is %FALSE (the default), output buffers will have the
2858  * %GST_BUFFER_FLAG_GAP flag unset.
2859  *
2860  * If set to %TRUE, the element must handle output buffers with this flag set
2861  * correctly, i.e. it can assume that the buffer contains neutral data but must
2862  * unset the flag if the output is no neutral data.
2863  *
2864  * MT safe.
2865  *
2866  * Since: 0.10.16
2867  */
2868 void
2869 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2870 {
2871   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2872
2873   GST_OBJECT_LOCK (trans);
2874   trans->priv->gap_aware = gap_aware;
2875   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2876   GST_OBJECT_UNLOCK (trans);
2877 }
2878
2879 /**
2880  * gst_base_transform_suggest:
2881  * @trans: a #GstBaseTransform
2882  * @caps: (transfer none): caps to suggest
2883  * @size: buffer size to suggest
2884  *
2885  * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
2886  * taken.
2887  *
2888  * Since: 0.10.21
2889  */
2890 void
2891 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
2892     guint size)
2893 {
2894   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2895
2896   GST_OBJECT_LOCK (trans->sinkpad);
2897   if (trans->priv->sink_suggest)
2898     gst_caps_unref (trans->priv->sink_suggest);
2899   if (caps)
2900     caps = gst_caps_copy (caps);
2901   trans->priv->sink_suggest = caps;
2902   trans->priv->size_suggest = size;
2903   trans->priv->suggest_pending = TRUE;
2904   GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
2905   GST_OBJECT_UNLOCK (trans->sinkpad);
2906 }
2907
2908 /**
2909  * gst_base_transform_reconfigure:
2910  * @trans: a #GstBaseTransform
2911  *
2912  * Instructs @trans to renegotiate a new downstream transform on the next
2913  * buffer. This function is typically called after properties on the transform
2914  * were set that influence the output format.
2915  *
2916  * Since: 0.10.21
2917  */
2918 void
2919 gst_base_transform_reconfigure (GstBaseTransform * trans)
2920 {
2921   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2922
2923   GST_OBJECT_LOCK (trans);
2924   GST_DEBUG_OBJECT (trans, "marking reconfigure");
2925   trans->priv->reconfigure = TRUE;
2926   gst_caps_replace (&trans->priv->sink_alloc, NULL);
2927   GST_OBJECT_UNLOCK (trans);
2928 }