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