libs/gst/base/gstbasetransform.*: Add vmethod that is called before we start the...
[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   /* upstream caps and size suggestions */
252   GstCaps *sink_suggest;
253   guint size_suggest;
254   gboolean suggest_pending;
255
256   gboolean reconfigure;
257 };
258
259 static GstElementClass *parent_class = NULL;
260
261 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
262 static void gst_base_transform_init (GstBaseTransform * trans,
263     GstBaseTransformClass * klass);
264 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
265     * trans, GstBuffer * input, GstBuffer ** buf);
266
267 GType
268 gst_base_transform_get_type (void)
269 {
270   static GType base_transform_type = 0;
271
272   if (!base_transform_type) {
273     static const GTypeInfo base_transform_info = {
274       sizeof (GstBaseTransformClass),
275       NULL,
276       NULL,
277       (GClassInitFunc) gst_base_transform_class_init,
278       NULL,
279       NULL,
280       sizeof (GstBaseTransform),
281       0,
282       (GInstanceInitFunc) gst_base_transform_init,
283     };
284
285     base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
286         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
287   }
288   return base_transform_type;
289 }
290
291 static void gst_base_transform_finalize (GObject * object);
292 static void gst_base_transform_set_property (GObject * object, guint prop_id,
293     const GValue * value, GParamSpec * pspec);
294 static void gst_base_transform_get_property (GObject * object, guint prop_id,
295     GValue * value, GParamSpec * pspec);
296 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
297     gboolean active);
298 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
299     gboolean active);
300 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
301     gboolean active);
302 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
303     GstCaps * caps, guint * size);
304
305 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
306 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
307     GstEvent * event);
308 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
309 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
310     GstEvent * event);
311 static gboolean gst_base_transform_check_get_range (GstPad * pad);
312 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
313     guint length, GstBuffer ** buffer);
314 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
315     GstBuffer * buffer);
316 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
317 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
318 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
319 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
320     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
321
322 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
323
324 static void
325 gst_base_transform_finalize (GObject * object)
326 {
327   GstBaseTransform *trans;
328
329   trans = GST_BASE_TRANSFORM (object);
330
331   gst_caps_replace (&trans->priv->sink_suggest, NULL);
332   g_mutex_free (trans->transform_lock);
333
334   G_OBJECT_CLASS (parent_class)->finalize (object);
335 }
336
337 static void
338 gst_base_transform_class_init (GstBaseTransformClass * klass)
339 {
340   GObjectClass *gobject_class;
341
342   gobject_class = G_OBJECT_CLASS (klass);
343
344   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
345       "basetransform element");
346
347   GST_DEBUG ("gst_base_transform_class_init");
348
349   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
350
351   parent_class = g_type_class_peek_parent (klass);
352
353   gobject_class->set_property =
354       GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
355   gobject_class->get_property =
356       GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
357
358   g_object_class_install_property (gobject_class, PROP_QOS,
359       g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
360           DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
361
362   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
363
364   klass->passthrough_on_same_caps = FALSE;
365   klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
366   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
367 }
368
369 static void
370 gst_base_transform_init (GstBaseTransform * trans,
371     GstBaseTransformClass * bclass)
372 {
373   GstPadTemplate *pad_template;
374
375   GST_DEBUG ("gst_base_transform_init");
376
377   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
378
379   pad_template =
380       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
381   g_return_if_fail (pad_template != NULL);
382   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
383   gst_pad_set_getcaps_function (trans->sinkpad,
384       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
385   gst_pad_set_acceptcaps_function (trans->sinkpad,
386       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
387   gst_pad_set_setcaps_function (trans->sinkpad,
388       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
389   gst_pad_set_event_function (trans->sinkpad,
390       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
391   gst_pad_set_chain_function (trans->sinkpad,
392       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
393   gst_pad_set_activatepush_function (trans->sinkpad,
394       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
395   gst_pad_set_bufferalloc_function (trans->sinkpad,
396       GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
397   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
398
399   pad_template =
400       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
401   g_return_if_fail (pad_template != NULL);
402   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
403   gst_pad_set_getcaps_function (trans->srcpad,
404       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
405   gst_pad_set_acceptcaps_function (trans->srcpad,
406       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
407   gst_pad_set_event_function (trans->srcpad,
408       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
409   gst_pad_set_checkgetrange_function (trans->srcpad,
410       GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
411   gst_pad_set_getrange_function (trans->srcpad,
412       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
413   gst_pad_set_activatepull_function (trans->srcpad,
414       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
415   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
416
417   trans->transform_lock = g_mutex_new ();
418   trans->pending_configure = FALSE;
419   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
420   trans->cache_caps1 = NULL;
421   trans->cache_caps2 = NULL;
422   trans->priv->pad_mode = GST_ACTIVATE_NONE;
423   trans->priv->gap_aware = FALSE;
424
425   trans->passthrough = FALSE;
426   if (bclass->transform == NULL) {
427     /* If no transform function, always_in_place is TRUE */
428     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
429     trans->always_in_place = TRUE;
430
431     if (bclass->transform_ip == NULL) {
432       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
433       trans->passthrough = TRUE;
434     }
435   }
436 }
437
438 /* given @caps on the src or sink pad (given by @direction)
439  * calculate the possible caps on the other pad.
440  *
441  * Returns new caps, unref after usage.
442  */
443 static GstCaps *
444 gst_base_transform_transform_caps (GstBaseTransform * trans,
445     GstPadDirection direction, GstCaps * caps)
446 {
447   GstCaps *ret;
448   GstBaseTransformClass *klass;
449
450   if (caps == NULL)
451     return NULL;
452
453   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
454
455   /* if there is a custom transform function, use this */
456   if (klass->transform_caps) {
457     GstCaps *temp;
458     gint i;
459
460     /* start with empty caps */
461     ret = gst_caps_new_empty ();
462     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
463
464     if (gst_caps_is_any (caps)) {
465       /* for any caps we still have to call the transform function */
466       GST_DEBUG_OBJECT (trans, "from: ANY");
467       temp = klass->transform_caps (trans, direction, caps);
468       GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);
469
470       temp = gst_caps_make_writable (temp);
471       gst_caps_append (ret, temp);
472     } else {
473       /* we send caps with just one structure to the transform
474        * function as this is easier for the element */
475       for (i = 0; i < gst_caps_get_size (caps); i++) {
476         GstCaps *nth;
477
478         nth = gst_caps_copy_nth (caps, i);
479         GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
480         temp = klass->transform_caps (trans, direction, nth);
481         gst_caps_unref (nth);
482         GST_LOG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
483
484         temp = gst_caps_make_writable (temp);
485
486         /* here we need to only append those structures, that are not yet
487          * in there, we use the merge function for this */
488         gst_caps_merge (ret, temp);
489
490         GST_LOG_OBJECT (trans, "  merged[%d]: %" GST_PTR_FORMAT, i, ret);
491       }
492       GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
493       /* we can't do much simplification here because we don't really want to
494        * change the caps order */
495     }
496   } else {
497     GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
498     /* no transform function, use the identity transform */
499     ret = gst_caps_ref (caps);
500   }
501
502   GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
503       ret);
504
505   return ret;
506 }
507
508 /* transform a buffer of @size with @caps on the pad with @direction to
509  * the size of a buffer with @othercaps and store the result in @othersize
510  *
511  * We have two ways of doing this:
512  *  1) use a custom transform size function, this is for complicated custom
513  *     cases with no fixed unit_size.
514  *  2) use the unit_size functions where there is a relationship between the
515  *     caps and the size of a buffer.
516  */
517 static gboolean
518 gst_base_transform_transform_size (GstBaseTransform * trans,
519     GstPadDirection direction, GstCaps * caps,
520     guint size, GstCaps * othercaps, guint * othersize)
521 {
522   guint inunitsize, outunitsize, units;
523   GstBaseTransformClass *klass;
524   gboolean ret;
525
526   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
527
528   GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
529       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
530       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
531
532   if (klass->transform_size) {
533     /* if there is a custom transform function, use this */
534     ret = klass->transform_size (trans, direction, caps, size, othercaps,
535         othersize);
536   } else {
537     /* there is no transform_size function, we have to use the unit_size
538      * functions. This method assumes there is a fixed unit_size associated with
539      * each caps. We provide the same amount of units on both sides. */
540     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
541       goto no_in_size;
542
543     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
544         inunitsize);
545
546     /* input size must be a multiple of the unit_size of the input caps */
547     if (inunitsize == 0 || (size % inunitsize != 0))
548       goto no_multiple;
549
550     /* get the amount of units */
551     units = size / inunitsize;
552
553     /* now get the unit size of the output */
554     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
555       goto no_out_size;
556
557     /* the output size is the unit_size times the amount of units on the
558      * input */
559     *othersize = units * outunitsize;
560     GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
561
562     ret = TRUE;
563   }
564   return ret;
565
566   /* ERRORS */
567 no_in_size:
568   {
569     GST_DEBUG_OBJECT (trans, "could not get in_size");
570     g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
571     return FALSE;
572   }
573 no_multiple:
574   {
575     GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
576         inunitsize);
577     g_warning ("%s: size %u is not a multiple of unit size %u",
578         GST_ELEMENT_NAME (trans), size, inunitsize);
579     return FALSE;
580   }
581 no_out_size:
582   {
583     GST_DEBUG_OBJECT (trans, "could not get out_size");
584     g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
585     return FALSE;
586   }
587 }
588
589 /* get the caps that can be handled by @pad. We perforn:
590  *
591  *  - take the caps of peer of otherpad,
592  *  - filter against the padtemplate of otherpad, 
593  *  - calculate all transforms of remaining caps
594  *  - filter against template of @pad
595  *
596  * If there is no peer, we simply return the caps of the padtemplate of pad.
597  */
598 static GstCaps *
599 gst_base_transform_getcaps (GstPad * pad)
600 {
601   GstBaseTransform *trans;
602   GstPad *otherpad;
603   GstCaps *caps;
604
605   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
606
607   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
608
609   /* we can do what the peer can */
610   caps = gst_pad_peer_get_caps (otherpad);
611   if (caps) {
612     GstCaps *temp;
613     const GstCaps *templ;
614
615     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, caps);
616
617     /* filtered against our padtemplate */
618     templ = gst_pad_get_pad_template_caps (otherpad);
619     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
620     temp = gst_caps_intersect (caps, templ);
621     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
622     gst_caps_unref (caps);
623
624     /* then see what we can transform this to */
625     caps = gst_base_transform_transform_caps (trans,
626         GST_PAD_DIRECTION (otherpad), temp);
627     GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
628     gst_caps_unref (temp);
629     if (caps == NULL)
630       goto done;
631
632     /* and filter against the template again */
633     templ = gst_pad_get_pad_template_caps (pad);
634     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
635     temp = gst_caps_intersect (caps, templ);
636     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
637     gst_caps_unref (caps);
638     /* this is what we can do */
639     caps = temp;
640   } else {
641     /* no peer or the peer can do anything, our padtemplate is enough then */
642     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
643   }
644
645 done:
646   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
647
648   gst_object_unref (trans);
649
650   return caps;
651 }
652
653 /* function triggered when the in and out caps are negotiated and need
654  * to be configured in the subclass. */
655 static gboolean
656 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
657     GstCaps * out)
658 {
659   gboolean ret = TRUE;
660   GstBaseTransformClass *klass;
661
662   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
663
664   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
665   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
666
667   /* clear the cache */
668   gst_caps_replace (&trans->cache_caps1, NULL);
669   gst_caps_replace (&trans->cache_caps2, NULL);
670
671   /* figure out same caps state */
672   trans->have_same_caps = gst_caps_is_equal (in, out);
673   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
674
675   /* If we've a transform_ip method and same input/output caps, set in_place
676    * by default. If for some reason the sub-class prefers using a transform
677    * function, it can clear the in place flag in the set_caps */
678   gst_base_transform_set_in_place (trans,
679       klass->transform_ip && trans->have_same_caps);
680
681   /* Set the passthrough if the class wants passthrough_on_same_caps
682    * and we have the same caps on each pad */
683   if (klass->passthrough_on_same_caps)
684     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
685
686   /* now configure the element with the caps */
687   if (klass->set_caps) {
688     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
689     ret = klass->set_caps (trans, in, out);
690   }
691
692   trans->negotiated = ret;
693
694   return ret;
695 }
696
697 /* check if caps @in on @pad can be transformed to @out on the other pad.
698  * We don't have a vmethod to test this yet so we have to do a somewhat less
699  * efficient check for this.
700  */
701 static gboolean
702 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
703     GstCaps * in, GstCaps * out)
704 {
705   GstCaps *othercaps;
706
707   /* convert the in caps to all possible out caps */
708   othercaps =
709       gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
710
711   /* check if transform is empty */
712   if (!othercaps || gst_caps_is_empty (othercaps))
713     goto no_transform;
714
715   /* check if the out caps is a subset of the othercaps */
716   if (!gst_caps_is_subset (out, othercaps))
717     goto no_subset;
718
719   if (othercaps)
720     gst_caps_unref (othercaps);
721
722   GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
723   GST_DEBUG_OBJECT (trans, "to   %" GST_PTR_FORMAT, out);
724
725   return TRUE;
726
727   /* ERRORS */
728 no_transform:
729   {
730     GST_DEBUG_OBJECT (trans,
731         "transform returned useless %" GST_PTR_FORMAT, othercaps);
732     if (othercaps)
733       gst_caps_unref (othercaps);
734     return FALSE;
735   }
736 no_subset:
737   {
738     GST_DEBUG_OBJECT (trans, "no subset");
739     if (othercaps)
740       gst_caps_unref (othercaps);
741     return FALSE;
742   }
743 }
744
745 /* given a fixed @caps on @pad, create the best possible caps for the
746  * other pad.
747  * @caps must be fixed when calling this function.
748  *
749  * This function calls the transform caps vmethod of the basetransform to figure
750  * out the possible target formats. It then tries to select the best format from
751  * this list by:
752  *
753  * - attempt passthrough if the target caps is a superset of the input caps
754  * - fixating by using peer caps
755  * - fixating with transform fixate function
756  * - fixating with pad fixate functions.
757  *
758  * this function returns a caps that can be transformed into and is accepted by
759  * the peer element.
760  */
761 static GstCaps *
762 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
763     GstCaps * caps)
764 {
765   GstBaseTransformClass *klass;
766   GstPad *otherpad, *otherpeer;
767   GstCaps *othercaps;
768   gboolean peer_checked = FALSE;
769
770   /* caps must be fixed here, this is a programming error if it's not */
771   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
772
773   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
774
775   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
776   otherpeer = gst_pad_get_peer (otherpad);
777
778   /* see how we can transform the input caps. We need to do this even for
779    * passthrough because it might be possible that this element cannot support
780    * passthrough at all. */
781   othercaps = gst_base_transform_transform_caps (trans,
782       GST_PAD_DIRECTION (pad), caps);
783
784   /* The caps we can actually output is the intersection of the transformed
785    * caps with the pad template for the pad */
786   if (othercaps) {
787     GstCaps *intersect;
788     const GstCaps *templ_caps;
789
790     templ_caps = gst_pad_get_pad_template_caps (otherpad);
791     GST_DEBUG_OBJECT (trans,
792         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
793
794     intersect = gst_caps_intersect (othercaps, templ_caps);
795
796     gst_caps_unref (othercaps);
797     othercaps = intersect;
798   }
799
800   /* check if transform is empty */
801   if (!othercaps || gst_caps_is_empty (othercaps))
802     goto no_transform;
803
804   /* if the othercaps are not fixed, we need to fixate them, first attempt
805    * is by attempting passthrough if the othercaps are a superset of caps. */
806   /* FIXME. maybe the caps is not fixed because it has multiple structures of
807    * fixed caps */
808   if (!gst_caps_is_fixed (othercaps)) {
809     GstCaps *temp;
810
811     GST_DEBUG_OBJECT (trans,
812         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
813
814     /* see if the target caps are a superset of the source caps, in this
815      * case we can try to perform passthrough */
816     temp = gst_caps_intersect (othercaps, caps);
817     GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
818     if (temp) {
819       if (!gst_caps_is_empty (temp)) {
820         GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
821         if (otherpeer) {
822           /* try passthrough. we know it's fixed, because caps is fixed */
823           if (gst_pad_accept_caps (otherpeer, caps)) {
824             GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
825             /* peer accepted unmodified caps, we free the original non-fixed
826              * caps and work with the passthrough caps */
827             gst_caps_unref (othercaps);
828             othercaps = gst_caps_ref (caps);
829             /* mark that we checked othercaps with the peer, this
830              * makes sure we don't call accept_caps again with these same
831              * caps */
832             peer_checked = TRUE;
833           } else {
834             GST_DEBUG_OBJECT (trans,
835                 "peer did not accept %" GST_PTR_FORMAT, caps);
836           }
837         } else {
838           GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
839           gst_caps_unref (othercaps);
840           othercaps = gst_caps_ref (caps);
841         }
842       }
843       gst_caps_unref (temp);
844     }
845   }
846
847   /* second attempt at fixation is done by intersecting with
848    * the peer caps */
849   if (!gst_caps_is_fixed (othercaps) && otherpeer) {
850     /* intersect against what the peer can do */
851     GstCaps *peercaps;
852     GstCaps *intersect;
853
854     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
855
856     peercaps = gst_pad_get_caps (otherpeer);
857     intersect = gst_caps_intersect (peercaps, othercaps);
858     gst_caps_unref (peercaps);
859     gst_caps_unref (othercaps);
860     othercaps = intersect;
861     peer_checked = FALSE;
862
863     GST_DEBUG_OBJECT (trans,
864         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
865   }
866
867   if (gst_caps_is_empty (othercaps))
868     goto no_transform_possible;
869
870   /* third attempt at fixation, call the fixate vmethod and
871    * ultimately call the pad fixate function. */
872   if (!gst_caps_is_fixed (othercaps)) {
873     GstCaps *temp;
874
875     GST_DEBUG_OBJECT (trans,
876         "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
877         othercaps, GST_DEBUG_PAD_NAME (otherpad));
878
879     /* since we have no other way to fixate left, we might as well just take
880      * the first of the caps list and fixate that */
881
882     /* FIXME: when fixating using the vmethod, it might make sense to fixate
883      * each of the caps; but Wim doesn't see a use case for that yet */
884     temp = gst_caps_copy_nth (othercaps, 0);
885     gst_caps_unref (othercaps);
886     othercaps = temp;
887     peer_checked = FALSE;
888
889     if (klass->fixate_caps) {
890       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
891           " using caps %" GST_PTR_FORMAT
892           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
893           GST_DEBUG_PAD_NAME (otherpad));
894       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
895     }
896     /* if still not fixed, no other option but to let the default pad fixate
897      * function do its job */
898     if (!gst_caps_is_fixed (othercaps)) {
899       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
900           " on pad %s:%s using gst_pad_fixate_caps", othercaps,
901           GST_DEBUG_PAD_NAME (otherpad));
902       gst_pad_fixate_caps (otherpad, othercaps);
903     }
904     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
905   } else {
906     /* else caps are fixed but the subclass may want to add fields */
907     if (klass->fixate_caps) {
908       othercaps = gst_caps_make_writable (othercaps);
909
910       GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
911           " using caps %" GST_PTR_FORMAT
912           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
913           GST_DEBUG_PAD_NAME (otherpad));
914
915       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
916     }
917   }
918
919   /* caps should be fixed now, if not we have to fail. */
920   if (!gst_caps_is_fixed (othercaps))
921     goto could_not_fixate;
922
923   /* and peer should accept, don't check again if we already checked the
924    * othercaps against the peer. */
925   if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
926     goto peer_no_accept;
927
928   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
929       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
930
931   if (otherpeer)
932     gst_object_unref (otherpeer);
933
934   return othercaps;
935
936   /* ERRORS */
937 no_transform:
938   {
939     GST_DEBUG_OBJECT (trans,
940         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
941     goto error_cleanup;
942   }
943 no_transform_possible:
944   {
945     GST_DEBUG_OBJECT (trans,
946         "transform could not transform %" GST_PTR_FORMAT
947         " in anything we support", caps);
948     goto error_cleanup;
949   }
950 could_not_fixate:
951   {
952     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
953     goto error_cleanup;
954   }
955 peer_no_accept:
956   {
957     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
958         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
959     goto error_cleanup;
960   }
961 error_cleanup:
962   {
963     if (otherpeer)
964       gst_object_unref (otherpeer);
965     if (othercaps)
966       gst_caps_unref (othercaps);
967     return NULL;
968   }
969 }
970
971 static gboolean
972 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
973 {
974   GstBaseTransform *trans;
975   GstPad *otherpad;
976   GstCaps *othercaps = NULL;
977   gboolean ret = TRUE;
978
979   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
980   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
981
982 #if 0
983   /* we need fixed caps for the check, fall back to the default implementation
984    * if we don't */
985   if (!gst_caps_is_fixed (caps))
986 #endif
987   {
988     GstCaps *allowed, *intersect;
989
990     GST_DEBUG_OBJECT (pad, "non fixed accept caps %" GST_PTR_FORMAT, caps);
991
992     /* get all the formats we can handle on this pad */
993     allowed = gst_pad_get_caps (pad);
994     if (!allowed)
995       goto no_transform_possible;
996
997     /* intersect with the requested format */
998     intersect = gst_caps_intersect (allowed, caps);
999
1000     GST_DEBUG_OBJECT (pad, "intersection %" GST_PTR_FORMAT, intersect);
1001
1002     /* we can accept if the intersection is not empty  */
1003     ret = !gst_caps_is_empty (intersect);
1004     gst_caps_unref (intersect);
1005     gst_caps_unref (allowed);
1006
1007     if (!ret)
1008       goto no_transform_possible;
1009   }
1010 #if 0
1011   else {
1012     GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1013
1014     /* find best possible caps for the other pad as a way to see if we can
1015      * transform this caps. */
1016     othercaps = gst_base_transform_find_transform (trans, pad, caps);
1017     if (!othercaps || gst_caps_is_empty (othercaps))
1018       goto no_transform_possible;
1019
1020     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1021   }
1022 #endif
1023
1024 done:
1025   if (othercaps)
1026     gst_caps_unref (othercaps);
1027   gst_object_unref (trans);
1028
1029   return ret;
1030
1031   /* ERRORS */
1032 no_transform_possible:
1033   {
1034     GST_WARNING_OBJECT (trans,
1035         "transform could not transform %" GST_PTR_FORMAT
1036         " in anything we support", caps);
1037     ret = FALSE;
1038     goto done;
1039   }
1040 }
1041
1042 /* called when new caps arrive on the sink or source pad,
1043  * We try to find the best caps for the other side using our _find_transform()
1044  * function. If there are caps, we configure the transform for this new
1045  * transformation.
1046  *
1047  * FIXME, this function is currently commutative but this should not really be
1048  * because we never set caps starting from the srcpad.
1049  */
1050 static gboolean
1051 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1052 {
1053   GstBaseTransform *trans;
1054   GstBaseTransformClass *klass;
1055   GstPad *otherpad, *otherpeer;
1056   GstCaps *othercaps = NULL;
1057   gboolean ret = TRUE;
1058   GstCaps *incaps, *outcaps;
1059
1060   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1061   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1062
1063   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1064   otherpeer = gst_pad_get_peer (otherpad);
1065
1066   /* if we get called recursively, we bail out now to avoid an
1067    * infinite loop. */
1068   if (GST_PAD_IS_IN_SETCAPS (otherpad))
1069     goto done;
1070
1071   GST_DEBUG_OBJECT (pad, "have new caps %" GST_PTR_FORMAT, caps);
1072
1073   /* find best possible caps for the other pad */
1074   othercaps = gst_base_transform_find_transform (trans, pad, caps);
1075   if (!othercaps || gst_caps_is_empty (othercaps))
1076     goto no_transform_possible;
1077
1078   /* configure the element now */
1079   /* make sure in and out caps are correct */
1080   if (pad == trans->sinkpad) {
1081     incaps = caps;
1082     outcaps = othercaps;
1083   } else {
1084     incaps = othercaps;
1085     outcaps = caps;
1086   }
1087
1088 #if 0
1089   /* if we have the same caps, we can optimize and reuse the input caps */
1090   if (gst_caps_is_equal (incaps, outcaps)) {
1091     GST_INFO_OBJECT (trans, "reuse caps");
1092     gst_caps_unref (outcaps);
1093     outcaps = gst_caps_ref (incaps);
1094   }
1095 #endif
1096
1097   /* call configure now */
1098   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1099     goto failed_configure;
1100
1101   /* we know this will work, we implement the setcaps */
1102   gst_pad_set_caps (otherpad, othercaps);
1103
1104   if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1105     /* FIXME hm? */
1106     ret &= gst_pad_set_caps (otherpeer, othercaps);
1107     if (!ret) {
1108       GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1109           othercaps);
1110     }
1111   }
1112
1113 done:
1114   if (otherpeer)
1115     gst_object_unref (otherpeer);
1116   if (othercaps)
1117     gst_caps_unref (othercaps);
1118
1119   trans->negotiated = ret;
1120
1121   gst_object_unref (trans);
1122
1123   return ret;
1124
1125   /* ERRORS */
1126 no_transform_possible:
1127   {
1128     GST_WARNING_OBJECT (trans,
1129         "transform could not transform %" GST_PTR_FORMAT
1130         " in anything we support", caps);
1131     ret = FALSE;
1132     goto done;
1133   }
1134 failed_configure:
1135   {
1136     GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1137         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1138     ret = FALSE;
1139     goto done;
1140   }
1141 }
1142
1143 /* Allocate a buffer using gst_pad_alloc_buffer
1144  *
1145  * This function can do renegotiation on the source pad
1146  *
1147  * The output buffer is always writable. outbuf can be equal to
1148  * inbuf, the caller should be prepared for this and perform 
1149  * appropriate refcounting.
1150  */
1151 static GstFlowReturn
1152 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1153     GstBuffer * in_buf, GstBuffer ** out_buf)
1154 {
1155   GstBaseTransformClass *bclass;
1156   GstBaseTransformPrivate *priv;
1157   GstFlowReturn ret = GST_FLOW_OK;
1158   guint outsize, newsize, expsize;
1159   gboolean discard;
1160   GstCaps *incaps, *oldcaps, *newcaps;
1161
1162   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1163
1164   priv = trans->priv;
1165
1166   *out_buf = NULL;
1167
1168   /* figure out how to allocate a buffer based on the current configuration */
1169   if (trans->passthrough) {
1170     GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1171     /* passthrough, we don't really need to call pad alloc but we still need to
1172      * in order to get upstream negotiation. The output size is the same as the
1173      * input size. */
1174     outsize = GST_BUFFER_SIZE (in_buf);
1175     /* we always alloc and discard here */
1176     discard = TRUE;
1177   } else {
1178     gboolean want_in_place = (bclass->transform_ip != NULL)
1179         && trans->always_in_place;
1180
1181     if (want_in_place) {
1182       GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1183       /* we alloc a buffer of the same size as the input */
1184       outsize = GST_BUFFER_SIZE (in_buf);
1185       /* only discard it when the input was not writable, otherwise, we reuse
1186        * the input buffer. */
1187       discard = gst_buffer_is_writable (in_buf);
1188       GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1189     } else {
1190       GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1191       /* copy transform, figure out the output size */
1192       if (!gst_base_transform_transform_size (trans,
1193               GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1194               GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1195               &outsize)) {
1196         goto unknown_size;
1197       }
1198       /* never discard this buffer, we need it for storing the output */
1199       discard = FALSE;
1200     }
1201   }
1202
1203   oldcaps = GST_PAD_CAPS (trans->srcpad);
1204
1205   if (bclass->prepare_output_buffer) {
1206     GST_DEBUG_OBJECT (trans,
1207         "calling prepare buffer with caps %" GST_PTR_FORMAT, oldcaps);
1208     ret =
1209         bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1210         out_buf);
1211
1212     /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1213      * update the pad caps if it wants */
1214     oldcaps = GST_PAD_CAPS (trans->srcpad);
1215
1216     /* FIXME 0.11:
1217      * decrease refcount again if vmethod returned refcounted in_buf. This
1218      * is because we need to make sure that the buffer is writable for the
1219      * in_place transform. The docs of the vmethod say that you should return
1220      * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1221     if (in_buf == *out_buf)
1222       gst_buffer_unref (in_buf);
1223
1224     /* never discard the buffer from the prepare_buffer method */
1225     if (*out_buf != NULL)
1226       discard = FALSE;
1227   }
1228
1229   if (ret != GST_FLOW_OK)
1230     goto alloc_failed;
1231
1232   if (*out_buf == NULL) {
1233     GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT, oldcaps);
1234
1235     ret = gst_pad_alloc_buffer (trans->srcpad,
1236         GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1237     if (ret != GST_FLOW_OK)
1238       goto alloc_failed;
1239   }
1240
1241   /* must always have a buffer by now */
1242   if (*out_buf == NULL)
1243     goto no_buffer;
1244
1245   /* check if we got different caps on this new output buffer */
1246   newcaps = GST_BUFFER_CAPS (*out_buf);
1247   newsize = GST_BUFFER_SIZE (*out_buf);
1248   if (!gst_caps_is_equal (newcaps, oldcaps)) {
1249     GstCaps *othercaps;
1250     gboolean can_convert;
1251
1252     GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1253
1254     incaps = GST_PAD_CAPS (trans->sinkpad);
1255
1256     /* it's possible that the buffer we got is of the wrong size, get the
1257      * expected size here, we will check the size if we are going to use the
1258      * buffer later on. */
1259     gst_base_transform_transform_size (trans,
1260         GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1261
1262     /* check if we can convert the current incaps to the new target caps */
1263     can_convert =
1264         gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1265         newcaps);
1266
1267     if (can_convert) {
1268       GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1269       /* caps not empty, try to renegotiate to the new format */
1270       if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1271         /* not sure we need to fail hard here, we can simply continue our
1272          * conversion with what we negotiated before */
1273         goto failed_configure;
1274       }
1275       /* new format configure, and use the new output buffer */
1276       gst_pad_set_caps (trans->srcpad, newcaps);
1277       discard = FALSE;
1278       /* if we got a buffer of the wrong size, discard it now and make sure we
1279        * allocate a propertly sized buffer later. */
1280       if (newsize != expsize) {
1281         if (in_buf != *out_buf)
1282           gst_buffer_unref (*out_buf);
1283         *out_buf = NULL;
1284       }
1285       outsize = expsize;
1286     } else {
1287       GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1288
1289       /* we cannot convert the current buffer but we might be able to suggest a
1290        * new format upstream, try to find what the best format is. */
1291       othercaps =
1292           gst_base_transform_find_transform (trans, trans->srcpad, newcaps);
1293
1294       if (!othercaps) {
1295         GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1296         /* we received caps that we cannot transform. Upstream is behaving badly
1297          * because it should have checked if we could handle these caps. We can
1298          * simply ignore these caps and produce a buffer with our original caps. */
1299       } else {
1300         guint size_suggest;
1301
1302         GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1303
1304         /* not a subset, we have a new upstream suggestion, remember it and
1305          * allocate a default buffer. First we try to convert the size */
1306         if (gst_base_transform_transform_size (trans,
1307                 GST_PAD_SRC, newcaps, expsize, othercaps, &size_suggest)) {
1308
1309           /* ok, remember the suggestions now */
1310           GST_DEBUG_OBJECT (trans,
1311               "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1312               size_suggest, othercaps);
1313
1314           GST_OBJECT_LOCK (trans->sinkpad);
1315           if (priv->sink_suggest)
1316             gst_caps_unref (priv->sink_suggest);
1317           priv->sink_suggest = gst_caps_ref (othercaps);
1318           priv->size_suggest = size_suggest;
1319           trans->priv->suggest_pending = TRUE;
1320           GST_OBJECT_UNLOCK (trans->sinkpad);
1321         }
1322         gst_caps_unref (othercaps);
1323       }
1324       if (in_buf != *out_buf)
1325         gst_buffer_unref (*out_buf);
1326       *out_buf = NULL;
1327     }
1328   }
1329
1330   if (*out_buf == NULL) {
1331     if (!discard) {
1332       GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1333           outsize);
1334       /* no valid buffer yet, make one */
1335       *out_buf = gst_buffer_new_and_alloc (outsize);
1336       gst_buffer_copy_metadata (*out_buf, in_buf,
1337           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1338     } else {
1339       GST_DEBUG_OBJECT (trans, "reuse input buffer");
1340       *out_buf = in_buf;
1341     }
1342   } else {
1343     if (trans->passthrough && in_buf != *out_buf) {
1344       /* we are asked to perform a passthrough transform but the input and
1345        * output buffers are different. We have to discard the output buffer and
1346        * reuse the input buffer. */
1347       GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1348       discard = TRUE;
1349     }
1350     if (discard) {
1351       GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1352       gst_buffer_unref (*out_buf);
1353       *out_buf = in_buf;
1354     } else {
1355       GST_DEBUG_OBJECT (trans, "using allocated buffer");
1356       gst_buffer_copy_metadata (*out_buf, in_buf,
1357           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1358     }
1359   }
1360   gst_buffer_set_caps (*out_buf, GST_PAD_CAPS (trans->srcpad));
1361
1362   /* clear the GAP flag when the subclass does not understand it */
1363   if (!trans->priv->gap_aware)
1364     GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1365
1366   return ret;
1367
1368   /* ERRORS */
1369 alloc_failed:
1370   {
1371     GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1372     return ret;
1373   }
1374 no_buffer:
1375   {
1376     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1377         ("Sub-class failed to provide an output buffer"), (NULL));
1378     return GST_FLOW_ERROR;
1379   }
1380 unknown_size:
1381   {
1382     GST_ERROR_OBJECT (trans, "unknown output size");
1383     return GST_FLOW_ERROR;
1384   }
1385 failed_configure:
1386   {
1387     GST_WARNING_OBJECT (trans, "failed to configure caps");
1388     return GST_FLOW_NOT_NEGOTIATED;
1389   }
1390 }
1391
1392 /* Given @caps calcultate the size of one unit.
1393  *
1394  * For video caps, this is the size of one frame (and thus one buffer).
1395  * For audio caps, this is the size of one sample.
1396  *
1397  * These values are cached since they do not change and the calculation
1398  * potentially involves parsing caps and other expensive stuff.
1399  *
1400  * We have two cache locations to store the size, one for the source caps
1401  * and one for the sink caps.
1402  *
1403  * this function returns FALSE if no size could be calculated.
1404  */
1405 static gboolean
1406 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1407     guint * size)
1408 {
1409   gboolean res = FALSE;
1410   GstBaseTransformClass *bclass;
1411
1412   /* see if we have the result cached */
1413   if (trans->cache_caps1 == caps) {
1414     *size = trans->cache_caps1_size;
1415     GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1416     return TRUE;
1417   }
1418   if (trans->cache_caps2 == caps) {
1419     *size = trans->cache_caps2_size;
1420     GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1421     return TRUE;
1422   }
1423
1424   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1425   if (bclass->get_unit_size) {
1426     res = bclass->get_unit_size (trans, caps, size);
1427     GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1428         ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1429
1430     if (res) {
1431       /* and cache the values */
1432       if (trans->cache_caps1 == NULL) {
1433         gst_caps_replace (&trans->cache_caps1, caps);
1434         trans->cache_caps1_size = *size;
1435         GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1436       } else if (trans->cache_caps2 == NULL) {
1437         gst_caps_replace (&trans->cache_caps2, caps);
1438         trans->cache_caps2_size = *size;
1439         GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1440       } else {
1441         GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1442       }
1443     }
1444   } else {
1445     GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1446   }
1447   return res;
1448 }
1449
1450 /* your upstream peer wants to send you a buffer
1451  * that buffer has the given offset, size and caps
1452  * you're requested to allocate a buffer
1453  */
1454 static GstFlowReturn
1455 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1456     GstCaps * caps, GstBuffer ** buf)
1457 {
1458   GstBaseTransform *trans;
1459   GstBaseTransformPrivate *priv;
1460   GstFlowReturn res;
1461   gboolean proxy, suggest, same_caps;
1462   GstCaps *sink_suggest;
1463   guint size_suggest;
1464
1465   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1466   priv = trans->priv;
1467
1468   GST_DEBUG_OBJECT (pad, "alloc with caps %" GST_PTR_FORMAT ", size %u", caps,
1469       size);
1470
1471   /* if the code below does not come up with a better buffer, we will return _OK
1472    * and an empty buffer. This will trigger the core to allocate a buffer with
1473    * given input size and caps. */
1474   *buf = NULL;
1475   res = GST_FLOW_OK;
1476
1477   /* we remember our previous alloc request to quickly see if we can proxy or
1478    * not. We skip this check if we have a pending suggestion. */
1479   GST_OBJECT_LOCK (pad);
1480   same_caps = !priv->suggest_pending && caps &&
1481       gst_caps_is_equal (priv->sink_alloc, caps);
1482   GST_OBJECT_UNLOCK (pad);
1483
1484   if (same_caps) {
1485     /* we have seen this before, see below if we need to proxy */
1486     GST_DEBUG_OBJECT (trans, "have old caps");
1487     sink_suggest = caps;
1488     size_suggest = size;
1489     suggest = FALSE;
1490   } else {
1491     GstCaps *temp;
1492     const GstCaps *templ;
1493     gboolean empty;
1494
1495     GST_DEBUG_OBJECT (trans, "new format %" GST_PTR_FORMAT, caps);
1496
1497     /* if we have a suggestion, pretend we got these as input */
1498     GST_OBJECT_LOCK (pad);
1499     if ((priv->sink_suggest && !gst_caps_is_equal (caps, priv->sink_suggest))) {
1500       sink_suggest = gst_caps_ref (priv->sink_suggest);
1501       size_suggest = priv->size_suggest;
1502       GST_DEBUG_OBJECT (trans, "have suggestion %" GST_PTR_FORMAT,
1503           sink_suggest);
1504       /* suggest is TRUE when we have a custom suggestion pending that we need
1505        * to unref later. */
1506       suggest = TRUE;
1507     } else {
1508       GST_DEBUG_OBJECT (trans, "using caps %" GST_PTR_FORMAT, caps);
1509       sink_suggest = caps;
1510       size_suggest = size;
1511       suggest = FALSE;
1512     }
1513     priv->suggest_pending = FALSE;
1514     GST_OBJECT_UNLOCK (pad);
1515
1516     /* check if we actually handle this format on the sinkpad */
1517     if (sink_suggest) {
1518       templ = gst_pad_get_pad_template_caps (pad);
1519       temp = gst_caps_intersect (sink_suggest, templ);
1520
1521       empty = gst_caps_is_empty (temp);
1522       gst_caps_unref (temp);
1523
1524       if (empty)
1525         goto not_supported;
1526     }
1527
1528     /* find the best format for the other side here we decide if we will proxy
1529      * the caps or not. */
1530     if (sink_suggest == NULL) {
1531       /* always proxy when the caps are NULL. When this is a new format, see if
1532        * we can proxy it downstream */
1533       GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
1534       priv->proxy_alloc = TRUE;
1535     } else {
1536       GstCaps *othercaps;
1537
1538       /* we have a new format, see what we need to proxy to */
1539       othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
1540       if (!othercaps || gst_caps_is_empty (othercaps)) {
1541         /* no transform possible, we certainly can't proxy */
1542         GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
1543         priv->proxy_alloc = FALSE;
1544       } else {
1545         /* we transformed into something */
1546         if (gst_caps_is_equal (caps, othercaps)) {
1547           GST_DEBUG_OBJECT (trans,
1548               "best caps same as input, marking for proxy");
1549           priv->proxy_alloc = TRUE;
1550         } else {
1551           GST_DEBUG_OBJECT (trans,
1552               "best caps different from input, disable proxy");
1553           priv->proxy_alloc = FALSE;
1554         }
1555       }
1556       if (othercaps)
1557         gst_caps_unref (othercaps);
1558     }
1559   }
1560   /* remember the new caps */
1561   GST_OBJECT_LOCK (pad);
1562   gst_caps_replace (&priv->sink_alloc, sink_suggest);
1563   GST_OBJECT_UNLOCK (pad);
1564
1565   proxy = priv->proxy_alloc;
1566   GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d", proxy);
1567
1568   /* we only want to proxy if we have no suggestion pending, FIXME */
1569   if (proxy && !suggest) {
1570     GstCaps *newcaps;
1571
1572     GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %" GST_PTR_FORMAT
1573         ", size %u", caps, size);
1574
1575     /* we always proxy the input caps, never the suggestion. The reason is that
1576      * We don't yet handle the caps of renegotiation in here. FIXME */
1577     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
1578     if (res != GST_FLOW_OK)
1579       goto alloc_failed;
1580
1581     /* check if the caps changed */
1582     newcaps = GST_BUFFER_CAPS (*buf);
1583
1584     GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
1585
1586     if (!gst_caps_is_equal (newcaps, caps)) {
1587       GST_DEBUG_OBJECT (trans, "caps are new");
1588       /* we have new caps, see if we can proxy downstream */
1589       if (gst_pad_peer_accept_caps (pad, newcaps)) {
1590         /* peer accepts the caps, return a buffer in this format */
1591         GST_DEBUG_OBJECT (trans, "peer accepted new caps");
1592         /* remember the format */
1593         GST_OBJECT_LOCK (pad);
1594         gst_caps_replace (&priv->sink_alloc, newcaps);
1595         GST_OBJECT_UNLOCK (pad);
1596       } else {
1597         GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
1598         /* peer does not accept the caps, free the buffer we received and
1599          * create a buffer of the requested format by the default handler. */
1600         gst_buffer_unref (*buf);
1601         *buf = NULL;
1602       }
1603     } else {
1604       GST_DEBUG_OBJECT (trans, "received required caps from peer");
1605     }
1606   }
1607
1608   if (suggest) {
1609     /* there was a custom suggestion, create a buffer of this format and return
1610      * it. Note that this format  */
1611     *buf = gst_buffer_new_and_alloc (size_suggest);
1612     GST_DEBUG_OBJECT (trans,
1613         "doing suggestion of size %u, caps %" GST_PTR_FORMAT, size_suggest,
1614         sink_suggest);
1615     GST_BUFFER_CAPS (*buf) = sink_suggest;
1616   }
1617
1618   gst_object_unref (trans);
1619
1620   return res;
1621
1622   /* ERRORS */
1623 alloc_failed:
1624   {
1625     GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
1626     if (suggest)
1627       gst_caps_unref (sink_suggest);
1628     gst_object_unref (trans);
1629     return res;
1630   }
1631 not_supported:
1632   {
1633     GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
1634     if (suggest)
1635       gst_caps_unref (sink_suggest);
1636     gst_object_unref (trans);
1637     return GST_FLOW_NOT_NEGOTIATED;
1638   }
1639 }
1640
1641 static gboolean
1642 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
1643 {
1644   GstBaseTransform *trans;
1645   GstBaseTransformClass *bclass;
1646   gboolean ret = TRUE;
1647   gboolean forward = TRUE;
1648
1649   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1650   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1651
1652   if (bclass->event)
1653     forward = bclass->event (trans, event);
1654
1655   /* FIXME, do this in the default event handler so the subclass can do
1656    * something different. */
1657   if (forward)
1658     ret = gst_pad_push_event (trans->srcpad, event);
1659   else
1660     gst_event_unref (event);
1661
1662   gst_object_unref (trans);
1663
1664   return ret;
1665 }
1666
1667 static gboolean
1668 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1669 {
1670   switch (GST_EVENT_TYPE (event)) {
1671     case GST_EVENT_FLUSH_START:
1672       break;
1673     case GST_EVENT_FLUSH_STOP:
1674       GST_OBJECT_LOCK (trans);
1675       /* reset QoS parameters */
1676       trans->priv->proportion = 1.0;
1677       trans->priv->earliest_time = -1;
1678       trans->priv->discont = FALSE;
1679       GST_OBJECT_UNLOCK (trans);
1680       /* we need new segment info after the flush. */
1681       trans->have_newsegment = FALSE;
1682       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1683       break;
1684     case GST_EVENT_EOS:
1685       break;
1686     case GST_EVENT_TAG:
1687       break;
1688     case GST_EVENT_NEWSEGMENT:
1689     {
1690       GstFormat format;
1691       gdouble rate, arate;
1692       gint64 start, stop, time;
1693       gboolean update;
1694
1695       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1696           &start, &stop, &time);
1697
1698       trans->have_newsegment = TRUE;
1699
1700       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
1701           format, start, stop, time);
1702
1703       if (format == GST_FORMAT_TIME) {
1704         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1705             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1706             ", accum %" GST_TIME_FORMAT,
1707             GST_TIME_ARGS (trans->segment.start),
1708             GST_TIME_ARGS (trans->segment.stop),
1709             GST_TIME_ARGS (trans->segment.time),
1710             GST_TIME_ARGS (trans->segment.accum));
1711       } else {
1712         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1713             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1714             ", accum %" G_GINT64_FORMAT,
1715             trans->segment.start, trans->segment.stop,
1716             trans->segment.time, trans->segment.accum);
1717       }
1718       break;
1719     }
1720     default:
1721       break;
1722   }
1723
1724   return TRUE;
1725 }
1726
1727 static gboolean
1728 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
1729 {
1730   GstBaseTransform *trans;
1731   GstBaseTransformClass *bclass;
1732   gboolean ret = TRUE;
1733
1734   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1735   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1736
1737   if (bclass->src_event)
1738     ret = bclass->src_event (trans, event);
1739
1740   gst_object_unref (trans);
1741
1742   return ret;
1743 }
1744
1745 static gboolean
1746 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1747 {
1748   gboolean ret;
1749
1750   switch (GST_EVENT_TYPE (event)) {
1751     case GST_EVENT_SEEK:
1752       break;
1753     case GST_EVENT_NAVIGATION:
1754       break;
1755     case GST_EVENT_QOS:
1756     {
1757       gdouble proportion;
1758       GstClockTimeDiff diff;
1759       GstClockTime timestamp;
1760
1761       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1762       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1763       break;
1764     }
1765     default:
1766       break;
1767   }
1768
1769   ret = gst_pad_push_event (trans->sinkpad, event);
1770
1771   return ret;
1772 }
1773
1774 /* perform a transform on @inbuf and put the result in @outbuf.
1775  *
1776  * This function is common to the push and pull-based operations.
1777  *
1778  * This function takes ownership of @inbuf */
1779 static GstFlowReturn
1780 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1781     GstBuffer ** outbuf)
1782 {
1783   GstBaseTransformClass *bclass;
1784   GstFlowReturn ret = GST_FLOW_OK;
1785   gboolean want_in_place, reconfigure;
1786   GstClockTime qostime;
1787   GstCaps *incaps;
1788
1789   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1790
1791   if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
1792     GST_OBJECT_LOCK (trans);
1793     reconfigure = trans->priv->reconfigure;
1794     trans->priv->reconfigure = FALSE;
1795     GST_OBJECT_UNLOCK (trans);
1796
1797     if (G_UNLIKELY (reconfigure)) {
1798       GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
1799       /* if we need to reconfigure we pretend a buffer with new caps arrived. This
1800        * will reconfigure the transform with the new output format. We can only
1801        * do this if the buffer actually has caps. */
1802       if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
1803         goto not_negotiated;
1804     }
1805   }
1806
1807   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1808     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1809         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1810         GST_BUFFER_OFFSET (inbuf));
1811   else
1812     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1813         inbuf, GST_BUFFER_SIZE (inbuf));
1814
1815   /* Don't allow buffer handling before negotiation, except in passthrough mode
1816    * or if the class doesn't implement a set_caps function (in which case it doesn't
1817    * care about caps)
1818    */
1819   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1820     goto not_negotiated;
1821
1822   /* Set discont flag so we can mark the outgoing buffer */
1823   if (GST_BUFFER_IS_DISCONT (inbuf)) {
1824     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
1825     trans->priv->discont = TRUE;
1826   }
1827
1828   /* can only do QoS if the segment is in TIME */
1829   if (trans->segment.format != GST_FORMAT_TIME)
1830     goto no_qos;
1831
1832   /* QOS is done on the running time of the buffer, get it now */
1833   qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1834       GST_BUFFER_TIMESTAMP (inbuf));
1835
1836   if (qostime != -1) {
1837     gboolean need_skip;
1838     GstClockTime earliest_time;
1839
1840     /* lock for getting the QoS parameters that are set (in a different thread)
1841      * with the QOS events */
1842     GST_OBJECT_LOCK (trans);
1843     earliest_time = trans->priv->earliest_time;
1844     /* check for QoS, don't perform conversion for buffers
1845      * that are known to be late. */
1846     need_skip = trans->priv->qos_enabled &&
1847         earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
1848     GST_OBJECT_UNLOCK (trans);
1849
1850     if (need_skip) {
1851       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1852           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1853           GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1854       /* mark discont for next buffer */
1855       trans->priv->discont = TRUE;
1856       goto skip;
1857     }
1858   }
1859
1860 no_qos:
1861
1862   /* first try to allocate an output buffer based on the currently negotiated
1863    * format. While we call pad-alloc we could renegotiate the srcpad format or
1864    * have a new suggestion for upstream buffer-alloc. 
1865    * In any case, outbuf will contain a buffer suitable for doing the configured
1866    * transform after this function. */
1867   ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
1868   if (G_UNLIKELY (ret != GST_FLOW_OK))
1869     goto no_buffer;
1870
1871   /* now perform the needed transform */
1872   if (trans->passthrough) {
1873     /* In passthrough mode, give transform_ip a look at the
1874      * buffer, without making it writable, or just push the
1875      * data through */
1876     if (bclass->transform_ip) {
1877       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
1878       ret = bclass->transform_ip (trans, *outbuf);
1879     } else {
1880       GST_DEBUG_OBJECT (trans, "element is in passthrough");
1881     }
1882   } else {
1883     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1884
1885     if (want_in_place) {
1886       GST_DEBUG_OBJECT (trans, "doing inplace transform");
1887
1888       if (inbuf != *outbuf) {
1889         /* different buffers, copy the input to the output first, we then do an
1890          * in-place transform on the output buffer. */
1891         memcpy (GST_BUFFER_DATA (*outbuf), GST_BUFFER_DATA (inbuf),
1892             GST_BUFFER_SIZE (inbuf));
1893       }
1894       ret = bclass->transform_ip (trans, *outbuf);
1895     } else {
1896       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
1897
1898       if (bclass->transform)
1899         ret = bclass->transform (trans, inbuf, *outbuf);
1900       else
1901         ret = GST_FLOW_NOT_SUPPORTED;
1902     }
1903   }
1904
1905 skip:
1906   /* only unref input buffer if we allocated a new outbuf buffer */
1907   if (*outbuf != inbuf)
1908     gst_buffer_unref (inbuf);
1909
1910   return ret;
1911
1912   /* ERRORS */
1913 not_negotiated:
1914   {
1915     gst_buffer_unref (inbuf);
1916     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1917         ("not negotiated"), ("not negotiated"));
1918     return GST_FLOW_NOT_NEGOTIATED;
1919   }
1920 no_buffer:
1921   {
1922     gst_buffer_unref (inbuf);
1923     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
1924         gst_flow_get_name (ret));
1925     return ret;
1926   }
1927 }
1928
1929 static gboolean
1930 gst_base_transform_check_get_range (GstPad * pad)
1931 {
1932   GstBaseTransform *trans;
1933   gboolean ret;
1934
1935   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1936
1937   ret = gst_pad_check_pull_range (trans->sinkpad);
1938
1939   gst_object_unref (trans);
1940
1941   return ret;
1942 }
1943
1944 /* FIXME, getrange is broken, need to pull range from the other
1945  * end based on the transform_size result.
1946  */
1947 static GstFlowReturn
1948 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1949     guint length, GstBuffer ** buffer)
1950 {
1951   GstBaseTransform *trans;
1952   GstBaseTransformClass *klass;
1953   GstFlowReturn ret;
1954   GstBuffer *inbuf;
1955
1956   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1957
1958   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1959   if (G_UNLIKELY (ret != GST_FLOW_OK))
1960     goto pull_error;
1961
1962   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1963   if (klass->before_transform)
1964     klass->before_transform (trans, inbuf);
1965
1966   GST_BASE_TRANSFORM_LOCK (trans);
1967   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1968   GST_BASE_TRANSFORM_UNLOCK (trans);
1969
1970 done:
1971   gst_object_unref (trans);
1972
1973   return ret;
1974
1975   /* ERRORS */
1976 pull_error:
1977   {
1978     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
1979         gst_flow_get_name (ret));
1980     goto done;
1981   }
1982 }
1983
1984 static GstFlowReturn
1985 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1986 {
1987   GstBaseTransform *trans;
1988   GstBaseTransformClass *klass;
1989   GstFlowReturn ret;
1990   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
1991   GstBuffer *outbuf = NULL;
1992
1993   trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
1994
1995   /* calculate end position of the incoming buffer */
1996   if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) {
1997     if (GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE)
1998       last_stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1999     else
2000       last_stop = GST_BUFFER_TIMESTAMP (buffer);
2001   }
2002
2003   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2004   if (klass->before_transform)
2005     klass->before_transform (trans, buffer);
2006
2007   /* protect transform method and concurrent buffer alloc */
2008   GST_BASE_TRANSFORM_LOCK (trans);
2009   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2010   GST_BASE_TRANSFORM_UNLOCK (trans);
2011
2012   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2013    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2014   if (outbuf != NULL) {
2015     if ((ret == GST_FLOW_OK)) {
2016       /* Remember last stop position */
2017       if ((last_stop != GST_CLOCK_TIME_NONE) &&
2018           (trans->segment.format == GST_FORMAT_TIME))
2019         gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2020
2021       /* apply DISCONT flag if the buffer is not yet marked as such */
2022       if (trans->priv->discont) {
2023         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2024           outbuf = gst_buffer_make_metadata_writable (outbuf);
2025           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2026         }
2027         trans->priv->discont = FALSE;
2028       }
2029       ret = gst_pad_push (trans->srcpad, outbuf);
2030     } else
2031       gst_buffer_unref (outbuf);
2032   }
2033
2034   /* convert internal flow to OK and mark discont for the next buffer. */
2035   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2036     trans->priv->discont = TRUE;
2037     ret = GST_FLOW_OK;
2038   }
2039
2040   return ret;
2041 }
2042
2043 static void
2044 gst_base_transform_set_property (GObject * object, guint prop_id,
2045     const GValue * value, GParamSpec * pspec)
2046 {
2047   GstBaseTransform *trans;
2048
2049   trans = GST_BASE_TRANSFORM (object);
2050
2051   switch (prop_id) {
2052     case PROP_QOS:
2053       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2054       break;
2055     default:
2056       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2057       break;
2058   }
2059 }
2060
2061 static void
2062 gst_base_transform_get_property (GObject * object, guint prop_id,
2063     GValue * value, GParamSpec * pspec)
2064 {
2065   GstBaseTransform *trans;
2066
2067   trans = GST_BASE_TRANSFORM (object);
2068
2069   switch (prop_id) {
2070     case PROP_QOS:
2071       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2072       break;
2073     default:
2074       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2075       break;
2076   }
2077 }
2078
2079 /* not a vmethod of anything, just an internal method */
2080 static gboolean
2081 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2082 {
2083   GstBaseTransformClass *bclass;
2084   gboolean result = TRUE;
2085
2086   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2087
2088   if (active) {
2089     if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2090       result &= bclass->start (trans);
2091
2092     GST_OBJECT_LOCK (trans);
2093
2094     if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2095       trans->have_same_caps =
2096           gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2097           GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2098     else
2099       trans->have_same_caps = trans->passthrough;
2100     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2101     trans->negotiated = FALSE;
2102     trans->have_newsegment = FALSE;
2103     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2104     trans->priv->proportion = 1.0;
2105     trans->priv->earliest_time = -1;
2106     trans->priv->discont = FALSE;
2107     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2108
2109     GST_OBJECT_UNLOCK (trans);
2110   } else {
2111     /* We must make sure streaming has finished before resetting things
2112      * and calling the ::stop vfunc */
2113     GST_PAD_STREAM_LOCK (trans->sinkpad);
2114     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2115
2116     trans->have_same_caps = FALSE;
2117     /* We can only reset the passthrough mode if the instance told us to 
2118        handle it in configure_caps */
2119     if (bclass->passthrough_on_same_caps) {
2120       gst_base_transform_set_passthrough (trans, FALSE);
2121     }
2122     gst_caps_replace (&trans->cache_caps1, NULL);
2123     gst_caps_replace (&trans->cache_caps2, NULL);
2124     gst_caps_replace (&trans->priv->sink_alloc, NULL);
2125     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2126
2127     if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2128       result &= bclass->stop (trans);
2129   }
2130
2131   return result;
2132 }
2133
2134 static gboolean
2135 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2136 {
2137   gboolean result = TRUE;
2138   GstBaseTransform *trans;
2139
2140   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2141
2142   result = gst_base_transform_activate (trans, active);
2143
2144   if (result)
2145     trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2146
2147   gst_object_unref (trans);
2148
2149   return result;
2150 }
2151
2152 static gboolean
2153 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2154 {
2155   gboolean result = FALSE;
2156   GstBaseTransform *trans;
2157
2158   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2159
2160   result = gst_pad_activate_pull (trans->sinkpad, active);
2161
2162   if (result)
2163     result &= gst_base_transform_activate (trans, active);
2164
2165   if (result)
2166     trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2167
2168   gst_object_unref (trans);
2169
2170   return result;
2171 }
2172
2173 /**
2174  * gst_base_transform_set_passthrough:
2175  * @trans: the #GstBaseTransform to set
2176  * @passthrough: boolean indicating passthrough mode.
2177  *
2178  * Set passthrough mode for this filter by default. This is mostly
2179  * useful for filters that do not care about negotiation.
2180  *
2181  * Always TRUE for filters which don't implement either a transform
2182  * or transform_ip method.
2183  *
2184  * MT safe.
2185  */
2186 void
2187 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2188     gboolean passthrough)
2189 {
2190   GstBaseTransformClass *bclass;
2191
2192   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2193
2194   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2195
2196   GST_OBJECT_LOCK (trans);
2197   if (passthrough == FALSE) {
2198     if (bclass->transform_ip || bclass->transform)
2199       trans->passthrough = FALSE;
2200   } else {
2201     trans->passthrough = TRUE;
2202   }
2203
2204   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2205   GST_OBJECT_UNLOCK (trans);
2206 }
2207
2208 /**
2209  * gst_base_transform_is_passthrough:
2210  * @trans: the #GstBaseTransform to query
2211  *
2212  * See if @trans is configured as a passthrough transform.
2213  *
2214  * Returns: TRUE is the transform is configured in passthrough mode.
2215  *
2216  * MT safe.
2217  */
2218 gboolean
2219 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2220 {
2221   gboolean result;
2222
2223   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2224
2225   GST_OBJECT_LOCK (trans);
2226   result = trans->passthrough;
2227   GST_OBJECT_UNLOCK (trans);
2228
2229   return result;
2230 }
2231
2232 /**
2233  * gst_base_transform_set_in_place:
2234  * @trans: the #GstBaseTransform to modify
2235  * @in_place: Boolean value indicating that we would like to operate
2236  * on in_place buffers.
2237  *
2238  * Determines whether a non-writable buffer will be copied before passing
2239  * to the transform_ip function.
2240  * <itemizedlist>
2241  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2242  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2243  * </itemizedlist>
2244  *
2245  * MT safe.
2246  */
2247 void
2248 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2249 {
2250   GstBaseTransformClass *bclass;
2251
2252   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2253
2254   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2255
2256   GST_OBJECT_LOCK (trans);
2257
2258   if (in_place) {
2259     if (bclass->transform_ip) {
2260       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2261       trans->always_in_place = TRUE;
2262     }
2263   } else {
2264     if (bclass->transform) {
2265       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2266       trans->always_in_place = FALSE;
2267     }
2268   }
2269
2270   GST_OBJECT_UNLOCK (trans);
2271 }
2272
2273 /**
2274  * gst_base_transform_is_in_place:
2275  * @trans: the #GstBaseTransform to query
2276  *
2277  * See if @trans is configured as a in_place transform.
2278  *
2279  * Returns: TRUE is the transform is configured in in_place mode.
2280  *
2281  * MT safe.
2282  */
2283 gboolean
2284 gst_base_transform_is_in_place (GstBaseTransform * trans)
2285 {
2286   gboolean result;
2287
2288   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2289
2290   GST_OBJECT_LOCK (trans);
2291   result = trans->always_in_place;
2292   GST_OBJECT_UNLOCK (trans);
2293
2294   return result;
2295 }
2296
2297 /**
2298  * gst_base_transform_update_qos:
2299  * @trans: a #GstBaseTransform
2300  * @proportion: the proportion
2301  * @diff: the diff against the clock
2302  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2303  * running_time.
2304  *
2305  * Set the QoS parameters in the transform. This function is called internally
2306  * when a QOS event is received but subclasses can provide custom information
2307  * when needed.
2308  *
2309  * MT safe.
2310  *
2311  * Since: 0.10.5
2312  */
2313 void
2314 gst_base_transform_update_qos (GstBaseTransform * trans,
2315     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2316 {
2317
2318   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2319
2320   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2321       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2322       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2323
2324   GST_OBJECT_LOCK (trans);
2325   trans->priv->proportion = proportion;
2326   trans->priv->earliest_time = timestamp + diff;
2327   GST_OBJECT_UNLOCK (trans);
2328 }
2329
2330 /**
2331  * gst_base_transform_set_qos_enabled:
2332  * @trans: a #GstBaseTransform
2333  * @enabled: new state
2334  *
2335  * Enable or disable QoS handling in the transform.
2336  *
2337  * MT safe.
2338  *
2339  * Since: 0.10.5
2340  */
2341 void
2342 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
2343 {
2344   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2345
2346   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
2347
2348   GST_OBJECT_LOCK (trans);
2349   trans->priv->qos_enabled = enabled;
2350   GST_OBJECT_UNLOCK (trans);
2351 }
2352
2353 /**
2354  * gst_base_transform_is_qos_enabled:
2355  * @trans: a #GstBaseTransform
2356  *
2357  * Queries if the transform will handle QoS.
2358  *
2359  * Returns: TRUE if QoS is enabled.
2360  *
2361  * MT safe.
2362  *
2363  * Since: 0.10.5
2364  */
2365 gboolean
2366 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
2367 {
2368   gboolean result;
2369
2370   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2371
2372   GST_OBJECT_LOCK (trans);
2373   result = trans->priv->qos_enabled;
2374   GST_OBJECT_UNLOCK (trans);
2375
2376   return result;
2377 }
2378
2379 /**
2380  * gst_base_transform_set_gap_aware:
2381  * @trans: a #GstBaseTransform
2382  * @gap_aware: New state
2383  *
2384  * If @gap_aware is %FALSE (the default), output buffers will have the
2385  * %GST_BUFFER_FLAG_GAP flag unset.
2386  *
2387  * If set to %TRUE, the element must handle output buffers with this flag set
2388  * correctly, i.e. it can assume that the buffer contains neutral data but must
2389  * unset the flag if the output is no neutral data.
2390  *
2391  * MT safe.
2392  *
2393  * Since: 0.10.16
2394  */
2395 void
2396 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
2397 {
2398   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2399
2400   GST_OBJECT_LOCK (trans);
2401   trans->priv->gap_aware = gap_aware;
2402   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
2403   GST_OBJECT_UNLOCK (trans);
2404 }
2405
2406 /**
2407  * gst_base_transform_suggest:
2408  * @trans: a #GstBaseTransform
2409  * @caps: caps to suggest
2410  * @size: buffer size to suggest
2411  *
2412  * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
2413  * taken.
2414  *
2415  * Since: 0.10.21
2416  */
2417 void
2418 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
2419     guint size)
2420 {
2421   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2422
2423   GST_OBJECT_LOCK (trans->sinkpad);
2424   if (trans->priv->sink_suggest)
2425     gst_caps_unref (trans->priv->sink_suggest);
2426   if (caps)
2427     caps = gst_caps_copy (caps);
2428   trans->priv->sink_suggest = caps;
2429   trans->priv->size_suggest = size;
2430   trans->priv->suggest_pending = TRUE;
2431   GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
2432   GST_OBJECT_UNLOCK (trans->sinkpad);
2433 }
2434
2435 /**
2436  * gst_base_transform_reconfigure:
2437  * @trans: a #GstBaseTransform
2438  *
2439  * Instructs @trans to renegotiate a new downstream transform on the next
2440  * buffer. This function is typically called after properties on the transform
2441  * were set that influence the output format.
2442  *
2443  * Since: 0.10.21
2444  */
2445 void
2446 gst_base_transform_reconfigure (GstBaseTransform * trans)
2447 {
2448   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2449
2450   GST_OBJECT_LOCK (trans);
2451   GST_DEBUG_OBJECT (trans, "marking reconfigure");
2452   trans->priv->reconfigure = TRUE;
2453   GST_OBJECT_UNLOCK (trans);
2454 }