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