]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blob - libs/gst/base/gstbasetransform.c
4408ef2f8c9ae4f6bea0499de91eed435c7c4557
[glsdk/gstreamer0-10.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  */
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  */
201 #ifdef HAVE_CONFIG_H
202 #  include "config.h"
203 #endif
205 #include <stdlib.h>
206 #include <string.h>
208 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
209  * with newer GLib versions (>= 2.31.0) */
210 #define GLIB_DISABLE_DEPRECATION_WARNINGS
211 #include "../../../gst/gst_private.h"
212 #include "../../../gst/gst-i18n-lib.h"
213 #include "../../../gst/glib-compat-private.h"
214 #include "gstbasetransform.h"
215 #include <gst/gstmarshal.h>
217 GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
218 #define GST_CAT_DEFAULT gst_base_transform_debug
220 /* BaseTransform signals and args */
221 enum
223   /* FILL ME */
224   LAST_SIGNAL
225 };
227 #define DEFAULT_PROP_QOS        FALSE
229 enum
231   PROP_0,
232   PROP_QOS
233 };
235 #define GST_BASE_TRANSFORM_GET_PRIVATE(obj)  \
236     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))
238 struct _GstBaseTransformPrivate
240   /* QoS *//* with LOCK */
241   gboolean qos_enabled;
242   gdouble proportion;
243   GstClockTime earliest_time;
244   /* previous buffer had a discont */
245   gboolean discont;
247   GstActivateMode pad_mode;
249   gboolean gap_aware;
251   /* caps used for allocating buffers */
252   gboolean proxy_alloc;
253   GstCaps *sink_alloc;
254   GstCaps *src_alloc;
256   /*
257    * This flag controls if basetransform should explicitly
258    * do a pad alloc when it receives a buffer even if it operates on
259    * passthrough, this is needed to check for downstream caps suggestions
260    * and this newly alloc'ed buffer is discarded.
261    *
262    * Without this flag basetransform would try a pad alloc whenever it
263    * gets a new buffer and pipelines like:
264    * "src ! basetrans1 ! basetrans2 ! basetrans3 ! sink"
265    * Would have a 3 pad allocs for each buffer pushed downstream from the src.
266    *
267    * This flag is set to TRUE on start up, on setcaps and when a buffer is
268    * pushed downstream. It is set to FALSE after a pad alloc has been requested
269    * downstream.
270    * The rationale is that when a pad alloc flows through the pipeline, all
271    * basetransform elements on passthrough will avoid pad alloc'ing when they
272    * get the buffer.
273    */
274   gboolean force_alloc;
276   /* upstream caps and size suggestions */
277   GstCaps *sink_suggest;
278   guint size_suggest;
279   gboolean suggest_pending;
281   gboolean reconfigure;
283   /* QoS stats */
284   guint64 processed;
285   guint64 dropped;
287   GstClockTime last_stop_out;
288   GList *delayed_events;
290   GstCaps *cached_peer_caps[2];
291   GstCaps *cached_transformed_caps[2];
292 };
294 static GstElementClass *parent_class = NULL;
296 static void gst_base_transform_class_init (GstBaseTransformClass * klass);
297 static void gst_base_transform_init (GstBaseTransform * trans,
298     GstBaseTransformClass * klass);
299 static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform
300     * trans, GstBuffer * input, GstBuffer ** buf);
302 GType
303 gst_base_transform_get_type (void)
305   static volatile gsize base_transform_type = 0;
307   if (g_once_init_enter (&base_transform_type)) {
308     GType _type;
309     static const GTypeInfo base_transform_info = {
310       sizeof (GstBaseTransformClass),
311       NULL,
312       NULL,
313       (GClassInitFunc) gst_base_transform_class_init,
314       NULL,
315       NULL,
316       sizeof (GstBaseTransform),
317       0,
318       (GInstanceInitFunc) gst_base_transform_init,
319     };
321     _type = g_type_register_static (GST_TYPE_ELEMENT,
322         "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
323     g_once_init_leave (&base_transform_type, _type);
324   }
325   return base_transform_type;
328 static void gst_base_transform_finalize (GObject * object);
329 static void gst_base_transform_set_property (GObject * object, guint prop_id,
330     const GValue * value, GParamSpec * pspec);
331 static void gst_base_transform_get_property (GObject * object, guint prop_id,
332     GValue * value, GParamSpec * pspec);
333 static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
334     gboolean active);
335 static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
336     gboolean active);
337 static gboolean gst_base_transform_activate (GstBaseTransform * trans,
338     gboolean active);
339 static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
340     GstCaps * caps, guint * size);
342 static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);
343 static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans,
344     GstEvent * event);
345 static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);
346 static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans,
347     GstEvent * event);
348 static gboolean gst_base_transform_check_get_range (GstPad * pad);
349 static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
350     guint length, GstBuffer ** buffer);
351 static GstFlowReturn gst_base_transform_chain (GstPad * pad,
352     GstBuffer * buffer);
353 static GstCaps *gst_base_transform_getcaps (GstPad * pad);
354 static gboolean gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps);
355 static gboolean gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
356     GstPadDirection direction, GstCaps * caps);
357 static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
358 static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
359     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
360 static gboolean gst_base_transform_query (GstPad * pad, GstQuery * query);
361 static gboolean gst_base_transform_default_query (GstBaseTransform * trans,
362     GstPadDirection direction, GstQuery * query);
363 static const GstQueryType *gst_base_transform_query_type (GstPad * pad);
365 /* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
367 static void
368 gst_base_transform_drop_delayed_events (GstBaseTransform * trans)
370   GST_OBJECT_LOCK (trans);
371   if (trans->priv->delayed_events) {
372     g_list_foreach (trans->priv->delayed_events, (GFunc) gst_event_unref, NULL);
373     g_list_free (trans->priv->delayed_events);
374     trans->priv->delayed_events = NULL;
375   }
376   GST_OBJECT_UNLOCK (trans);
379 static void
380 gst_base_transform_clear_transformed_caps_cache (GstBaseTransform * trans)
382   struct _GstBaseTransformPrivate *priv = trans->priv;
383   int n;
385   for (n = 0; n < 2; ++n) {
386     if (priv->cached_peer_caps[n]) {
387       gst_caps_unref (priv->cached_peer_caps[n]);
388       priv->cached_peer_caps[n] = NULL;
389     }
390     if (priv->cached_transformed_caps[n]) {
391       gst_caps_unref (priv->cached_transformed_caps[n]);
392       priv->cached_transformed_caps[n] = NULL;
393     }
394   }
397 static void
398 gst_base_transform_finalize (GObject * object)
400   GstBaseTransform *trans;
402   trans = GST_BASE_TRANSFORM (object);
404   gst_base_transform_drop_delayed_events (trans);
405   gst_caps_replace (&trans->priv->sink_suggest, NULL);
406   g_mutex_free (trans->transform_lock);
408   gst_base_transform_clear_transformed_caps_cache (trans);
410   G_OBJECT_CLASS (parent_class)->finalize (object);
413 static void
414 gst_base_transform_class_init (GstBaseTransformClass * klass)
416   GObjectClass *gobject_class;
418   gobject_class = G_OBJECT_CLASS (klass);
420   GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
421       "basetransform element");
423   GST_DEBUG ("gst_base_transform_class_init");
425   g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate));
427   parent_class = g_type_class_peek_parent (klass);
429   gobject_class->set_property = gst_base_transform_set_property;
430   gobject_class->get_property = gst_base_transform_get_property;
432   g_object_class_install_property (gobject_class, PROP_QOS,
433       g_param_spec_boolean ("qos", "QoS", "Handle Quality-of-Service events",
434           DEFAULT_PROP_QOS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
436   gobject_class->finalize = gst_base_transform_finalize;
438   klass->passthrough_on_same_caps = FALSE;
439   klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc);
440   klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);
441   klass->accept_caps =
442       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps_default);
443   klass->query = GST_DEBUG_FUNCPTR (gst_base_transform_default_query);
446 static void
447 gst_base_transform_init (GstBaseTransform * trans,
448     GstBaseTransformClass * bclass)
450   GstPadTemplate *pad_template;
452   GST_DEBUG ("gst_base_transform_init");
454   trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans);
456   pad_template =
457       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
458   g_return_if_fail (pad_template != NULL);
459   trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
460   gst_pad_set_getcaps_function (trans->sinkpad,
461       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
462   gst_pad_set_acceptcaps_function (trans->sinkpad,
463       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
464   gst_pad_set_setcaps_function (trans->sinkpad,
465       GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
466   gst_pad_set_event_function (trans->sinkpad,
467       GST_DEBUG_FUNCPTR (gst_base_transform_sink_event));
468   gst_pad_set_chain_function (trans->sinkpad,
469       GST_DEBUG_FUNCPTR (gst_base_transform_chain));
470   gst_pad_set_activatepush_function (trans->sinkpad,
471       GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
472   gst_pad_set_bufferalloc_function (trans->sinkpad,
473       GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
474   gst_pad_set_query_function (trans->sinkpad,
475       GST_DEBUG_FUNCPTR (gst_base_transform_query));
476   gst_pad_set_query_type_function (trans->sinkpad,
477       GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
478   gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
480   pad_template =
481       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
482   g_return_if_fail (pad_template != NULL);
483   trans->srcpad = gst_pad_new_from_template (pad_template, "src");
484   gst_pad_set_getcaps_function (trans->srcpad,
485       GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
486   gst_pad_set_acceptcaps_function (trans->srcpad,
487       GST_DEBUG_FUNCPTR (gst_base_transform_acceptcaps));
488   gst_pad_set_event_function (trans->srcpad,
489       GST_DEBUG_FUNCPTR (gst_base_transform_src_event));
490   gst_pad_set_checkgetrange_function (trans->srcpad,
491       GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range));
492   gst_pad_set_getrange_function (trans->srcpad,
493       GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
494   gst_pad_set_activatepull_function (trans->srcpad,
495       GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
496   gst_pad_set_query_function (trans->srcpad,
497       GST_DEBUG_FUNCPTR (gst_base_transform_query));
498   gst_pad_set_query_type_function (trans->srcpad,
499       GST_DEBUG_FUNCPTR (gst_base_transform_query_type));
500   gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
502   trans->transform_lock = g_mutex_new ();
503   trans->pending_configure = FALSE;
504   trans->priv->qos_enabled = DEFAULT_PROP_QOS;
505   trans->cache_caps1 = NULL;
506   trans->cache_caps2 = NULL;
507   trans->priv->pad_mode = GST_ACTIVATE_NONE;
508   trans->priv->gap_aware = FALSE;
509   trans->priv->delayed_events = NULL;
511   trans->passthrough = FALSE;
512   if (bclass->transform == NULL) {
513     /* If no transform function, always_in_place is TRUE */
514     GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
515     trans->always_in_place = TRUE;
517     if (bclass->transform_ip == NULL) {
518       GST_DEBUG_OBJECT (trans, "setting passthrough TRUE");
519       trans->passthrough = TRUE;
520     }
521   }
523   trans->priv->processed = 0;
524   trans->priv->dropped = 0;
525   trans->priv->force_alloc = TRUE;
528 /* given @caps on the src or sink pad (given by @direction)
529  * calculate the possible caps on the other pad.
530  *
531  * Returns new caps, unref after usage.
532  */
533 static GstCaps *
534 gst_base_transform_transform_caps (GstBaseTransform * trans,
535     GstPadDirection direction, GstCaps * caps)
537   GstCaps *ret;
538   GstBaseTransformClass *klass;
540   if (caps == NULL)
541     return NULL;
543   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
545   /* if there is a custom transform function, use this */
546   if (klass->transform_caps) {
547     GstCaps *temp;
548     gint i;
550     /* start with empty caps */
551     ret = gst_caps_new_empty ();
552     GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction);
554     if (gst_caps_is_any (caps)) {
555       /* for any caps we still have to call the transform function */
556       GST_DEBUG_OBJECT (trans, "from: ANY");
557       temp = klass->transform_caps (trans, direction, caps);
558       GST_DEBUG_OBJECT (trans, "  to: %" GST_PTR_FORMAT, temp);
560       temp = gst_caps_make_writable (temp);
561       gst_caps_append (ret, temp);
562     } else {
563       gint n = gst_caps_get_size (caps);
564       /* we send caps with just one structure to the transform
565        * function as this is easier for the element */
566       for (i = 0; i < n; i++) {
567         GstCaps *nth;
569         nth = gst_caps_copy_nth (caps, i);
570         GST_LOG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
571         temp = klass->transform_caps (trans, direction, nth);
572         gst_caps_unref (nth);
573         GST_LOG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
575         temp = gst_caps_make_writable (temp);
577         /* here we need to only append those structures, that are not yet
578          * in there, we use the merge function for this */
579         gst_caps_merge (ret, temp);
581         GST_LOG_OBJECT (trans, "  merged[%d]: %" GST_PTR_FORMAT, i, ret);
582       }
583       GST_LOG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
584       /* FIXME: we can't do much simplification here because we don't really want to
585        * change the caps order
586        gst_caps_do_simplify (ret);
587        GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret));
588        */
589     }
590   } else {
591     GST_DEBUG_OBJECT (trans, "identity from: %" GST_PTR_FORMAT, caps);
592     /* no transform function, use the identity transform */
593     ret = gst_caps_ref (caps);
594   }
596   GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret),
597       ret);
599   return ret;
602 /* transform a buffer of @size with @caps on the pad with @direction to
603  * the size of a buffer with @othercaps and store the result in @othersize
604  *
605  * We have two ways of doing this:
606  *  1) use a custom transform size function, this is for complicated custom
607  *     cases with no fixed unit_size.
608  *  2) use the unit_size functions where there is a relationship between the
609  *     caps and the size of a buffer.
610  */
611 static gboolean
612 gst_base_transform_transform_size (GstBaseTransform * trans,
613     GstPadDirection direction, GstCaps * caps,
614     guint size, GstCaps * othercaps, guint * othersize)
616   guint inunitsize, outunitsize, units;
617   GstBaseTransformClass *klass;
618   gboolean ret;
620   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
622   GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
623       GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
624       size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
626   if (klass->transform_size) {
627     /* if there is a custom transform function, use this */
628     ret = klass->transform_size (trans, direction, caps, size, othercaps,
629         othersize);
630   } else if (klass->get_unit_size == NULL) {
631     /* if there is no transform_size and no unit_size, it means the
632      * element does not modify the size of a buffer */
633     *othersize = size;
634     ret = TRUE;
635   } else {
636     /* there is no transform_size function, we have to use the unit_size
637      * functions. This method assumes there is a fixed unit_size associated with
638      * each caps. We provide the same amount of units on both sides. */
639     if (!gst_base_transform_get_unit_size (trans, caps, &inunitsize))
640       goto no_in_size;
642     GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
643         inunitsize);
645     /* input size must be a multiple of the unit_size of the input caps */
646     if (inunitsize == 0 || (size % inunitsize != 0))
647       goto no_multiple;
649     /* get the amount of units */
650     units = size / inunitsize;
652     /* now get the unit size of the output */
653     if (!gst_base_transform_get_unit_size (trans, othercaps, &outunitsize))
654       goto no_out_size;
656     /* the output size is the unit_size times the amount of units on the
657      * input */
658     *othersize = units * outunitsize;
659     GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
661     ret = TRUE;
662   }
663   return ret;
665   /* ERRORS */
666 no_in_size:
667   {
668     GST_DEBUG_OBJECT (trans, "could not get in_size");
669     g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans));
670     return FALSE;
671   }
672 no_multiple:
673   {
674     GST_DEBUG_OBJECT (trans, "Size %u is not a multiple of unit size %u", size,
675         inunitsize);
676     g_warning ("%s: size %u is not a multiple of unit size %u",
677         GST_ELEMENT_NAME (trans), size, inunitsize);
678     return FALSE;
679   }
680 no_out_size:
681   {
682     GST_DEBUG_OBJECT (trans, "could not get out_size");
683     g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans));
684     return FALSE;
685   }
688 /* get the caps that can be handled by @pad. We perform:
689  *
690  *  - take the caps of peer of otherpad,
691  *  - filter against the padtemplate of otherpad,
692  *  - calculate all transforms of remaining caps
693  *  - filter against template of @pad
694  *
695  * If there is no peer, we simply return the caps of the padtemplate of pad.
696  */
697 static GstCaps *
698 gst_base_transform_getcaps (GstPad * pad)
700   GstBaseTransform *trans;
701   GstPad *otherpad;
702   const GstCaps *templ;
703   GstCaps *peercaps, *caps, *temp;
704   gboolean samecaps;
705   int cache_index;
707   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
709   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
710   cache_index = (pad == trans->srcpad) ? 0 : 1;
712   /* we can do what the peer can */
713   peercaps = gst_pad_peer_get_caps_reffed (otherpad);
714   GST_OBJECT_LOCK (trans);
715   samecaps = (peercaps && trans->priv->cached_peer_caps[cache_index]
716       && gst_caps_is_strictly_equal (peercaps,
717           trans->priv->cached_peer_caps[cache_index]));
718   if (!samecaps) {
719     if (trans->priv->cached_peer_caps[cache_index]) {
720       gst_caps_unref (trans->priv->cached_peer_caps[cache_index]);
721       trans->priv->cached_peer_caps[cache_index] = NULL;
722     }
723     if (trans->priv->cached_transformed_caps[cache_index]) {
724       gst_caps_unref (trans->priv->cached_transformed_caps[cache_index]);
725       trans->priv->cached_transformed_caps[cache_index] = NULL;
726     }
727   } else {
728     GST_DEBUG_OBJECT (trans,
729         "Returning cached transformed caps (index = %d)", cache_index);
730     caps = gst_caps_ref (trans->priv->cached_transformed_caps[cache_index]);
731     goto done;
732   }
733   GST_OBJECT_UNLOCK (trans);
735   if (peercaps) {
736     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
738     /* filtered against our padtemplate on the other side */
739     templ = gst_pad_get_pad_template_caps (otherpad);
740     GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
741     temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
742     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
743   } else {
744     temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
745     GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
746         temp);
747   }
749   /* then see what we can transform this to */
750   caps = gst_base_transform_transform_caps (trans,
751       GST_PAD_DIRECTION (otherpad), temp);
752   GST_DEBUG_OBJECT (pad, "transformed  %" GST_PTR_FORMAT, caps);
753   gst_caps_unref (temp);
754   if (caps == NULL)
755     goto done_update_cache;
757   /* and filter against the template of this pad */
758   templ = gst_pad_get_pad_template_caps (pad);
759   GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, templ);
760   /* We keep the caps sorted like the returned caps */
761   temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
762   GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
763   gst_caps_unref (caps);
764   caps = temp;
766   if (peercaps) {
767     /* Now try if we can put the untransformed downstream caps first */
768     temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
769     if (!gst_caps_is_empty (temp)) {
770       gst_caps_merge (temp, caps);
771       caps = temp;
772     } else {
773       gst_caps_unref (temp);
774     }
775   }
777 done_update_cache:
778   GST_DEBUG_OBJECT (trans, "returning  %" GST_PTR_FORMAT, caps);
780   GST_OBJECT_LOCK (trans);
781   if (peercaps) {
782     trans->priv->cached_peer_caps[cache_index] = gst_caps_ref (peercaps);
783   }
784   if (caps) {
785     trans->priv->cached_transformed_caps[cache_index] = gst_caps_ref (caps);
786   }
788 done:
789   GST_OBJECT_UNLOCK (trans);
791   if (peercaps)
792     gst_caps_unref (peercaps);
794   gst_object_unref (trans);
796   return caps;
799 /* function triggered when the in and out caps are negotiated and need
800  * to be configured in the subclass. */
801 static gboolean
802 gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
803     GstCaps * out)
805   gboolean ret = TRUE;
806   GstBaseTransformClass *klass;
808   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
810   GST_DEBUG_OBJECT (trans, "in caps:  %" GST_PTR_FORMAT, in);
811   GST_DEBUG_OBJECT (trans, "out caps: %" GST_PTR_FORMAT, out);
813   /* clear the cache */
814   gst_caps_replace (&trans->cache_caps1, NULL);
815   gst_caps_replace (&trans->cache_caps2, NULL);
817   /* figure out same caps state */
818   trans->have_same_caps = gst_caps_is_equal (in, out);
819   GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
821   /* If we've a transform_ip method and same input/output caps, set in_place
822    * by default. If for some reason the sub-class prefers using a transform
823    * function, it can clear the in place flag in the set_caps */
824   gst_base_transform_set_in_place (trans,
825       klass->transform_ip && trans->have_same_caps);
827   /* Set the passthrough if the class wants passthrough_on_same_caps
828    * and we have the same caps on each pad */
829   if (klass->passthrough_on_same_caps)
830     gst_base_transform_set_passthrough (trans, trans->have_same_caps);
832   /* now configure the element with the caps */
833   if (klass->set_caps) {
834     GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
835     ret = klass->set_caps (trans, in, out);
836   }
838   GST_OBJECT_LOCK (trans);
839   /* make sure we reevaluate how the buffer_alloc works wrt to proxy allocating
840    * the buffer. FIXME, this triggers some quite heavy codepaths that don't need
841    * to be taken.. */
842   trans->priv->suggest_pending = TRUE;
843   GST_OBJECT_UNLOCK (trans);
844   trans->negotiated = ret;
846   return ret;
849 /* check if caps @in on @pad can be transformed to @out on the other pad.
850  * We don't have a vmethod to test this yet so we have to do a somewhat less
851  * efficient check for this.
852  */
853 static gboolean
854 gst_base_transform_can_transform (GstBaseTransform * trans, GstPad * pad,
855     GstCaps * in, GstCaps * out)
857   GstCaps *othercaps;
859   /* convert the in caps to all possible out caps */
860   othercaps =
861       gst_base_transform_transform_caps (trans, GST_PAD_DIRECTION (pad), in);
863   /* check if transform is empty */
864   if (!othercaps || gst_caps_is_empty (othercaps))
865     goto no_transform;
867   /* check if the out caps is a subset of the othercaps */
868   if (!gst_caps_can_intersect (out, othercaps))
869     goto no_subset;
871   if (othercaps)
872     gst_caps_unref (othercaps);
874   GST_DEBUG_OBJECT (trans, "from %" GST_PTR_FORMAT, in);
875   GST_DEBUG_OBJECT (trans, "to   %" GST_PTR_FORMAT, out);
877   return TRUE;
879   /* ERRORS */
880 no_transform:
881   {
882     GST_DEBUG_OBJECT (trans,
883         "transform returned useless %" GST_PTR_FORMAT, othercaps);
884     if (othercaps)
885       gst_caps_unref (othercaps);
886     return FALSE;
887   }
888 no_subset:
889   {
890     GST_DEBUG_OBJECT (trans, "no subset");
891     if (othercaps)
892       gst_caps_unref (othercaps);
893     return FALSE;
894   }
897 /* given a fixed @caps on @pad, create the best possible caps for the
898  * other pad.
899  * @caps must be fixed when calling this function.
900  *
901  * This function calls the transform caps vmethod of the basetransform to figure
902  * out the possible target formats. It then tries to select the best format from
903  * this list by:
904  *
905  * - attempt passthrough if the target caps is a superset of the input caps
906  * - fixating by using peer caps
907  * - fixating with transform fixate function
908  * - fixating with pad fixate functions.
909  *
910  * this function returns a caps that can be transformed into and is accepted by
911  * the peer element.
912  */
913 static GstCaps *
914 gst_base_transform_find_transform (GstBaseTransform * trans, GstPad * pad,
915     GstCaps * caps)
917   GstBaseTransformClass *klass;
918   GstPad *otherpad, *otherpeer;
919   GstCaps *othercaps;
920   gboolean peer_checked = FALSE;
921   gboolean is_fixed;
923   /* caps must be fixed here, this is a programming error if it's not */
924   g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
926   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
928   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
929   otherpeer = gst_pad_get_peer (otherpad);
931   /* see how we can transform the input caps. We need to do this even for
932    * passthrough because it might be possible that this element cannot support
933    * passthrough at all. */
934   othercaps = gst_base_transform_transform_caps (trans,
935       GST_PAD_DIRECTION (pad), caps);
937   /* The caps we can actually output is the intersection of the transformed
938    * caps with the pad template for the pad */
939   if (othercaps) {
940     GstCaps *intersect;
941     const GstCaps *templ_caps;
943     templ_caps = gst_pad_get_pad_template_caps (otherpad);
944     GST_DEBUG_OBJECT (trans,
945         "intersecting against padtemplate %" GST_PTR_FORMAT, templ_caps);
947     intersect =
948         gst_caps_intersect_full (othercaps, templ_caps,
949         GST_CAPS_INTERSECT_FIRST);
951     gst_caps_unref (othercaps);
952     othercaps = intersect;
953   }
955   /* check if transform is empty */
956   if (!othercaps || gst_caps_is_empty (othercaps))
957     goto no_transform;
959   /* if the othercaps are not fixed, we need to fixate them, first attempt
960    * is by attempting passthrough if the othercaps are a superset of caps. */
961   /* FIXME. maybe the caps is not fixed because it has multiple structures of
962    * fixed caps */
963   is_fixed = gst_caps_is_fixed (othercaps);
964   if (!is_fixed) {
965     GST_DEBUG_OBJECT (trans,
966         "transform returned non fixed  %" GST_PTR_FORMAT, othercaps);
968     /* see if the target caps are a superset of the source caps, in this
969      * case we can try to perform passthrough */
970     if (gst_caps_can_intersect (othercaps, caps)) {
971       GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
972       if (otherpeer) {
973         /* try passthrough. we know it's fixed, because caps is fixed */
974         if (gst_pad_accept_caps (otherpeer, caps)) {
975           GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
976           /* peer accepted unmodified caps, we free the original non-fixed
977            * caps and work with the passthrough caps */
978           gst_caps_unref (othercaps);
979           othercaps = gst_caps_ref (caps);
980           is_fixed = TRUE;
981           /* mark that we checked othercaps with the peer, this
982            * makes sure we don't call accept_caps again with these same
983            * caps */
984           peer_checked = TRUE;
985         } else {
986           GST_DEBUG_OBJECT (trans,
987               "peer did not accept %" GST_PTR_FORMAT, caps);
988         }
989       } else {
990         GST_DEBUG_OBJECT (trans, "no peer, doing passthrough");
991         gst_caps_unref (othercaps);
992         othercaps = gst_caps_ref (caps);
993         is_fixed = TRUE;
994       }
995     }
996   }
998   /* second attempt at fixation is done by intersecting with
999    * the peer caps */
1000   if (!is_fixed && otherpeer) {
1001     /* intersect against what the peer can do */
1002     GstCaps *peercaps;
1003     GstCaps *intersect;
1005     GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
1007     peercaps = gst_pad_get_caps_reffed (otherpeer);
1008     intersect = gst_caps_intersect (peercaps, othercaps);
1009     gst_caps_unref (peercaps);
1010     gst_caps_unref (othercaps);
1011     othercaps = intersect;
1012     peer_checked = FALSE;
1014     is_fixed = gst_caps_is_fixed (othercaps);
1016     GST_DEBUG_OBJECT (trans,
1017         "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
1018   }
1020   if (gst_caps_is_empty (othercaps))
1021     goto no_transform_possible;
1023   /* third attempt at fixation, call the fixate vmethod and
1024    * ultimately call the pad fixate function. */
1025   if (!is_fixed) {
1026     GST_DEBUG_OBJECT (trans,
1027         "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
1028         othercaps, GST_DEBUG_PAD_NAME (otherpad));
1030     /* since we have no other way to fixate left, we might as well just take
1031      * the first of the caps list and fixate that */
1033     /* FIXME: when fixating using the vmethod, it might make sense to fixate
1034      * each of the caps; but Wim doesn't see a use case for that yet */
1035     gst_caps_truncate (othercaps);
1036     peer_checked = FALSE;
1038     if (klass->fixate_caps) {
1039       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1040           " using caps %" GST_PTR_FORMAT
1041           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1042           GST_DEBUG_PAD_NAME (otherpad));
1043       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1044       is_fixed = gst_caps_is_fixed (othercaps);
1045     }
1046     /* if still not fixed, no other option but to let the default pad fixate
1047      * function do its job */
1048     if (!is_fixed) {
1049       GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
1050           " on pad %s:%s using gst_pad_fixate_caps", othercaps,
1051           GST_DEBUG_PAD_NAME (otherpad));
1052       gst_pad_fixate_caps (otherpad, othercaps);
1053       is_fixed = gst_caps_is_fixed (othercaps);
1054     }
1055     GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
1056   } else {
1057     GST_DEBUG ("caps are fixed");
1058     /* else caps are fixed but the subclass may want to add fields */
1059     if (klass->fixate_caps) {
1060       othercaps = gst_caps_make_writable (othercaps);
1062       GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1063           " using caps %" GST_PTR_FORMAT
1064           " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
1065           GST_DEBUG_PAD_NAME (otherpad));
1067       klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
1068       is_fixed = gst_caps_is_fixed (othercaps);
1069     }
1070   }
1072   /* caps should be fixed now, if not we have to fail. */
1073   if (!is_fixed)
1074     goto could_not_fixate;
1076   /* and peer should accept, don't check again if we already checked the
1077    * othercaps against the peer. */
1078   if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
1079     goto peer_no_accept;
1081   GST_DEBUG_OBJECT (trans, "Input caps were %" GST_PTR_FORMAT
1082       ", and got final caps %" GST_PTR_FORMAT, caps, othercaps);
1084   if (otherpeer)
1085     gst_object_unref (otherpeer);
1087   return othercaps;
1089   /* ERRORS */
1090 no_transform:
1091   {
1092     GST_DEBUG_OBJECT (trans,
1093         "transform returned useless  %" GST_PTR_FORMAT, othercaps);
1094     goto error_cleanup;
1095   }
1096 no_transform_possible:
1097   {
1098     GST_DEBUG_OBJECT (trans,
1099         "transform could not transform %" GST_PTR_FORMAT
1100         " in anything we support", caps);
1101     goto error_cleanup;
1102   }
1103 could_not_fixate:
1104   {
1105     GST_DEBUG_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
1106     goto error_cleanup;
1107   }
1108 peer_no_accept:
1109   {
1110     GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
1111         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1112     goto error_cleanup;
1113   }
1114 error_cleanup:
1115   {
1116     if (otherpeer)
1117       gst_object_unref (otherpeer);
1118     if (othercaps)
1119       gst_caps_unref (othercaps);
1120     return NULL;
1121   }
1124 static gboolean
1125 gst_base_transform_acceptcaps_default (GstBaseTransform * trans,
1126     GstPadDirection direction, GstCaps * caps)
1128 #if 0
1129   GstPad *otherpad;
1130   GstCaps *othercaps = NULL;
1131 #endif
1132   gboolean ret = TRUE;
1134 #if 0
1135   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1137   /* we need fixed caps for the check, fall back to the default implementation
1138    * if we don't */
1139   if (!gst_caps_is_fixed (caps))
1140 #endif
1141   {
1142     GstCaps *allowed;
1144     GST_DEBUG_OBJECT (trans, "non fixed accept caps %" GST_PTR_FORMAT, caps);
1146     /* get all the formats we can handle on this pad */
1147     if (direction == GST_PAD_SRC)
1148       allowed = gst_pad_get_caps_reffed (trans->srcpad);
1149     else
1150       allowed = gst_pad_get_caps_reffed (trans->sinkpad);
1152     if (!allowed) {
1153       GST_DEBUG_OBJECT (trans, "gst_pad_get_caps() failed");
1154       goto no_transform_possible;
1155     }
1157     GST_DEBUG_OBJECT (trans, "allowed caps %" GST_PTR_FORMAT, allowed);
1159     /* intersect with the requested format */
1160     ret = gst_caps_can_intersect (allowed, caps);
1161     gst_caps_unref (allowed);
1163     if (!ret)
1164       goto no_transform_possible;
1165   }
1166 #if 0
1167   else {
1168     GST_DEBUG_OBJECT (pad, "accept caps %" GST_PTR_FORMAT, caps);
1170     /* find best possible caps for the other pad as a way to see if we can
1171      * transform this caps. */
1172     othercaps = gst_base_transform_find_transform (trans, pad, caps);
1173     if (!othercaps || gst_caps_is_empty (othercaps))
1174       goto no_transform_possible;
1176     GST_DEBUG_OBJECT (pad, "we can transform to %" GST_PTR_FORMAT, othercaps);
1177   }
1178 #endif
1180 done:
1181 #if 0
1182   /* We know it's always NULL since we never use it */
1183   if (othercaps)
1184     gst_caps_unref (othercaps);
1185 #endif
1187   return ret;
1189   /* ERRORS */
1190 no_transform_possible:
1191   {
1192     GST_DEBUG_OBJECT (trans,
1193         "transform could not transform %" GST_PTR_FORMAT
1194         " in anything we support", caps);
1195     ret = FALSE;
1196     goto done;
1197   }
1200 static gboolean
1201 gst_base_transform_acceptcaps (GstPad * pad, GstCaps * caps)
1203   gboolean ret = TRUE;
1204   GstBaseTransform *trans;
1205   GstBaseTransformClass *bclass;
1207   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1208   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1210   if (bclass->accept_caps)
1211     ret = bclass->accept_caps (trans, GST_PAD_DIRECTION (pad), caps);
1213   gst_object_unref (trans);
1215   return ret;
1218 /* called when new caps arrive on the sink or source pad,
1219  * We try to find the best caps for the other side using our _find_transform()
1220  * function. If there are caps, we configure the transform for this new
1221  * transformation.
1222  *
1223  * FIXME, this function is currently commutative but this should not really be
1224  * because we never set caps starting from the srcpad.
1225  */
1226 static gboolean
1227 gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
1229   GstBaseTransform *trans;
1230   GstPad *otherpad, *otherpeer;
1231   GstCaps *othercaps = NULL;
1232   gboolean ret = TRUE;
1233   GstCaps *incaps, *outcaps;
1235   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1237   otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
1238   otherpeer = gst_pad_get_peer (otherpad);
1240   /* if we get called recursively, we bail out now to avoid an
1241    * infinite loop. */
1242   if (GST_PAD_IS_IN_SETCAPS (otherpad))
1243     goto done;
1245   GST_DEBUG_OBJECT (pad, "have new caps %p %" GST_PTR_FORMAT, caps, caps);
1247   /* find best possible caps for the other pad */
1248   othercaps = gst_base_transform_find_transform (trans, pad, caps);
1249   if (!othercaps || gst_caps_is_empty (othercaps))
1250     goto no_transform_possible;
1252   /* configure the element now */
1253   /* make sure in and out caps are correct */
1254   if (pad == trans->sinkpad) {
1255     incaps = caps;
1256     outcaps = othercaps;
1257   } else {
1258     incaps = othercaps;
1259     outcaps = caps;
1260   }
1262   /* if we have the same caps, we can optimize and reuse the input caps */
1263   if (gst_caps_is_equal (incaps, outcaps)) {
1264     GST_INFO_OBJECT (trans, "reuse caps");
1265     gst_caps_unref (othercaps);
1266     outcaps = othercaps = gst_caps_ref (incaps);
1267   }
1269   /* call configure now */
1270   if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
1271     goto failed_configure;
1273   /* we know this will work, we implement the setcaps */
1274   gst_pad_set_caps (otherpad, othercaps);
1276   if (pad == trans->srcpad && trans->priv->pad_mode == GST_ACTIVATE_PULL) {
1277     /* FIXME hm? */
1278     ret &= gst_pad_set_caps (otherpeer, othercaps);
1279     if (!ret) {
1280       GST_INFO_OBJECT (trans, "otherpeer setcaps(%" GST_PTR_FORMAT ") failed",
1281           othercaps);
1282     }
1283   }
1285 done:
1286   /* new caps, force alloc on next buffer on the chain */
1287   trans->priv->force_alloc = TRUE;
1288   if (otherpeer)
1289     gst_object_unref (otherpeer);
1290   if (othercaps)
1291     gst_caps_unref (othercaps);
1293   trans->negotiated = ret;
1295   gst_object_unref (trans);
1297   return ret;
1299   /* ERRORS */
1300 no_transform_possible:
1301   {
1302     GST_WARNING_OBJECT (trans,
1303         "transform could not transform %" GST_PTR_FORMAT
1304         " in anything we support", caps);
1305     ret = FALSE;
1306     goto done;
1307   }
1308 failed_configure:
1309   {
1310     GST_WARNING_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
1311         " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
1312     ret = FALSE;
1313     goto done;
1314   }
1317 static gboolean
1318 gst_base_transform_default_query (GstBaseTransform * trans,
1319     GstPadDirection direction, GstQuery * query)
1321   gboolean ret = FALSE;
1322   GstPad *otherpad;
1324   otherpad = (direction == GST_PAD_SRC) ? trans->sinkpad : trans->srcpad;
1326   switch (GST_QUERY_TYPE (query)) {
1327     case GST_QUERY_POSITION:{
1328       GstFormat format;
1330       gst_query_parse_position (query, &format, NULL);
1331       if (format == GST_FORMAT_TIME && trans->segment.format == GST_FORMAT_TIME) {
1332         gint64 pos;
1333         ret = TRUE;
1335         if ((direction == GST_PAD_SINK)
1336             || (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
1337           pos =
1338               gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1339               trans->segment.last_stop);
1340         } else {
1341           pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
1342               trans->priv->last_stop_out);
1343         }
1344         gst_query_set_position (query, format, pos);
1345       } else {
1346         ret = gst_pad_peer_query (otherpad, query);
1347       }
1348       break;
1349     }
1350     default:
1351       ret = gst_pad_peer_query (otherpad, query);
1352       break;
1353   }
1355   return ret;
1358 static gboolean
1359 gst_base_transform_query (GstPad * pad, GstQuery * query)
1361   GstBaseTransform *trans;
1362   GstBaseTransformClass *bclass;
1363   gboolean ret;
1365   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1366   if (G_UNLIKELY (trans == NULL))
1367     return FALSE;
1369   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1371   if (bclass->query)
1372     ret = bclass->query (trans, GST_PAD_DIRECTION (pad), query);
1373   else
1374     ret = gst_pad_query_default (pad, query);
1376   gst_object_unref (trans);
1378   return ret;
1381 static const GstQueryType *
1382 gst_base_transform_query_type (GstPad * pad)
1384   static const GstQueryType types[] = {
1385     GST_QUERY_POSITION,
1386     GST_QUERY_NONE
1387   };
1389   return types;
1392 static void
1393 compute_upstream_suggestion (GstBaseTransform * trans, guint expsize,
1394     GstCaps * caps)
1396   GstCaps *othercaps;
1397   GstBaseTransformPrivate *priv = trans->priv;
1399   GST_DEBUG_OBJECT (trans, "trying to find upstream suggestion");
1401   /* we cannot convert the current buffer but we might be able to suggest a
1402    * new format upstream, try to find what the best format is. */
1403   othercaps = gst_base_transform_find_transform (trans, trans->srcpad, caps);
1405   if (!othercaps) {
1406     GST_DEBUG_OBJECT (trans, "incompatible caps, ignoring");
1407     /* we received caps that we cannot transform. Upstream is behaving badly
1408      * because it should have checked if we could handle these caps. We can
1409      * simply ignore these caps and produce a buffer with our original caps. */
1410   } else {
1411     guint size_suggest;
1413     GST_DEBUG_OBJECT (trans, "getting size of suggestion");
1415     /* not a subset, we have a new upstream suggestion, remember it and
1416      * allocate a default buffer. First we try to convert the size */
1417     if (gst_base_transform_transform_size (trans,
1418             GST_PAD_SRC, caps, expsize, othercaps, &size_suggest)) {
1420       /* ok, remember the suggestions now */
1421       GST_DEBUG_OBJECT (trans,
1422           "storing new caps and size suggestion of %u and %" GST_PTR_FORMAT,
1423           size_suggest, othercaps);
1425       GST_OBJECT_LOCK (trans->sinkpad);
1426       if (priv->sink_suggest)
1427         gst_caps_unref (priv->sink_suggest);
1428       priv->sink_suggest = gst_caps_ref (othercaps);
1429       priv->size_suggest = size_suggest;
1430       trans->priv->suggest_pending = TRUE;
1431       GST_OBJECT_UNLOCK (trans->sinkpad);
1432     }
1433     gst_caps_unref (othercaps);
1434   }
1437 /* Allocate a buffer using gst_pad_alloc_buffer
1438  *
1439  * This function can do renegotiation on the source pad
1440  *
1441  * The output buffer is always writable. outbuf can be equal to
1442  * inbuf, the caller should be prepared for this and perform
1443  * appropriate refcounting.
1444  */
1445 static GstFlowReturn
1446 gst_base_transform_prepare_output_buffer (GstBaseTransform * trans,
1447     GstBuffer * in_buf, GstBuffer ** out_buf)
1449   GstBaseTransformClass *bclass;
1450   GstBaseTransformPrivate *priv;
1451   GstFlowReturn ret = GST_FLOW_OK;
1452   guint outsize, newsize, expsize;
1453   gboolean discard, setcaps, copymeta;
1454   GstCaps *incaps, *oldcaps, *newcaps, *outcaps;
1456   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1458   priv = trans->priv;
1460   *out_buf = NULL;
1462   /* figure out how to allocate a buffer based on the current configuration */
1463   if (trans->passthrough) {
1464     GST_DEBUG_OBJECT (trans, "doing passthrough alloc");
1465     /* passthrough, we don't really need to call pad alloc but we still need to
1466      * in order to get upstream negotiation. The output size is the same as the
1467      * input size. */
1468     outsize = GST_BUFFER_SIZE (in_buf);
1469     /* we always alloc and discard here */
1470     discard = TRUE;
1471   } else {
1472     gboolean want_in_place = (bclass->transform_ip != NULL)
1473         && trans->always_in_place;
1475     if (want_in_place) {
1476       GST_DEBUG_OBJECT (trans, "doing inplace alloc");
1477       /* we alloc a buffer of the same size as the input */
1478       outsize = GST_BUFFER_SIZE (in_buf);
1479       /* only discard it when the input was not writable, otherwise, we reuse
1480        * the input buffer. */
1481       discard = gst_buffer_is_writable (in_buf);
1482       GST_DEBUG_OBJECT (trans, "discard: %d", discard);
1483     } else {
1484       GST_DEBUG_OBJECT (trans, "getting output size for copy transform");
1485       /* copy transform, figure out the output size */
1486       if (!gst_base_transform_transform_size (trans,
1487               GST_PAD_SINK, GST_PAD_CAPS (trans->sinkpad),
1488               GST_BUFFER_SIZE (in_buf), GST_PAD_CAPS (trans->srcpad),
1489               &outsize)) {
1490         goto unknown_size;
1491       }
1492       /* never discard this buffer, we need it for storing the output */
1493       discard = FALSE;
1494     }
1495   }
1497   oldcaps = GST_PAD_CAPS (trans->srcpad);
1499   if (bclass->prepare_output_buffer) {
1500     GST_DEBUG_OBJECT (trans,
1501         "calling prepare buffer with caps %p %" GST_PTR_FORMAT, oldcaps,
1502         oldcaps);
1503     ret =
1504         bclass->prepare_output_buffer (trans, in_buf, outsize, oldcaps,
1505         out_buf);
1507     /* get a new ref to the srcpad caps, the prepare_output_buffer function can
1508      * update the pad caps if it wants */
1509     oldcaps = GST_PAD_CAPS (trans->srcpad);
1511     /* FIXME 0.11:
1512      * decrease refcount again if vmethod returned refcounted in_buf. This
1513      * is because we need to make sure that the buffer is writable for the
1514      * in_place transform. The docs of the vmethod say that you should return
1515      * a reffed inbuf, which is exactly what we don't want :), oh well.. */
1516     if (in_buf == *out_buf)
1517       gst_buffer_unref (in_buf);
1519     /* never discard the buffer from the prepare_buffer method */
1520     if (*out_buf != NULL)
1521       discard = FALSE;
1522   }
1524   if (ret != GST_FLOW_OK)
1525     goto alloc_failed;
1527   if (*out_buf == NULL) {
1528     if (trans->passthrough && !trans->priv->force_alloc) {
1529       GST_DEBUG_OBJECT (trans, "Avoiding pad alloc");
1530       *out_buf = gst_buffer_ref (in_buf);
1531     } else {
1532       GST_DEBUG_OBJECT (trans, "doing alloc with caps %" GST_PTR_FORMAT,
1533           oldcaps);
1535       ret = gst_pad_alloc_buffer (trans->srcpad,
1536           GST_BUFFER_OFFSET (in_buf), outsize, oldcaps, out_buf);
1537       if (ret != GST_FLOW_OK)
1538         goto alloc_failed;
1539     }
1540   }
1542   /* must always have a buffer by now */
1543   if (*out_buf == NULL)
1544     goto no_buffer;
1546   /* check if we got different caps on this new output buffer */
1547   newcaps = GST_BUFFER_CAPS (*out_buf);
1548   newsize = GST_BUFFER_SIZE (*out_buf);
1550   if (newcaps && !gst_caps_is_equal (newcaps, oldcaps)) {
1551     GstCaps *othercaps;
1552     gboolean can_convert;
1554     GST_DEBUG_OBJECT (trans, "received new caps %" GST_PTR_FORMAT, newcaps);
1556     incaps = GST_PAD_CAPS (trans->sinkpad);
1558     /* check if we can convert the current incaps to the new target caps */
1559     can_convert =
1560         gst_base_transform_can_transform (trans, trans->sinkpad, incaps,
1561         newcaps);
1563     if (!can_convert) {
1564       GST_DEBUG_OBJECT (trans, "cannot perform transform on current buffer");
1566       gst_base_transform_transform_size (trans,
1567           GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1569       compute_upstream_suggestion (trans, expsize, newcaps);
1571       /* we got a suggested caps but we can't transform to it. See if there is
1572        * another downstream format that we can transform to */
1573       othercaps =
1574           gst_base_transform_find_transform (trans, trans->sinkpad, incaps);
1576       if (othercaps && !gst_caps_is_empty (othercaps)) {
1577         GST_DEBUG_OBJECT (trans, "we found target caps %" GST_PTR_FORMAT,
1578             othercaps);
1579         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1580         gst_buffer_set_caps (*out_buf, othercaps);
1581         gst_caps_unref (othercaps);
1582         newcaps = GST_BUFFER_CAPS (*out_buf);
1583         can_convert = TRUE;
1584       } else if (othercaps)
1585         gst_caps_unref (othercaps);
1586     }
1588     /* it's possible that the buffer we got is of the wrong size, get the
1589      * expected size here, we will check the size if we are going to use the
1590      * buffer later on. */
1591     gst_base_transform_transform_size (trans,
1592         GST_PAD_SINK, incaps, GST_BUFFER_SIZE (in_buf), newcaps, &expsize);
1594     if (can_convert) {
1595       GST_DEBUG_OBJECT (trans, "reconfigure transform for current buffer");
1597       /* subclass might want to add fields to the caps */
1598       if (bclass->fixate_caps != NULL) {
1599         newcaps = gst_caps_copy (newcaps);
1601         GST_DEBUG_OBJECT (trans, "doing fixate %" GST_PTR_FORMAT
1602             " using caps %" GST_PTR_FORMAT
1603             " on pad %s:%s using fixate_caps vmethod", newcaps, incaps,
1604             GST_DEBUG_PAD_NAME (trans->srcpad));
1605         bclass->fixate_caps (trans, GST_PAD_SINK, incaps, newcaps);
1607         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1608         gst_buffer_set_caps (*out_buf, newcaps);
1609         gst_caps_unref (newcaps);
1610         newcaps = GST_BUFFER_CAPS (*out_buf);
1611       }
1613       /* caps not empty, try to renegotiate to the new format */
1614       if (!gst_base_transform_configure_caps (trans, incaps, newcaps)) {
1615         /* not sure we need to fail hard here, we can simply continue our
1616          * conversion with what we negotiated before */
1617         goto failed_configure;
1618       }
1619       /* new format configure, and use the new output buffer */
1620       gst_pad_set_caps (trans->srcpad, newcaps);
1621       discard = FALSE;
1622       /* clear previous cached sink-pad caps, so buffer_alloc knows that
1623        * it needs to revisit the decision about whether to proxy or not: */
1624       gst_caps_replace (&priv->sink_alloc, NULL);
1625       /* if we got a buffer of the wrong size, discard it now and make sure we
1626        * allocate a properly sized buffer later. */
1627       if (newsize != expsize) {
1628         if (in_buf != *out_buf)
1629           gst_buffer_unref (*out_buf);
1630         *out_buf = NULL;
1631       }
1632       outsize = expsize;
1633     } else {
1634       compute_upstream_suggestion (trans, expsize, newcaps);
1636       if (in_buf != *out_buf)
1637         gst_buffer_unref (*out_buf);
1638       *out_buf = NULL;
1639     }
1640   } else if (outsize != newsize) {
1641     GST_WARNING_OBJECT (trans, "Caps did not change but allocated size does "
1642         "not match expected size (%d != %d)", newsize, outsize);
1643     if (in_buf != *out_buf)
1644       gst_buffer_unref (*out_buf);
1645     *out_buf = NULL;
1646   }
1648   /* these are the final output caps */
1649   outcaps = GST_PAD_CAPS (trans->srcpad);
1651   copymeta = FALSE;
1652   if (*out_buf == NULL) {
1653     if (!discard) {
1654       GST_DEBUG_OBJECT (trans, "make default output buffer of size %d",
1655           outsize);
1656       /* no valid buffer yet, make one, metadata is writable */
1657       *out_buf = gst_buffer_new_and_alloc (outsize);
1658       gst_buffer_copy_metadata (*out_buf, in_buf,
1659           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1660     } else {
1661       GST_DEBUG_OBJECT (trans, "reuse input buffer");
1662       *out_buf = in_buf;
1663     }
1664   } else {
1665     if (trans->passthrough && in_buf != *out_buf) {
1666       /* we are asked to perform a passthrough transform but the input and
1667        * output buffers are different. We have to discard the output buffer and
1668        * reuse the input buffer. */
1669       GST_DEBUG_OBJECT (trans, "passthrough but different buffers");
1670       discard = TRUE;
1671     }
1672     if (discard) {
1673       GST_DEBUG_OBJECT (trans, "discard buffer, reuse input buffer");
1674       gst_buffer_unref (*out_buf);
1675       *out_buf = in_buf;
1676     } else {
1677       GST_DEBUG_OBJECT (trans, "using allocated buffer in %p, out %p", in_buf,
1678           *out_buf);
1679       /* if we have different buffers, check if the metadata is ok */
1680       if (*out_buf != in_buf) {
1681         guint mask;
1683         mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
1684             GST_BUFFER_FLAG_DELTA_UNIT | GST_BUFFER_FLAG_DISCONT |
1685             GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_MEDIA1 |
1686             GST_BUFFER_FLAG_MEDIA2 | GST_BUFFER_FLAG_MEDIA3;
1687         /* see if the flags and timestamps match */
1688         copymeta =
1689             (GST_MINI_OBJECT_FLAGS (*out_buf) & mask) ==
1690             (GST_MINI_OBJECT_FLAGS (in_buf) & mask);
1691         copymeta |=
1692             GST_BUFFER_TIMESTAMP (*out_buf) != GST_BUFFER_TIMESTAMP (in_buf) ||
1693             GST_BUFFER_DURATION (*out_buf) != GST_BUFFER_DURATION (in_buf) ||
1694             GST_BUFFER_OFFSET (*out_buf) != GST_BUFFER_OFFSET (in_buf) ||
1695             GST_BUFFER_OFFSET_END (*out_buf) != GST_BUFFER_OFFSET_END (in_buf);
1696       }
1697     }
1698   }
1700   /* check if we need to make things writable. We need this when we need to
1701    * update the caps or the metadata on the output buffer. */
1702   newcaps = GST_BUFFER_CAPS (*out_buf);
1703   /* we check the pointers as a quick check and then go to the more involved
1704    * check. This is needed when we receive different pointers on the sinkpad
1705    * that mean the same caps. What we then want to do is prefer those caps over
1706    * the ones on the srcpad and set the srcpad caps to the buffer caps */
1707   setcaps = !newcaps || ((newcaps != outcaps)
1708       && (!gst_caps_is_equal (newcaps, outcaps)));
1709   /* we need to modify the metadata when the element is not gap aware,
1710    * passthrough is not used and the gap flag is set */
1711   copymeta |= !trans->priv->gap_aware && !trans->passthrough
1712       && (GST_MINI_OBJECT_FLAGS (*out_buf) & GST_BUFFER_FLAG_GAP);
1714   if (setcaps || copymeta) {
1715     GST_DEBUG_OBJECT (trans, "setcaps %d, copymeta %d", setcaps, copymeta);
1716     if (!gst_buffer_is_metadata_writable (*out_buf)) {
1717       GST_DEBUG_OBJECT (trans, "buffer metadata %p not writable", *out_buf);
1718       if (in_buf == *out_buf)
1719         *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
1720       else
1721         *out_buf = gst_buffer_make_metadata_writable (*out_buf);
1722     }
1723     /* when we get here, the metadata should be writable */
1724     if (setcaps)
1725       gst_buffer_set_caps (*out_buf, outcaps);
1726     if (copymeta)
1727       gst_buffer_copy_metadata (*out_buf, in_buf,
1728           GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
1729     /* clear the GAP flag when the subclass does not understand it */
1730     if (!trans->priv->gap_aware)
1731       GST_BUFFER_FLAG_UNSET (*out_buf, GST_BUFFER_FLAG_GAP);
1732   }
1734   return ret;
1736   /* ERRORS */
1737 alloc_failed:
1738   {
1739     GST_WARNING_OBJECT (trans, "pad-alloc failed: %s", gst_flow_get_name (ret));
1740     return ret;
1741   }
1742 no_buffer:
1743   {
1744     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
1745         ("Sub-class failed to provide an output buffer"), (NULL));
1746     return GST_FLOW_ERROR;
1747   }
1748 unknown_size:
1749   {
1750     GST_ERROR_OBJECT (trans, "unknown output size");
1751     return GST_FLOW_ERROR;
1752   }
1753 failed_configure:
1754   {
1755     GST_WARNING_OBJECT (trans, "failed to configure caps");
1756     return GST_FLOW_NOT_NEGOTIATED;
1757   }
1760 /* Given @caps calcultate the size of one unit.
1761  *
1762  * For video caps, this is the size of one frame (and thus one buffer).
1763  * For audio caps, this is the size of one sample.
1764  *
1765  * These values are cached since they do not change and the calculation
1766  * potentially involves parsing caps and other expensive stuff.
1767  *
1768  * We have two cache locations to store the size, one for the source caps
1769  * and one for the sink caps.
1770  *
1771  * this function returns FALSE if no size could be calculated.
1772  */
1773 static gboolean
1774 gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
1775     guint * size)
1777   gboolean res = FALSE;
1778   GstBaseTransformClass *bclass;
1780   /* see if we have the result cached */
1781   if (trans->cache_caps1 == caps) {
1782     *size = trans->cache_caps1_size;
1783     GST_DEBUG_OBJECT (trans, "returned %d from first cache", *size);
1784     return TRUE;
1785   }
1786   if (trans->cache_caps2 == caps) {
1787     *size = trans->cache_caps2_size;
1788     GST_DEBUG_OBJECT (trans, "returned %d from second cached", *size);
1789     return TRUE;
1790   }
1792   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
1793   if (bclass->get_unit_size) {
1794     res = bclass->get_unit_size (trans, caps, size);
1795     GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
1796         ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
1798     if (res) {
1799       /* and cache the values */
1800       if (trans->cache_caps1 == NULL) {
1801         gst_caps_replace (&trans->cache_caps1, caps);
1802         trans->cache_caps1_size = *size;
1803         GST_DEBUG_OBJECT (trans, "caching %d in first cache", *size);
1804       } else if (trans->cache_caps2 == NULL) {
1805         gst_caps_replace (&trans->cache_caps2, caps);
1806         trans->cache_caps2_size = *size;
1807         GST_DEBUG_OBJECT (trans, "caching %d in second cache", *size);
1808       } else {
1809         GST_DEBUG_OBJECT (trans, "no free spot to cache unit_size");
1810       }
1811     }
1812   } else {
1813     GST_DEBUG_OBJECT (trans, "Sub-class does not implement get_unit_size");
1814   }
1815   return res;
1818 /* your upstream peer wants to send you a buffer
1819  * that buffer has the given offset, size and caps
1820  * you're requested to allocate a buffer
1821  */
1822 static GstFlowReturn
1823 gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
1824     GstCaps * caps, GstBuffer ** buf)
1826   GstBaseTransform *trans;
1827   GstBaseTransformPrivate *priv;
1828   GstFlowReturn res;
1829   gboolean alloced = FALSE;
1830   gboolean proxy, suggest, new_caps;
1831   GstCaps *sink_suggest = NULL;
1832   guint size_suggest;
1834   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
1835   if (G_UNLIKELY (trans == NULL))
1836     return GST_FLOW_WRONG_STATE;
1837   priv = trans->priv;
1839   GST_DEBUG_OBJECT (pad, "alloc with caps %p %" GST_PTR_FORMAT ", size %u",
1840       caps, caps, size);
1842   /* if the code below does not come up with a better buffer, we will return _OK
1843    * and an empty buffer. This will trigger the core to allocate a buffer with
1844    * given input size and caps. */
1845   *buf = NULL;
1846   res = GST_FLOW_OK;
1848   /* we remember our previous alloc request to quickly see if we can proxy or
1849    * not. We skip this check if we have a pending suggestion. */
1850   GST_OBJECT_LOCK (pad);
1851   suggest = priv->suggest_pending;
1852   GST_OBJECT_UNLOCK (pad);
1854   if (!suggest) {
1855     /* we have no suggestion, see below if we need to proxy */
1856     gst_caps_replace (&sink_suggest, caps);
1857     size_suggest = size;
1858     suggest = FALSE;
1859     new_caps = sink_suggest
1860         && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1862     if (new_caps)
1863       GST_DEBUG_OBJECT (trans, "new format %p %" GST_PTR_FORMAT, caps, caps);
1864     else
1865       GST_DEBUG_OBJECT (trans, "have old caps %p, size %u", caps, size);
1866   } else {
1867     /* if we have a suggestion, pretend we got these as input */
1868     GST_OBJECT_LOCK (pad);
1869     if (priv->sink_suggest &&
1870         !gst_caps_can_intersect (caps, priv->sink_suggest)) {
1871       sink_suggest = gst_caps_ref (priv->sink_suggest);
1872       size_suggest = priv->size_suggest;
1873       GST_DEBUG_OBJECT (trans, "have suggestion %p %" GST_PTR_FORMAT " size %u",
1874           sink_suggest, sink_suggest, priv->size_suggest);
1875     } else {
1876       GST_DEBUG_OBJECT (trans,
1877           "have suggestion equal to upstream caps %p %" GST_PTR_FORMAT, caps,
1878           caps);
1879       gst_caps_replace (&sink_suggest, caps);
1880       size_suggest = size;
1881       suggest = FALSE;
1882     }
1883     priv->suggest_pending = FALSE;
1884     GST_OBJECT_UNLOCK (pad);
1886     /* check if we actually handle this format on the sinkpad */
1887     if (suggest) {
1888       GstCaps *peercaps;
1890       /* Always intersect with the peer caps to get correct
1891        * and complete caps. The suggested caps could be incomplete,
1892        * for example video/x-raw-yuv without any fields at all.
1893        */
1894       peercaps =
1895           gst_pad_peer_get_caps_reffed (GST_BASE_TRANSFORM_SINK_PAD (trans));
1897       if (peercaps) {
1898         GstCaps *intersect;
1900         intersect =
1901             gst_caps_intersect_full (sink_suggest, peercaps,
1902             GST_CAPS_INTERSECT_FIRST);
1903         gst_caps_unref (peercaps);
1905         /* If intersected caps is empty then just keep them empty. The
1906          * code below will try to come up with possible caps if there
1907          * are any */
1908         gst_caps_unref (sink_suggest);
1909         sink_suggest = intersect;
1910       }
1912       /* If the suggested caps are not empty and not fixed, try to fixate them */
1913       if (!gst_caps_is_fixed (sink_suggest)
1914           && !gst_caps_is_empty (sink_suggest)) {
1915         GST_DEBUG_OBJECT (trans,
1916             "Suggested caps is not fixed: %" GST_PTR_FORMAT, sink_suggest);
1918         /* try the alloc caps if it is still not fixed */
1919         if (!gst_caps_is_fixed (sink_suggest)) {
1920           GstCaps *intersect;
1922           GST_DEBUG_OBJECT (trans, "Checking if the input caps is compatible "
1923               "with the non-fixed caps suggestion");
1924           intersect =
1925               gst_caps_intersect_full (sink_suggest, caps,
1926               GST_CAPS_INTERSECT_FIRST);
1927           if (!gst_caps_is_empty (intersect)) {
1928             GST_DEBUG_OBJECT (trans, "It is, using it");
1929             gst_caps_replace (&sink_suggest, caps);
1930           }
1931           gst_caps_unref (intersect);
1932         }
1934         /* be safe and call default fixate */
1935         sink_suggest = gst_caps_make_writable (sink_suggest);
1936         gst_pad_fixate_caps (GST_BASE_TRANSFORM_SINK_PAD (trans), sink_suggest);
1938         if (!gst_caps_is_fixed (sink_suggest)) {
1939           GST_DEBUG_OBJECT (trans,
1940               "Impossible to fixate caps, using upstream caps");
1941           gst_caps_replace (&sink_suggest, caps);
1942           size_suggest = size;
1943           suggest = FALSE;
1944         }
1946         GST_DEBUG_OBJECT (trans, "Caps fixed to: %" GST_PTR_FORMAT,
1947             sink_suggest);
1948       }
1949     }
1951     new_caps = sink_suggest
1952         && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1953   }
1955   /* Check if the new caps are compatible with our
1956    * sinkpad template caps and if they're not
1957    * we try to come up with any supported caps
1958    */
1959   if (new_caps) {
1960     const GstCaps *templ;
1962     templ = gst_pad_get_pad_template_caps (pad);
1964     /* Fall back to the upstream caps if the suggested caps
1965      * are not actually supported. Shouldn't really happen
1966      */
1967     if (suggest && !gst_caps_can_intersect (sink_suggest, templ)) {
1968       GST_DEBUG_OBJECT (trans,
1969           "Suggested caps not supported by sinkpad, using upstream caps");
1970       gst_caps_replace (&sink_suggest, caps);
1971       size_suggest = size;
1972       suggest = FALSE;
1973       new_caps = sink_suggest
1974           && !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
1975     }
1977     if (new_caps && (suggest || !gst_caps_can_intersect (sink_suggest, templ))) {
1978       GstCaps *allowed, *peercaps;
1980       GST_DEBUG_OBJECT (trans,
1981           "Requested pad alloc caps are not supported: %" GST_PTR_FORMAT,
1982           sink_suggest);
1983       /* the requested pad alloc caps are not supported, so let's try
1984        * picking something allowed between the pads (they are linked,
1985        * there must be something) */
1986       allowed = gst_pad_get_allowed_caps (pad);
1987       if (allowed && !gst_caps_is_empty (allowed)) {
1988         GST_DEBUG_OBJECT (trans,
1989             "pads could agree on one of the following caps: " "%"
1990             GST_PTR_FORMAT, allowed);
1992         /* Check which caps would be possible with downstream */
1993         peercaps =
1994             gst_pad_get_allowed_caps (GST_BASE_TRANSFORM_SRC_PAD (trans));
1995         if (peercaps) {
1996           GstCaps *tmp, *intersect;
1998           tmp =
1999               gst_base_transform_transform_caps (trans, GST_PAD_SRC, peercaps);
2000           gst_caps_unref (peercaps);
2001           intersect = gst_caps_intersect (allowed, tmp);
2002           gst_caps_unref (tmp);
2003           gst_caps_unref (allowed);
2005           if (gst_caps_is_empty (intersect)) {
2006             gst_caps_unref (intersect);
2007             goto not_supported;
2008           }
2010           allowed = intersect;
2011         }
2013         allowed = gst_caps_make_writable (allowed);
2015         /* Fixate them to be safe if the subclass didn't do it */
2016         gst_caps_truncate (allowed);
2017         gst_pad_fixate_caps (pad, allowed);
2019         if (!gst_caps_is_fixed (allowed)) {
2020           GST_ERROR_OBJECT (trans, "Impossible to fixate any caps");
2021           gst_caps_unref (allowed);
2022           goto not_supported;
2023         }
2025         gst_caps_replace (&sink_suggest, allowed);
2026         gst_caps_unref (allowed);
2028         suggest = TRUE;
2029         new_caps = !gst_caps_is_equal (sink_suggest, priv->sink_alloc);
2031         GST_DEBUG_OBJECT (trans, "Calculated new suggestion caps %"
2032             GST_PTR_FORMAT, sink_suggest);
2033       } else {
2034         if (allowed)
2035           gst_caps_unref (allowed);
2036         goto not_supported;
2037       }
2038     }
2039   }
2041   /* find the best format for the other side here we decide if we will proxy
2042    * the caps or not. */
2043   if (sink_suggest == NULL) {
2044     /* always proxy when the caps are NULL. When this is a new format, see if
2045      * we can proxy it downstream */
2046     GST_DEBUG_OBJECT (trans, "null caps, marking for proxy");
2047     priv->proxy_alloc = TRUE;
2048   } else if (new_caps) {
2049     GstCaps *othercaps;
2051     /* we have a new format, see what we need to proxy to */
2052     othercaps = gst_base_transform_find_transform (trans, pad, sink_suggest);
2053     if (!othercaps || gst_caps_is_empty (othercaps)) {
2054       /* no transform possible, we certainly can't proxy */
2055       GST_DEBUG_OBJECT (trans, "can't find transform, disable proxy");
2056       priv->proxy_alloc = FALSE;
2057     } else {
2058       /* we transformed into something */
2059       if (gst_caps_is_equal (sink_suggest, othercaps)) {
2060         GST_DEBUG_OBJECT (trans, "best caps same as input, marking for proxy");
2061         priv->proxy_alloc = TRUE;
2062       } else {
2063         GST_DEBUG_OBJECT (trans,
2064             "best caps different from input, disable proxy");
2065         priv->proxy_alloc = FALSE;
2066       }
2067     }
2068     if (othercaps)
2069       gst_caps_unref (othercaps);
2070   }
2072   /* remember the new caps */
2073   GST_OBJECT_LOCK (pad);
2074   gst_caps_replace (&priv->sink_alloc, sink_suggest);
2075   GST_OBJECT_UNLOCK (pad);
2077   proxy = priv->proxy_alloc;
2078   GST_DEBUG_OBJECT (trans, "doing default alloc, proxy %d, suggest %d", proxy,
2079       suggest);
2081   /* we only want to proxy if we have no suggestion pending, FIXME */
2082   if (proxy && !suggest) {
2083     GstCaps *newcaps;
2085     GST_DEBUG_OBJECT (trans, "proxy buffer-alloc with caps %p %" GST_PTR_FORMAT
2086         ", size %u", caps, caps, size);
2088     /* we always proxy the input caps, never the suggestion. The reason is that
2089      * We don't yet handle the caps of renegotiation in here. FIXME */
2090     res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
2091     if (res != GST_FLOW_OK)
2092       goto alloc_failed;
2093     alloced = TRUE;
2095     /* check if the caps changed */
2096     newcaps = GST_BUFFER_CAPS (*buf);
2098     GST_DEBUG_OBJECT (trans, "got caps %" GST_PTR_FORMAT, newcaps);
2100     if (!gst_caps_is_equal (newcaps, caps)) {
2101       GST_DEBUG_OBJECT (trans, "caps are new");
2102       /* we have new caps, see if we can proxy downstream */
2103       if (gst_pad_peer_accept_caps (pad, newcaps)) {
2104         /* peer accepts the caps, return a buffer in this format */
2105         GST_DEBUG_OBJECT (trans, "peer accepted new caps");
2106         /* remember the format */
2107         GST_OBJECT_LOCK (pad);
2108         gst_caps_replace (&priv->sink_alloc, newcaps);
2109         GST_OBJECT_UNLOCK (pad);
2110       } else {
2111         GST_DEBUG_OBJECT (trans, "peer did not accept new caps");
2112         /* peer does not accept the caps, disable proxy_alloc, free the
2113          * buffer we received and create a buffer of the requested format
2114          * by the default handler. */
2115         GST_DEBUG_OBJECT (trans, "disabling proxy");
2116         priv->proxy_alloc = FALSE;
2117         gst_buffer_unref (*buf);
2118         *buf = NULL;
2119       }
2120     } else {
2121       GST_DEBUG_OBJECT (trans, "received required caps from peer");
2122     }
2123   } else if (suggest) {
2124     /* there was a custom suggestion, create a buffer of this format and return
2125      * it. Note that this format  */
2126     *buf = gst_buffer_new_and_alloc (size_suggest);
2127     GST_DEBUG_OBJECT (trans,
2128         "doing suggestion of size %u, caps %p %" GST_PTR_FORMAT, size_suggest,
2129         sink_suggest, sink_suggest);
2130     GST_BUFFER_CAPS (*buf) = sink_suggest;
2131     sink_suggest = NULL;
2132   } else {
2133     /* fallback buffer allocation by gst_pad_alloc_buffer() with the
2134      * caps and size provided by the caller */
2135   }
2137   if (sink_suggest)
2138     gst_caps_unref (sink_suggest);
2140   if (res == GST_FLOW_OK && alloced) {
2141     /* just alloc'ed a buffer, so we only want to do this again if we
2142      * received a buffer */
2143     GST_DEBUG_OBJECT (trans, "Cleaning force alloc");
2144     trans->priv->force_alloc = FALSE;
2145   }
2147   gst_object_unref (trans);
2148   return res;
2150   /* ERRORS */
2151 alloc_failed:
2152   {
2153     GST_DEBUG_OBJECT (trans, "pad alloc failed: %s", gst_flow_get_name (res));
2154     if (sink_suggest)
2155       gst_caps_unref (sink_suggest);
2156     gst_object_unref (trans);
2157     return res;
2158   }
2159 not_supported:
2160   {
2161     GST_DEBUG_OBJECT (trans, "pad alloc with unsupported caps");
2162     if (sink_suggest)
2163       gst_caps_unref (sink_suggest);
2164     gst_object_unref (trans);
2165     return GST_FLOW_NOT_NEGOTIATED;
2166   }
2169 static void
2170 gst_base_transform_send_delayed_events (GstBaseTransform * trans)
2172   GList *list, *tmp;
2174   GST_OBJECT_LOCK (trans);
2175   list = trans->priv->delayed_events;
2176   trans->priv->delayed_events = NULL;
2177   GST_OBJECT_UNLOCK (trans);
2178   if (!list)
2179     return;
2181   for (tmp = list; tmp; tmp = tmp->next) {
2182     GstEvent *ev = tmp->data;
2184     GST_DEBUG_OBJECT (trans->srcpad, "Sending delayed event %s",
2185         GST_EVENT_TYPE_NAME (ev));
2186     gst_pad_push_event (trans->srcpad, ev);
2187   }
2188   g_list_free (list);
2191 static gboolean
2192 gst_base_transform_sink_event (GstPad * pad, GstEvent * event)
2194   GstBaseTransform *trans;
2195   GstBaseTransformClass *bclass;
2196   gboolean ret = TRUE;
2197   gboolean forward = TRUE;
2199   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2200   if (G_UNLIKELY (trans == NULL)) {
2201     gst_event_unref (event);
2202     return FALSE;
2203   }
2204   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2206   if (bclass->event)
2207     forward = bclass->event (trans, event);
2209   /* FIXME, do this in the default event handler so the subclass can do
2210    * something different. */
2211   if (forward) {
2212     gboolean delay, caps_set = (GST_PAD_CAPS (trans->srcpad) != NULL);
2214     /* src caps may not yet be set, so we delay any serialized events
2215        that we receive before (in particular newsegment events), except
2216        EOS and flush stops, since those'll obsolete previous events */
2217     if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
2218       gst_base_transform_drop_delayed_events (trans);
2219       delay = FALSE;
2220     } else {
2221       delay = GST_EVENT_IS_SERIALIZED (event) && !caps_set
2222           && GST_EVENT_TYPE (event) != GST_EVENT_EOS;
2223     }
2225     if (delay) {
2226       GST_OBJECT_LOCK (trans);
2227       trans->priv->delayed_events =
2228           g_list_append (trans->priv->delayed_events, event);
2229       GST_OBJECT_UNLOCK (trans);
2230     } else {
2231       if (caps_set && GST_EVENT_IS_SERIALIZED (event))
2232         gst_base_transform_send_delayed_events (trans);
2233       ret = gst_pad_push_event (trans->srcpad, event);
2234     }
2235   } else
2236     gst_event_unref (event);
2238   gst_object_unref (trans);
2240   return ret;
2243 static gboolean
2244 gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
2246   switch (GST_EVENT_TYPE (event)) {
2247     case GST_EVENT_FLUSH_START:
2248       break;
2249     case GST_EVENT_FLUSH_STOP:
2250       GST_OBJECT_LOCK (trans);
2251       /* reset QoS parameters */
2252       trans->priv->proportion = 1.0;
2253       trans->priv->earliest_time = -1;
2254       trans->priv->discont = FALSE;
2255       trans->priv->processed = 0;
2256       trans->priv->dropped = 0;
2257       GST_OBJECT_UNLOCK (trans);
2258       /* we need new segment info after the flush. */
2259       trans->have_newsegment = FALSE;
2260       gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2261       trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2262       break;
2263     case GST_EVENT_EOS:
2264       break;
2265     case GST_EVENT_TAG:
2266       break;
2267     case GST_EVENT_NEWSEGMENT:
2268     {
2269       GstFormat format;
2270       gdouble rate, arate;
2271       gint64 start, stop, time;
2272       gboolean update;
2274       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
2275           &start, &stop, &time);
2277       trans->have_newsegment = TRUE;
2279       gst_segment_set_newsegment_full (&trans->segment, update, rate, arate,
2280           format, start, stop, time);
2282       if (format == GST_FORMAT_TIME) {
2283         GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
2284             " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
2285             ", accum %" GST_TIME_FORMAT,
2286             GST_TIME_ARGS (trans->segment.start),
2287             GST_TIME_ARGS (trans->segment.stop),
2288             GST_TIME_ARGS (trans->segment.time),
2289             GST_TIME_ARGS (trans->segment.accum));
2290       } else {
2291         GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
2292             " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
2293             ", accum %" G_GINT64_FORMAT,
2294             trans->segment.start, trans->segment.stop,
2295             trans->segment.time, trans->segment.accum);
2296       }
2297       break;
2298     }
2299     default:
2300       break;
2301   }
2303   return TRUE;
2306 static gboolean
2307 gst_base_transform_src_event (GstPad * pad, GstEvent * event)
2309   GstBaseTransform *trans;
2310   GstBaseTransformClass *bclass;
2311   gboolean ret = TRUE;
2313   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2314   if (G_UNLIKELY (trans == NULL)) {
2315     gst_event_unref (event);
2316     return FALSE;
2317   }
2319   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2321   if (bclass->src_event)
2322     ret = bclass->src_event (trans, event);
2323   else
2324     gst_event_unref (event);
2326   gst_object_unref (trans);
2328   return ret;
2331 static gboolean
2332 gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event)
2334   gboolean ret;
2336   GST_DEBUG_OBJECT (trans, "handling event %p %" GST_PTR_FORMAT, event, event);
2338   switch (GST_EVENT_TYPE (event)) {
2339     case GST_EVENT_SEEK:
2340       break;
2341     case GST_EVENT_NAVIGATION:
2342       break;
2343     case GST_EVENT_QOS:
2344     {
2345       gdouble proportion;
2346       GstClockTimeDiff diff;
2347       GstClockTime timestamp;
2349       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
2350       gst_base_transform_update_qos (trans, proportion, diff, timestamp);
2351       break;
2352     }
2353     default:
2354       break;
2355   }
2357   ret = gst_pad_push_event (trans->sinkpad, event);
2359   return ret;
2362 /* perform a transform on @inbuf and put the result in @outbuf.
2363  *
2364  * This function is common to the push and pull-based operations.
2365  *
2366  * This function takes ownership of @inbuf */
2367 static GstFlowReturn
2368 gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
2369     GstBuffer ** outbuf)
2371   GstBaseTransformClass *bclass;
2372   GstFlowReturn ret = GST_FLOW_OK;
2373   gboolean want_in_place, reconfigure;
2374   GstClockTime running_time;
2375   GstClockTime timestamp;
2376   GstCaps *incaps;
2378   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2380   if (G_LIKELY ((incaps = GST_BUFFER_CAPS (inbuf)))) {
2381     GST_OBJECT_LOCK (trans);
2382     reconfigure = trans->priv->reconfigure;
2383     trans->priv->reconfigure = FALSE;
2384     GST_OBJECT_UNLOCK (trans);
2386     if (G_UNLIKELY (reconfigure)) {
2387       GST_DEBUG_OBJECT (trans, "we had a pending reconfigure");
2388       /* if we need to reconfigure we pretend a buffer with new caps arrived. This
2389        * will reconfigure the transform with the new output format. We can only
2390        * do this if the buffer actually has caps. */
2391       if (!gst_base_transform_setcaps (trans->sinkpad, incaps))
2392         goto not_negotiated;
2393     }
2394   }
2396   if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
2397     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset %"
2398         G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
2399         GST_BUFFER_OFFSET (inbuf));
2400   else
2401     GST_DEBUG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
2402         inbuf, GST_BUFFER_SIZE (inbuf));
2404   /* Don't allow buffer handling before negotiation, except in passthrough mode
2405    * or if the class doesn't implement a set_caps function (in which case it doesn't
2406    * care about caps)
2407    */
2408   if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
2409     goto not_negotiated;
2411   /* Set discont flag so we can mark the outgoing buffer */
2412   if (GST_BUFFER_IS_DISCONT (inbuf)) {
2413     GST_DEBUG_OBJECT (trans, "got DISCONT buffer %p", inbuf);
2414     trans->priv->discont = TRUE;
2415   }
2417   /* can only do QoS if the segment is in TIME */
2418   if (trans->segment.format != GST_FORMAT_TIME)
2419     goto no_qos;
2421   /* QOS is done on the running time of the buffer, get it now */
2422   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
2423   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
2424       timestamp);
2426   if (running_time != -1) {
2427     gboolean need_skip;
2428     GstClockTime earliest_time;
2429     gdouble proportion;
2431     /* lock for getting the QoS parameters that are set (in a different thread)
2432      * with the QOS events */
2433     GST_OBJECT_LOCK (trans);
2434     earliest_time = trans->priv->earliest_time;
2435     proportion = trans->priv->proportion;
2436     /* check for QoS, don't perform conversion for buffers
2437      * that are known to be late. */
2438     need_skip = trans->priv->qos_enabled &&
2439         earliest_time != -1 && running_time <= earliest_time;
2440     GST_OBJECT_UNLOCK (trans);
2442     if (need_skip) {
2443       GstMessage *qos_msg;
2444       GstClockTime duration;
2445       guint64 stream_time;
2446       gint64 jitter;
2448       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
2449           GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
2450           GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time));
2452       trans->priv->dropped++;
2454       duration = GST_BUFFER_DURATION (inbuf);
2455       stream_time =
2456           gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
2457           timestamp);
2458       jitter = GST_CLOCK_DIFF (running_time, earliest_time);
2460       qos_msg =
2461           gst_message_new_qos (GST_OBJECT_CAST (trans), FALSE, running_time,
2462           stream_time, timestamp, duration);
2463       gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000);
2464       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS,
2465           trans->priv->processed, trans->priv->dropped);
2466       gst_element_post_message (GST_ELEMENT_CAST (trans), qos_msg);
2468       /* mark discont for next buffer */
2469       trans->priv->discont = TRUE;
2470       goto skip;
2471     }
2472   }
2474 no_qos:
2476   /* first try to allocate an output buffer based on the currently negotiated
2477    * format. While we call pad-alloc we could renegotiate the srcpad format or
2478    * have a new suggestion for upstream buffer-alloc.
2479    * In any case, outbuf will contain a buffer suitable for doing the configured
2480    * transform after this function. */
2481   ret = gst_base_transform_prepare_output_buffer (trans, inbuf, outbuf);
2482   if (G_UNLIKELY (ret != GST_FLOW_OK))
2483     goto no_buffer;
2485   /* now perform the needed transform */
2486   if (trans->passthrough) {
2487     /* In passthrough mode, give transform_ip a look at the
2488      * buffer, without making it writable, or just push the
2489      * data through */
2490     if (bclass->transform_ip) {
2491       GST_DEBUG_OBJECT (trans, "doing passthrough transform");
2492       ret = bclass->transform_ip (trans, *outbuf);
2493     } else {
2494       GST_DEBUG_OBJECT (trans, "element is in passthrough");
2495     }
2496   } else {
2497     want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
2499     if (want_in_place) {
2500       GST_DEBUG_OBJECT (trans, "doing inplace transform");
2502       if (inbuf != *outbuf) {
2503         guint8 *indata, *outdata;
2505         /* Different buffer. The data can still be the same when we are dealing
2506          * with subbuffers of the same buffer. Note that because of the FIXME in
2507          * prepare_output_buffer() we have decreased the refcounts of inbuf and
2508          * outbuf to keep them writable */
2509         indata = GST_BUFFER_DATA (inbuf);
2510         outdata = GST_BUFFER_DATA (*outbuf);
2512         if (indata != outdata)
2513           memcpy (outdata, indata, GST_BUFFER_SIZE (inbuf));
2514       }
2515       ret = bclass->transform_ip (trans, *outbuf);
2516     } else {
2517       GST_DEBUG_OBJECT (trans, "doing non-inplace transform");
2519       if (bclass->transform)
2520         ret = bclass->transform (trans, inbuf, *outbuf);
2521       else
2522         ret = GST_FLOW_NOT_SUPPORTED;
2523     }
2524   }
2526 skip:
2527   /* only unref input buffer if we allocated a new outbuf buffer */
2528   if (*outbuf != inbuf)
2529     gst_buffer_unref (inbuf);
2531   /* pushed a buffer, we can now try an alloc */
2532   GST_DEBUG_OBJECT (trans, "Pushed a buffer, setting force alloc to true");
2533   trans->priv->force_alloc = TRUE;
2534   return ret;
2536   /* ERRORS */
2537 not_negotiated:
2538   {
2539     gst_buffer_unref (inbuf);
2540     GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
2541         ("not negotiated"), ("not negotiated"));
2542     return GST_FLOW_NOT_NEGOTIATED;
2543   }
2544 no_buffer:
2545   {
2546     gst_buffer_unref (inbuf);
2547     GST_WARNING_OBJECT (trans, "could not get buffer from pool: %s",
2548         gst_flow_get_name (ret));
2549     return ret;
2550   }
2553 static gboolean
2554 gst_base_transform_check_get_range (GstPad * pad)
2556   GstBaseTransform *trans;
2557   gboolean ret;
2559   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2561   ret = gst_pad_check_pull_range (trans->sinkpad);
2563   gst_object_unref (trans);
2565   return ret;
2568 /* FIXME, getrange is broken, need to pull range from the other
2569  * end based on the transform_size result.
2570  */
2571 static GstFlowReturn
2572 gst_base_transform_getrange (GstPad * pad, guint64 offset,
2573     guint length, GstBuffer ** buffer)
2575   GstBaseTransform *trans;
2576   GstBaseTransformClass *klass;
2577   GstFlowReturn ret;
2578   GstBuffer *inbuf;
2580   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2582   ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
2583   if (G_UNLIKELY (ret != GST_FLOW_OK))
2584     goto pull_error;
2586   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2587   if (klass->before_transform)
2588     klass->before_transform (trans, inbuf);
2590   GST_BASE_TRANSFORM_LOCK (trans);
2591   ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
2592   GST_BASE_TRANSFORM_UNLOCK (trans);
2594 done:
2595   gst_object_unref (trans);
2597   return ret;
2599   /* ERRORS */
2600 pull_error:
2601   {
2602     GST_DEBUG_OBJECT (trans, "failed to pull a buffer: %s",
2603         gst_flow_get_name (ret));
2604     goto done;
2605   }
2608 static GstFlowReturn
2609 gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
2611   GstBaseTransform *trans;
2612   GstBaseTransformClass *klass;
2613   GstFlowReturn ret;
2614   GstClockTime last_stop = GST_CLOCK_TIME_NONE;
2615   GstClockTime timestamp, duration;
2616   GstBuffer *outbuf = NULL;
2618   trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
2620   timestamp = GST_BUFFER_TIMESTAMP (buffer);
2621   duration = GST_BUFFER_DURATION (buffer);
2623   /* calculate end position of the incoming buffer */
2624   if (timestamp != GST_CLOCK_TIME_NONE) {
2625     if (duration != GST_CLOCK_TIME_NONE)
2626       last_stop = timestamp + duration;
2627     else
2628       last_stop = timestamp;
2629   }
2631   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2632   if (klass->before_transform)
2633     klass->before_transform (trans, buffer);
2635   gst_base_transform_send_delayed_events (trans);
2637   /* protect transform method and concurrent buffer alloc */
2638   GST_BASE_TRANSFORM_LOCK (trans);
2639   ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
2640   GST_BASE_TRANSFORM_UNLOCK (trans);
2642   /* outbuf can be NULL, this means a dropped buffer, if we have a buffer but
2643    * GST_BASE_TRANSFORM_FLOW_DROPPED we will not push either. */
2644   if (outbuf != NULL) {
2645     if ((ret == GST_FLOW_OK)) {
2646       GstClockTime last_stop_out = GST_CLOCK_TIME_NONE;
2648       /* Remember last stop position */
2649       if (last_stop != GST_CLOCK_TIME_NONE &&
2650           trans->segment.format == GST_FORMAT_TIME)
2651         gst_segment_set_last_stop (&trans->segment, GST_FORMAT_TIME, last_stop);
2653       if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) {
2654         last_stop_out = GST_BUFFER_TIMESTAMP (outbuf);
2655         if (GST_BUFFER_DURATION_IS_VALID (outbuf))
2656           last_stop_out += GST_BUFFER_DURATION (outbuf);
2657       } else if (last_stop != GST_CLOCK_TIME_NONE) {
2658         last_stop_out = last_stop;
2659       }
2660       if (last_stop_out != GST_CLOCK_TIME_NONE
2661           && trans->segment.format == GST_FORMAT_TIME)
2662         trans->priv->last_stop_out = last_stop_out;
2664       /* apply DISCONT flag if the buffer is not yet marked as such */
2665       if (trans->priv->discont) {
2666         if (!GST_BUFFER_IS_DISCONT (outbuf)) {
2667           outbuf = gst_buffer_make_metadata_writable (outbuf);
2668           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
2669         }
2670         trans->priv->discont = FALSE;
2671       }
2672       trans->priv->processed++;
2674       ret = gst_pad_push (trans->srcpad, outbuf);
2675     } else {
2676       gst_buffer_unref (outbuf);
2677     }
2678   }
2680   /* convert internal flow to OK and mark discont for the next buffer. */
2681   if (ret == GST_BASE_TRANSFORM_FLOW_DROPPED) {
2682     trans->priv->discont = TRUE;
2683     ret = GST_FLOW_OK;
2684   }
2686   return ret;
2689 static void
2690 gst_base_transform_set_property (GObject * object, guint prop_id,
2691     const GValue * value, GParamSpec * pspec)
2693   GstBaseTransform *trans;
2695   trans = GST_BASE_TRANSFORM (object);
2697   switch (prop_id) {
2698     case PROP_QOS:
2699       gst_base_transform_set_qos_enabled (trans, g_value_get_boolean (value));
2700       break;
2701     default:
2702       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2703       break;
2704   }
2707 static void
2708 gst_base_transform_get_property (GObject * object, guint prop_id,
2709     GValue * value, GParamSpec * pspec)
2711   GstBaseTransform *trans;
2713   trans = GST_BASE_TRANSFORM (object);
2715   switch (prop_id) {
2716     case PROP_QOS:
2717       g_value_set_boolean (value, gst_base_transform_is_qos_enabled (trans));
2718       break;
2719     default:
2720       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2721       break;
2722   }
2725 /* not a vmethod of anything, just an internal method */
2726 static gboolean
2727 gst_base_transform_activate (GstBaseTransform * trans, gboolean active)
2729   GstBaseTransformClass *bclass;
2730   gboolean result = TRUE;
2732   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2734   GST_OBJECT_LOCK (trans);
2735   gst_base_transform_clear_transformed_caps_cache (trans);
2736   GST_OBJECT_UNLOCK (trans);
2738   if (active) {
2739     if (trans->priv->pad_mode == GST_ACTIVATE_NONE && bclass->start)
2740       result &= bclass->start (trans);
2742     GST_OBJECT_LOCK (trans);
2744     if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
2745       trans->have_same_caps =
2746           gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
2747           GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
2748     else
2749       trans->have_same_caps = trans->passthrough;
2750     GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
2751     trans->negotiated = FALSE;
2752     trans->have_newsegment = FALSE;
2753     gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
2754     trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
2755     trans->priv->proportion = 1.0;
2756     trans->priv->earliest_time = -1;
2757     trans->priv->discont = FALSE;
2758     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2759     trans->priv->processed = 0;
2760     trans->priv->dropped = 0;
2761     trans->priv->force_alloc = TRUE;
2763     GST_OBJECT_UNLOCK (trans);
2764   } else {
2765     /* We must make sure streaming has finished before resetting things
2766      * and calling the ::stop vfunc */
2767     GST_PAD_STREAM_LOCK (trans->sinkpad);
2768     GST_PAD_STREAM_UNLOCK (trans->sinkpad);
2770     gst_base_transform_drop_delayed_events (trans);
2772     trans->have_same_caps = FALSE;
2773     /* We can only reset the passthrough mode if the instance told us to
2774        handle it in configure_caps */
2775     if (bclass->passthrough_on_same_caps) {
2776       gst_base_transform_set_passthrough (trans, FALSE);
2777     }
2778     gst_caps_replace (&trans->cache_caps1, NULL);
2779     gst_caps_replace (&trans->cache_caps2, NULL);
2780     gst_caps_replace (&trans->priv->sink_alloc, NULL);
2781     gst_caps_replace (&trans->priv->sink_suggest, NULL);
2783     if (trans->priv->pad_mode != GST_ACTIVATE_NONE && bclass->stop)
2784       result &= bclass->stop (trans);
2785   }
2787   return result;
2790 static gboolean
2791 gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
2793   gboolean result = TRUE;
2794   GstBaseTransform *trans;
2796   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2798   result = gst_base_transform_activate (trans, active);
2800   if (result)
2801     trans->priv->pad_mode = active ? GST_ACTIVATE_PUSH : GST_ACTIVATE_NONE;
2803   gst_object_unref (trans);
2805   return result;
2808 static gboolean
2809 gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
2811   gboolean result = FALSE;
2812   GstBaseTransform *trans;
2814   trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
2816   result = gst_pad_activate_pull (trans->sinkpad, active);
2818   if (result)
2819     result &= gst_base_transform_activate (trans, active);
2821   if (result)
2822     trans->priv->pad_mode = active ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
2824   gst_object_unref (trans);
2826   return result;
2829 /**
2830  * gst_base_transform_set_passthrough:
2831  * @trans: the #GstBaseTransform to set
2832  * @passthrough: boolean indicating passthrough mode.
2833  *
2834  * Set passthrough mode for this filter by default. This is mostly
2835  * useful for filters that do not care about negotiation.
2836  *
2837  * Always TRUE for filters which don't implement either a transform
2838  * or transform_ip method.
2839  *
2840  * MT safe.
2841  */
2842 void
2843 gst_base_transform_set_passthrough (GstBaseTransform * trans,
2844     gboolean passthrough)
2846   GstBaseTransformClass *bclass;
2848   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2850   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2852   GST_OBJECT_LOCK (trans);
2853   if (passthrough == FALSE) {
2854     if (bclass->transform_ip || bclass->transform)
2855       trans->passthrough = FALSE;
2856   } else {
2857     trans->passthrough = TRUE;
2858   }
2860   GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
2861   GST_OBJECT_UNLOCK (trans);
2864 /**
2865  * gst_base_transform_is_passthrough:
2866  * @trans: the #GstBaseTransform to query
2867  *
2868  * See if @trans is configured as a passthrough transform.
2869  *
2870  * Returns: TRUE is the transform is configured in passthrough mode.
2871  *
2872  * MT safe.
2873  */
2874 gboolean
2875 gst_base_transform_is_passthrough (GstBaseTransform * trans)
2877   gboolean result;
2879   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2881   GST_OBJECT_LOCK (trans);
2882   result = trans->passthrough;
2883   GST_OBJECT_UNLOCK (trans);
2885   return result;
2888 /**
2889  * gst_base_transform_set_in_place:
2890  * @trans: the #GstBaseTransform to modify
2891  * @in_place: Boolean value indicating that we would like to operate
2892  * on in_place buffers.
2893  *
2894  * Determines whether a non-writable buffer will be copied before passing
2895  * to the transform_ip function.
2896  * <itemizedlist>
2897  *   <listitem>Always TRUE if no transform function is implemented.</listitem>
2898  *   <listitem>Always FALSE if ONLY transform function is implemented.</listitem>
2899  * </itemizedlist>
2900  *
2901  * MT safe.
2902  */
2903 void
2904 gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
2906   GstBaseTransformClass *bclass;
2908   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2910   bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
2912   GST_OBJECT_LOCK (trans);
2914   if (in_place) {
2915     if (bclass->transform_ip) {
2916       GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
2917       trans->always_in_place = TRUE;
2918     }
2919   } else {
2920     if (bclass->transform) {
2921       GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
2922       trans->always_in_place = FALSE;
2923     }
2924   }
2926   GST_OBJECT_UNLOCK (trans);
2929 /**
2930  * gst_base_transform_is_in_place:
2931  * @trans: the #GstBaseTransform to query
2932  *
2933  * See if @trans is configured as a in_place transform.
2934  *
2935  * Returns: TRUE is the transform is configured in in_place mode.
2936  *
2937  * MT safe.
2938  */
2939 gboolean
2940 gst_base_transform_is_in_place (GstBaseTransform * trans)
2942   gboolean result;
2944   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
2946   GST_OBJECT_LOCK (trans);
2947   result = trans->always_in_place;
2948   GST_OBJECT_UNLOCK (trans);
2950   return result;
2953 /**
2954  * gst_base_transform_update_qos:
2955  * @trans: a #GstBaseTransform
2956  * @proportion: the proportion
2957  * @diff: the diff against the clock
2958  * @timestamp: the timestamp of the buffer generating the QoS expressed in
2959  * running_time.
2960  *
2961  * Set the QoS parameters in the transform. This function is called internally
2962  * when a QOS event is received but subclasses can provide custom information
2963  * when needed.
2964  *
2965  * MT safe.
2966  *
2967  * Since: 0.10.5
2968  */
2969 void
2970 gst_base_transform_update_qos (GstBaseTransform * trans,
2971     gdouble proportion, GstClockTimeDiff diff, GstClockTime timestamp)
2974   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
2976   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans,
2977       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2978       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (timestamp));
2980   GST_OBJECT_LOCK (trans);
2981   trans->priv->proportion = proportion;
2982   trans->priv->earliest_time = timestamp + diff;
2983   GST_OBJECT_UNLOCK (trans);
2986 /**
2987  * gst_base_transform_set_qos_enabled:
2988  * @trans: a #GstBaseTransform
2989  * @enabled: new state
2990  *
2991  * Enable or disable QoS handling in the transform.
2992  *
2993  * MT safe.
2994  *
2995  * Since: 0.10.5
2996  */
2997 void
2998 gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled)
3000   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3002   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "enabled: %d", enabled);
3004   GST_OBJECT_LOCK (trans);
3005   trans->priv->qos_enabled = enabled;
3006   GST_OBJECT_UNLOCK (trans);
3009 /**
3010  * gst_base_transform_is_qos_enabled:
3011  * @trans: a #GstBaseTransform
3012  *
3013  * Queries if the transform will handle QoS.
3014  *
3015  * Returns: TRUE if QoS is enabled.
3016  *
3017  * MT safe.
3018  *
3019  * Since: 0.10.5
3020  */
3021 gboolean
3022 gst_base_transform_is_qos_enabled (GstBaseTransform * trans)
3024   gboolean result;
3026   g_return_val_if_fail (GST_IS_BASE_TRANSFORM (trans), FALSE);
3028   GST_OBJECT_LOCK (trans);
3029   result = trans->priv->qos_enabled;
3030   GST_OBJECT_UNLOCK (trans);
3032   return result;
3035 /**
3036  * gst_base_transform_set_gap_aware:
3037  * @trans: a #GstBaseTransform
3038  * @gap_aware: New state
3039  *
3040  * If @gap_aware is %FALSE (the default), output buffers will have the
3041  * %GST_BUFFER_FLAG_GAP flag unset.
3042  *
3043  * If set to %TRUE, the element must handle output buffers with this flag set
3044  * correctly, i.e. it can assume that the buffer contains neutral data but must
3045  * unset the flag if the output is no neutral data.
3046  *
3047  * MT safe.
3048  *
3049  * Since: 0.10.16
3050  */
3051 void
3052 gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware)
3054   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3056   GST_OBJECT_LOCK (trans);
3057   trans->priv->gap_aware = gap_aware;
3058   GST_DEBUG_OBJECT (trans, "set gap aware %d", trans->priv->gap_aware);
3059   GST_OBJECT_UNLOCK (trans);
3062 /**
3063  * gst_base_transform_suggest:
3064  * @trans: a #GstBaseTransform
3065  * @caps: (transfer none): caps to suggest
3066  * @size: buffer size to suggest
3067  *
3068  * Instructs @trans to suggest new @caps upstream. A copy of @caps will be
3069  * taken.
3070  *
3071  * Since: 0.10.21
3072  */
3073 void
3074 gst_base_transform_suggest (GstBaseTransform * trans, GstCaps * caps,
3075     guint size)
3077   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3079   GST_OBJECT_LOCK (trans->sinkpad);
3080   if (trans->priv->sink_suggest)
3081     gst_caps_unref (trans->priv->sink_suggest);
3082   if (caps)
3083     caps = gst_caps_copy (caps);
3084   trans->priv->sink_suggest = caps;
3085   trans->priv->size_suggest = size;
3086   trans->priv->suggest_pending = TRUE;
3087   gst_base_transform_clear_transformed_caps_cache (trans);
3088   GST_DEBUG_OBJECT (trans, "new suggest %" GST_PTR_FORMAT, caps);
3089   GST_OBJECT_UNLOCK (trans->sinkpad);
3092 /**
3093  * gst_base_transform_reconfigure:
3094  * @trans: a #GstBaseTransform
3095  *
3096  * Instructs @trans to renegotiate a new downstream transform on the next
3097  * buffer. This function is typically called after properties on the transform
3098  * were set that influence the output format.
3099  *
3100  * Since: 0.10.21
3101  */
3102 void
3103 gst_base_transform_reconfigure (GstBaseTransform * trans)
3105   g_return_if_fail (GST_IS_BASE_TRANSFORM (trans));
3107   GST_OBJECT_LOCK (trans);
3108   GST_DEBUG_OBJECT (trans, "marking reconfigure");
3109   trans->priv->reconfigure = TRUE;
3110   gst_base_transform_clear_transformed_caps_cache (trans);
3111   gst_caps_replace (&trans->priv->sink_alloc, NULL);
3112   GST_OBJECT_UNLOCK (trans);