docs/design/part-overview.txt: Make upsteam/downstream concepts more clear.
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasetransform.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 Wim Taymans <wim@fluendo.com>
5  *                    2005 Andy Wingo <wingo@fluendo.com>
6  *                    2005 Thomas Vander Stichele <thomas at apestaart dot org>
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  * Use Cases:
48  * <orderedlist>
49  * <listitem>
50  *   <itemizedlist><title>Passthrough mode</title>
51  *   <listitem><para>
52  *     Element has no interest in modifying the buffer. It may want to inspect it,
53  *     in which case the element should have a transform_ip function. If there
54  *     is no transform_ip function in passthrough mode, the buffer is pushed
55  *     intact.
56  *   </para></listitem>
57  *   <listitem><para>
58  *     On the GstBaseTransformClass is the passthrough_on_same_caps variable
59  *     which will automatically set/unset passthrough based on whether the
60  *     element negotiates the same caps on both pads.
61  *   </para></listitem>
62  *   <listitem><para>
63  *     passthrough_on_same_caps on an element that doesn't implement a
64  *     transform_caps function is useful for elements that only inspect data
65  *     (such as level)
66  *   </para></listitem>
67  *   </itemizedlist>
68  *   <itemizedlist>
69  *   <title>Example elements</title>
70  *     <listitem>Level</listitem>
71  *     <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in
72  *     certain modes.</listitem>
73  *   </itemizedlist>
74  * </listitem>
75  * <listitem>
76  *   <itemizedlist>
77  *     <title>Modifications in-place - input buffer and output buffer are the
78  *     same thing.</title>
79  *   <listitem><para>
80  *     The element must implement a transform_ip function.
81  *   </para></listitem>
82  *   <listitem><para>
83  *     Output buffer size must <= input buffer size
84  *   </para></listitem>
85  *   <listitem><para>
86  *     If the always_in_place flag is set, non-writable buffers will be copied
87  *     and passed to the transform_ip function, otherwise a new buffer will be
88  *     created and the transform function called.
89  *   </para></listitem>
90  *   <listitem><para>
91  *     Incoming writable buffers will be passed to the transform_ip function
92  *     immediately.  </para></listitem>
93  *   <listitem><para>
94  *     only implementing transform_ip and not transform implies always_in_place
95  *     = TRUE
96  *   </para></listitem>
97  *   </itemizedlist>
98  *   <itemizedlist>
99  *   <title>Example elements</title>
100  *     <listitem>Volume</listitem>
101  *     <listitem>Audioconvert in certain modes (signed/unsigned
102  *     conversion)</listitem>
103  *     <listitem>ffmpegcolorspace in certain modes (endianness
104  *     swapping)</listitem>
105  *   </itemizedlist>
106  *  </listitem>
107  * <listitem>
108  *   <itemizedlist>
109  *   <title>Modifications only to the caps/metadata of a buffer</title>
110  *   <listitem><para>
111  *     The element does not require writable data, but non-writable buffers
112  *     should be subbuffered so that the meta-information can be replaced.
113  *   </para></listitem>
114  *   <listitem><para>
115  *     Elements wishing to operate in this mode should replace the
116  *     prepare_output_buffer method to create subbuffers of the input buffer
117  *     and set always_in_place to TRUE
118  *   </para></listitem>
119  *   </itemizedlist>
120  *   <itemizedlist>
121  *   <title>Example elements</title>
122  *     <listitem>Capsfilter when setting caps on outgoing buffers that have
123  *     none.</listitem>
124  *     <listitem>identity when it is going to re-timestamp buffers by
125  *     datarate.</listitem>
126  *   </itemizedlist>
127  * </listitem>
128  * <listitem>
129  *   <itemizedlist><title>Normal mode</title>
130  *   <listitem><para>
131  *     always_in_place flag is not set, or there is no transform_ip function
132  *   </para></listitem>
133  *   <listitem><para>
134  *     Element will receive an input buffer and output buffer to operate on.
135  *   </para></listitem>
136  *   <listitem><para>
137  *     Output buffer is allocated by calling the prepare_output_buffer function.
138  *   </para></listitem>
139  *   </itemizedlist>
140  *   <itemizedlist>
141  *   <title>Example elements</title>
142  *     <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing
143  *     scaling/conversions</listitem>
144  *   </itemizedlist>
145  * </listitem>
146  * <listitem>
147  *   <itemizedlist><title>Special output buffer allocations</title>
148  *   <listitem><para>
149  *     Elements which need to do special allocation of their output buffers
150  *     other than what gst_buffer_pad_alloc allows should implement a
151  *     prepare_output_buffer method, which calls the parent implementation and
152  *     passes the newly allocated buffer.
153  *   </para></listitem>
154  *   </itemizedlist>
155  *   <itemizedlist>
156  *   <title>Example elements</title>
157  *     <listitem>efence</listitem>
158  *   </itemizedlist>
159  * </listitem>
160  * </orderedlist>
161  *
162  * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
163  * <listitem><para>
164  *   <itemizedlist><title>passthrough</title>
165  *     <listitem><para>
166  *       Implies that in the current configuration, the sub-class is not
167  *       interested in modifying the buffers.
168  *     </para></listitem>
169  *     <listitem><para>
170  *       Elements which are always in passthrough mode whenever the same caps
171  *       has been negotiated on both pads can set the class variable
172  *       passthrough_on_same_caps to have this behaviour automatically.
173  *     </para></listitem>
174  *   </itemizedlist>
175  * </para></listitem>
176  * <listitem><para>
177  *   <itemizedlist><title>always_in_place</title>
178  *     <listitem><para>
179  *       Determines whether a non-writable buffer will be copied before passing
180  *       to the transform_ip function.
181  *     </para></listitem>
182  *     <listitem><para>
183  *       Implied TRUE if no transform function is implemented.
184  *     </para></listitem>
185  *     <listitem><para>
186  *       Implied FALSE if ONLY transform function is implemented.
187  *     </para></listitem>
188  *   </itemizedlist>
189  * </para></listitem>
190  * </itemizedlist>
191  *
192 */
193
194 #ifdef HAVE_CONFIG_H
195 #  include "config.h"
196 #endif
197
198 #include <stdlib.h>
199 #include <string.h>
200
201 #include "../../../gst/gst_private.h"
202 #include "../../../gst/gst-i18n-lib.h"
203 #include "gstbasetransform.h"
204 #include <gst/gstmarshal.h>
205
206 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
207 #define GST_CAT_DEFAULT gst_base_transform_debug
208
209 /* BaseTransform signals and args */
210 enum
211 {
212   /* FILL ME */
213   LAST_SIGNAL
214 };
215
216 #define DEFAULT_PROP_QOS        FALSE
217
218 enum
219 {
220   PROP_0,
221   PROP_QOS
222 };
223
224 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
225     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
226
227 struct _GstBaseTransformPrivate
228 {
229   /* QoS *//* with LOCK */
230   gboolean qos_enabled;
231   gdouble proportion;
232   GstClockTime earliest_time;
233 };
234
235 static GstElementClass *parent_class = NULL;
236
237 static void gst_base_transform_base_init (gpointer g_class);
238 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
239 static void gst_base_transform_init (GstBaseTransform * trans,
240     GstBaseTransformClass * klass);
241 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
242     * trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
243
244 GType
245 gst_base_transform_get_type (void)
246 {
247   static GType base_transform_type = 0;
248
249   if (!base_transform_type) {
250     static const GTypeInfo base_transform_info = {
251       sizeof (GstBaseTransformClass),
252       (GBaseInitFunc) gst_base_transform_base_init,
253       NULL,
254       (GClassInitFunc) gst_base_transform_class_init,
255       NULL,
256       NULL,
257       sizeof (GstBaseTransform),
258       0,
259       (GInstanceInitFunc) gst_base_transform_init,
260     };
261
262     base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
263         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
264   }
265   return base_transform_type;
266 }
267
268 static void gst_base_transform_finalize (GObject * object);
269 static void gst_base_transform_set_property (GObject * object, guint prop_id,
270     const GValue * value, GParamSpec * pspec);
271 static void gst_base_transform_get_property (GObject * object, guint prop_id,
272     GValue * value, GParamSpec * pspec);
273 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
274     gboolean active);
275 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
276     gboolean active);
277 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
278     GstCaps * caps, guint * size);
279
280 static GstStateChangeReturn gst_base_transform_change_state (GstElement *
281     element, GstStateChange transition);
282
283 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
284 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
285     GstEvent * event);
286 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
287 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
288     GstEvent * event);
289 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
290     guint length, GstBuffer ** buffer);
291 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
292     GstBuffer * buffer);
293 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
294 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
295 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
296     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
297
298 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
299
300 static void
301 gst_base_transform_base_init (gpointer g_class)
302 {
303   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
304       "basetransform element");
305 }
306
307 static void
308 gst_base_transform_finalize (GObject * object)
309 {
310   GstBaseTransform *trans;
311
312   trans = GST_BASE_TRANSFORM (object);
313
314   g_mutex_free (trans->transform_lock);
315
316   G_OBJECT_CLASS (parent_class)->finalize (object);
317 }
318
319 static void
320 gst_base_transform_class_init (GstBaseTransformClass * klass)
321 {
322   GObjectClass *gobject_class;
323   GstElementClass *gstelement_class;
324
325   gobject_class = G_OBJECT_CLASS (klass);
326   gstelement_class = GST_ELEMENT_CLASS (klass);
327
328   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
329
330   parent_class = g_type_class_peek_parent (klass);
331
332   gobject_class->set_property =
333       GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
334   gobject_class->get_property =
335       GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
336
337   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QOS,
338       g_param_spec_boolean ("qos", "QoS", "handle QoS messages",
339           DEFAULT_PROP_QOS, G_PARAM_READWRITE));
340
341   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
342
343   gstelement_class->change_state =
344       GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
345
346   klass->passthrough_on_same_caps = FALSE;
347   klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
348   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
349 }
350
351 static void
352 gst_base_transform_init (GstBaseTransform * trans,
353     GstBaseTransformClass * bclass)
354 {
355   GstPadTemplate *pad_template;
356
357   GST_DEBUG ("gst_base_transform_init");
358
359   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
360
361   pad_template =
362       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
363   g_return_if_fail (pad_template != NULL);
364   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
365   gst_pad_set_getcaps_function (trans->sinkpad,
366       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
367   gst_pad_set_setcaps_function (trans->sinkpad,
368       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
369   gst_pad_set_event_function (trans->sinkpad,
370       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
371   gst_pad_set_chain_function (trans->sinkpad,
372       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
373   gst_pad_set_activatepush_function (trans->sinkpad,
374       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
375   gst_pad_set_bufferalloc_function (trans->sinkpad,
376       GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
377   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
378
379   pad_template =
380       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
381   g_return_if_fail (pad_template != NULL);
382   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
383   gst_pad_set_getcaps_function (trans->srcpad,
384       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
385   gst_pad_set_setcaps_function (trans->srcpad,
386       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
387   gst_pad_set_event_function (trans->srcpad,
388       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
389   gst_pad_set_getrange_function (trans->srcpad,
390       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
391   gst_pad_set_activatepull_function (trans->srcpad,
392       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
393   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
394
395   trans->transform_lock = g_mutex_new ();
396   trans->delay_configure = FALSE;
397   trans->pending_configure = FALSE;
398   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
399   trans->cache_caps1 = NULL;
400   trans->cache_caps2 = NULL;
401
402   trans->passthrough = FALSE;
403   if (bclass->transform == NULL) {
404     /* If no transform function, always_in_place is TRUE */
405     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
406     trans->always_in_place = TRUE;
407
408     if (bclass->transform_ip == NULL)
409       trans->passthrough = TRUE;
410   }
411 }
412
413 /* given @caps on the src or sink pad (given by @direction)
414  * calculate the possible caps on the other pad.
415  *
416  * Returns new caps, unref after usage.
417  */
418 static GstCaps *
419 gst_base_transform_transform_caps (GstBaseTransform * trans,
420     GstPadDirection direction, GstCaps * caps)
421 {
422   GstCaps *ret;
423   GstBaseTransformClass *klass;
424
425   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
426
427   /* if there is a custom transform function, use this */
428   if (klass->transform_caps) {
429     GstCaps *temp;
430     gint i;
431
432     /* start with empty caps */
433     ret = gst_caps_new_empty ();
434
435     if (gst_caps_is_any (caps)) {
436       /* for any caps we still have to call the transform function */
437       GST_DEBUG_OBJECT (trans, "from ANY:");
438       temp = klass->transform_caps (trans, direction, caps);
439       GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);
440
441       temp = gst_caps_make_writable (temp);
442       gst_caps_append (ret, temp);
443     } else {
444       /* we send caps with just one structure to the transform
445        * function as this is easier for the element */
446       for (i = 0; i < gst_caps_get_size (caps); i++) {
447         GstCaps *nth;
448
449         nth = gst_caps_copy_nth (caps, i);
450         GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
451         temp = klass->transform_caps (trans, direction, nth);
452         gst_caps_unref (nth);
453         GST_DEBUG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
454
455         temp = gst_caps_make_writable (temp);
456         gst_caps_append (ret, temp);
457       }
458     }
459   } else {
460     /* else use the identity transform */
461     ret = gst_caps_ref (caps);
462   }
463
464   GST_DEBUG_OBJECT (trans, "to:   %" GST_PTR_FORMAT, ret);
465
466   return ret;
467 }
468
469 static gboolean
470 gst_base_transform_transform_size (GstBaseTransform * trans,
471     GstPadDirection direction, GstCaps * caps,
472     guint size, GstCaps * othercaps, guint * othersize)
473 {
474   guint inunitsize, outunitsize, units;
475   GstBaseTransformClass *klass;
476   gboolean ret;
477
478   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
479
480   GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
481       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
482       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
483
484   /* if there is a custom transform function, use this */
485   if (klass->transform_size) {
486     ret = klass->transform_size (trans, direction, caps, size, othercaps,
487         othersize);
488   } else {
489     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
490       goto no_in_size;
491
492     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
493         inunitsize);
494
495     if (inunitsize == 0 || (size % inunitsize != 0))
496       goto no_multiple;
497
498     units = size / inunitsize;
499     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
500       goto no_out_size;
501
502     *othersize = units * outunitsize;
503     GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
504
505     ret = TRUE;
506   }
507   return ret;
508
509   /* ERRORS */
510 no_in_size:
511   {
512     GST_DEBUG_OBJECT (trans, "could not get in_size");
513     g_warning ("could not get in_size");
514     return FALSE;
515   }
516 no_multiple:
517   {
518     GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
519         inunitsize);
520     g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
521     return FALSE;
522   }
523 no_out_size:
524   {
525     GST_DEBUG_OBJECT (trans, "could not get out_size");
526     g_warning ("could not get out_size");
527     return FALSE;
528   }
529 }
530
531 static GstCaps *
532 gst_base_transform_getcaps (GstPad * pad)
533 {
534   GstBaseTransform *trans;
535   GstPad *otherpad;
536   GstCaps *caps;
537
538   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
539
540   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
541
542   /* we can do what the peer can */
543   caps = gst_pad_peer_get_caps (otherpad);
544   if (caps) {
545     GstCaps *temp;
546     const GstCaps *templ;
547
548     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, caps);
549
550     /* filtered against our padtemplate */
551     templ = gst_pad_get_pad_template_caps (otherpad);
552     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
553     temp = gst_caps_intersect (caps, templ);
554     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
555     gst_caps_unref (caps);
556     /* then see what we can transform this to */
557     caps = gst_base_transform_transform_caps (trans,
558         GST_PAD_DIRECTION (otherpad), temp);
559     GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
560     gst_caps_unref (temp);
561     if (caps == NULL)
562       goto done;
563
564     /* and filter against the template again */
565     templ = gst_pad_get_pad_template_caps (pad);
566     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
567     temp = gst_caps_intersect (caps, templ);
568     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
569     gst_caps_unref (caps);
570     /* this is what we can do */
571     caps = temp;
572   } else {
573     /* no peer, our padtemplate is enough then */
574     caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
575   }
576
577 done:
578   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
579
580   gst_object_unref (trans);
581
582   return caps;
583 }
584
585 /* function triggered when the in and out caps are negotiated and need
586  * to be configured in the subclass. */
587 static gboolean
588 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
589     GstCaps * out)
590 {
591   gboolean ret = TRUE;
592   GstBaseTransformClass *klass;
593
594   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
595
596   /* clear the cache */
597   gst_caps_replace (&trans->cache_caps1, NULL);
598   gst_caps_replace (&trans->cache_caps2, NULL);
599
600   /* If we've a transform_ip method and same input/output caps, set in_place
601    * by default. If for some reason the sub-class prefers using a transform
602    * function, it can clear the in place flag in the set_caps */
603   gst_base_transform_set_in_place (trans,
604       klass->transform_ip && trans->have_same_caps);
605
606   /* Set the passthrough if the class wants passthrough_on_same_caps
607    * and we have the same caps on each pad */
608   if (klass->passthrough_on_same_caps)
609     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
610
611   /* now configure the element with the caps */
612   if (klass->set_caps) {
613     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
614     ret = klass->set_caps (trans, in, out);
615   }
616
617   trans->negotiated = ret;
618
619   return ret;
620 }
621
622 /* called when new caps arrive on the sink or source pad */
623 static gboolean
624 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
625 {
626   GstBaseTransform *trans;
627   GstBaseTransformClass *klass;
628   GstPad *otherpad, *otherpeer;
629   GstCaps *othercaps = NULL;
630   gboolean ret = TRUE;
631   gboolean peer_checked = FALSE;
632
633   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
634   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
635
636   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
637   otherpeer = gst_pad_get_peer (otherpad);
638
639   /* if we get called recursively, we bail out now to avoid an
640    * infinite loop. */
641   if (GST_PAD_IS_IN_SETCAPS (otherpad))
642     goto done;
643
644   /* caps must be fixed here */
645   if (!gst_caps_is_fixed (caps))
646     goto unfixed_caps;
647
648   /* see how we can transform the input caps. */
649   othercaps = gst_base_transform_transform_caps (trans,
650       GST_PAD_DIRECTION (pad), caps);
651
652   /* The caps we can actually output is the intersection of the transformed
653    * caps with the pad template for the pad */
654   if (othercaps) {
655     GstCaps *intersect;
656     const GstCaps *templ_caps;
657
658     templ_caps = gst_pad_get_pad_template_caps (otherpad);
659     intersect = gst_caps_intersect (othercaps, templ_caps);
660
661     gst_caps_unref (othercaps);
662     othercaps = intersect;
663   }
664
665   /* check if transform is empty */
666   if (!othercaps || gst_caps_is_empty (othercaps))
667     goto no_transform;
668
669   /* if the othercaps are not fixed, we need to fixate them, first attempt
670    * is by attempting passthrough if the othercaps are a superset of caps. */
671   if (!gst_caps_is_fixed (othercaps)) {
672     GstCaps *temp;
673
674     GST_DEBUG_OBJECT (trans,
675         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
676
677     /* see if the target caps are a superset of the source caps, in this
678      * case we can try to perform passthrough */
679     temp = gst_caps_intersect (othercaps, caps);
680     GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
681     if (temp) {
682       if (!gst_caps_is_empty (temp) && otherpeer) {
683         GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
684         /* try passthrough. we know it's fixed, because caps is fixed */
685         if (gst_pad_accept_caps (otherpeer, caps)) {
686           GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
687           /* peer accepted unmodified caps, we free the original non-fixed
688            * caps and work with the passthrough caps */
689           gst_caps_unref (othercaps);
690           othercaps = gst_caps_ref (caps);
691           /* mark that we checked othercaps with the peer, this
692            * makes sure we don't call accept_caps again with these same
693            * caps */
694           peer_checked = TRUE;
695         } else {
696           GST_DEBUG_OBJECT (trans,
697               "peer did not accept %" GST_PTR_FORMAT, caps);
698         }
699       }
700       gst_caps_unref (temp);
701     }
702   }
703
704   /* second attempt at fixation is done by intersecting with
705    * the peer caps */
706   if (!gst_caps_is_fixed (othercaps) && otherpeer) {
707     /* intersect against what the peer can do */
708     GstCaps *peercaps;
709     GstCaps *intersect;
710
711     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
712
713     peercaps = gst_pad_get_caps (otherpeer);
714     intersect = gst_caps_intersect (peercaps, othercaps);
715     gst_caps_unref (peercaps);
716     gst_caps_unref (othercaps);
717     othercaps = intersect;
718     peer_checked = FALSE;
719
720     GST_DEBUG_OBJECT (trans,
721         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
722   }
723
724   if (gst_caps_is_empty (othercaps))
725     goto no_transform_possible;
726
727   /* third attempt at fixation, call the fixate vmethod and
728    * ultimately call the pad fixate function. */
729   if (!gst_caps_is_fixed (othercaps)) {
730     GstCaps *temp;
731
732     GST_DEBUG_OBJECT (trans,
733         "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
734         othercaps, GST_DEBUG_PAD_NAME (otherpad));
735
736     /* since we have no other way to fixate left, we might as well just take
737      * the first of the caps list and fixate that */
738
739     /* FIXME: when fixating using the vmethod, it might make sense to fixate
740      * each of the caps; but Wim doesn't see a use case for that yet */
741     temp = gst_caps_copy_nth (othercaps, 0);
742     gst_caps_unref (othercaps);
743     othercaps = temp;
744     peer_checked = FALSE;
745
746     if (klass->fixate_caps) {
747       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
748           " using caps %" GST_PTR_FORMAT
749           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
750           GST_DEBUG_PAD_NAME (otherpad));
751       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
752     }
753     /* if still not fixed, no other option but to let the default pad fixate
754      * function do its job */
755     if (!gst_caps_is_fixed (othercaps)) {
756       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
757           " on pad %s:%s using gst_pad_fixate_caps", othercaps,
758           GST_DEBUG_PAD_NAME (otherpad));
759       gst_pad_fixate_caps (otherpad, othercaps);
760     }
761     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
762   }
763
764   /* caps should be fixed now, if not we have to fail. */
765   if (!gst_caps_is_fixed (othercaps))
766     goto could_not_fixate;
767
768   /* and peer should accept, don't check again if we already checked the
769    * othercaps against the peer. */
770   if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
771     goto peer_no_accept;
772
773   GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
774
775   trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
776   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
777
778   /* see if we have to configure the element now */
779   if (!trans->delay_configure) {
780     GstCaps *incaps, *outcaps;
781
782     /* make sure in and out caps are correct */
783     if (pad == trans->sinkpad) {
784       incaps = caps;
785       outcaps = othercaps;
786     } else {
787       incaps = othercaps;
788       outcaps = caps;
789     }
790     /* call configure now */
791     if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
792       goto failed_configure;
793   } else {
794     /* set pending configure, the configure will happen later with the
795      * caps we set on the pads above. */
796     trans->pending_configure = TRUE;
797   }
798
799   /* we know this will work, we implement the setcaps */
800   gst_pad_set_caps (otherpad, othercaps);
801
802 done:
803   if (otherpeer)
804     gst_object_unref (otherpeer);
805   if (othercaps)
806     gst_caps_unref (othercaps);
807
808   trans->negotiated = ret;
809
810   gst_object_unref (trans);
811
812   return ret;
813
814   /* ERRORS */
815 unfixed_caps:
816   {
817     GST_DEBUG_OBJECT (trans, "caps are not fixed  %" GST_PTR_FORMAT, caps);
818     ret = FALSE;
819     goto done;
820   }
821 no_transform:
822   {
823     GST_DEBUG_OBJECT (trans,
824         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
825     ret = FALSE;
826     goto done;
827   }
828 no_transform_possible:
829   {
830     GST_DEBUG_OBJECT (trans,
831         "transform could not transform %" GST_PTR_FORMAT
832         " in anything we support", caps);
833     ret = FALSE;
834     goto done;
835   }
836 could_not_fixate:
837   {
838     GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
839     ret = FALSE;
840     goto done;
841   }
842 peer_no_accept:
843   {
844     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
845         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
846     ret = FALSE;
847     goto done;
848   }
849 failed_configure:
850   {
851     GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
852         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
853     ret = FALSE;
854     goto done;
855   }
856 }
857
858 /* Allocate a buffer using gst_pad_alloc_buffer
859  *
860  * This function does not do renegotiation on the source pad
861  */
862 static GstFlowReturn
863 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
864     GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
865 {
866   GstBaseTransformClass *bclass;
867   GstFlowReturn ret = GST_FLOW_OK;
868   gboolean copy_inbuf = FALSE;
869
870   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
871
872   /* we cannot reconfigure the element yet as we are still processing
873    * the old buffer. We will therefore delay the reconfiguration of the
874    * element until we have processed this last buffer. */
875   trans->delay_configure = TRUE;
876   /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS 
877      macro. If a set_caps occurs during this function this caps will become
878      invalid. We want to keep them during preparation of the output buffer. */
879   if (out_caps)
880     gst_caps_ref (out_caps);
881
882   /* see if the subclass wants to alloc a buffer */
883   if (bclass->prepare_output_buffer) {
884     ret =
885         bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
886         out_buf);
887     if (ret != GST_FLOW_OK)
888       goto done;
889   }
890
891   /* See if we want to prepare the buffer for in place output */
892   if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
893       && bclass->transform_ip) {
894     if (gst_buffer_is_writable (in_buf)) {
895       if (trans->have_same_caps) {
896         /* Input buffer is already writable and caps are the same, just ref and return it */
897         *out_buf = in_buf;
898         gst_buffer_ref (in_buf);
899       } else {
900         /* Writable buffer, but need to change caps => subbuffer */
901         *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
902         gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
903       }
904       goto done;
905     } else {
906       /* Make a writable buffer below and copy the data */
907       copy_inbuf = TRUE;
908     }
909   }
910
911   if (*out_buf == NULL) {
912     /* Sub-class didn't already provide a buffer for us. Make one */
913     ret = gst_pad_alloc_buffer (trans->srcpad,
914         GST_BUFFER_OFFSET (in_buf), out_size, out_caps, out_buf);
915     if (ret != GST_FLOW_OK || *out_buf == NULL)
916       goto done;
917
918     /* allocated buffer could be of different caps than what we requested */
919     if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
920       /* FIXME, it is possible we can reconfigure the transform with new caps at this
921        * point but for now we just create a buffer ourselves */
922       gst_buffer_unref (*out_buf);
923       *out_buf = gst_buffer_new_and_alloc (out_size);
924       gst_buffer_set_caps (*out_buf, out_caps);
925     }
926   }
927
928   /* If the output buffer metadata is modifiable, copy timestamps and
929    * buffer flags */
930   if (*out_buf != in_buf && gst_buffer_is_metadata_writable (*out_buf)) {
931
932     if (copy_inbuf && gst_buffer_is_writable (*out_buf))
933       memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
934
935     gst_buffer_stamp (*out_buf, in_buf);
936     GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
937         (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_DISCONT |
938         GST_BUFFER_FLAG_IN_CAPS | GST_BUFFER_FLAG_DELTA_UNIT);
939   }
940
941 done:
942   if (out_caps)
943     gst_caps_unref (out_caps);
944   trans->delay_configure = FALSE;
945
946   return ret;
947 }
948
949 /* Given @caps calcultate the size of one unit.
950  *
951  * For video caps, this is the size of one frame (and thus one buffer).
952  * For audio caps, this is the size of one sample.
953  *
954  * These values are cached since they do not change and the calculation
955  * potentially involves parsing caps and other expensive stuff.
956  *
957  * We have two cache locations to store the size, one for the source caps
958  * and one for the sink caps.
959  *
960  * this function returns FALSE if no size could be calculated.
961  */
962 static gboolean
963 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
964     guint * size)
965 {
966   gboolean res = FALSE;
967   GstBaseTransformClass *bclass;
968
969   /* see if we have the result cached */
970   if (trans->cache_caps1 == caps) {
971     *size = trans->cache_caps1_size;
972     GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
973     return TRUE;
974   }
975   if (trans->cache_caps2 == caps) {
976     *size = trans->cache_caps2_size;
977     GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
978     return TRUE;
979   }
980
981   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
982   if (bclass->get_unit_size) {
983     res = bclass->get_unit_size (trans, caps, size);
984     GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
985         ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
986
987     if (res) {
988       /* and cache the values */
989       if (trans->cache_caps1 == NULL) {
990         gst_caps_replace (&trans->cache_caps1, caps);
991         trans->cache_caps1_size = *size;
992         GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
993       } else if (trans->cache_caps2 == NULL) {
994         gst_caps_replace (&trans->cache_caps2, caps);
995         trans->cache_caps2_size = *size;
996         GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
997       } else {
998         GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
999       }
1000     }
1001   } else {
1002     GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1003   }
1004   return res;
1005 }
1006
1007 /* your upstream peer wants to send you a buffer
1008  * that buffer has the given offset, size and caps
1009  * you're requested to allocate a buffer
1010  */
1011 static GstFlowReturn
1012 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1013     GstCaps * caps, GstBuffer ** buf)
1014 {
1015   GstBaseTransform *trans;
1016   GstFlowReturn res;
1017   guint new_size;
1018
1019   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1020
1021   /* we cannot run this when we are transforming data and as such doing 
1022    * another negotiation in the transform method. */
1023   g_mutex_lock (trans->transform_lock);
1024
1025   *buf = NULL;
1026
1027   GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size);
1028   if (offset == GST_BUFFER_OFFSET_NONE)
1029     GST_DEBUG_OBJECT (trans, "... and offset NONE");
1030   else
1031     GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
1032
1033   /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
1034    * a renegotiation and change that to FALSE */
1035   if (trans->have_same_caps) {
1036     /* request a buffer with the same caps */
1037     GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
1038
1039     res =
1040         gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, size, caps,
1041         buf);
1042   } else {
1043     /* if we are configured, request a buffer with the src caps */
1044     GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
1045     GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
1046
1047     if (!srccaps)
1048       goto not_configured;
1049
1050     if (sinkcaps != NULL) {
1051       if (sinkcaps != caps || !gst_caps_is_equal (sinkcaps, caps)) {
1052         gst_caps_unref (sinkcaps);
1053         gst_caps_unref (srccaps);
1054         goto not_configured;
1055       }
1056       gst_caps_unref (sinkcaps);
1057     }
1058
1059     GST_DEBUG_OBJECT (trans, "calling transform_size");
1060     if (!gst_base_transform_transform_size (trans,
1061             GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
1062       gst_caps_unref (srccaps);
1063       goto unknown_size;
1064     }
1065
1066     res =
1067         gst_pad_alloc_buffer_and_set_caps (trans->srcpad, offset, new_size,
1068         srccaps, buf);
1069     gst_caps_unref (srccaps);
1070   }
1071
1072   if (res == GST_FLOW_OK && !trans->have_same_caps) {
1073     /* note that we might have had same caps before, but calling the
1074        alloc_buffer caused setcaps to switch us out of in_place -- in any case
1075        the alloc_buffer served to transmit caps information but we can't use the
1076        buffer. fall through and allocate a buffer corresponding to our sink
1077        caps, if any */
1078     GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
1079     GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
1080
1081     if (!sinkcaps)
1082       goto not_configured;
1083
1084     if (!gst_base_transform_transform_size (trans,
1085             GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
1086             sinkcaps, &new_size)) {
1087       gst_caps_unref (srccaps);
1088       gst_caps_unref (sinkcaps);
1089       goto unknown_size;
1090     }
1091
1092     gst_buffer_unref (*buf);
1093
1094     *buf = gst_buffer_new_and_alloc (new_size);
1095     gst_buffer_set_caps (*buf, sinkcaps);
1096     GST_BUFFER_OFFSET (*buf) = offset;
1097     res = GST_FLOW_OK;
1098
1099     gst_caps_unref (srccaps);
1100     gst_caps_unref (sinkcaps);
1101   }
1102
1103 done:
1104   g_mutex_unlock (trans->transform_lock);
1105   gst_object_unref (trans);
1106
1107   return res;
1108
1109 not_configured:
1110   {
1111     /* let the default allocator handle it */
1112     GST_DEBUG_OBJECT (trans, "not configured");
1113     gst_buffer_replace (buf, NULL);
1114     res = GST_FLOW_OK;
1115     goto done;
1116   }
1117 unknown_size:
1118   {
1119     /* let the default allocator handle it */
1120     GST_DEBUG_OBJECT (trans, "unknown size");
1121     gst_buffer_replace (buf, NULL);
1122     res = GST_FLOW_OK;
1123     goto done;
1124   }
1125 }
1126
1127 static gboolean
1128 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
1129 {
1130   GstBaseTransform *trans;
1131   GstBaseTransformClass *bclass;
1132   gboolean ret = TRUE;
1133
1134   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1135   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1136
1137   if (bclass->event)
1138     ret = bclass->event (trans, event);
1139
1140   /* FIXME, do this in the default event handler so the subclass can do
1141    * something different. */
1142   if (ret)
1143     ret = gst_pad_push_event (trans->srcpad, event);
1144
1145   gst_object_unref (trans);
1146
1147   return ret;
1148 }
1149
1150 static gboolean
1151 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
1152 {
1153   switch (GST_EVENT_TYPE (event)) {
1154     case GST_EVENT_FLUSH_START:
1155       break;
1156     case GST_EVENT_FLUSH_STOP:
1157       GST_OBJECT_LOCK (trans);
1158       /* reset QoS parameters */
1159       trans->priv->proportion = 1.0;
1160       trans->priv->earliest_time = -1;
1161       GST_OBJECT_UNLOCK (trans);
1162       /* we need new segment info after the flush. */
1163       trans->have_newsegment = FALSE;
1164       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1165       break;
1166     case GST_EVENT_EOS:
1167       break;
1168     case GST_EVENT_TAG:
1169       break;
1170     case GST_EVENT_NEWSEGMENT:
1171     {
1172       GstFormat format;
1173       gdouble rate, arate;
1174       gint64 start, stop, time;
1175       gboolean update;
1176
1177       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1178           &start, &stop, &time);
1179
1180       if (trans->segment.format != format)
1181         gst_segment_init (&trans->segment, format);
1182
1183       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
1184           format, start, stop, time);
1185
1186       trans->have_newsegment = TRUE;
1187
1188       if (format == GST_FORMAT_TIME) {
1189         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
1190             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
1191             ", accum %" GST_TIME_FORMAT,
1192             GST_TIME_ARGS (trans->segment.start),
1193             GST_TIME_ARGS (trans->segment.stop),
1194             GST_TIME_ARGS (trans->segment.time),
1195             GST_TIME_ARGS (trans->segment.accum));
1196       } else {
1197         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
1198             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
1199             ", accum %" G_GINT64_FORMAT,
1200             trans->segment.start, trans->segment.stop,
1201             trans->segment.time, trans->segment.accum);
1202       }
1203       break;
1204     }
1205     default:
1206       break;
1207   }
1208
1209   return TRUE;
1210 }
1211
1212 static gboolean
1213 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
1214 {
1215   GstBaseTransform *trans;
1216   GstBaseTransformClass *bclass;
1217   gboolean ret = TRUE;
1218
1219   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1220   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1221
1222   if (bclass->src_event)
1223     ret = bclass->src_event (trans, event);
1224
1225   gst_object_unref (trans);
1226
1227   return ret;
1228 }
1229
1230 static gboolean
1231 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
1232 {
1233   gboolean ret;
1234
1235   switch (GST_EVENT_TYPE (event)) {
1236     case GST_EVENT_SEEK:
1237       break;
1238     case GST_EVENT_NAVIGATION:
1239       break;
1240     case GST_EVENT_QOS:
1241     {
1242       gdouble proportion;
1243       GstClockTimeDiff diff;
1244       GstClockTime timestamp;
1245
1246       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1247       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
1248       break;
1249     }
1250     default:
1251       break;
1252   }
1253
1254   ret = gst_pad_push_event (trans->sinkpad, event);
1255
1256   return ret;
1257 }
1258
1259 static GstFlowReturn
1260 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
1261     GstBuffer ** outbuf)
1262 {
1263   GstBaseTransformClass *bclass;
1264   GstFlowReturn ret = GST_FLOW_OK;
1265   guint out_size;
1266   gboolean want_in_place;
1267   GstClockTime qostime;
1268
1269   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1270
1271   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
1272     GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
1273         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
1274         GST_BUFFER_OFFSET (inbuf));
1275   else
1276     GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
1277         inbuf, GST_BUFFER_SIZE (inbuf));
1278
1279   /* Don't allow buffer handling before negotiation, except in passthrough mode
1280    * or if the class doesn't implement a set_caps function (in which case it doesn't
1281    * care about caps)
1282    */
1283   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
1284     goto not_negotiated;
1285
1286   /* can only do QoS if the segment is in TIME */
1287   if (trans->segment.format != GST_FORMAT_TIME)
1288     goto no_qos;
1289
1290   qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
1291       GST_BUFFER_TIMESTAMP (inbuf));
1292
1293   if (qostime != -1) {
1294     gboolean need_skip;
1295     GstClockTime earliest_time;
1296
1297     GST_OBJECT_LOCK (trans);
1298     earliest_time = trans->priv->earliest_time;
1299     /* check for QoS, don't perform conversion for buffers
1300      * that are known to be late. */
1301     need_skip = trans->priv->qos_enabled &&
1302         earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
1303     GST_OBJECT_UNLOCK (trans);
1304
1305     if (need_skip) {
1306       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
1307           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
1308           GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
1309       goto skip;
1310     }
1311   }
1312
1313 no_qos:
1314   if (trans->passthrough) {
1315     /* In passthrough mode, give transform_ip a look at the
1316      * buffer, without making it writable, or just push the
1317      * data through */
1318     GST_LOG_OBJECT (trans, "element is in passthrough mode");
1319
1320     if (bclass->transform_ip)
1321       ret = bclass->transform_ip (trans, inbuf);
1322
1323     *outbuf = inbuf;
1324
1325     return ret;
1326   }
1327
1328   want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
1329   *outbuf = NULL;
1330
1331   if (want_in_place) {
1332     /* If want_in_place is TRUE, we may need to prepare a new output buffer
1333      * Sub-classes can implement a prepare_output_buffer function as they
1334      * wish. */
1335     GST_LOG_OBJECT (trans, "doing inplace transform");
1336
1337     ret = gst_base_transform_prepare_output_buffer (trans, inbuf,
1338         GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
1339     if (G_UNLIKELY (ret != GST_FLOW_OK))
1340       goto no_buffer;
1341
1342     ret = bclass->transform_ip (trans, *outbuf);
1343
1344   } else {
1345     GST_LOG_OBJECT (trans, "doing non-inplace transform");
1346
1347     /* not transforming inplace, figure out the output size */
1348     if (trans->always_in_place) {
1349       out_size = GST_BUFFER_SIZE (inbuf);
1350     } else {
1351       if (!gst_base_transform_transform_size (trans,
1352               GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
1353               GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
1354               &out_size)) {
1355         /* we have an error */
1356         goto no_size;
1357       }
1358     }
1359
1360     /* no in place transform, get buffer, this might renegotiate. */
1361     ret = gst_base_transform_prepare_output_buffer (trans, inbuf, out_size,
1362         GST_PAD_CAPS (trans->srcpad), outbuf);
1363     if (ret != GST_FLOW_OK)
1364       goto no_buffer;
1365
1366     if (bclass->transform)
1367       ret = bclass->transform (trans, inbuf, *outbuf);
1368     else
1369       ret = GST_FLOW_NOT_SUPPORTED;
1370   }
1371
1372   /* if we got renegotiated we can configure now */
1373   if (trans->pending_configure) {
1374     gboolean success;
1375
1376     success =
1377         gst_base_transform_configure_caps (trans,
1378         GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
1379
1380     trans->pending_configure = FALSE;
1381
1382     if (!success)
1383       goto configure_failed;
1384   }
1385 skip:
1386   gst_buffer_unref (inbuf);
1387
1388   return ret;
1389
1390   /* ERRORS */
1391 not_negotiated:
1392   {
1393     gst_buffer_unref (inbuf);
1394     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1395         ("not negotiated"), ("not negotiated"));
1396     return GST_FLOW_NOT_NEGOTIATED;
1397   }
1398 no_size:
1399   {
1400     gst_buffer_unref (inbuf);
1401     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1402         ("subclass did not specify output size"),
1403         ("subclass did not specify output size"));
1404     return GST_FLOW_ERROR;
1405   }
1406 no_buffer:
1407   {
1408     gst_buffer_unref (inbuf);
1409     GST_DEBUG_OBJECT (trans, "could not get buffer from pool: %s",
1410         gst_flow_get_name (ret));
1411     return ret;
1412   }
1413 configure_failed:
1414   {
1415     gst_buffer_unref (inbuf);
1416     GST_DEBUG_OBJECT (trans, "could not negotiate");
1417     return GST_FLOW_NOT_NEGOTIATED;
1418   }
1419 }
1420
1421 /* FIXME, getrange is broken, need to pull range from the other
1422  * end based on the transform_size result.
1423  */
1424 static GstFlowReturn
1425 gst_base_transform_getrange (GstPad * pad, guint64 offset,
1426     guint length, GstBuffer ** buffer)
1427 {
1428   GstBaseTransform *trans;
1429   GstFlowReturn ret;
1430   GstBuffer *inbuf;
1431
1432   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1433
1434   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
1435   if (ret == GST_FLOW_OK) {
1436     g_mutex_lock (trans->transform_lock);
1437     ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
1438     g_mutex_unlock (trans->transform_lock);
1439   }
1440
1441   gst_object_unref (trans);
1442
1443   return ret;
1444 }
1445
1446 static GstFlowReturn
1447 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
1448 {
1449   GstBaseTransform *trans;
1450   GstFlowReturn ret;
1451   GstBuffer *outbuf = NULL;
1452
1453   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1454
1455   /* protect transform method and concurrent buffer alloc */
1456   g_mutex_lock (trans->transform_lock);
1457   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
1458   g_mutex_unlock (trans->transform_lock);
1459
1460   /* outbuf can be NULL, this means a dropped buffer */
1461   if (outbuf != NULL) {
1462     if (ret == GST_FLOW_OK)
1463       ret = gst_pad_push (trans->srcpad, outbuf);
1464     else
1465       gst_buffer_unref (outbuf);
1466   }
1467
1468   gst_object_unref (trans);
1469
1470   return ret;
1471 }
1472
1473 static void
1474 gst_base_transform_set_property (GObject * object, guint prop_id,
1475     const GValue * value, GParamSpec * pspec)
1476 {
1477   GstBaseTransform *trans;
1478
1479   trans = GST_BASE_TRANSFORM (object);
1480
1481   switch (prop_id) {
1482     case PROP_QOS:
1483       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
1484       break;
1485     default:
1486       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1487       break;
1488   }
1489 }
1490
1491 static void
1492 gst_base_transform_get_property (GObject * object, guint prop_id,
1493     GValue * value, GParamSpec * pspec)
1494 {
1495   GstBaseTransform *trans;
1496
1497   trans = GST_BASE_TRANSFORM (object);
1498
1499   switch (prop_id) {
1500     case PROP_QOS:
1501       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
1502       break;
1503     default:
1504       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1505       break;
1506   }
1507 }
1508
1509 static gboolean
1510 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
1511 {
1512   gboolean result = TRUE;
1513   GstBaseTransform *trans;
1514   GstBaseTransformClass *bclass;
1515
1516   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1517   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1518
1519   if (active) {
1520     if (bclass->start)
1521       result = bclass->start (trans);
1522   }
1523   gst_object_unref (trans);
1524
1525   return result;
1526 }
1527
1528 static gboolean
1529 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
1530 {
1531   gboolean result = FALSE;
1532   GstBaseTransform *trans;
1533   GstBaseTransformClass *bclass;
1534
1535   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1536   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1537
1538   result = gst_pad_activate_pull (trans->sinkpad, active);
1539
1540   if (active) {
1541     if (result && bclass->start)
1542       result &= bclass->start (trans);
1543   }
1544   gst_object_unref (trans);
1545
1546   return result;
1547 }
1548
1549 static GstStateChangeReturn
1550 gst_base_transform_change_state (GstElement * element,
1551     GstStateChange transition)
1552 {
1553   GstBaseTransform *trans;
1554   GstBaseTransformClass *bclass;
1555   GstStateChangeReturn result;
1556
1557   trans = GST_BASE_TRANSFORM (element);
1558   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1559
1560
1561   switch (transition) {
1562     case GST_STATE_CHANGE_NULL_TO_READY:
1563       break;
1564     case GST_STATE_CHANGE_READY_TO_PAUSED:
1565       GST_OBJECT_LOCK (trans);
1566       if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
1567         trans->have_same_caps =
1568             gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
1569             GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
1570       else
1571         trans->have_same_caps = trans->passthrough;
1572       GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
1573       trans->negotiated = FALSE;
1574       trans->have_newsegment = FALSE;
1575       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
1576       trans->priv->proportion = 1.0;
1577       trans->priv->earliest_time = -1;
1578       GST_OBJECT_UNLOCK (trans);
1579       break;
1580     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1581       break;
1582     default:
1583       break;
1584   }
1585
1586   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1587
1588   switch (transition) {
1589     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1590       break;
1591     case GST_STATE_CHANGE_PAUSED_TO_READY:
1592       trans->have_same_caps = FALSE;
1593       /* We can only reset the passthrough mode if the instance told us to 
1594          handle it in configure_caps */
1595       if (bclass->passthrough_on_same_caps) {
1596         gst_base_transform_set_passthrough (trans, FALSE);
1597       }
1598       gst_caps_replace (&trans->cache_caps1, NULL);
1599       gst_caps_replace (&trans->cache_caps2, NULL);
1600       if (bclass->stop)
1601         result = bclass->stop (trans);
1602       break;
1603     case GST_STATE_CHANGE_READY_TO_NULL:
1604       break;
1605     default:
1606       break;
1607   }
1608
1609   return result;
1610 }
1611
1612 /**
1613  * gst_base_transform_set_passthrough:
1614  * @trans: the #GstBaseTransform to set
1615  * @passthrough: boolean indicating passthrough mode.
1616  *
1617  * Set passthrough mode for this filter by default. This is mostly
1618  * useful for filters that do not care about negotiation.
1619  *
1620  * Always TRUE for filters which don't implement either a transform
1621  * or transform_ip method.
1622  *
1623  * MT safe.
1624  */
1625 void
1626 gst_base_transform_set_passthrough (GstBaseTransform * trans,
1627     gboolean passthrough)
1628 {
1629   GstBaseTransformClass *bclass;
1630
1631   g_return_if_fail (trans != NULL);
1632
1633   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1634
1635   GST_OBJECT_LOCK (trans);
1636   if (passthrough == FALSE) {
1637     if (bclass->transform_ip || bclass->transform)
1638       trans->passthrough = FALSE;
1639   } else {
1640     trans->passthrough = TRUE;
1641   }
1642
1643   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
1644   GST_OBJECT_UNLOCK (trans);
1645 }
1646
1647 /**
1648  * gst_base_transform_is_passthrough:
1649  * @trans: the #GstBaseTransform to query
1650  *
1651  * See if @trans is configured as a passthrough transform.
1652  *
1653  * Returns: TRUE is the transform is configured in passthrough mode.
1654  *
1655  * MT safe.
1656  */
1657 gboolean
1658 gst_base_transform_is_passthrough (GstBaseTransform * trans)
1659 {
1660   gboolean result;
1661
1662   g_return_val_if_fail (trans != NULL, FALSE);
1663
1664   GST_OBJECT_LOCK (trans);
1665   result = trans->passthrough;
1666   GST_OBJECT_UNLOCK (trans);
1667
1668   return result;
1669 }
1670
1671 /**
1672  * gst_base_transform_set_in_place:
1673  * @trans: the #GstBaseTransform to modify
1674  * @in_place: Boolean value indicating that we would like to operate
1675  * on in_place buffers.
1676  *
1677  * Determines whether a non-writable buffer will be copied before passing
1678  * to the transform_ip function.
1679  * <itemizedlist>
1680  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
1681  *   <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
1682  * </itemizedlist>
1683  *
1684  * MT safe.
1685  */
1686 void
1687 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
1688 {
1689   GstBaseTransformClass *bclass;
1690
1691   g_return_if_fail (trans != NULL);
1692
1693   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1694
1695   GST_OBJECT_LOCK (trans);
1696
1697   if (in_place) {
1698     if (bclass->transform_ip) {
1699       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
1700       trans->always_in_place = TRUE;
1701     }
1702   } else {
1703     if (bclass->transform) {
1704       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
1705       trans->always_in_place = FALSE;
1706     }
1707   }
1708
1709   GST_OBJECT_UNLOCK (trans);
1710 }
1711
1712 /**
1713  * gst_base_transform_is_in_place:
1714  * @trans: the #GstBaseTransform to query
1715  *
1716  * See if @trans is configured as a in_place transform.
1717  *
1718  * Returns: TRUE is the transform is configured in in_place mode.
1719  *
1720  * MT safe.
1721  */
1722 gboolean
1723 gst_base_transform_is_in_place (GstBaseTransform * trans)
1724 {
1725   gboolean result;
1726
1727   g_return_val_if_fail (trans != NULL, FALSE);
1728
1729   GST_OBJECT_LOCK (trans);
1730   result = trans->always_in_place;
1731   GST_OBJECT_UNLOCK (trans);
1732
1733   return result;
1734 }
1735
1736 /**
1737  * gst_base_transform_update_qos:
1738  * @trans: a #GstBaseTransform
1739  * @proportion: the proportion
1740  * @diff: the diff against the clock
1741  * @timestamp: the timestamp of the buffer generating the QoS
1742  *
1743  * Set the QoS parameters in the transform.
1744  *
1745  * Since: 0.10.5
1746  *
1747  * MT safe.
1748  */
1749 void
1750 gst_base_transform_update_qos (GstBaseTransform * trans,
1751     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
1752 {
1753
1754   g_return_if_fail (trans != NULL);
1755
1756   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
1757       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
1758       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
1759
1760   GST_OBJECT_LOCK (trans);
1761   trans->priv->proportion = proportion;
1762   trans->priv->earliest_time = timestamp + diff;
1763   GST_OBJECT_UNLOCK (trans);
1764 }
1765
1766 /**
1767  * gst_base_transform_set_qos_enabled:
1768  * @trans: a #GstBaseTransform
1769  * @enabled: new state
1770  *
1771  * Enable or disable QoS handling in the transform.
1772  *
1773  * Since: 0.10.5
1774  *
1775  * MT safe.
1776  */
1777 void
1778 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
1779 {
1780   g_return_if_fail (trans != NULL);
1781
1782   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
1783
1784   GST_OBJECT_LOCK (trans);
1785   trans->priv->qos_enabled = enabled;
1786   GST_OBJECT_UNLOCK (trans);
1787 }
1788
1789 /**
1790  * gst_base_transform_is_qos_enabled:
1791  * @trans: a #GstBaseTransform
1792  *
1793  * Queries if the transform will handle QoS.
1794  *
1795  * Returns: TRUE if QoS is enabled.
1796  *
1797  * Since: 0.10.5
1798  *
1799  * MT safe.
1800  */
1801 gboolean
1802 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
1803 {
1804   gboolean result;
1805
1806   g_return_val_if_fail (trans != NULL, FALSE);
1807
1808   GST_OBJECT_LOCK (trans);
1809   result = trans->priv->qos_enabled;
1810   GST_OBJECT_UNLOCK (trans);
1811
1812   return result;
1813 }