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