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