basetransform: remove metadata tagged with the memory tag
[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_query_remove_nth_allocation_meta (query, i);
816       i--;
817     }
818   }
819
820   return TRUE;
821 }
822
823 static gboolean
824 gst_base_transform_do_bufferpool (GstBaseTransform * trans, GstCaps * outcaps)
825 {
826   GstQuery *query;
827   gboolean result = TRUE;
828   GstBufferPool *pool = NULL;
829   guint size, min, max, prefix, alignment;
830   GstBaseTransformClass *klass;
831   GstAllocator *allocator = NULL;
832
833   /* there are these possibilities:
834    *
835    * 1) we negotiated passthrough, we can proxy the bufferpool directly and we
836    *    will do that whenever some upstream does an allocation query.
837    * 2) we need to do a transform, we need to get a bufferpool from downstream
838    *    and configure it. When upstream does the ALLOCATION query, the
839    *    propose_allocation vmethod will be called and we will configure the
840    *    upstream allocator with our proposed values then.
841    */
842   if (trans->passthrough || trans->always_in_place) {
843     /* we are in passthrough, the input buffer is never copied and always passed
844      * along. We never allocate an output buffer on the srcpad. What we do is
845      * let the upstream element decide if it wants to use a bufferpool and
846      * then we will proxy the downstream pool */
847     GST_DEBUG_OBJECT (trans, "we're passthough, delay bufferpool");
848     gst_base_transform_set_allocation (trans, NULL, NULL, 0, 0, NULL);
849     return TRUE;
850   }
851
852   /* not passthrough, we need to allocate */
853   /* find a pool for the negotiated caps now */
854   GST_DEBUG_OBJECT (trans, "doing allocation query");
855   query = gst_query_new_allocation (outcaps, TRUE);
856   if (!gst_pad_peer_query (trans->srcpad, query)) {
857     /* not a problem, just debug a little */
858     GST_DEBUG_OBJECT (trans, "peer ALLOCATION query failed");
859   }
860
861   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
862
863   GST_DEBUG_OBJECT (trans, "calling decide_allocation");
864   if (G_LIKELY (klass->decide_allocation))
865     if ((result = klass->decide_allocation (trans, query)) == FALSE)
866       goto no_decide_allocation;
867
868   /* we got configuration from our peer, parse them */
869   gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
870       &alignment, &pool);
871
872   if (size == 0) {
873     /* no size, we have variable size buffers */
874     if (gst_query_get_n_allocation_memories (query) > 0) {
875       if ((allocator = gst_query_parse_nth_allocation_memory (query, 0)))
876         gst_allocator_ref (allocator);
877     }
878     GST_DEBUG_OBJECT (trans, "no size, using allocator %p", allocator);
879   } else if (pool == NULL) {
880     GstStructure *config;
881
882     /* we did not get a pool, make one ourselves then */
883     pool = gst_buffer_pool_new ();
884
885     GST_DEBUG_OBJECT (trans, "no pool, making one");
886     config = gst_buffer_pool_get_config (pool);
887     gst_buffer_pool_config_set (config, outcaps, size, min, max, prefix,
888         alignment);
889     gst_buffer_pool_set_config (pool, config);
890   }
891
892   /* and store */
893   result =
894       gst_base_transform_set_allocation (trans, pool, allocator, prefix,
895       alignment, query);
896
897   return result;
898
899   /* Errors */
900 no_decide_allocation:
901   {
902     GST_WARNING_OBJECT (trans, "Subclass failed to decide allocation");
903     gst_query_unref (query);
904
905     return result;
906   }
907 }
908
909 /* function triggered when the in and out caps are negotiated and need
910  * to be configured in the subclass. */
911 static gboolean
912 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
913     GstCaps * out)
914 {
915   gboolean ret = TRUE;
916   GstBaseTransformClass *klass;
917
918   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
919
920   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
921   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
922
923   /* clear the cache */
924   gst_caps_replace (&trans->cache_caps1, NULL);
925   gst_caps_replace (&trans->cache_caps2, NULL);
926
927   /* figure out same caps state */
928   trans->have_same_caps = gst_caps_is_equal (in, out);
929   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
930
931   /* If we've a transform_ip method and same input/output caps, set in_place
932    * by default. If for some reason the sub-class prefers using a transform
933    * function, it can clear the in place flag in the set_caps */
934   gst_base_transform_set_in_place (trans,
935       klass->transform_ip && trans->have_same_caps);
936
937   /* Set the passthrough if the class wants passthrough_on_same_caps
938    * and we have the same caps on each pad */
939   if (klass->passthrough_on_same_caps)
940     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
941
942   /* now configure the element with the caps */
943   if (klass->set_caps) {
944     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
945     ret = klass->set_caps (trans, in, out);
946   }
947
948   trans->negotiated = ret;
949
950   return ret;
951 }
952
953 static GstCaps *
954 gst_base_transform_default_fixate_caps (GstBaseTransform * trans,
955     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
956 {
957   othercaps = gst_caps_make_writable (othercaps);
958   gst_caps_fixate (othercaps);
959   GST_DEBUG_OBJECT (trans, "fixated to %" GST_PTR_FORMAT, othercaps);
960
961   return othercaps;
962 }
963
964 /* given a fixed @caps on @pad, create the best possible caps for the
965  * other pad.
966  * @caps must be fixed when calling this function.
967  *
968  * This function calls the transform caps vmethod of the basetransform to figure
969  * out the possible target formats. It then tries to select the best format from
970  * this list by:
971  *
972  * - attempt passthrough if the target caps is a superset of the input caps
973  * - fixating by using peer caps
974  * - fixating with transform fixate function
975  * - fixating with pad fixate functions.
976  *
977  * this function returns a caps that can be transformed into and is accepted by
978  * the peer element.
979  */
980 static GstCaps *
981 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
982     GstCaps * caps)
983 {
984   GstBaseTransformClass *klass;
985   GstPad *otherpad, *otherpeer;
986   GstCaps *othercaps;
987   gboolean is_fixed;
988
989   /* caps must be fixed here, this is a programming error if it's not */
990   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
991
992   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
993
994   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
995   otherpeer = gst_pad_get_peer (otherpad);
996
997   /* see how we can transform the input caps. We need to do this even for
998    * passthrough because it might be possible that this element cannot support
999    * passthrough at all. */
1000   othercaps = gst_base_transform_transform_caps (trans,
1001       GST_PAD_DIRECTION (pad), caps, NULL);
1002
1003   /* The caps we can actually output is the intersection of the transformed
1004    * caps with the pad template for the pad */
1005   if (othercaps) {
1006     GstCaps *intersect, *templ_caps;
1007
1008     templ_caps = gst_pad_get_pad_template_caps (otherpad);
1009     GST_DEBUG_OBJECT (trans,
1010         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
1011
1012     intersect =
1013         gst_caps_intersect_full (othercaps, templ_caps,
1014         GST_CAPS_INTERSECT_FIRST);
1015
1016     gst_caps_unref (othercaps);
1017     gst_caps_unref (templ_caps);
1018     othercaps = intersect;
1019   }
1020
1021   /* check if transform is empty */
1022   if (!othercaps || gst_caps_is_empty (othercaps))
1023     goto no_transform;
1024
1025   /* if the othercaps are not fixed, we need to fixate them, first attempt
1026    * is by attempting passthrough if the othercaps are a superset of caps. */
1027   /* FIXME. maybe the caps is not fixed because it has multiple structures of
1028    * fixed caps */
1029   is_fixed = gst_caps_is_fixed (othercaps);
1030   if (!is_fixed) {
1031     GST_DEBUG_OBJECT (trans,
1032         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
1033
1034     /* Now let's see what the peer suggests based on our transformed caps */
1035     if (otherpeer) {
1036       GstCaps *peercaps, *intersection, *templ_caps;
1037
1038       GST_DEBUG_OBJECT (trans,
1039           "Checking peer caps with filter %" GST_PTR_FORMAT, othercaps);
1040
1041       peercaps = gst_pad_query_caps (otherpeer, othercaps);
1042       GST_DEBUG_OBJECT (trans, "Resulted in %" GST_PTR_FORMAT, peercaps);
1043       if (!gst_caps_is_empty (peercaps)) {
1044         templ_caps = gst_pad_get_pad_template_caps (otherpad);
1045
1046         GST_DEBUG_OBJECT (trans,
1047             "Intersecting with template caps %" GST_PTR_FORMAT, templ_caps);
1048
1049         intersection =
1050             gst_caps_intersect_full (peercaps, templ_caps,
1051             GST_CAPS_INTERSECT_FIRST);
1052         GST_DEBUG_OBJECT (trans, "Intersection: %" GST_PTR_FORMAT,
1053             intersection);
1054         gst_caps_unref (peercaps);
1055         gst_caps_unref (templ_caps);
1056         peercaps = intersection;
1057
1058         GST_DEBUG_OBJECT (trans,
1059             "Intersecting with transformed caps %" GST_PTR_FORMAT, othercaps);
1060         intersection =
1061             gst_caps_intersect_full (peercaps, othercaps,
1062             GST_CAPS_INTERSECT_FIRST);
1063         GST_DEBUG_OBJECT (trans, "Intersection: %" GST_PTR_FORMAT,
1064             intersection);
1065         gst_caps_unref (peercaps);
1066         gst_caps_unref (othercaps);
1067         othercaps = intersection;
1068       } else {
1069         othercaps = peercaps;
1070       }
1071
1072       is_fixed = gst_caps_is_fixed (othercaps);
1073     } else {
1074       GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
1075       gst_caps_unref (othercaps);
1076       othercaps = gst_caps_ref (caps);
1077       is_fixed = TRUE;
1078     }
1079   }
1080   if (gst_caps_is_empty (othercaps))
1081     goto no_transform_possible;
1082
1083   GST_DEBUG ("have %sfixed caps %" GST_PTR_FORMAT, (is_fixed ? "" : "non-"),
1084       othercaps);
1085
1086   /* second attempt at fixation, call the fixate vmethod */
1087   /* caps could be fixed but the subclass may want to add fields */
1088   if (klass->fixate_caps) {
1089     GST_DEBUG_OBJECT (trans, "calling fixate_caps for %" GST_PTR_FORMAT
1090         " using caps %" GST_PTR_FORMAT " on pad %s:%s", othercaps, caps,
1091         GST_DEBUG_PAD_NAME (otherpad));
1092     /* note that we pass the complete array of structures to the fixate
1093      * function, it needs to truncate itself */
1094     othercaps =
1095         klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1096     is_fixed = gst_caps_is_fixed (othercaps);
1097     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
1098   }
1099
1100   /* caps should be fixed now, if not we have to fail. */
1101   if (!is_fixed)
1102     goto could_not_fixate;
1103
1104   /* and peer should accept */
1105   if (otherpeer && !gst_pad_query_accept_caps (otherpeer, othercaps))
1106     goto peer_no_accept;
1107
1108   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1109       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1110
1111   if (otherpeer)
1112     gst_object_unref (otherpeer);
1113
1114   return othercaps;
1115
1116   /* ERRORS */
1117 no_transform:
1118   {
1119     GST_DEBUG_OBJECT (trans,
1120         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
1121     goto error_cleanup;
1122   }
1123 no_transform_possible:
1124   {
1125     GST_DEBUG_OBJECT (trans,
1126         "transform could not transform %" GST_PTR_FORMAT
1127         " in anything we support", caps);
1128     goto error_cleanup;
1129   }
1130 could_not_fixate:
1131   {
1132     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1133     goto error_cleanup;
1134   }
1135 peer_no_accept:
1136   {
1137     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1138         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1139     goto error_cleanup;
1140   }
1141 error_cleanup:
1142   {
1143     if (otherpeer)
1144       gst_object_unref (otherpeer);
1145     if (othercaps)
1146       gst_caps_unref (othercaps);
1147     return NULL;
1148   }
1149 }
1150
1151 static gboolean
1152 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1153     GstPadDirection direction, GstCaps * caps)
1154 {
1155 #if 0
1156   GstPad *otherpad;
1157   GstCaps *othercaps = NULL;
1158 #endif
1159   gboolean ret = TRUE;
1160
1161 #if 0
1162   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1163
1164   /* we need fixed caps for the check, fall back to the default implementation
1165    * if we don't */
1166   if (!gst_caps_is_fixed (caps))
1167 #endif
1168   {
1169     GstCaps *allowed;
1170
1171     GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1172
1173     /* get all the formats we can handle on this pad */
1174     if (direction == GST_PAD_SRC)
1175       allowed = gst_pad_query_caps (trans->srcpad, NULL);
1176     else
1177       allowed = gst_pad_query_caps (trans->sinkpad, NULL);
1178
1179     if (!allowed) {
1180       GST_DEBUG_OBJECT (trans, "gst_pad_query_caps() failed");
1181       goto no_transform_possible;
1182     }
1183
1184     GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1185
1186     /* intersect with the requested format */
1187     ret = gst_caps_is_subset (caps, allowed);
1188     gst_caps_unref (allowed);
1189
1190     if (!ret)
1191       goto no_transform_possible;
1192   }
1193 #if 0
1194   else {
1195     GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1196
1197     /* find best possible caps for the other pad as a way to see if we can
1198      * transform this caps. */
1199     othercaps = gst_base_transform_find_transform (trans, pad, caps, FALSE);
1200     if (!othercaps || gst_caps_is_empty (othercaps))
1201       goto no_transform_possible;
1202
1203     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1204   }
1205 #endif
1206
1207 done:
1208 #if 0
1209   /* We know it's always NULL since we never use it */
1210   if (othercaps)
1211     gst_caps_unref (othercaps);
1212 #endif
1213
1214   return ret;
1215
1216   /* ERRORS */
1217 no_transform_possible:
1218   {
1219     GST_DEBUG_OBJECT (trans,
1220         "transform could not transform %" GST_PTR_FORMAT
1221         " in anything we support", caps);
1222     ret = FALSE;
1223     goto done;
1224   }
1225 }
1226
1227 /* called when new caps arrive on the sink pad,
1228  * We try to find the best caps for the other side using our _find_transform()
1229  * function. If there are caps, we configure the transform for this new
1230  * transformation.
1231  */
1232 static gboolean
1233 gst_base_transform_setcaps (GstBaseTransform * trans, GstPad * pad,
1234     GstCaps * incaps)
1235 {
1236   GstCaps *outcaps;
1237   gboolean ret = TRUE;
1238
1239   GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, incaps, incaps);
1240
1241   /* find best possible caps for the other pad */
1242   outcaps = gst_base_transform_find_transform (trans, pad, incaps);
1243   if (!outcaps || gst_caps_is_empty (outcaps))
1244     goto no_transform_possible;
1245
1246   /* configure the element now */
1247
1248   /* if we have the same caps, we can optimize and reuse the input caps */
1249   if (gst_caps_is_equal (incaps, outcaps)) {
1250     GST_INFO_OBJECT (trans, "reuse caps");
1251     gst_caps_unref (outcaps);
1252     outcaps = gst_caps_ref (incaps);
1253   }
1254
1255   /* call configure now */
1256   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1257     goto failed_configure;
1258
1259   GST_OBJECT_LOCK (trans->sinkpad);
1260   GST_OBJECT_FLAG_UNSET (trans->srcpad, GST_PAD_FLAG_NEED_RECONFIGURE);
1261   trans->priv->reconfigure = FALSE;
1262   GST_OBJECT_UNLOCK (trans->sinkpad);
1263
1264   /* we know this will work, we implement the setcaps */
1265   gst_pad_push_event (trans->srcpad, gst_event_new_caps (outcaps));
1266
1267   if (ret) {
1268     /* try to get a pool when needed */
1269     ret = gst_base_transform_do_bufferpool (trans, outcaps);
1270   }
1271
1272 done:
1273   if (outcaps)
1274     gst_caps_unref (outcaps);
1275
1276   trans->negotiated = ret;
1277
1278   return ret;
1279
1280   /* ERRORS */
1281 no_transform_possible:
1282   {
1283     GST_WARNING_OBJECT (trans,
1284         "transform could not transform %" GST_PTR_FORMAT
1285         " in anything we support", incaps);
1286     ret = FALSE;
1287     goto done;
1288   }
1289 failed_configure:
1290   {
1291     GST_WARNING_OBJECT (trans, "FAILED to configure incaps %" GST_PTR_FORMAT
1292         " and outcaps %" GST_PTR_FORMAT, incaps, outcaps);
1293     ret = FALSE;
1294     goto done;
1295   }
1296 }
1297
1298 static gboolean
1299 gst_base_transform_default_propose_allocation (GstBaseTransform * trans,
1300     GstQuery * decide_query, GstQuery * query)
1301 {
1302   gboolean ret;
1303
1304   if (decide_query == NULL) {
1305     GST_DEBUG_OBJECT (trans, "doing passthrough query");
1306     ret = gst_pad_peer_query (trans->srcpad, query);
1307   } else {
1308     ret = FALSE;
1309   }
1310   return ret;
1311 }
1312
1313 static gboolean
1314 gst_base_transform_default_query (GstBaseTransform * trans,
1315     GstPadDirection direction, GstQuery * query)
1316 {
1317   gboolean ret = FALSE;
1318   GstPad *pad, *otherpad;
1319   GstBaseTransformClass *klass;
1320
1321   if (direction == GST_PAD_SRC) {
1322     pad = trans->srcpad;
1323     otherpad = trans->sinkpad;
1324   } else {
1325     pad = trans->sinkpad;
1326     otherpad = trans->srcpad;
1327   }
1328
1329   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1330
1331   switch (GST_QUERY_TYPE (query)) {
1332     case GST_QUERY_ALLOCATION:
1333     {
1334       GstQuery *decide_query;
1335
1336       /* can only be done on the sinkpad */
1337       if (direction != GST_PAD_SINK)
1338         goto done;
1339
1340       GST_OBJECT_LOCK (trans);
1341       if ((decide_query = trans->priv->query))
1342         gst_query_ref (decide_query);
1343       GST_OBJECT_UNLOCK (trans);
1344
1345       GST_DEBUG_OBJECT (trans,
1346           "calling propose allocation with query %" GST_PTR_FORMAT,
1347           decide_query);
1348
1349       /* pass the query to the propose_allocation vmethod if any */
1350       if (G_LIKELY (klass->propose_allocation))
1351         ret = klass->propose_allocation (trans, decide_query, query);
1352       else
1353         ret = FALSE;
1354
1355       if (decide_query)
1356         gst_query_unref (decide_query);
1357
1358       GST_DEBUG_OBJECT (trans, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret,
1359           query);
1360       break;
1361     }
1362     case GST_QUERY_POSITION:
1363     {
1364       GstFormat format;
1365
1366       gst_query_parse_position (query, &format, NULL);
1367       if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1368         gint64 pos;
1369         ret = TRUE;
1370
1371         if ((direction == GST_PAD_SINK)
1372             || (trans->priv->position_out == GST_CLOCK_TIME_NONE)) {
1373           pos =
1374               gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1375               trans->segment.position);
1376         } else {
1377           pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1378               trans->priv->position_out);
1379         }
1380         gst_query_set_position (query, format, pos);
1381       } else {
1382         ret = gst_pad_peer_query (otherpad, query);
1383       }
1384       break;
1385     }
1386     case GST_QUERY_ACCEPT_CAPS:
1387     {
1388       GstCaps *caps;
1389
1390       gst_query_parse_accept_caps (query, &caps);
1391       if (klass->accept_caps) {
1392         ret = klass->accept_caps (trans, direction, caps);
1393         gst_query_set_accept_caps_result (query, ret);
1394         /* return TRUE, we answered the query */
1395         ret = TRUE;
1396       }
1397       break;
1398     }
1399     case GST_QUERY_CAPS:
1400     {
1401       GstCaps *filter, *caps;
1402
1403       gst_query_parse_caps (query, &filter);
1404       caps = gst_base_transform_query_caps (trans, pad, filter);
1405       gst_query_set_caps_result (query, caps);
1406       gst_caps_unref (caps);
1407       ret = TRUE;
1408       break;
1409     }
1410     default:
1411       ret = gst_pad_peer_query (otherpad, query);
1412       break;
1413   }
1414
1415 done:
1416   return ret;
1417 }
1418
1419 static gboolean
1420 gst_base_transform_query (GstPad * pad, GstObject * parent, GstQuery * query)
1421 {
1422   GstBaseTransform *trans;
1423   GstBaseTransformClass *bclass;
1424   gboolean ret = FALSE;
1425
1426   trans = GST_BASE_TRANSFORM (parent);
1427   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1428
1429   if (bclass->query)
1430     ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1431
1432   return ret;
1433 }
1434
1435 /* this function either returns the input buffer without incrementing the
1436  * refcount or it allocates a new (writable) buffer */
1437 static GstFlowReturn
1438 default_prepare_output_buffer (GstBaseTransform * trans,
1439     GstBuffer * inbuf, GstBuffer ** outbuf)
1440 {
1441   GstBaseTransformPrivate *priv;
1442   GstFlowReturn ret = GST_FLOW_OK;
1443   GstBaseTransformClass *bclass;
1444   GstCaps *incaps, *outcaps;
1445   gsize insize, outsize;
1446   gboolean res;
1447
1448   priv = trans->priv;
1449   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1450
1451   /* figure out how to allocate an output buffer */
1452   if (trans->passthrough) {
1453     /* passthrough, we will not modify the incomming buffer so we can just
1454      * reuse it */
1455     GST_DEBUG_OBJECT (trans, "passthrough: reusing input buffer");
1456     *outbuf = inbuf;
1457     goto done;
1458   }
1459
1460   /* we can't reuse the input buffer */
1461   if (priv->pool) {
1462     GST_DEBUG_OBJECT (trans, "using pool alloc");
1463     ret = gst_buffer_pool_acquire_buffer (priv->pool, outbuf, NULL);
1464     goto copy_meta;
1465   }
1466
1467   /* no pool, we need to figure out the size of the output buffer first */
1468   if ((bclass->transform_ip != NULL) && trans->always_in_place) {
1469     /* we want to do an in-place alloc */
1470     if (gst_buffer_is_writable (inbuf)) {
1471       GST_DEBUG_OBJECT (trans, "inplace reuse writable input buffer");
1472       *outbuf = inbuf;
1473     } else {
1474       GST_DEBUG_OBJECT (trans, "making writable buffer copy");
1475       /* we make a copy of the input buffer */
1476       *outbuf = gst_buffer_copy (inbuf);
1477     }
1478     goto done;
1479   }
1480
1481   /* else use the transform function to get the size */
1482   incaps = gst_pad_get_current_caps (trans->sinkpad);
1483   outcaps = gst_pad_get_current_caps (trans->srcpad);
1484
1485   GST_DEBUG_OBJECT (trans, "getting output size for alloc");
1486   /* copy transform, figure out the output size */
1487   insize = gst_buffer_get_size (inbuf);
1488   res = gst_base_transform_transform_size (trans,
1489       GST_PAD_SINK, incaps, insize, outcaps, &outsize);
1490
1491   gst_caps_unref (incaps);
1492   gst_caps_unref (outcaps);
1493
1494   if (!res)
1495     goto unknown_size;
1496
1497   GST_DEBUG_OBJECT (trans, "doing alloc of size %" G_GSIZE_FORMAT, outsize);
1498   *outbuf = gst_buffer_new_allocate (priv->allocator, outsize, priv->alignment);
1499
1500 copy_meta:
1501   /* copy the metadata */
1502   if (bclass->copy_metadata)
1503     if (!bclass->copy_metadata (trans, inbuf, *outbuf)) {
1504       /* something failed, post a warning */
1505       GST_ELEMENT_WARNING (trans, STREAM, NOT_IMPLEMENTED,
1506           ("could not copy metadata"), (NULL));
1507     }
1508
1509 done:
1510   return ret;
1511
1512   /* ERRORS */
1513 unknown_size:
1514   {
1515     GST_ERROR_OBJECT (trans, "unknown output size");
1516     return GST_FLOW_ERROR;
1517   }
1518 }
1519
1520 static gboolean
1521 default_copy_metadata (GstBaseTransform * trans,
1522     GstBuffer * inbuf, GstBuffer * outbuf)
1523 {
1524   GstBaseTransformPrivate *priv = trans->priv;
1525
1526   /* now copy the metadata */
1527   GST_DEBUG_OBJECT (trans, "copying metadata");
1528
1529   /* this should not happen, buffers allocated from a pool or with
1530    * new_allocate should always be writable. */
1531   if (!gst_buffer_is_writable (outbuf))
1532     goto not_writable;
1533
1534   /* when we get here, the metadata should be writable */
1535   gst_buffer_copy_into (outbuf, inbuf,
1536       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
1537
1538   /* clear the GAP flag when the subclass does not understand it */
1539   if (!priv->gap_aware)
1540     GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP);
1541
1542   return TRUE;
1543
1544   /* ERRORS */
1545 not_writable:
1546   {
1547     GST_WARNING_OBJECT (trans, "buffer %p not writable", outbuf);
1548     return FALSE;
1549   }
1550 }
1551
1552 /* Given @caps calcultate the size of one unit.
1553  *
1554  * For video caps, this is the size of one frame (and thus one buffer).
1555  * For audio caps, this is the size of one sample.
1556  *
1557  * These values are cached since they do not change and the calculation
1558  * potentially involves parsing caps and other expensive stuff.
1559  *
1560  * We have two cache locations to store the size, one for the source caps
1561  * and one for the sink caps.
1562  *
1563  * this function returns FALSE if no size could be calculated.
1564  */
1565 static gboolean
1566 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1567     gsize * size)
1568 {
1569   gboolean res = FALSE;
1570   GstBaseTransformClass *bclass;
1571
1572   /* see if we have the result cached */
1573   if (trans->cache_caps1 == caps) {
1574     *size = trans->cache_caps1_size;
1575     GST_DEBUG_OBJECT (trans,
1576         "returned %" G_GSIZE_FORMAT " from first cache", *size);
1577     return TRUE;
1578   }
1579   if (trans->cache_caps2 == caps) {
1580     *size = trans->cache_caps2_size;
1581     GST_DEBUG_OBJECT (trans,
1582         "returned %" G_GSIZE_FORMAT " from second cached", *size);
1583     return TRUE;
1584   }
1585
1586   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1587   res = bclass->get_unit_size (trans, caps, size);
1588   GST_DEBUG_OBJECT (trans,
1589       "caps %" GST_PTR_FORMAT ") has unit size %" G_GSIZE_FORMAT ", res %s",
1590       caps, *size, res ? "TRUE" : "FALSE");
1591
1592   if (res) {
1593     /* and cache the values */
1594     if (trans->cache_caps1 == NULL) {
1595       gst_caps_replace (&trans->cache_caps1, caps);
1596       trans->cache_caps1_size = *size;
1597       GST_DEBUG_OBJECT (trans,
1598           "caching %" G_GSIZE_FORMAT " in first cache", *size);
1599     } else if (trans->cache_caps2 == NULL) {
1600       gst_caps_replace (&trans->cache_caps2, caps);
1601       trans->cache_caps2_size = *size;
1602       GST_DEBUG_OBJECT (trans,
1603           "caching %" G_GSIZE_FORMAT " in second cache", *size);
1604     } else {
1605       GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1606     }
1607   }
1608   return res;
1609 }
1610
1611 static gboolean
1612 gst_base_transform_sink_event (GstPad * pad, GstObject * parent,
1613     GstEvent * event)
1614 {
1615   GstBaseTransform *trans;
1616   GstBaseTransformClass *bclass;
1617   gboolean ret = TRUE;
1618
1619   trans = GST_BASE_TRANSFORM (parent);
1620   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1621
1622   if (bclass->sink_event)
1623     ret = bclass->sink_event (trans, event);
1624   else
1625     gst_event_unref (event);
1626
1627   return ret;
1628 }
1629
1630 static gboolean
1631 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1632 {
1633   gboolean ret = TRUE, forward = TRUE;
1634
1635   switch (GST_EVENT_TYPE (event)) {
1636     case GST_EVENT_FLUSH_START:
1637       break;
1638     case GST_EVENT_FLUSH_STOP:
1639       GST_OBJECT_LOCK (trans);
1640       /* reset QoS parameters */
1641       trans->priv->proportion = 1.0;
1642       trans->priv->earliest_time = -1;
1643       trans->priv->discont = FALSE;
1644       trans->priv->processed = 0;
1645       trans->priv->dropped = 0;
1646       GST_OBJECT_UNLOCK (trans);
1647       /* we need new segment info after the flush. */
1648       trans->have_segment = FALSE;
1649       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1650       trans->priv->position_out = GST_CLOCK_TIME_NONE;
1651       break;
1652     case GST_EVENT_EOS:
1653       break;
1654     case GST_EVENT_TAG:
1655       break;
1656     case GST_EVENT_CAPS:
1657     {
1658       GstCaps *caps;
1659
1660       gst_event_parse_caps (event, &caps);
1661       ret = gst_base_transform_setcaps (trans, trans->sinkpad, caps);
1662
1663       forward = FALSE;
1664       break;
1665     }
1666     case GST_EVENT_SEGMENT:
1667     {
1668       gst_event_copy_segment (event, &trans->segment);
1669       trans->have_segment = TRUE;
1670
1671       GST_DEBUG_OBJECT (trans, "received SEGMENT %" GST_SEGMENT_FORMAT,
1672           &trans->segment);
1673       break;
1674     }
1675     default:
1676       break;
1677   }
1678
1679   if (ret && forward)
1680     ret = gst_pad_push_event (trans->srcpad, event);
1681   else
1682     gst_event_unref (event);
1683
1684   return ret;
1685 }
1686
1687 static gboolean
1688 gst_base_transform_src_event (GstPad * pad, GstObject * parent,
1689     GstEvent * event)
1690 {
1691   GstBaseTransform *trans;
1692   GstBaseTransformClass *bclass;
1693   gboolean ret = TRUE;
1694
1695   trans = GST_BASE_TRANSFORM (parent);
1696   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1697
1698   if (bclass->src_event)
1699     ret = bclass->src_event (trans, event);
1700   else
1701     gst_event_unref (event);
1702
1703   return ret;
1704 }
1705
1706 static gboolean
1707 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1708 {
1709   gboolean ret;
1710
1711   GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
1712
1713   switch (GST_EVENT_TYPE (event)) {
1714     case GST_EVENT_SEEK:
1715       break;
1716     case GST_EVENT_NAVIGATION:
1717       break;
1718     case GST_EVENT_QOS:
1719     {
1720       gdouble proportion;
1721       GstClockTimeDiff diff;
1722       GstClockTime timestamp;
1723
1724       gst_event_parse_qos (event, NULL, &proportion, &diff, &timestamp);
1725       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1726       break;
1727     }
1728     default:
1729       break;
1730   }
1731
1732   ret = gst_pad_push_event (trans->sinkpad, event);
1733
1734   return ret;
1735 }
1736
1737 /* perform a transform on @inbuf and put the result in @outbuf.
1738  *
1739  * This function is common to the push and pull-based operations.
1740  *
1741  * This function takes ownership of @inbuf */
1742 static GstFlowReturn
1743 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1744     GstBuffer ** outbuf)
1745 {
1746   GstBaseTransformClass *bclass;
1747   GstFlowReturn ret = GST_FLOW_OK;
1748   gboolean want_in_place;
1749   GstClockTime running_time;
1750   GstClockTime timestamp;
1751   gboolean reconfigure;
1752
1753   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1754
1755   GST_OBJECT_LOCK (trans->sinkpad);
1756   reconfigure = GST_PAD_NEEDS_RECONFIGURE (trans->srcpad)
1757       || trans->priv->reconfigure;
1758   GST_OBJECT_FLAG_UNSET (trans->srcpad, GST_PAD_FLAG_NEED_RECONFIGURE);
1759   trans->priv->reconfigure = FALSE;
1760   GST_OBJECT_UNLOCK (trans->sinkpad);
1761
1762   if (G_UNLIKELY (reconfigure)) {
1763     GstCaps *incaps;
1764
1765     GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
1766
1767     incaps = gst_pad_get_current_caps (trans->sinkpad);
1768     if (incaps == NULL)
1769       goto no_reconfigure;
1770
1771     /* if we need to reconfigure we pretend new caps arrived. This
1772      * will reconfigure the transform with the new output format. */
1773     if (!gst_base_transform_setcaps (trans, trans->sinkpad, incaps)) {
1774       gst_caps_unref (incaps);
1775       goto not_negotiated;
1776     }
1777     gst_caps_unref (incaps);
1778   }
1779
1780 no_reconfigure:
1781   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1782     GST_DEBUG_OBJECT (trans,
1783         "handling buffer %p of size %" G_GSIZE_FORMAT " and offset %"
1784         G_GUINT64_FORMAT, inbuf, gst_buffer_get_size (inbuf),
1785         GST_BUFFER_OFFSET (inbuf));
1786   else
1787     GST_DEBUG_OBJECT (trans,
1788         "handling buffer %p of size %" G_GSIZE_FORMAT " and offset NONE", inbuf,
1789         gst_buffer_get_size (inbuf));
1790
1791   /* Don't allow buffer handling before negotiation, except in passthrough mode
1792    * or if the class doesn't implement a set_caps function (in which case it doesn't
1793    * care about caps)
1794    */
1795   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1796     goto not_negotiated;
1797
1798   /* Set discont flag so we can mark the outgoing buffer */
1799   if (GST_BUFFER_IS_DISCONT (inbuf)) {
1800     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
1801     trans->priv->discont = TRUE;
1802   }
1803
1804   /* can only do QoS if the segment is in TIME */
1805   if (trans->segment.format != GST_FORMAT_TIME)
1806     goto no_qos;
1807
1808   /* QOS is done on the running time of the buffer, get it now */
1809   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
1810   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1811       timestamp);
1812
1813   if (running_time != -1) {
1814     gboolean need_skip;
1815     GstClockTime earliest_time;
1816     gdouble proportion;
1817
1818     /* lock for getting the QoS parameters that are set (in a different thread)
1819      * with the QOS events */
1820     GST_OBJECT_LOCK (trans);
1821     earliest_time = trans->priv->earliest_time;
1822     proportion = trans->priv->proportion;
1823     /* check for QoS, don't perform conversion for buffers
1824      * that are known to be late. */
1825     need_skip = trans->priv->qos_enabled &&
1826         earliest_time != -1 && running_time <= earliest_time;
1827     GST_OBJECT_UNLOCK (trans);
1828
1829     if (need_skip) {
1830       GstMessage *qos_msg;
1831       GstClockTime duration;
1832       guint64 stream_time;
1833       gint64 jitter;
1834
1835       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1836           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1837           GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
1838
1839       trans->priv->dropped++;
1840
1841       duration = GST_BUFFER_DURATION (inbuf);
1842       stream_time =
1843           gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1844           timestamp);
1845       jitter = GST_CLOCK_DIFF (running_time, earliest_time);
1846
1847       qos_msg =
1848           gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
1849           stream_time, timestamp, duration);
1850       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
1851       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
1852           trans->priv->processed, trans->priv->dropped);
1853       gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
1854
1855       /* mark discont for next buffer */
1856       trans->priv->discont = TRUE;
1857       goto skip;
1858     }
1859   }
1860
1861 no_qos:
1862
1863   /* first try to allocate an output buffer based on the currently negotiated
1864    * format. outbuf will contain a buffer suitable for doing the configured
1865    * transform after this function. */
1866   if (bclass->prepare_output_buffer == NULL)
1867     goto no_prepare;
1868
1869   GST_DEBUG_OBJECT (trans, "calling prepare buffer");
1870   ret = bclass->prepare_output_buffer (trans, inbuf, outbuf);
1871
1872   if (ret != GST_FLOW_OK || *outbuf == NULL)
1873     goto no_buffer;
1874
1875   GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", inbuf,
1876       *outbuf);
1877
1878   /* now perform the needed transform */
1879   if (trans->passthrough) {
1880     /* In passthrough mode, give transform_ip a look at the
1881      * buffer, without making it writable, or just push the
1882      * data through */
1883     if (bclass->transform_ip) {
1884       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
1885       ret = bclass->transform_ip (trans, *outbuf);
1886     } else {
1887       GST_DEBUG_OBJECT (trans, "element is in passthrough");
1888     }
1889   } else {
1890     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1891
1892     if (want_in_place) {
1893       GST_DEBUG_OBJECT (trans, "doing inplace transform");
1894       ret = bclass->transform_ip (trans, *outbuf);
1895     } else {
1896       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
1897
1898       if (bclass->transform)
1899         ret = bclass->transform (trans, inbuf, *outbuf);
1900       else
1901         ret = GST_FLOW_NOT_SUPPORTED;
1902     }
1903   }
1904
1905 skip:
1906   /* only unref input buffer if we allocated a new outbuf buffer. If we reused
1907    * the input buffer, no refcount is changed to keep the input buffer writable
1908    * when needed. */
1909   if (*outbuf != inbuf)
1910     gst_buffer_unref (inbuf);
1911
1912   return ret;
1913
1914   /* ERRORS */
1915 not_negotiated:
1916   {
1917     gst_buffer_unref (inbuf);
1918     *outbuf = NULL;
1919     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1920         ("not negotiated"), ("not negotiated"));
1921     return GST_FLOW_NOT_NEGOTIATED;
1922   }
1923 no_prepare:
1924   {
1925     gst_buffer_unref (inbuf);
1926     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1927         ("Sub-class has no prepare_output_buffer implementation"), (NULL));
1928     return GST_FLOW_NOT_SUPPORTED;
1929   }
1930 no_buffer:
1931   {
1932     gst_buffer_unref (inbuf);
1933     *outbuf = NULL;
1934     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
1935         gst_flow_get_name (ret));
1936     return ret;
1937   }
1938 }
1939
1940 /* FIXME, getrange is broken, need to pull range from the other
1941  * end based on the transform_size result.
1942  */
1943 static GstFlowReturn
1944 gst_base_transform_getrange (GstPad * pad, GstObject * parent, guint64 offset,
1945     guint length, GstBuffer ** buffer)
1946 {
1947   GstBaseTransform *trans;
1948   GstBaseTransformClass *klass;
1949   GstFlowReturn ret;
1950   GstBuffer *inbuf;
1951
1952   trans = GST_BASE_TRANSFORM (parent);
1953
1954   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1955   if (G_UNLIKELY (ret != GST_FLOW_OK))
1956     goto pull_error;
1957
1958   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1959   if (klass->before_transform)
1960     klass->before_transform (trans, inbuf);
1961
1962   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1963
1964 done:
1965   return ret;
1966
1967   /* ERRORS */
1968 pull_error:
1969   {
1970     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
1971         gst_flow_get_name (ret));
1972     goto done;
1973   }
1974 }
1975
1976 static GstFlowReturn
1977 gst_base_transform_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1978 {
1979   GstBaseTransform *trans;
1980   GstBaseTransformClass *klass;
1981   GstFlowReturn ret;
1982   GstClockTime position = GST_CLOCK_TIME_NONE;
1983   GstClockTime timestamp, duration;
1984   GstBuffer *outbuf = NULL;
1985
1986   trans = GST_BASE_TRANSFORM (parent);
1987
1988   timestamp = GST_BUFFER_TIMESTAMP (buffer);
1989   duration = GST_BUFFER_DURATION (buffer);
1990
1991   /* calculate end position of the incoming buffer */
1992   if (timestamp != GST_CLOCK_TIME_NONE) {
1993     if (duration != GST_CLOCK_TIME_NONE)
1994       position = timestamp + duration;
1995     else
1996       position = timestamp;
1997   }
1998
1999   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2000   if (klass->before_transform)
2001     klass->before_transform (trans, buffer);
2002
2003   /* protect transform method and concurrent buffer alloc */
2004   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2005
2006   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2007    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2008   if (outbuf != NULL) {
2009     if (ret == GST_FLOW_OK) {
2010       GstClockTime position_out = GST_CLOCK_TIME_NONE;
2011
2012       /* Remember last stop position */
2013       if (position != GST_CLOCK_TIME_NONE &&
2014           trans->segment.format == GST_FORMAT_TIME)
2015         trans->segment.position = position;
2016
2017       if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2018         position_out = GST_BUFFER_TIMESTAMP (outbuf);
2019         if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2020           position_out += GST_BUFFER_DURATION (outbuf);
2021       } else if (position != GST_CLOCK_TIME_NONE) {
2022         position_out = position;
2023       }
2024       if (position_out != GST_CLOCK_TIME_NONE
2025           && trans->segment.format == GST_FORMAT_TIME)
2026         trans->priv->position_out = position_out;
2027
2028       /* apply DISCONT flag if the buffer is not yet marked as such */
2029       if (trans->priv->discont) {
2030         GST_DEBUG_OBJECT (trans, "we have a pending DISCONT");
2031         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2032           GST_DEBUG_OBJECT (trans, "marking DISCONT on output buffer");
2033           outbuf = gst_buffer_make_writable (outbuf);
2034           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2035         }
2036         trans->priv->discont = FALSE;
2037       }
2038       trans->priv->processed++;
2039
2040       ret = gst_pad_push (trans->srcpad, outbuf);
2041     } else {
2042       GST_DEBUG_OBJECT (trans, "we got return %s", gst_flow_get_name (ret));
2043       gst_buffer_unref (outbuf);
2044     }
2045   }
2046
2047   /* convert internal flow to OK and mark discont for the next buffer. */
2048   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2049     GST_DEBUG_OBJECT (trans, "dropped a buffer, marking DISCONT");
2050     trans->priv->discont = TRUE;
2051     ret = GST_FLOW_OK;
2052   }
2053
2054   return ret;
2055 }
2056
2057 static void
2058 gst_base_transform_set_property (GObject * object, guint prop_id,
2059     const GValue * value, GParamSpec * pspec)
2060 {
2061   GstBaseTransform *trans;
2062
2063   trans = GST_BASE_TRANSFORM (object);
2064
2065   switch (prop_id) {
2066     case PROP_QOS:
2067       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2068       break;
2069     default:
2070       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2071       break;
2072   }
2073 }
2074
2075 static void
2076 gst_base_transform_get_property (GObject * object, guint prop_id,
2077     GValue * value, GParamSpec * pspec)
2078 {
2079   GstBaseTransform *trans;
2080
2081   trans = GST_BASE_TRANSFORM (object);
2082
2083   switch (prop_id) {
2084     case PROP_QOS:
2085       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2086       break;
2087     default:
2088       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2089       break;
2090   }
2091 }
2092
2093 /* not a vmethod of anything, just an internal method */
2094 static gboolean
2095 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2096 {
2097   GstBaseTransformClass *bclass;
2098   gboolean result = TRUE;
2099
2100   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2101
2102   if (active) {
2103     GstCaps *incaps, *outcaps;
2104
2105     if (trans->priv->pad_mode == GST_PAD_MODE_NONE && bclass->start)
2106       result &= bclass->start (trans);
2107
2108     incaps = gst_pad_get_current_caps (trans->sinkpad);
2109     outcaps = gst_pad_get_current_caps (trans->srcpad);
2110
2111     GST_OBJECT_LOCK (trans);
2112     if (incaps && outcaps)
2113       trans->have_same_caps =
2114           gst_caps_is_equal (incaps, outcaps) || trans->passthrough;
2115     else
2116       trans->have_same_caps = trans->passthrough;
2117     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2118     trans->negotiated = FALSE;
2119     trans->have_segment = FALSE;
2120     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2121     trans->priv->position_out = GST_CLOCK_TIME_NONE;
2122     trans->priv->proportion = 1.0;
2123     trans->priv->earliest_time = -1;
2124     trans->priv->discont = FALSE;
2125     trans->priv->processed = 0;
2126     trans->priv->dropped = 0;
2127     GST_OBJECT_UNLOCK (trans);
2128
2129     if (incaps)
2130       gst_caps_unref (incaps);
2131     if (outcaps)
2132       gst_caps_unref (outcaps);
2133   } else {
2134     /* We must make sure streaming has finished before resetting things
2135      * and calling the ::stop vfunc */
2136     GST_PAD_STREAM_LOCK (trans->sinkpad);
2137     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2138
2139     trans->have_same_caps = FALSE;
2140     /* We can only reset the passthrough mode if the instance told us to 
2141        handle it in configure_caps */
2142     if (bclass->passthrough_on_same_caps) {
2143       gst_base_transform_set_passthrough (trans, FALSE);
2144     }
2145     gst_caps_replace (&trans->cache_caps1, NULL);
2146     gst_caps_replace (&trans->cache_caps2, NULL);
2147
2148     if (trans->priv->pad_mode != GST_PAD_MODE_NONE && bclass->stop)
2149       result &= bclass->stop (trans);
2150
2151     gst_base_transform_set_allocation (trans, NULL, NULL, 0, 0, NULL);
2152   }
2153
2154   return result;
2155 }
2156
2157 static gboolean
2158 gst_base_transform_sink_activate_mode (GstPad * pad, GstObject * parent,
2159     GstPadMode mode, gboolean active)
2160 {
2161   gboolean result = FALSE;
2162   GstBaseTransform *trans;
2163
2164   trans = GST_BASE_TRANSFORM (parent);
2165
2166   switch (mode) {
2167     case GST_PAD_MODE_PUSH:
2168     {
2169       result = gst_base_transform_activate (trans, active);
2170
2171       if (result)
2172         trans->priv->pad_mode = active ? GST_PAD_MODE_PUSH : GST_PAD_MODE_NONE;
2173
2174       break;
2175     }
2176     default:
2177       result = TRUE;
2178       break;
2179   }
2180   return result;
2181 }
2182
2183 static gboolean
2184 gst_base_transform_src_activate_mode (GstPad * pad, GstObject * parent,
2185     GstPadMode mode, gboolean active)
2186 {
2187   gboolean result = FALSE;
2188   GstBaseTransform *trans;
2189
2190   trans = GST_BASE_TRANSFORM (parent);
2191
2192   switch (mode) {
2193     case GST_PAD_MODE_PULL:
2194     {
2195       result =
2196           gst_pad_activate_mode (trans->sinkpad, GST_PAD_MODE_PULL, active);
2197
2198       if (result)
2199         result &= gst_base_transform_activate (trans, active);
2200
2201       if (result)
2202         trans->priv->pad_mode = active ? mode : GST_PAD_MODE_NONE;
2203       break;
2204     }
2205     default:
2206       result = TRUE;
2207       break;
2208   }
2209
2210   return result;
2211 }
2212
2213 /**
2214  * gst_base_transform_set_passthrough:
2215  * @trans: the #GstBaseTransform to set
2216  * @passthrough: boolean indicating passthrough mode.
2217  *
2218  * Set passthrough mode for this filter by default. This is mostly
2219  * useful for filters that do not care about negotiation.
2220  *
2221  * Always TRUE for filters which don't implement either a transform
2222  * or transform_ip method.
2223  *
2224  * MT safe.
2225  */
2226 void
2227 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2228     gboolean passthrough)
2229 {
2230   GstBaseTransformClass *bclass;
2231
2232   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2233
2234   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2235
2236   GST_OBJECT_LOCK (trans);
2237   if (passthrough == FALSE) {
2238     if (bclass->transform_ip || bclass->transform)
2239       trans->passthrough = FALSE;
2240   } else {
2241     trans->passthrough = TRUE;
2242   }
2243
2244   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2245   GST_OBJECT_UNLOCK (trans);
2246 }
2247
2248 /**
2249  * gst_base_transform_is_passthrough:
2250  * @trans: the #GstBaseTransform to query
2251  *
2252  * See if @trans is configured as a passthrough transform.
2253  *
2254  * Returns: TRUE is the transform is configured in passthrough mode.
2255  *
2256  * MT safe.
2257  */
2258 gboolean
2259 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2260 {
2261   gboolean result;
2262
2263   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2264
2265   GST_OBJECT_LOCK (trans);
2266   result = trans->passthrough;
2267   GST_OBJECT_UNLOCK (trans);
2268
2269   return result;
2270 }
2271
2272 /**
2273  * gst_base_transform_set_in_place:
2274  * @trans: the #GstBaseTransform to modify
2275  * @in_place: Boolean value indicating that we would like to operate
2276  * on in_place buffers.
2277  *
2278  * Determines whether a non-writable buffer will be copied before passing
2279  * to the transform_ip function.
2280  * <itemizedlist>
2281  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2282  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2283  * </itemizedlist>
2284  *
2285  * MT safe.
2286  */
2287 void
2288 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2289 {
2290   GstBaseTransformClass *bclass;
2291
2292   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2293
2294   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2295
2296   GST_OBJECT_LOCK (trans);
2297
2298   if (in_place) {
2299     if (bclass->transform_ip) {
2300       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2301       trans->always_in_place = TRUE;
2302     }
2303   } else {
2304     if (bclass->transform) {
2305       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2306       trans->always_in_place = FALSE;
2307     }
2308   }
2309
2310   GST_OBJECT_UNLOCK (trans);
2311 }
2312
2313 /**
2314  * gst_base_transform_is_in_place:
2315  * @trans: the #GstBaseTransform to query
2316  *
2317  * See if @trans is configured as a in_place transform.
2318  *
2319  * Returns: TRUE is the transform is configured in in_place mode.
2320  *
2321  * MT safe.
2322  */
2323 gboolean
2324 gst_base_transform_is_in_place (GstBaseTransform * trans)
2325 {
2326   gboolean result;
2327
2328   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2329
2330   GST_OBJECT_LOCK (trans);
2331   result = trans->always_in_place;
2332   GST_OBJECT_UNLOCK (trans);
2333
2334   return result;
2335 }
2336
2337 /**
2338  * gst_base_transform_update_qos:
2339  * @trans: a #GstBaseTransform
2340  * @proportion: the proportion
2341  * @diff: the diff against the clock
2342  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2343  * running_time.
2344  *
2345  * Set the QoS parameters in the transform. This function is called internally
2346  * when a QOS event is received but subclasses can provide custom information
2347  * when needed.
2348  *
2349  * MT safe.
2350  *
2351  * Since: 0.10.5
2352  */
2353 void
2354 gst_base_transform_update_qos (GstBaseTransform * trans,
2355     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2356 {
2357
2358   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2359
2360   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2361       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2362       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2363
2364   GST_OBJECT_LOCK (trans);
2365   trans->priv->proportion = proportion;
2366   trans->priv->earliest_time = timestamp + diff;
2367   GST_OBJECT_UNLOCK (trans);
2368 }
2369
2370 /**
2371  * gst_base_transform_set_qos_enabled:
2372  * @trans: a #GstBaseTransform
2373  * @enabled: new state
2374  *
2375  * Enable or disable QoS handling in the transform.
2376  *
2377  * MT safe.
2378  *
2379  * Since: 0.10.5
2380  */
2381 void
2382 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2383 {
2384   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2385
2386   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2387
2388   GST_OBJECT_LOCK (trans);
2389   trans->priv->qos_enabled = enabled;
2390   GST_OBJECT_UNLOCK (trans);
2391 }
2392
2393 /**
2394  * gst_base_transform_is_qos_enabled:
2395  * @trans: a #GstBaseTransform
2396  *
2397  * Queries if the transform will handle QoS.
2398  *
2399  * Returns: TRUE if QoS is enabled.
2400  *
2401  * MT safe.
2402  *
2403  * Since: 0.10.5
2404  */
2405 gboolean
2406 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2407 {
2408   gboolean result;
2409
2410   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2411
2412   GST_OBJECT_LOCK (trans);
2413   result = trans->priv->qos_enabled;
2414   GST_OBJECT_UNLOCK (trans);
2415
2416   return result;
2417 }
2418
2419 /**
2420  * gst_base_transform_set_gap_aware:
2421  * @trans: a #GstBaseTransform
2422  * @gap_aware: New state
2423  *
2424  * If @gap_aware is %FALSE (the default), output buffers will have the
2425  * %GST_BUFFER_FLAG_GAP flag unset.
2426  *
2427  * If set to %TRUE, the element must handle output buffers with this flag set
2428  * correctly, i.e. it can assume that the buffer contains neutral data but must
2429  * unset the flag if the output is no neutral data.
2430  *
2431  * MT safe.
2432  *
2433  * Since: 0.10.16
2434  */
2435 void
2436 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2437 {
2438   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2439
2440   GST_OBJECT_LOCK (trans);
2441   trans->priv->gap_aware = gap_aware;
2442   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2443   GST_OBJECT_UNLOCK (trans);
2444 }
2445
2446 /**
2447  * gst_base_transform_reconfigure_sink:
2448  * @trans: a #GstBaseTransform
2449  *
2450  * Instructs @trans to request renegotiation upstream. This function is
2451  * typically called after properties on the transform were set that
2452  * influence the input format.
2453  */
2454 void
2455 gst_base_transform_reconfigure_sink (GstBaseTransform * trans)
2456 {
2457   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2458
2459   /* push the renegotiate event */
2460   if (!gst_pad_push_event (GST_BASE_TRANSFORM_SINK_PAD (trans),
2461           gst_event_new_reconfigure ()))
2462     GST_DEBUG_OBJECT (trans, "Renegotiate event wasn't handled");
2463 }
2464
2465 /**
2466  * gst_base_transform_reconfigure_src:
2467  * @trans: a #GstBaseTransform
2468  *
2469  * Instructs @trans to renegotiate a new downstream transform on the next
2470  * buffer. This function is typically called after properties on the transform
2471  * were set that influence the output format.
2472  *
2473  * Since: 0.10.21
2474  */
2475 void
2476 gst_base_transform_reconfigure_src (GstBaseTransform * trans)
2477 {
2478   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2479
2480   GST_OBJECT_LOCK (trans);
2481   GST_DEBUG_OBJECT (trans, "marking reconfigure");
2482   trans->priv->reconfigure = TRUE;
2483   GST_OBJECT_UNLOCK (trans);
2484 }