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