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