gst_plugins_base/gst/audioresample/gstaudioresample.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
     1 /* GStreamer
     1 /* GStreamer
     2  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
     2  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
     3  * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
     3  * Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
     4  * Copyright (C) 2007-2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
       
     5  *
     4  *
     6  * This library is free software; you can redistribute it and/or
     5  * This library is free software; you can redistribute it and/or
     7  * modify it under the terms of the GNU Library General Public
     6  * modify it under the terms of the GNU Library General Public
     8  * License as published by the Free Software Foundation; either
     7  * License as published by the Free Software Foundation; either
     9  * version 2 of the License, or (at your option) any later version.
     8  * version 2 of the License, or (at your option) any later version.
    16  * You should have received a copy of the GNU Library General Public
    15  * You should have received a copy of the GNU Library General Public
    17  * License along with this library; if not, write to the
    16  * License along with this library; if not, write to the
    18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    19  * Boston, MA 02111-1307, USA.
    18  * Boston, MA 02111-1307, USA.
    20  */
    19  */
       
    20 /* Element-Checklist-Version: 5 */
    21 
    21 
    22 /**
    22 /**
    23  * SECTION:element-audioresample
    23  * SECTION:element-audioresample
    24  *
    24  *
    25  * audioresample resamples raw audio buffers to different sample rates using
    25  * <refsect2>
       
    26  * Audioresample resamples raw audio buffers to different sample rates using
    26  * a configurable windowing function to enhance quality.
    27  * a configurable windowing function to enhance quality.
       
    28  * <title>Example launch line</title>
       
    29  * <para>
       
    30  * <programlisting>
       
    31  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
       
    32  * </programlisting>
       
    33  * Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa. 
       
    34  * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
       
    35  * </para>
       
    36  * </refsect2>
    27  *
    37  *
    28  * <refsect2>
    38  * Last reviewed on 2006-03-02 (0.10.4)
    29  * <title>Example launch line</title>
       
    30  * |[
       
    31  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! audio/x-raw-int, rate=8000 ! alsasink
       
    32  * ]| Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
       
    33  * To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
       
    34  * </refsect2>
       
    35  */
       
    36 
       
    37 /* TODO:
       
    38  *  - Enable SSE/ARM optimizations and select at runtime
       
    39  */
    39  */
    40 
    40 
    41 #ifdef HAVE_CONFIG_H
    41 #ifdef HAVE_CONFIG_H
    42 #include "config.h"
    42 #include "config.h"
    43 #endif
    43 #endif
    44 
    44 
    45 #include <string.h>
    45 #include <string.h>
    46 #include <math.h>
    46 #include <math.h>
    47 
    47 
       
    48 /*#define DEBUG_ENABLED */
    48 #include "gstaudioresample.h"
    49 #include "gstaudioresample.h"
    49 #include <gst/audio/audio.h>
    50 #include <gst/audio/audio.h>
    50 #include <gst/base/gstbasetransform.h>
    51 #include <gst/base/gstbasetransform.h>
    51 
    52 
    52 #if defined AUDIORESAMPLE_FORMAT_AUTO
    53 GST_DEBUG_CATEGORY_STATIC (audioresample_debug);
    53 #define OIL_ENABLE_UNSTABLE_API
    54 #define GST_CAT_DEFAULT audioresample_debug
    54 #include <liboil/liboilprofile.h>
    55 
    55 #include <liboil/liboil.h>
    56 /* elementfactory information */
    56 #endif
    57 static const GstElementDetails gst_audioresample_details =
    57 
    58 GST_ELEMENT_DETAILS ("Audio scaler",
    58 GST_DEBUG_CATEGORY (audio_resample_debug);
    59     "Filter/Converter/Audio",
    59 #define GST_CAT_DEFAULT audio_resample_debug
    60     "Resample audio",
       
    61     "David Schleef <ds@schleef.org>");
       
    62 
       
    63 #define DEFAULT_FILTERLEN       16
    60 
    64 
    61 enum
    65 enum
    62 {
    66 {
    63   PROP_0,
    67   PROP_0,
    64   PROP_QUALITY,
    68   PROP_FILTERLEN
    65   PROP_FILTER_LENGTH
       
    66 };
    69 };
    67 
    70 
    68 #define SUPPORTED_CAPS \
    71 #define SUPPORTED_CAPS \
    69 GST_STATIC_CAPS ( \
    72 GST_STATIC_CAPS ( \
    70     "audio/x-raw-float, " \
    73     "audio/x-raw-int, " \
    71       "rate = (int) [ 1, MAX ], "	\
    74       "rate = (int) [ 1, MAX ], " \
    72       "channels = (int) [ 1, MAX ], " \
    75       "channels = (int) [ 1, MAX ], " \
    73       "endianness = (int) BYTE_ORDER, " \
    76       "endianness = (int) BYTE_ORDER, " \
    74       "width = (int) { 32, 64 }; " \
    77       "width = (int) 16, " \
       
    78       "depth = (int) 16, " \
       
    79       "signed = (boolean) true;" \
    75     "audio/x-raw-int, " \
    80     "audio/x-raw-int, " \
    76       "rate = (int) [ 1, MAX ], " \
    81       "rate = (int) [ 1, MAX ], " \
    77       "channels = (int) [ 1, MAX ], " \
    82       "channels = (int) [ 1, MAX ], " \
    78       "endianness = (int) BYTE_ORDER, " \
    83       "endianness = (int) BYTE_ORDER, " \
    79       "width = (int) 32, " \
    84       "width = (int) 32, " \
    80       "depth = (int) 32, " \
    85       "depth = (int) 32, " \
    81       "signed = (boolean) true; " \
    86       "signed = (boolean) true;" \
    82     "audio/x-raw-int, " \
    87     "audio/x-raw-float, " \
    83       "rate = (int) [ 1, MAX ], " \
    88       "rate = (int) [ 1, MAX ], "	\
    84       "channels = (int) [ 1, MAX ], " \
    89       "channels = (int) [ 1, MAX ], " \
    85       "endianness = (int) BYTE_ORDER, " \
    90       "endianness = (int) BYTE_ORDER, " \
    86       "width = (int) 24, " \
    91       "width = (int) 32; " \
    87       "depth = (int) 24, " \
    92     "audio/x-raw-float, " \
    88       "signed = (boolean) true; " \
    93       "rate = (int) [ 1, MAX ], "	\
    89     "audio/x-raw-int, " \
       
    90       "rate = (int) [ 1, MAX ], " \
       
    91       "channels = (int) [ 1, MAX ], " \
    94       "channels = (int) [ 1, MAX ], " \
    92       "endianness = (int) BYTE_ORDER, " \
    95       "endianness = (int) BYTE_ORDER, " \
    93       "width = (int) 16, " \
    96       "width = (int) 64" \
    94       "depth = (int) 16, " \
       
    95       "signed = (boolean) true; " \
       
    96     "audio/x-raw-int, " \
       
    97       "rate = (int) [ 1, MAX ], " \
       
    98       "channels = (int) [ 1, MAX ], " \
       
    99       "endianness = (int) BYTE_ORDER, " \
       
   100       "width = (int) 8, " \
       
   101       "depth = (int) 8, " \
       
   102       "signed = (boolean) true" \
       
   103 )
    97 )
   104 
    98 
   105 /* If TRUE integer arithmetic resampling is faster and will be used if appropiate */
    99 static GstStaticPadTemplate gst_audioresample_sink_template =
   106 #if defined AUDIORESAMPLE_FORMAT_INT
       
   107 static gboolean gst_audio_resample_use_int = TRUE;
       
   108 #elif defined AUDIORESAMPLE_FORMAT_FLOAT
       
   109 static gboolean gst_audio_resample_use_int = FALSE;
       
   110 #else
       
   111 static gboolean gst_audio_resample_use_int = FALSE;
       
   112 #endif
       
   113 
       
   114 static GstStaticPadTemplate gst_audio_resample_sink_template =
       
   115 GST_STATIC_PAD_TEMPLATE ("sink",
   100 GST_STATIC_PAD_TEMPLATE ("sink",
   116     GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
   101     GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
   117 
   102 
   118 static GstStaticPadTemplate gst_audio_resample_src_template =
   103 static GstStaticPadTemplate gst_audioresample_src_template =
   119 GST_STATIC_PAD_TEMPLATE ("src",
   104 GST_STATIC_PAD_TEMPLATE ("src",
   120     GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
   105     GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
   121 
   106 
   122 static void gst_audio_resample_set_property (GObject * object,
   107 static void gst_audioresample_set_property (GObject * object,
   123     guint prop_id, const GValue * value, GParamSpec * pspec);
   108     guint prop_id, const GValue * value, GParamSpec * pspec);
   124 static void gst_audio_resample_get_property (GObject * object,
   109 static void gst_audioresample_get_property (GObject * object,
   125     guint prop_id, GValue * value, GParamSpec * pspec);
   110     guint prop_id, GValue * value, GParamSpec * pspec);
   126 
   111 
   127 /* vmethods */
   112 /* vmethods */
   128 static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
   113 static gboolean audioresample_get_unit_size (GstBaseTransform * base,
   129     GstCaps * caps, guint * size);
   114     GstCaps * caps, guint * size);
   130 static GstCaps *gst_audio_resample_transform_caps (GstBaseTransform * base,
   115 static GstCaps *audioresample_transform_caps (GstBaseTransform * base,
   131     GstPadDirection direction, GstCaps * caps);
   116     GstPadDirection direction, GstCaps * caps);
   132 static void gst_audio_resample_fixate_caps (GstBaseTransform * base,
   117 static gboolean audioresample_transform_size (GstBaseTransform * trans,
   133     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
       
   134 static gboolean gst_audio_resample_transform_size (GstBaseTransform * trans,
       
   135     GstPadDirection direction, GstCaps * incaps, guint insize,
   118     GstPadDirection direction, GstCaps * incaps, guint insize,
   136     GstCaps * outcaps, guint * outsize);
   119     GstCaps * outcaps, guint * outsize);
   137 static gboolean gst_audio_resample_set_caps (GstBaseTransform * base,
   120 static gboolean audioresample_set_caps (GstBaseTransform * base,
   138     GstCaps * incaps, GstCaps * outcaps);
   121     GstCaps * incaps, GstCaps * outcaps);
   139 static GstFlowReturn gst_audio_resample_transform (GstBaseTransform * base,
   122 static GstFlowReturn audioresample_pushthrough (GstAudioresample *
       
   123     audioresample);
       
   124 static GstFlowReturn audioresample_transform (GstBaseTransform * base,
   140     GstBuffer * inbuf, GstBuffer * outbuf);
   125     GstBuffer * inbuf, GstBuffer * outbuf);
   141 static gboolean gst_audio_resample_event (GstBaseTransform * base,
   126 static gboolean audioresample_event (GstBaseTransform * base, GstEvent * event);
   142     GstEvent * event);
   127 static gboolean audioresample_start (GstBaseTransform * base);
   143 static gboolean gst_audio_resample_start (GstBaseTransform * base);
   128 static gboolean audioresample_stop (GstBaseTransform * base);
   144 static gboolean gst_audio_resample_stop (GstBaseTransform * base);
   129 
   145 static gboolean gst_audio_resample_query (GstPad * pad, GstQuery * query);
   130 static gboolean audioresample_query (GstPad * pad, GstQuery * query);
   146 static const GstQueryType *gst_audio_resample_query_type (GstPad * pad);
   131 static const GstQueryType *audioresample_query_type (GstPad * pad);
   147 
   132 
   148 GST_BOILERPLATE (GstAudioResample, gst_audio_resample, GstBaseTransform,
   133 #define DEBUG_INIT(bla) \
   149     GST_TYPE_BASE_TRANSFORM);
   134   GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, "audio resampling element");
       
   135 
       
   136 GST_BOILERPLATE_FULL (GstAudioresample, gst_audioresample, GstBaseTransform,
       
   137     GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
   150 
   138 
   151 static void
   139 static void
   152 gst_audio_resample_base_init (gpointer g_class)
   140 gst_audioresample_base_init (gpointer g_class)
   153 {
   141 {
   154   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
   142   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
   155 
   143 
   156   gst_element_class_add_pad_template (gstelement_class,
   144   gst_element_class_add_pad_template (gstelement_class,
   157       gst_static_pad_template_get (&gst_audio_resample_src_template));
   145       gst_static_pad_template_get (&gst_audioresample_src_template));
   158   gst_element_class_add_pad_template (gstelement_class,
   146   gst_element_class_add_pad_template (gstelement_class,
   159       gst_static_pad_template_get (&gst_audio_resample_sink_template));
   147       gst_static_pad_template_get (&gst_audioresample_sink_template));
   160 
   148 
   161   gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
   149   gst_element_class_set_details (gstelement_class, &gst_audioresample_details);
   162       "Filter/Converter/Audio", "Resamples audio",
       
   163       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
       
   164 }
   150 }
   165 
   151 
   166 static void
   152 static void
   167 gst_audio_resample_class_init (GstAudioResampleClass * klass)
   153 gst_audioresample_class_init (GstAudioresampleClass * klass)
   168 {
   154 {
   169   GObjectClass *gobject_class = (GObjectClass *) klass;
   155   GObjectClass *gobject_class;
   170 
   156 
   171   gobject_class->set_property = gst_audio_resample_set_property;
   157   gobject_class = (GObjectClass *) klass;
   172   gobject_class->get_property = gst_audio_resample_get_property;
   158 
   173 
   159   gobject_class->set_property = gst_audioresample_set_property;
   174   g_object_class_install_property (gobject_class, PROP_QUALITY,
   160   gobject_class->get_property = gst_audioresample_get_property;
   175       g_param_spec_int ("quality", "Quality", "Resample quality with 0 being "
   161 
   176           "the lowest and 10 being the best",
   162   g_object_class_install_property (gobject_class, PROP_FILTERLEN,
   177           SPEEX_RESAMPLER_QUALITY_MIN, SPEEX_RESAMPLER_QUALITY_MAX,
   163       g_param_spec_int ("filter_length", "filter_length", "filter_length",
   178           SPEEX_RESAMPLER_QUALITY_DEFAULT,
   164           0, G_MAXINT, DEFAULT_FILTERLEN,
   179           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   165           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   180 
   166 
   181   /* FIXME 0.11: Remove this property, it's just for compatibility
       
   182    * with old audioresample
       
   183    */
       
   184   /**
       
   185    * GstAudioResample:filter-length:
       
   186    *
       
   187    * Length of the resample filter
       
   188    *
       
   189    * Deprectated: Use #GstAudioResample:quality property instead
       
   190    */
       
   191   g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH,
       
   192       g_param_spec_int ("filter-length", "Filter length",
       
   193           "Length of the resample filter", 0, G_MAXINT, 64, G_PARAM_READWRITE));
       
   194 
       
   195   GST_BASE_TRANSFORM_CLASS (klass)->start =
   167   GST_BASE_TRANSFORM_CLASS (klass)->start =
   196       GST_DEBUG_FUNCPTR (gst_audio_resample_start);
   168       GST_DEBUG_FUNCPTR (audioresample_start);
   197   GST_BASE_TRANSFORM_CLASS (klass)->stop =
   169   GST_BASE_TRANSFORM_CLASS (klass)->stop =
   198       GST_DEBUG_FUNCPTR (gst_audio_resample_stop);
   170       GST_DEBUG_FUNCPTR (audioresample_stop);
   199   GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
   171   GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
   200       GST_DEBUG_FUNCPTR (gst_audio_resample_transform_size);
   172       GST_DEBUG_FUNCPTR (audioresample_transform_size);
   201   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
   173   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
   202       GST_DEBUG_FUNCPTR (gst_audio_resample_get_unit_size);
   174       GST_DEBUG_FUNCPTR (audioresample_get_unit_size);
   203   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
   175   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
   204       GST_DEBUG_FUNCPTR (gst_audio_resample_transform_caps);
   176       GST_DEBUG_FUNCPTR (audioresample_transform_caps);
   205   GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
       
   206       GST_DEBUG_FUNCPTR (gst_audio_resample_fixate_caps);
       
   207   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
   177   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
   208       GST_DEBUG_FUNCPTR (gst_audio_resample_set_caps);
   178       GST_DEBUG_FUNCPTR (audioresample_set_caps);
   209   GST_BASE_TRANSFORM_CLASS (klass)->transform =
   179   GST_BASE_TRANSFORM_CLASS (klass)->transform =
   210       GST_DEBUG_FUNCPTR (gst_audio_resample_transform);
   180       GST_DEBUG_FUNCPTR (audioresample_transform);
   211   GST_BASE_TRANSFORM_CLASS (klass)->event =
   181   GST_BASE_TRANSFORM_CLASS (klass)->event =
   212       GST_DEBUG_FUNCPTR (gst_audio_resample_event);
   182       GST_DEBUG_FUNCPTR (audioresample_event);
   213 
   183 
   214   GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
   184   GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
   215 }
   185 }
   216 
   186 
       
   187 
   217 static void
   188 static void
   218 gst_audio_resample_init (GstAudioResample * resample,
   189 gst_audioresample_init (GstAudioresample * audioresample,
   219     GstAudioResampleClass * klass)
   190     GstAudioresampleClass * klass)
   220 {
   191 {
   221   GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
   192   GstBaseTransform *trans;
   222 
   193 
   223   resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
   194   trans = GST_BASE_TRANSFORM (audioresample);
   224 
   195 
   225   resample->need_discont = FALSE;
   196   /* buffer alloc passthrough is too impossible. FIXME, it
   226 
   197    * is trivial in the passthrough case. */
   227   gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
   198   gst_pad_set_bufferalloc_function (trans->sinkpad, NULL);
   228   gst_pad_set_query_type_function (trans->srcpad,
   199 
   229       gst_audio_resample_query_type);
   200   audioresample->filter_length = DEFAULT_FILTERLEN;
       
   201 
       
   202   audioresample->need_discont = FALSE;
       
   203 
       
   204   gst_pad_set_query_function (trans->srcpad, audioresample_query);
       
   205   gst_pad_set_query_type_function (trans->srcpad, audioresample_query_type);
   230 }
   206 }
   231 
   207 
   232 /* vmethods */
   208 /* vmethods */
   233 static gboolean
   209 static gboolean
   234 gst_audio_resample_start (GstBaseTransform * base)
   210 audioresample_start (GstBaseTransform * base)
   235 {
   211 {
   236   GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
   212   GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
   237 
   213 
   238   resample->next_offset = -1;
   214   audioresample->resample = resample_new ();
   239   resample->next_ts = -1;
   215   audioresample->ts_offset = -1;
   240   resample->next_upstream_ts = -1;
   216   audioresample->offset = -1;
       
   217   audioresample->next_ts = -1;
       
   218 
       
   219   resample_set_filter_length (audioresample->resample,
       
   220       audioresample->filter_length);
   241 
   221 
   242   return TRUE;
   222   return TRUE;
   243 }
   223 }
   244 
   224 
   245 static gboolean
   225 static gboolean
   246 gst_audio_resample_stop (GstBaseTransform * base)
   226 audioresample_stop (GstBaseTransform * base)
   247 {
   227 {
   248   GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
   228   GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
   249 
   229 
   250   if (resample->state) {
   230   if (audioresample->resample) {
   251     resample->funcs->destroy (resample->state);
   231     resample_free (audioresample->resample);
   252     resample->state = NULL;
   232     audioresample->resample = NULL;
   253   }
   233   }
   254 
   234 
   255   resample->funcs = NULL;
   235   gst_caps_replace (&audioresample->sinkcaps, NULL);
   256 
   236   gst_caps_replace (&audioresample->srccaps, NULL);
   257   g_free (resample->tmp_in);
       
   258   resample->tmp_in = NULL;
       
   259   resample->tmp_in_size = 0;
       
   260 
       
   261   g_free (resample->tmp_out);
       
   262   resample->tmp_out = NULL;
       
   263   resample->tmp_out_size = 0;
       
   264 
       
   265   gst_caps_replace (&resample->sinkcaps, NULL);
       
   266   gst_caps_replace (&resample->srccaps, NULL);
       
   267 
   237 
   268   return TRUE;
   238   return TRUE;
   269 }
   239 }
   270 
   240 
   271 static gboolean
   241 static gboolean
   272 gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
   242 audioresample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
   273     guint * size)
   243     guint * size)
   274 {
   244 {
   275   gint width, channels;
   245   gint width, channels;
   276   GstStructure *structure;
   246   GstStructure *structure;
   277   gboolean ret;
   247   gboolean ret;
   278 
   248 
   279   g_return_val_if_fail (size != NULL, FALSE);
   249   g_assert (size);
   280 
   250 
   281   /* this works for both float and int */
   251   /* this works for both float and int */
   282   structure = gst_caps_get_structure (caps, 0);
   252   structure = gst_caps_get_structure (caps, 0);
   283   ret = gst_structure_get_int (structure, "width", &width);
   253   ret = gst_structure_get_int (structure, "width", &width);
   284   ret &= gst_structure_get_int (structure, "channels", &channels);
   254   ret &= gst_structure_get_int (structure, "channels", &channels);
   285 
   255   g_return_val_if_fail (ret, FALSE);
   286   if (G_UNLIKELY (!ret))
   256 
   287     return FALSE;
   257   *size = width * channels / 8;
   288 
       
   289   *size = (width / 8) * channels;
       
   290 
   258 
   291   return TRUE;
   259   return TRUE;
   292 }
   260 }
   293 
   261 
   294 static GstCaps *
   262 static GstCaps *
   295 gst_audio_resample_transform_caps (GstBaseTransform * base,
   263 audioresample_transform_caps (GstBaseTransform * base,
   296     GstPadDirection direction, GstCaps * caps)
   264     GstPadDirection direction, GstCaps * caps)
   297 {
   265 {
   298   const GValue *val;
       
   299   GstStructure *s;
       
   300   GstCaps *res;
   266   GstCaps *res;
   301 
   267   GstStructure *structure;
   302   /* transform single caps into input_caps + input_caps with the rate
   268 
   303    * field set to our supported range. This ensures that upstream knows
   269   /* transform caps gives one single caps so we can just replace
   304    * about downstream's prefered rate(s) and can negotiate accordingly. */
   270    * the rate property with our range. */
   305   res = gst_caps_copy (caps);
   271   res = gst_caps_copy (caps);
   306 
   272   structure = gst_caps_get_structure (res, 0);
   307   /* first, however, check if the caps contain a range for the rate field, in
   273   gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
   308    * which case that side isn't going to care much about the exact sample rate
       
   309    * chosen and we should just assume things will get fixated to something sane
       
   310    * and we may just as well offer our full range instead of the range in the
       
   311    * caps. If the rate is not an int range value, it's likely to express a
       
   312    * real preference or limitation and we should maintain that structure as
       
   313    * preference by putting it first into the transformed caps, and only add
       
   314    * our full rate range as second option  */
       
   315   s = gst_caps_get_structure (res, 0);
       
   316   val = gst_structure_get_value (s, "rate");
       
   317   if (val == NULL || GST_VALUE_HOLDS_INT_RANGE (val)) {
       
   318     /* overwrite existing range, or add field if it doesn't exist yet */
       
   319     gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
       
   320   } else {
       
   321     /* append caps with full range to existing caps with non-range rate field */
       
   322     s = gst_structure_copy (s);
       
   323     gst_structure_set (s, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
       
   324     gst_caps_append_structure (res, s);
       
   325   }
       
   326 
   274 
   327   return res;
   275   return res;
   328 }
   276 }
   329 
   277 
   330 /* Fixate rate to the allowed rate that has the smallest difference */
   278 static gboolean
   331 static void
   279 resample_set_state_from_caps (ResampleState * state, GstCaps * incaps,
   332 gst_audio_resample_fixate_caps (GstBaseTransform * base,
   280     GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate)
   333     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
       
   334 {
       
   335   GstStructure *s;
       
   336   gint rate;
       
   337 
       
   338   s = gst_caps_get_structure (caps, 0);
       
   339   if (G_UNLIKELY (!gst_structure_get_int (s, "rate", &rate)))
       
   340     return;
       
   341 
       
   342   s = gst_caps_get_structure (othercaps, 0);
       
   343   gst_structure_fixate_field_nearest_int (s, "rate", rate);
       
   344 }
       
   345 
       
   346 static const SpeexResampleFuncs *
       
   347 gst_audio_resample_get_funcs (gint width, gboolean fp)
       
   348 {
       
   349   const SpeexResampleFuncs *funcs = NULL;
       
   350 
       
   351   if (gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
       
   352     funcs = &int_funcs;
       
   353   else if ((!gst_audio_resample_use_int && (width == 8 || width == 16) && !fp)
       
   354       || (width == 32 && fp))
       
   355     funcs = &float_funcs;
       
   356   else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp))
       
   357     funcs = &double_funcs;
       
   358   else
       
   359     g_assert_not_reached ();
       
   360 
       
   361   return funcs;
       
   362 }
       
   363 
       
   364 static SpeexResamplerState *
       
   365 gst_audio_resample_init_state (GstAudioResample * resample, gint width,
       
   366     gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
       
   367 {
       
   368   SpeexResamplerState *ret = NULL;
       
   369   gint err = RESAMPLER_ERR_SUCCESS;
       
   370   const SpeexResampleFuncs *funcs = gst_audio_resample_get_funcs (width, fp);
       
   371 
       
   372   ret = funcs->init (channels, inrate, outrate, quality, &err);
       
   373 
       
   374   if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
       
   375     GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s",
       
   376         funcs->strerror (err));
       
   377     return NULL;
       
   378   }
       
   379 
       
   380   funcs->skip_zeros (ret);
       
   381 
       
   382   return ret;
       
   383 }
       
   384 
       
   385 static gboolean
       
   386 gst_audio_resample_update_state (GstAudioResample * resample, gint width,
       
   387     gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
       
   388 {
       
   389   gboolean ret = TRUE;
       
   390   gboolean updated_latency = FALSE;
       
   391 
       
   392   updated_latency = (resample->inrate != inrate
       
   393       || quality != resample->quality) && resample->state != NULL;
       
   394 
       
   395   if (resample->state == NULL) {
       
   396     ret = TRUE;
       
   397   } else if (resample->channels != channels || fp != resample->fp
       
   398       || width != resample->width) {
       
   399     resample->funcs->destroy (resample->state);
       
   400     resample->state =
       
   401         gst_audio_resample_init_state (resample, width, channels, inrate,
       
   402         outrate, quality, fp);
       
   403 
       
   404     resample->funcs = gst_audio_resample_get_funcs (width, fp);
       
   405     ret = (resample->state != NULL);
       
   406   } else if (resample->inrate != inrate || resample->outrate != outrate) {
       
   407     gint err = RESAMPLER_ERR_SUCCESS;
       
   408 
       
   409     err = resample->funcs->set_rate (resample->state, inrate, outrate);
       
   410 
       
   411     if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
       
   412       GST_ERROR_OBJECT (resample, "Failed to update rate: %s",
       
   413           resample->funcs->strerror (err));
       
   414 
       
   415     ret = (err == RESAMPLER_ERR_SUCCESS);
       
   416   } else if (quality != resample->quality) {
       
   417     gint err = RESAMPLER_ERR_SUCCESS;
       
   418 
       
   419     err = resample->funcs->set_quality (resample->state, quality);
       
   420 
       
   421     if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS))
       
   422       GST_ERROR_OBJECT (resample, "Failed to update quality: %s",
       
   423           resample->funcs->strerror (err));
       
   424 
       
   425     ret = (err == RESAMPLER_ERR_SUCCESS);
       
   426   }
       
   427 
       
   428   resample->width = width;
       
   429   resample->channels = channels;
       
   430   resample->fp = fp;
       
   431   resample->quality = quality;
       
   432   resample->inrate = inrate;
       
   433   resample->outrate = outrate;
       
   434 
       
   435   if (updated_latency)
       
   436     gst_element_post_message (GST_ELEMENT (resample),
       
   437         gst_message_new_latency (GST_OBJECT (resample)));
       
   438 
       
   439   return ret;
       
   440 }
       
   441 
       
   442 static void
       
   443 gst_audio_resample_reset_state (GstAudioResample * resample)
       
   444 {
       
   445   if (resample->state)
       
   446     resample->funcs->reset_mem (resample->state);
       
   447 }
       
   448 
       
   449 static gboolean
       
   450 gst_audio_resample_parse_caps (GstCaps * incaps,
       
   451     GstCaps * outcaps, gint * width, gint * channels, gint * inrate,
       
   452     gint * outrate, gboolean * fp)
       
   453 {
   281 {
   454   GstStructure *structure;
   282   GstStructure *structure;
   455   gboolean ret;
   283   gboolean ret;
   456   gint mywidth, myinrate, myoutrate, mychannels;
   284   gint myinrate, myoutrate;
   457   gboolean myfp;
   285   int mychannels;
       
   286   gint width, depth;
       
   287   ResampleFormat format;
   458 
   288 
   459   GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
   289   GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
   460       GST_PTR_FORMAT, incaps, outcaps);
   290       GST_PTR_FORMAT, incaps, outcaps);
   461 
   291 
   462   structure = gst_caps_get_structure (incaps, 0);
   292   structure = gst_caps_get_structure (incaps, 0);
   463 
   293 
   464   if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float"))
   294   /* get width */
   465     myfp = TRUE;
   295   ret = gst_structure_get_int (structure, "width", &width);
   466   else
   296   if (!ret)
   467     myfp = FALSE;
   297     goto no_width;
   468 
   298 
       
   299   /* figure out the format */
       
   300   if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
       
   301     if (width == 32)
       
   302       format = RESAMPLE_FORMAT_F32;
       
   303     else if (width == 64)
       
   304       format = RESAMPLE_FORMAT_F64;
       
   305     else
       
   306       goto wrong_depth;
       
   307   } else {
       
   308     /* for int, depth and width must be the same */
       
   309     ret = gst_structure_get_int (structure, "depth", &depth);
       
   310     if (!ret || width != depth)
       
   311       goto not_equal;
       
   312 
       
   313     if (width == 16)
       
   314       format = RESAMPLE_FORMAT_S16;
       
   315     else if (width == 32)
       
   316       format = RESAMPLE_FORMAT_S32;
       
   317     else
       
   318       goto wrong_depth;
       
   319   }
   469   ret = gst_structure_get_int (structure, "rate", &myinrate);
   320   ret = gst_structure_get_int (structure, "rate", &myinrate);
   470   ret &= gst_structure_get_int (structure, "channels", &mychannels);
   321   ret &= gst_structure_get_int (structure, "channels", &mychannels);
   471   ret &= gst_structure_get_int (structure, "width", &mywidth);
   322   if (!ret)
   472   if (G_UNLIKELY (!ret))
       
   473     goto no_in_rate_channels;
   323     goto no_in_rate_channels;
   474 
   324 
   475   structure = gst_caps_get_structure (outcaps, 0);
   325   structure = gst_caps_get_structure (outcaps, 0);
   476   ret = gst_structure_get_int (structure, "rate", &myoutrate);
   326   ret = gst_structure_get_int (structure, "rate", &myoutrate);
   477   if (G_UNLIKELY (!ret))
   327   if (!ret)
   478     goto no_out_rate;
   328     goto no_out_rate;
   479 
   329 
   480   if (channels)
   330   if (channels)
   481     *channels = mychannels;
   331     *channels = mychannels;
   482   if (inrate)
   332   if (inrate)
   483     *inrate = myinrate;
   333     *inrate = myinrate;
   484   if (outrate)
   334   if (outrate)
   485     *outrate = myoutrate;
   335     *outrate = myoutrate;
   486   if (width)
   336 
   487     *width = mywidth;
   337   resample_set_format (state, format);
   488   if (fp)
   338   resample_set_n_channels (state, mychannels);
   489     *fp = myfp;
   339   resample_set_input_rate (state, myinrate);
       
   340   resample_set_output_rate (state, myoutrate);
   490 
   341 
   491   return TRUE;
   342   return TRUE;
   492 
   343 
   493   /* ERRORS */
   344   /* ERRORS */
       
   345 no_width:
       
   346   {
       
   347     GST_DEBUG ("failed to get width from caps");
       
   348     return FALSE;
       
   349   }
       
   350 not_equal:
       
   351   {
       
   352     GST_DEBUG ("width %d and depth %d must be the same", width, depth);
       
   353     return FALSE;
       
   354   }
       
   355 wrong_depth:
       
   356   {
       
   357     GST_DEBUG ("unknown depth %d found", depth);
       
   358     return FALSE;
       
   359   }
   494 no_in_rate_channels:
   360 no_in_rate_channels:
   495   {
   361   {
   496     GST_DEBUG ("could not get input rate and channels");
   362     GST_DEBUG ("could not get input rate and channels");
   497     return FALSE;
   363     return FALSE;
   498   }
   364   }
   501     GST_DEBUG ("could not get output rate");
   367     GST_DEBUG ("could not get output rate");
   502     return FALSE;
   368     return FALSE;
   503   }
   369   }
   504 }
   370 }
   505 
   371 
   506 static gint
   372 static gboolean
   507 _gcd (gint a, gint b)
   373 audioresample_transform_size (GstBaseTransform * base,
   508 {
       
   509   while (b != 0) {
       
   510     int temp = a;
       
   511 
       
   512     a = b;
       
   513     b = temp % b;
       
   514   }
       
   515 
       
   516   return ABS (a);
       
   517 }
       
   518 
       
   519 static gboolean
       
   520 gst_audio_resample_transform_size (GstBaseTransform * base,
       
   521     GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
   374     GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
   522     guint * othersize)
   375     guint * othersize)
   523 {
   376 {
       
   377   GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
       
   378   ResampleState *state;
   524   GstCaps *srccaps, *sinkcaps;
   379   GstCaps *srccaps, *sinkcaps;
       
   380   gboolean use_internal = FALSE;        /* whether we use the internal state */
   525   gboolean ret = TRUE;
   381   gboolean ret = TRUE;
   526   guint32 ratio_den, ratio_num;
       
   527   gint inrate, outrate, gcd;
       
   528   gint bytes_per_samp, channels;
       
   529 
   382 
   530   GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
   383   GST_LOG_OBJECT (base, "asked to transform size %d in direction %s",
   531       size, direction == GST_PAD_SINK ? "SINK" : "SRC");
   384       size, direction == GST_PAD_SINK ? "SINK" : "SRC");
   532   if (direction == GST_PAD_SINK) {
   385   if (direction == GST_PAD_SINK) {
   533     sinkcaps = caps;
   386     sinkcaps = caps;
   535   } else {
   388   } else {
   536     sinkcaps = othercaps;
   389     sinkcaps = othercaps;
   537     srccaps = caps;
   390     srccaps = caps;
   538   }
   391   }
   539 
   392 
   540   /* Get sample width -> bytes_per_samp, channels, inrate, outrate */
   393   /* if the caps are the ones that _set_caps got called with; we can use
   541   ret =
   394    * our own state; otherwise we'll have to create a state */
   542       gst_audio_resample_parse_caps (caps, othercaps, &bytes_per_samp,
   395   if (gst_caps_is_equal (sinkcaps, audioresample->sinkcaps) &&
   543       &channels, &inrate, &outrate, NULL);
   396       gst_caps_is_equal (srccaps, audioresample->srccaps)) {
   544   if (G_UNLIKELY (!ret)) {
   397     use_internal = TRUE;
   545     GST_ERROR_OBJECT (base, "Wrong caps");
   398     state = audioresample->resample;
   546     return FALSE;
   399   } else {
   547   }
   400     GST_DEBUG_OBJECT (audioresample,
   548   /* Number of samples in either buffer is size / (width*channels) ->
   401         "caps are not the set caps, creating state");
   549    * calculate the factor */
   402     state = resample_new ();
   550   bytes_per_samp = bytes_per_samp * channels / 8;
   403     resample_set_filter_length (state, audioresample->filter_length);
   551   /* Convert source buffer size to samples */
   404     resample_set_state_from_caps (state, sinkcaps, srccaps, NULL, NULL, NULL);
   552   size /= bytes_per_samp;
   405   }
   553 
       
   554   /* Simplify the conversion ratio factors */
       
   555   gcd = _gcd (inrate, outrate);
       
   556   ratio_num = inrate / gcd;
       
   557   ratio_den = outrate / gcd;
       
   558 
   406 
   559   if (direction == GST_PAD_SINK) {
   407   if (direction == GST_PAD_SINK) {
   560     /* asked to convert size of an incoming buffer. Round up the output size */
   408     /* asked to convert size of an incoming buffer */
   561     *othersize = (size * ratio_den + ratio_num - 1) / ratio_num;
   409     *othersize = resample_get_output_size_for_input (state, size);
   562     *othersize *= bytes_per_samp;
       
   563   } else {
   410   } else {
   564     /* asked to convert size of an outgoing buffer. Round down the input size */
   411     /* asked to convert size of an outgoing buffer */
   565     *othersize = (size * ratio_num) / ratio_den;
   412     *othersize = resample_get_input_size_for_output (state, size);
   566     *othersize *= bytes_per_samp;
   413   }
   567   }
   414   g_assert (*othersize % state->sample_size == 0);
   568 
   415 
   569   GST_LOG_OBJECT (base, "transformed size %d to %d", size * bytes_per_samp,
   416   /* we make room for one extra sample, given that the resampling filter
   570       *othersize);
   417    * can output an extra one for non-integral i_rate/o_rate */
       
   418   GST_LOG_OBJECT (base, "transformed size %d to %d", size, *othersize);
       
   419 
       
   420   if (!use_internal) {
       
   421     resample_free (state);
       
   422   }
   571 
   423 
   572   return ret;
   424   return ret;
   573 }
   425 }
   574 
   426 
   575 static gboolean
   427 static gboolean
   576 gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
   428 audioresample_set_caps (GstBaseTransform * base, GstCaps * incaps,
   577     GstCaps * outcaps)
   429     GstCaps * outcaps)
   578 {
   430 {
   579   gboolean ret;
   431   gboolean ret;
   580   gint width = 0, inrate = 0, outrate = 0, channels = 0;
   432   gint inrate, outrate;
   581   gboolean fp;
   433   int channels;
   582   GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
   434   GstAudioresample *audioresample = GST_AUDIORESAMPLE (base);
   583 
   435 
   584   GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
   436   GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
   585       GST_PTR_FORMAT, incaps, outcaps);
   437       GST_PTR_FORMAT, incaps, outcaps);
   586 
   438 
   587   ret = gst_audio_resample_parse_caps (incaps, outcaps,
   439   ret = resample_set_state_from_caps (audioresample->resample, incaps, outcaps,
   588       &width, &channels, &inrate, &outrate, &fp);
   440       &channels, &inrate, &outrate);
   589 
   441 
   590   if (G_UNLIKELY (!ret))
   442   g_return_val_if_fail (ret, FALSE);
   591     return FALSE;
   443 
   592 
   444   audioresample->channels = channels;
   593   ret =
   445   GST_DEBUG_OBJECT (audioresample, "set channels to %d", channels);
   594       gst_audio_resample_update_state (resample, width, channels, inrate,
   446   audioresample->i_rate = inrate;
   595       outrate, resample->quality, fp);
   447   GST_DEBUG_OBJECT (audioresample, "set i_rate to %d", inrate);
   596 
   448   audioresample->o_rate = outrate;
   597   if (G_UNLIKELY (!ret))
   449   GST_DEBUG_OBJECT (audioresample, "set o_rate to %d", outrate);
   598     return FALSE;
       
   599 
   450 
   600   /* save caps so we can short-circuit in the size_transform if the caps
   451   /* save caps so we can short-circuit in the size_transform if the caps
   601    * are the same */
   452    * are the same */
   602   gst_caps_replace (&resample->sinkcaps, incaps);
   453   gst_caps_replace (&audioresample->sinkcaps, incaps);
   603   gst_caps_replace (&resample->srccaps, outcaps);
   454   gst_caps_replace (&audioresample->srccaps, outcaps);
   604 
   455 
   605   return TRUE;
   456   return TRUE;
   606 }
   457 }
   607 
   458 
   608 #define GST_MAXINT24 (8388607)
   459 static gboolean
   609 #define GST_MININT24 (-8388608)
   460 audioresample_event (GstBaseTransform * base, GstEvent * event)
   610 
   461 {
   611 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
   462   GstAudioresample *audioresample;
   612 #define GST_READ_UINT24 GST_READ_UINT24_LE
   463 
   613 #define GST_WRITE_UINT24 GST_WRITE_UINT24_LE
   464   audioresample = GST_AUDIORESAMPLE (base);
   614 #else
   465 
   615 #define GST_READ_UINT24 GST_READ_UINT24_BE
   466   switch (GST_EVENT_TYPE (event)) {
   616 #define GST_WRITE_UINT24 GST_WRITE_UINT24_BE
   467     case GST_EVENT_FLUSH_START:
   617 #endif
   468       break;
   618 
   469     case GST_EVENT_FLUSH_STOP:
   619 static void
   470       resample_input_flush (audioresample->resample);
   620 gst_audio_resample_convert_buffer (GstAudioResample * resample,
   471       audioresample->ts_offset = -1;
   621     const guint8 * in, guint8 * out, guint len, gboolean inverse)
   472       audioresample->next_ts = -1;
   622 {
   473       audioresample->offset = -1;
   623   len *= resample->channels;
   474       break;
   624 
   475     case GST_EVENT_NEWSEGMENT:
   625   if (inverse) {
   476       resample_input_pushthrough (audioresample->resample);
   626     if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
   477       audioresample_pushthrough (audioresample);
   627       gint8 *o = (gint8 *) out;
   478       audioresample->ts_offset = -1;
   628       gint16 *i = (gint16 *) in;
   479       audioresample->next_ts = -1;
   629       gint32 tmp;
   480       audioresample->offset = -1;
   630 
   481       break;
   631       while (len) {
   482     case GST_EVENT_EOS:
   632         tmp = *i + (G_MAXINT8 >> 1);
   483       resample_input_eos (audioresample->resample);
   633         *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8);
   484       audioresample_pushthrough (audioresample);
   634         o++;
   485       break;
   635         i++;
   486     default:
   636         len--;
   487       break;
   637       }
   488   }
   638     } else if (!gst_audio_resample_use_int && resample->width == 8
   489   parent_class->event (base, event);
   639         && !resample->fp) {
   490 
   640       gint8 *o = (gint8 *) out;
   491   return TRUE;
   641       gfloat *i = (gfloat *) in;
   492 }
   642       gfloat tmp;
   493 
   643 
   494 static GstFlowReturn
   644       while (len) {
   495 audioresample_do_output (GstAudioresample * audioresample, GstBuffer * outbuf)
   645         tmp = *i;
   496 {
   646         *o = (gint8) CLAMP (tmp * G_MAXINT8 + 0.5, G_MININT8, G_MAXINT8);
   497   int outsize;
   647         o++;
   498   int outsamples;
   648         i++;
   499   ResampleState *r;
   649         len--;
   500 
   650       }
   501   r = audioresample->resample;
   651     } else if (!gst_audio_resample_use_int && resample->width == 16
   502 
   652         && !resample->fp) {
   503   outsize = resample_get_output_size (r);
   653       gint16 *o = (gint16 *) out;
   504   GST_LOG_OBJECT (audioresample, "audioresample can give me %d bytes", outsize);
   654       gfloat *i = (gfloat *) in;
   505 
   655       gfloat tmp;
   506   /* protect against mem corruption */
   656 
   507   if (outsize > GST_BUFFER_SIZE (outbuf)) {
   657       while (len) {
   508     GST_WARNING_OBJECT (audioresample,
   658         tmp = *i;
   509         "overriding audioresample's outsize %d with outbuffer's size %d",
   659         *o = (gint16) CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
   510         outsize, GST_BUFFER_SIZE (outbuf));
   660         o++;
   511     outsize = GST_BUFFER_SIZE (outbuf);
   661         i++;
   512   }
   662         len--;
   513   /* catch possibly wrong size differences */
   663       }
   514   if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
   664     } else if (resample->width == 24 && !resample->fp) {
   515     GST_WARNING_OBJECT (audioresample,
   665       guint8 *o = (guint8 *) out;
   516         "audioresample's outsize %d too far from outbuffer's size %d",
   666       gdouble *i = (gdouble *) in;
   517         outsize, GST_BUFFER_SIZE (outbuf));
   667       gdouble tmp;
   518   }
   668 
   519 
   669       while (len) {
   520   outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize);
   670         tmp = *i;
   521   outsamples = outsize / r->sample_size;
   671         GST_WRITE_UINT24 (o, (gint32) CLAMP (tmp * GST_MAXINT24 + 0.5,
   522   GST_LOG_OBJECT (audioresample, "resample gave me %d bytes or %d samples",
   672                 GST_MININT24, GST_MAXINT24));
   523       outsize, outsamples);
   673         o += 3;
   524 
   674         i++;
   525   GST_BUFFER_OFFSET (outbuf) = audioresample->offset;
   675         len--;
   526   GST_BUFFER_TIMESTAMP (outbuf) = audioresample->next_ts;
   676       }
   527 
   677     } else if (resample->width == 32 && !resample->fp) {
   528   if (audioresample->ts_offset != -1) {
   678       gint32 *o = (gint32 *) out;
   529     audioresample->offset += outsamples;
   679       gdouble *i = (gdouble *) in;
   530     audioresample->ts_offset += outsamples;
   680       gdouble tmp;
   531     audioresample->next_ts =
   681 
   532         gst_util_uint64_scale_int (audioresample->ts_offset, GST_SECOND,
   682       while (len) {
   533         audioresample->o_rate);
   683         tmp = *i;
   534     GST_BUFFER_OFFSET_END (outbuf) = audioresample->offset;
   684         *o = (gint32) CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32);
   535 
   685         o++;
   536     /* we calculate DURATION as the difference between "next" timestamp
   686         i++;
   537      * and current timestamp so we ensure a contiguous stream, instead of
   687         len--;
   538      * having rounding errors. */
   688       }
   539     GST_BUFFER_DURATION (outbuf) = audioresample->next_ts -
   689     } else {
   540         GST_BUFFER_TIMESTAMP (outbuf);
   690       g_assert_not_reached ();
       
   691     }
       
   692   } else {
   541   } else {
   693     if (gst_audio_resample_use_int && resample->width == 8 && !resample->fp) {
   542     /* no valid offset know, we can still sortof calculate the duration though */
   694       gint8 *i = (gint8 *) in;
   543     GST_BUFFER_DURATION (outbuf) =
   695       gint16 *o = (gint16 *) out;
   544         gst_util_uint64_scale_int (outsamples, GST_SECOND,
   696       gint32 tmp;
   545         audioresample->o_rate);
   697 
   546   }
   698       while (len) {
   547 
   699         tmp = *i;
   548   /* check for possible mem corruption */
   700         *o = tmp << 8;
   549   if (outsize > GST_BUFFER_SIZE (outbuf)) {
   701         o++;
   550     /* this is an error that when it happens, would need fixing in the
   702         i++;
   551      * resample library; we told it we wanted only GST_BUFFER_SIZE (outbuf),
   703         len--;
   552      * and it gave us more ! */
   704       }
   553     GST_WARNING_OBJECT (audioresample,
   705     } else if (!gst_audio_resample_use_int && resample->width == 8
   554         "audioresample, you memory corrupting bastard. "
   706         && !resample->fp) {
   555         "you gave me outsize %d while my buffer was size %d",
   707       gint8 *i = (gint8 *) in;
   556         outsize, GST_BUFFER_SIZE (outbuf));
   708       gfloat *o = (gfloat *) out;
   557     return GST_FLOW_ERROR;
   709       gfloat tmp;
   558   }
   710 
   559   /* catch possibly wrong size differences */
   711       while (len) {
   560   if (GST_BUFFER_SIZE (outbuf) - outsize > r->sample_size) {
   712         tmp = *i;
   561     GST_WARNING_OBJECT (audioresample,
   713         *o = tmp / G_MAXINT8;
   562         "audioresample's written outsize %d too far from outbuffer's size %d",
   714         o++;
   563         outsize, GST_BUFFER_SIZE (outbuf));
   715         i++;
   564   }
   716         len--;
   565   GST_BUFFER_SIZE (outbuf) = outsize;
   717       }
   566 
   718     } else if (!gst_audio_resample_use_int && resample->width == 16
   567   if (G_UNLIKELY (audioresample->need_discont)) {
   719         && !resample->fp) {
   568     GST_DEBUG_OBJECT (audioresample,
   720       gint16 *i = (gint16 *) in;
   569         "marking this buffer with the DISCONT flag");
   721       gfloat *o = (gfloat *) out;
   570     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   722       gfloat tmp;
   571     audioresample->need_discont = FALSE;
   723 
   572   }
   724       while (len) {
   573 
   725         tmp = *i;
   574   GST_LOG_OBJECT (audioresample, "transformed to buffer of %d bytes, ts %"
   726         *o = tmp / G_MAXINT16;
   575       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
   727         o++;
   576       G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
   728         i++;
   577       outsize, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
   729         len--;
   578       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
   730       }
   579       GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
   731     } else if (resample->width == 24 && !resample->fp) {
   580 
   732       guint8 *i = (guint8 *) in;
   581 
   733       gdouble *o = (gdouble *) out;
   582   return GST_FLOW_OK;
   734       gdouble tmp;
   583 }
   735       guint32 tmp2;
   584 
   736 
   585 static gboolean
   737       while (len) {
   586 audioresample_check_discont (GstAudioresample * audioresample,
   738         tmp2 = GST_READ_UINT24 (i);
       
   739         if (tmp2 & 0x00800000)
       
   740           tmp2 |= 0xff000000;
       
   741         tmp = (gint32) tmp2;
       
   742         *o = tmp / GST_MAXINT24;
       
   743         o++;
       
   744         i += 3;
       
   745         len--;
       
   746       }
       
   747     } else if (resample->width == 32 && !resample->fp) {
       
   748       gint32 *i = (gint32 *) in;
       
   749       gdouble *o = (gdouble *) out;
       
   750       gdouble tmp;
       
   751 
       
   752       while (len) {
       
   753         tmp = *i;
       
   754         *o = tmp / G_MAXINT32;
       
   755         o++;
       
   756         i++;
       
   757         len--;
       
   758       }
       
   759     } else {
       
   760       g_assert_not_reached ();
       
   761     }
       
   762   }
       
   763 }
       
   764 
       
   765 static void
       
   766 gst_audio_resample_push_drain (GstAudioResample * resample)
       
   767 {
       
   768   GstBuffer *buf;
       
   769   GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
       
   770   GstFlowReturn res;
       
   771   gint outsize;
       
   772   guint out_len, out_processed;
       
   773   gint err;
       
   774   guint num, den, len;
       
   775   guint8 *outtmp = NULL;
       
   776   gboolean need_convert = FALSE;
       
   777 
       
   778   if (!resample->state)
       
   779     return;
       
   780 
       
   781   /* Don't drain samples if we were resetted. */
       
   782   if (resample->next_ts == -1)
       
   783     return;
       
   784 
       
   785   need_convert = (resample->funcs->width != resample->width);
       
   786 
       
   787   resample->funcs->get_ratio (resample->state, &num, &den);
       
   788 
       
   789   out_len = resample->funcs->get_input_latency (resample->state);
       
   790   out_len = out_processed = (out_len * den + num - 1) / num;
       
   791   outsize = (resample->width / 8) * out_len * resample->channels;
       
   792 
       
   793   if (need_convert) {
       
   794     guint outsize_tmp =
       
   795         (resample->funcs->width / 8) * out_len * resample->channels;
       
   796     if (outsize_tmp <= resample->tmp_out_size) {
       
   797       outtmp = resample->tmp_out;
       
   798     } else {
       
   799       resample->tmp_out_size = outsize_tmp;
       
   800       resample->tmp_out = outtmp = g_realloc (resample->tmp_out, outsize_tmp);
       
   801     }
       
   802   }
       
   803 
       
   804   res =
       
   805       gst_pad_alloc_buffer_and_set_caps (trans->srcpad, GST_BUFFER_OFFSET_NONE,
       
   806       outsize, GST_PAD_CAPS (trans->srcpad), &buf);
       
   807 
       
   808   if (G_UNLIKELY (res != GST_FLOW_OK)) {
       
   809     GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes",
       
   810         outsize);
       
   811     return;
       
   812   }
       
   813 
       
   814   len = resample->funcs->get_input_latency (resample->state);
       
   815 
       
   816   err =
       
   817       resample->funcs->process (resample->state,
       
   818       NULL, &len, (need_convert) ? outtmp : GST_BUFFER_DATA (buf),
       
   819       &out_processed);
       
   820 
       
   821   if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
       
   822     GST_WARNING_OBJECT (resample, "Failed to process drain: %s",
       
   823         resample->funcs->strerror (err));
       
   824     gst_buffer_unref (buf);
       
   825     return;
       
   826   }
       
   827 
       
   828   if (G_UNLIKELY (out_processed == 0)) {
       
   829     GST_WARNING_OBJECT (resample, "Failed to get drain, dropping buffer");
       
   830     gst_buffer_unref (buf);
       
   831     return;
       
   832   }
       
   833 
       
   834   /* If we wrote more than allocated something is really wrong now
       
   835    * and we should better abort immediately */
       
   836   g_assert (out_len >= out_processed);
       
   837 
       
   838   if (need_convert)
       
   839     gst_audio_resample_convert_buffer (resample, outtmp, GST_BUFFER_DATA (buf),
       
   840         out_processed, TRUE);
       
   841 
       
   842   GST_BUFFER_DURATION (buf) =
       
   843       GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
       
   844   GST_BUFFER_SIZE (buf) =
       
   845       out_processed * resample->channels * (resample->width / 8);
       
   846 
       
   847   if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
       
   848     GST_BUFFER_OFFSET (buf) = resample->next_offset;
       
   849     GST_BUFFER_OFFSET_END (buf) = resample->next_offset + out_processed;
       
   850     GST_BUFFER_TIMESTAMP (buf) = resample->next_ts;
       
   851 
       
   852     resample->next_ts += GST_BUFFER_DURATION (buf);
       
   853     resample->next_offset += out_processed;
       
   854   }
       
   855 
       
   856   GST_LOG_OBJECT (resample,
       
   857       "Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
       
   858       " duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %"
       
   859       G_GUINT64_FORMAT, GST_BUFFER_SIZE (buf),
       
   860       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
       
   861       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
       
   862       GST_BUFFER_OFFSET_END (buf));
       
   863 
       
   864   res = gst_pad_push (trans->srcpad, buf);
       
   865 
       
   866   if (G_UNLIKELY (res != GST_FLOW_OK))
       
   867     GST_WARNING_OBJECT (resample, "Failed to push drain: %s",
       
   868         gst_flow_get_name (res));
       
   869 
       
   870   return;
       
   871 }
       
   872 
       
   873 static gboolean
       
   874 gst_audio_resample_event (GstBaseTransform * base, GstEvent * event)
       
   875 {
       
   876   GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
       
   877 
       
   878   switch (GST_EVENT_TYPE (event)) {
       
   879     case GST_EVENT_FLUSH_STOP:
       
   880       gst_audio_resample_reset_state (resample);
       
   881       resample->next_offset = -1;
       
   882       resample->next_ts = -1;
       
   883       resample->next_upstream_ts = -1;
       
   884       break;
       
   885     case GST_EVENT_NEWSEGMENT:
       
   886       gst_audio_resample_push_drain (resample);
       
   887       gst_audio_resample_reset_state (resample);
       
   888       resample->next_offset = -1;
       
   889       resample->next_ts = -1;
       
   890       resample->next_upstream_ts = -1;
       
   891       break;
       
   892     case GST_EVENT_EOS:
       
   893       gst_audio_resample_push_drain (resample);
       
   894       gst_audio_resample_reset_state (resample);
       
   895       break;
       
   896     default:
       
   897       break;
       
   898   }
       
   899 
       
   900   return parent_class->event (base, event);
       
   901 }
       
   902 
       
   903 static gboolean
       
   904 gst_audio_resample_check_discont (GstAudioResample * resample,
       
   905     GstClockTime timestamp)
   587     GstClockTime timestamp)
   906 {
   588 {
   907   if (timestamp != GST_CLOCK_TIME_NONE &&
   589   if (timestamp != GST_CLOCK_TIME_NONE &&
   908       resample->next_upstream_ts != GST_CLOCK_TIME_NONE &&
   590       audioresample->prev_ts != GST_CLOCK_TIME_NONE &&
   909       timestamp != resample->next_upstream_ts) {
   591       audioresample->prev_duration != GST_CLOCK_TIME_NONE &&
       
   592       timestamp != audioresample->prev_ts + audioresample->prev_duration) {
   910     /* Potentially a discontinuous buffer. However, it turns out that many
   593     /* Potentially a discontinuous buffer. However, it turns out that many
   911      * elements generate imperfect streams due to rounding errors, so we permit
   594      * elements generate imperfect streams due to rounding errors, so we permit
   912      * a small error (up to one sample) without triggering a filter 
   595      * a small error (up to one sample) without triggering a filter 
   913      * flush/restart (if triggered incorrectly, this will be audible) */
   596      * flush/restart (if triggered incorrectly, this will be audible) */
   914     GstClockTimeDiff diff = timestamp - resample->next_upstream_ts;
   597     GstClockTimeDiff diff = timestamp -
   915 
   598         (audioresample->prev_ts + audioresample->prev_duration);
   916     if (ABS (diff) > (GST_SECOND + resample->inrate - 1) / resample->inrate) {
   599 
   917       GST_WARNING_OBJECT (resample,
   600     if (ABS (diff) > GST_SECOND / audioresample->i_rate) {
   918           "encountered timestamp discontinuity of %s%" GST_TIME_FORMAT,
   601       GST_WARNING_OBJECT (audioresample,
   919           (diff < 0) ? "-" : "", GST_TIME_ARGS ((GstClockTime) ABS (diff)));
   602           "encountered timestamp discontinuity of %" G_GINT64_FORMAT, diff);
   920       return TRUE;
   603       return TRUE;
   921     }
   604     }
   922   }
   605   }
   923 
   606 
   924   return FALSE;
   607   return FALSE;
   925 }
   608 }
   926 
   609 
   927 static GstFlowReturn
   610 static GstFlowReturn
   928 gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
   611 audioresample_transform (GstBaseTransform * base, GstBuffer * inbuf,
   929     GstBuffer * outbuf)
   612     GstBuffer * outbuf)
   930 {
   613 {
   931   guint32 in_len, in_processed;
   614   GstAudioresample *audioresample;
   932   guint32 out_len, out_processed;
   615   ResampleState *r;
   933   gint err = RESAMPLER_ERR_SUCCESS;
   616   guchar *data, *datacopy;
   934   guint8 *in_tmp = NULL, *out_tmp = NULL;
       
   935   gboolean need_convert = (resample->funcs->width != resample->width);
       
   936 
       
   937   in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
       
   938   out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
       
   939 
       
   940   in_len /= (resample->width / 8);
       
   941   out_len /= (resample->width / 8);
       
   942 
       
   943   in_processed = in_len;
       
   944   out_processed = out_len;
       
   945 
       
   946   if (need_convert) {
       
   947     guint in_size_tmp =
       
   948         in_len * resample->channels * (resample->funcs->width / 8);
       
   949     guint out_size_tmp =
       
   950         out_len * resample->channels * (resample->funcs->width / 8);
       
   951 
       
   952     if (in_size_tmp <= resample->tmp_in_size) {
       
   953       in_tmp = resample->tmp_in;
       
   954     } else {
       
   955       resample->tmp_in = in_tmp = g_realloc (resample->tmp_in, in_size_tmp);
       
   956       resample->tmp_in_size = in_size_tmp;
       
   957     }
       
   958 
       
   959     gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
       
   960         in_tmp, in_len, FALSE);
       
   961 
       
   962     if (out_size_tmp <= resample->tmp_out_size) {
       
   963       out_tmp = resample->tmp_out;
       
   964     } else {
       
   965       resample->tmp_out = out_tmp = g_realloc (resample->tmp_out, out_size_tmp);
       
   966       resample->tmp_out_size = out_size_tmp;
       
   967     }
       
   968   }
       
   969 
       
   970   if (need_convert) {
       
   971     err = resample->funcs->process (resample->state,
       
   972         in_tmp, &in_processed, out_tmp, &out_processed);
       
   973   } else {
       
   974     err = resample->funcs->process (resample->state,
       
   975         (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed,
       
   976         (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed);
       
   977   }
       
   978 
       
   979   if (G_UNLIKELY (in_len != in_processed))
       
   980     GST_WARNING_OBJECT (resample, "Converted %d of %d input samples",
       
   981         in_processed, in_len);
       
   982 
       
   983   if (out_len != out_processed) {
       
   984     if (out_processed == 0) {
       
   985       GST_DEBUG_OBJECT (resample, "Converted to 0 samples, buffer dropped");
       
   986 
       
   987       return GST_BASE_TRANSFORM_FLOW_DROPPED;
       
   988     }
       
   989 
       
   990     /* If we wrote more than allocated something is really wrong now
       
   991      * and we should better abort immediately */
       
   992     g_assert (out_len >= out_processed);
       
   993   }
       
   994 
       
   995   if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
       
   996     GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
       
   997         resample->funcs->strerror (err));
       
   998     return GST_FLOW_ERROR;
       
   999   } else {
       
  1000 
       
  1001     if (need_convert)
       
  1002       gst_audio_resample_convert_buffer (resample, out_tmp,
       
  1003           GST_BUFFER_DATA (outbuf), out_processed, TRUE);
       
  1004 
       
  1005     GST_BUFFER_DURATION (outbuf) =
       
  1006         GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate);
       
  1007     GST_BUFFER_SIZE (outbuf) =
       
  1008         out_processed * resample->channels * (resample->width / 8);
       
  1009 
       
  1010     if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
       
  1011       GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts;
       
  1012       GST_BUFFER_OFFSET (outbuf) = resample->next_offset;
       
  1013       GST_BUFFER_OFFSET_END (outbuf) = resample->next_offset + out_processed;
       
  1014 
       
  1015       resample->next_ts += GST_BUFFER_DURATION (outbuf);
       
  1016       resample->next_offset += out_processed;
       
  1017     }
       
  1018 
       
  1019     GST_LOG_OBJECT (resample,
       
  1020         "Converted to buffer of %u bytes with timestamp %" GST_TIME_FORMAT
       
  1021         ", duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
       
  1022         ", offset_end %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
       
  1023         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
       
  1024         GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
       
  1025         GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
       
  1026 
       
  1027     return GST_FLOW_OK;
       
  1028   }
       
  1029 }
       
  1030 
       
  1031 static GstFlowReturn
       
  1032 gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
       
  1033     GstBuffer * outbuf)
       
  1034 {
       
  1035   GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
       
  1036   guint8 *data;
       
  1037   gulong size;
   617   gulong size;
  1038   GstClockTime timestamp;
   618   GstClockTime timestamp;
  1039   guint outsamples, insamples;
   619 
  1040   GstFlowReturn ret;
   620   audioresample = GST_AUDIORESAMPLE (base);
  1041 
   621   r = audioresample->resample;
  1042   if (resample->state == NULL) {
       
  1043     if (G_UNLIKELY (!(resample->state =
       
  1044                 gst_audio_resample_init_state (resample, resample->width,
       
  1045                     resample->channels, resample->inrate, resample->outrate,
       
  1046                     resample->quality, resample->fp))))
       
  1047       return GST_FLOW_ERROR;
       
  1048 
       
  1049     resample->funcs =
       
  1050         gst_audio_resample_get_funcs (resample->width, resample->fp);
       
  1051   }
       
  1052 
   622 
  1053   data = GST_BUFFER_DATA (inbuf);
   623   data = GST_BUFFER_DATA (inbuf);
  1054   size = GST_BUFFER_SIZE (inbuf);
   624   size = GST_BUFFER_SIZE (inbuf);
  1055   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
   625   timestamp = GST_BUFFER_TIMESTAMP (inbuf);
  1056 
   626 
  1057   GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %"
   627   GST_LOG_OBJECT (audioresample, "transforming buffer of %ld bytes, ts %"
  1058       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
   628       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
  1059       G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
   629       G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
  1060       size, GST_TIME_ARGS (timestamp),
   630       size, GST_TIME_ARGS (timestamp),
  1061       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
   631       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
  1062       GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
   632       GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
  1063 
   633 
  1064   /* check for timestamp discontinuities and flush/reset if needed */
   634   /* check for timestamp discontinuities and flush/reset if needed */
  1065   if (G_UNLIKELY (gst_audio_resample_check_discont (resample, timestamp)
   635   if (G_UNLIKELY (audioresample_check_discont (audioresample, timestamp))) {
  1066           || GST_BUFFER_IS_DISCONT (inbuf))) {
       
  1067     /* Flush internal samples */
   636     /* Flush internal samples */
  1068     gst_audio_resample_reset_state (resample);
   637     audioresample_pushthrough (audioresample);
  1069     /* Inform downstream element about discontinuity */
   638     /* Inform downstream element about discontinuity */
  1070     resample->need_discont = TRUE;
   639     audioresample->need_discont = TRUE;
  1071     /* We want to recalculate the timestamps */
   640     /* We want to recalculate the offset */
  1072     resample->next_ts = -1;
   641     audioresample->ts_offset = -1;
  1073     resample->next_upstream_ts = -1;
   642   }
  1074     resample->next_offset = -1;
   643 
  1075   }
   644   if (audioresample->ts_offset == -1) {
  1076 
   645     /* if we don't know the initial offset yet, calculate it based on the 
  1077   insamples = GST_BUFFER_SIZE (inbuf) / resample->channels;
   646      * input timestamp. */
  1078   insamples /= (resample->width / 8);
   647     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
  1079 
   648       GstClockTime stime;
  1080   outsamples = GST_BUFFER_SIZE (outbuf) / resample->channels;
   649 
  1081   outsamples /= (resample->width / 8);
   650       /* offset used to calculate the timestamps. We use the sample offset for
  1082 
   651        * this to make it more accurate. We want the first buffer to have the
  1083   if (GST_CLOCK_TIME_IS_VALID (timestamp)
   652        * same timestamp as the incoming timestamp. */
  1084       && !GST_CLOCK_TIME_IS_VALID (resample->next_ts)) {
   653       audioresample->next_ts = timestamp;
  1085     resample->next_ts = timestamp;
   654       audioresample->ts_offset =
  1086     resample->next_offset =
   655           gst_util_uint64_scale_int (timestamp, r->o_rate, GST_SECOND);
  1087         GST_CLOCK_TIME_TO_FRAMES (timestamp, resample->outrate);
   656       /* offset used to set as the buffer offset, this offset is always
  1088   }
   657        * relative to the stream time, note that timestamp is not... */
  1089 
   658       stime = (timestamp - base->segment.start) + base->segment.time;
  1090   if (G_UNLIKELY (resample->need_discont)) {
   659       audioresample->offset =
  1091     GST_DEBUG_OBJECT (resample, "marking this buffer with the DISCONT flag");
   660           gst_util_uint64_scale_int (stime, r->o_rate, GST_SECOND);
  1092     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
   661     }
  1093     resample->need_discont = FALSE;
   662   }
  1094   }
   663   audioresample->prev_ts = timestamp;
  1095 
   664   audioresample->prev_duration = GST_BUFFER_DURATION (inbuf);
  1096   ret = gst_audio_resample_process (resample, inbuf, outbuf);
   665 
  1097   if (G_UNLIKELY (ret != GST_FLOW_OK))
   666   /* need to memdup, resample takes ownership. */
  1098     return ret;
   667   datacopy = g_memdup (data, size);
  1099 
   668   resample_add_input_data (r, datacopy, size, g_free, datacopy);
  1100   if (GST_CLOCK_TIME_IS_VALID (timestamp)
   669 
  1101       && !GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts))
   670   return audioresample_do_output (audioresample, outbuf);
  1102     resample->next_upstream_ts = timestamp;
   671 }
  1103 
   672 
  1104   if (GST_CLOCK_TIME_IS_VALID (resample->next_upstream_ts))
   673 /* push remaining data in the buffers out */
  1105     resample->next_upstream_ts +=
   674 static GstFlowReturn
  1106         GST_FRAMES_TO_CLOCK_TIME (insamples, resample->inrate);
   675 audioresample_pushthrough (GstAudioresample * audioresample)
  1107 
   676 {
  1108   return GST_FLOW_OK;
   677   int outsize;
  1109 }
   678   ResampleState *r;
  1110 
   679   GstBuffer *outbuf;
  1111 static gboolean
   680   GstFlowReturn res = GST_FLOW_OK;
  1112 gst_audio_resample_query (GstPad * pad, GstQuery * query)
   681   GstBaseTransform *trans;
  1113 {
   682 
  1114   GstAudioResample *resample = GST_AUDIO_RESAMPLE (gst_pad_get_parent (pad));
   683   r = audioresample->resample;
  1115   GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
   684 
       
   685   outsize = resample_get_output_size (r);
       
   686   if (outsize == 0) {
       
   687     GST_DEBUG_OBJECT (audioresample, "no internal buffers needing flush");
       
   688     goto done;
       
   689   }
       
   690 
       
   691   trans = GST_BASE_TRANSFORM (audioresample);
       
   692 
       
   693   res = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize,
       
   694       GST_PAD_CAPS (trans->srcpad), &outbuf);
       
   695   if (G_UNLIKELY (res != GST_FLOW_OK)) {
       
   696     GST_WARNING_OBJECT (audioresample, "failed allocating buffer of %d bytes",
       
   697         outsize);
       
   698     goto done;
       
   699   }
       
   700 
       
   701   res = audioresample_do_output (audioresample, outbuf);
       
   702   if (G_UNLIKELY (res != GST_FLOW_OK))
       
   703     goto done;
       
   704 
       
   705   res = gst_pad_push (trans->srcpad, outbuf);
       
   706 
       
   707 done:
       
   708   return res;
       
   709 }
       
   710 
       
   711 static gboolean
       
   712 audioresample_query (GstPad * pad, GstQuery * query)
       
   713 {
       
   714   GstAudioresample *audioresample =
       
   715       GST_AUDIORESAMPLE (gst_pad_get_parent (pad));
       
   716   GstBaseTransform *trans = GST_BASE_TRANSFORM (audioresample);
  1116   gboolean res = TRUE;
   717   gboolean res = TRUE;
  1117 
   718 
  1118   switch (GST_QUERY_TYPE (query)) {
   719   switch (GST_QUERY_TYPE (query)) {
  1119     case GST_QUERY_LATENCY:
   720     case GST_QUERY_LATENCY:
  1120     {
   721     {
  1121       GstClockTime min, max;
   722       GstClockTime min, max;
  1122       gboolean live;
   723       gboolean live;
  1123       guint64 latency;
   724       guint64 latency;
  1124       GstPad *peer;
   725       GstPad *peer;
  1125       gint rate = resample->inrate;
   726       gint rate = audioresample->i_rate;
  1126       gint resampler_latency;
   727       gint resampler_latency = audioresample->filter_length / 2;
  1127 
       
  1128       if (resample->state)
       
  1129         resampler_latency =
       
  1130             resample->funcs->get_input_latency (resample->state);
       
  1131       else
       
  1132         resampler_latency = 0;
       
  1133 
   728 
  1134       if (gst_base_transform_is_passthrough (trans))
   729       if (gst_base_transform_is_passthrough (trans))
  1135         resampler_latency = 0;
   730         resampler_latency = 0;
  1136 
   731 
  1137       if ((peer = gst_pad_get_peer (trans->sinkpad))) {
   732       if ((peer = gst_pad_get_peer (trans->sinkpad))) {
  1138         if ((res = gst_pad_query (peer, query))) {
   733         if ((res = gst_pad_query (peer, query))) {
  1139           gst_query_parse_latency (query, &live, &min, &max);
   734           gst_query_parse_latency (query, &live, &min, &max);
  1140 
   735 
  1141           GST_DEBUG_OBJECT (resample, "Peer latency: min %"
   736           GST_DEBUG ("Peer latency: min %"
  1142               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
   737               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
  1143               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
   738               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
  1144 
   739 
  1145           /* add our own latency */
   740           /* add our own latency */
  1146           if (rate != 0 && resampler_latency != 0)
   741           if (rate != 0 && resampler_latency != 0)
  1147             latency =
   742             latency =
  1148                 gst_util_uint64_scale (resampler_latency, GST_SECOND, rate);
   743                 gst_util_uint64_scale (resampler_latency, GST_SECOND, rate);
  1149           else
   744           else
  1150             latency = 0;
   745             latency = 0;
  1151 
   746 
  1152           GST_DEBUG_OBJECT (resample, "Our latency: %" GST_TIME_FORMAT,
   747           GST_DEBUG ("Our latency: %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
  1153               GST_TIME_ARGS (latency));
       
  1154 
   748 
  1155           min += latency;
   749           min += latency;
  1156           if (max != GST_CLOCK_TIME_NONE)
   750           if (max != GST_CLOCK_TIME_NONE)
  1157             max += latency;
   751             max += latency;
  1158 
   752 
  1159           GST_DEBUG_OBJECT (resample, "Calculated total latency : min %"
   753           GST_DEBUG ("Calculated total latency : min %"
  1160               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
   754               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
  1161               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
   755               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
  1162 
   756 
  1163           gst_query_set_latency (query, live, min, max);
   757           gst_query_set_latency (query, live, min, max);
  1164         }
   758         }
  1168     }
   762     }
  1169     default:
   763     default:
  1170       res = gst_pad_query_default (pad, query);
   764       res = gst_pad_query_default (pad, query);
  1171       break;
   765       break;
  1172   }
   766   }
  1173   gst_object_unref (resample);
   767   gst_object_unref (audioresample);
  1174   return res;
   768   return res;
  1175 }
   769 }
  1176 
   770 
  1177 static const GstQueryType *
   771 static const GstQueryType *
  1178 gst_audio_resample_query_type (GstPad * pad)
   772 audioresample_query_type (GstPad * pad)
  1179 {
   773 {
  1180   static const GstQueryType types[] = {
   774   static const GstQueryType types[] = {
  1181     GST_QUERY_LATENCY,
   775     GST_QUERY_LATENCY,
  1182     0
   776     0
  1183   };
   777   };
  1184 
   778 
  1185   return types;
   779   return types;
  1186 }
   780 }
  1187 
   781 
  1188 static void
   782 static void
  1189 gst_audio_resample_set_property (GObject * object, guint prop_id,
   783 gst_audioresample_set_property (GObject * object, guint prop_id,
  1190     const GValue * value, GParamSpec * pspec)
   784     const GValue * value, GParamSpec * pspec)
  1191 {
   785 {
  1192   GstAudioResample *resample;
   786   GstAudioresample *audioresample;
  1193 
   787 
  1194   resample = GST_AUDIO_RESAMPLE (object);
   788   audioresample = GST_AUDIORESAMPLE (object);
  1195 
   789 
  1196   switch (prop_id) {
   790   switch (prop_id) {
  1197     case PROP_QUALITY:
   791     case PROP_FILTERLEN:
  1198       GST_BASE_TRANSFORM_LOCK (resample);
   792       audioresample->filter_length = g_value_get_int (value);
  1199       resample->quality = g_value_get_int (value);
   793       GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d",
  1200       GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
   794           audioresample->filter_length);
  1201 
   795       if (audioresample->resample) {
  1202       gst_audio_resample_update_state (resample, resample->width,
   796         resample_set_filter_length (audioresample->resample,
  1203           resample->channels, resample->inrate, resample->outrate,
   797             audioresample->filter_length);
  1204           resample->quality, resample->fp);
   798         gst_element_post_message (GST_ELEMENT (audioresample),
  1205       GST_BASE_TRANSFORM_UNLOCK (resample);
   799             gst_message_new_latency (GST_OBJECT (audioresample)));
  1206       break;
   800       }
  1207     case PROP_FILTER_LENGTH:{
   801       break;
  1208       gint filter_length = g_value_get_int (value);
       
  1209 
       
  1210       GST_BASE_TRANSFORM_LOCK (resample);
       
  1211       if (filter_length <= 8)
       
  1212         resample->quality = 0;
       
  1213       else if (filter_length <= 16)
       
  1214         resample->quality = 1;
       
  1215       else if (filter_length <= 32)
       
  1216         resample->quality = 2;
       
  1217       else if (filter_length <= 48)
       
  1218         resample->quality = 3;
       
  1219       else if (filter_length <= 64)
       
  1220         resample->quality = 4;
       
  1221       else if (filter_length <= 80)
       
  1222         resample->quality = 5;
       
  1223       else if (filter_length <= 96)
       
  1224         resample->quality = 6;
       
  1225       else if (filter_length <= 128)
       
  1226         resample->quality = 7;
       
  1227       else if (filter_length <= 160)
       
  1228         resample->quality = 8;
       
  1229       else if (filter_length <= 192)
       
  1230         resample->quality = 9;
       
  1231       else
       
  1232         resample->quality = 10;
       
  1233 
       
  1234       GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
       
  1235 
       
  1236       gst_audio_resample_update_state (resample, resample->width,
       
  1237           resample->channels, resample->inrate, resample->outrate,
       
  1238           resample->quality, resample->fp);
       
  1239       GST_BASE_TRANSFORM_UNLOCK (resample);
       
  1240       break;
       
  1241     }
       
  1242     default:
   802     default:
  1243       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   803       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1244       break;
   804       break;
  1245   }
   805   }
  1246 }
   806 }
  1247 
   807 
  1248 static void
   808 static void
  1249 gst_audio_resample_get_property (GObject * object, guint prop_id,
   809 gst_audioresample_get_property (GObject * object, guint prop_id,
  1250     GValue * value, GParamSpec * pspec)
   810     GValue * value, GParamSpec * pspec)
  1251 {
   811 {
  1252   GstAudioResample *resample;
   812   GstAudioresample *audioresample;
  1253 
   813 
  1254   resample = GST_AUDIO_RESAMPLE (object);
   814   audioresample = GST_AUDIORESAMPLE (object);
  1255 
   815 
  1256   switch (prop_id) {
   816   switch (prop_id) {
  1257     case PROP_QUALITY:
   817     case PROP_FILTERLEN:
  1258       g_value_set_int (value, resample->quality);
   818       g_value_set_int (value, audioresample->filter_length);
  1259       break;
       
  1260     case PROP_FILTER_LENGTH:
       
  1261       switch (resample->quality) {
       
  1262         case 0:
       
  1263           g_value_set_int (value, 8);
       
  1264           break;
       
  1265         case 1:
       
  1266           g_value_set_int (value, 16);
       
  1267           break;
       
  1268         case 2:
       
  1269           g_value_set_int (value, 32);
       
  1270           break;
       
  1271         case 3:
       
  1272           g_value_set_int (value, 48);
       
  1273           break;
       
  1274         case 4:
       
  1275           g_value_set_int (value, 64);
       
  1276           break;
       
  1277         case 5:
       
  1278           g_value_set_int (value, 80);
       
  1279           break;
       
  1280         case 6:
       
  1281           g_value_set_int (value, 96);
       
  1282           break;
       
  1283         case 7:
       
  1284           g_value_set_int (value, 128);
       
  1285           break;
       
  1286         case 8:
       
  1287           g_value_set_int (value, 160);
       
  1288           break;
       
  1289         case 9:
       
  1290           g_value_set_int (value, 192);
       
  1291           break;
       
  1292         case 10:
       
  1293           g_value_set_int (value, 256);
       
  1294           break;
       
  1295       }
       
  1296       break;
   819       break;
  1297     default:
   820     default:
  1298       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   821       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1299       break;
   822       break;
  1300   }
   823   }
  1301 }
   824 }
  1302 
   825 
  1303 #if defined AUDIORESAMPLE_FORMAT_AUTO
       
  1304 #define BENCHMARK_SIZE 512
       
  1305 
       
  1306 static gboolean
       
  1307 _benchmark_int_float (SpeexResamplerState * st)
       
  1308 {
       
  1309   gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
       
  1310   gfloat in_tmp[BENCHMARK_SIZE], out_tmp[BENCHMARK_SIZE / 2];
       
  1311   gint i;
       
  1312   guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
       
  1313 
       
  1314   for (i = 0; i < BENCHMARK_SIZE; i++) {
       
  1315     gfloat tmp = in[i];
       
  1316     in_tmp[i] = tmp / G_MAXINT16;
       
  1317   }
       
  1318 
       
  1319   resample_float_resampler_process_interleaved_float (st,
       
  1320       (const guint8 *) in_tmp, &inlen, (guint8 *) out_tmp, &outlen);
       
  1321 
       
  1322   if (outlen == 0) {
       
  1323     GST_ERROR ("Failed to use float resampler");
       
  1324     return FALSE;
       
  1325   }
       
  1326 
       
  1327   for (i = 0; i < outlen; i++) {
       
  1328     gfloat tmp = out_tmp[i];
       
  1329     out[i] = CLAMP (tmp * G_MAXINT16 + 0.5, G_MININT16, G_MAXINT16);
       
  1330   }
       
  1331 
       
  1332   return TRUE;
       
  1333 }
       
  1334 
       
  1335 static gboolean
       
  1336 _benchmark_int_int (SpeexResamplerState * st)
       
  1337 {
       
  1338   gint16 in[BENCHMARK_SIZE] = { 0, }, out[BENCHMARK_SIZE / 2];
       
  1339   guint32 inlen = BENCHMARK_SIZE, outlen = BENCHMARK_SIZE / 2;
       
  1340 
       
  1341   resample_int_resampler_process_interleaved_int (st, (const guint8 *) in,
       
  1342       &inlen, (guint8 *) out, &outlen);
       
  1343 
       
  1344   if (outlen == 0) {
       
  1345     GST_ERROR ("Failed to use int resampler");
       
  1346     return FALSE;
       
  1347   }
       
  1348 
       
  1349   return TRUE;
       
  1350 }
       
  1351 
       
  1352 static gboolean
       
  1353 _benchmark_integer_resampling (void)
       
  1354 {
       
  1355   OilProfile a, b;
       
  1356   gdouble av, bv;
       
  1357   SpeexResamplerState *sta, *stb;
       
  1358   int i;
       
  1359 
       
  1360   oil_profile_init (&a);
       
  1361   oil_profile_init (&b);
       
  1362 
       
  1363   sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL);
       
  1364   if (sta == NULL) {
       
  1365     GST_ERROR ("Failed to create float resampler state");
       
  1366     return FALSE;
       
  1367   }
       
  1368 
       
  1369   stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL);
       
  1370   if (stb == NULL) {
       
  1371     resample_float_resampler_destroy (sta);
       
  1372     GST_ERROR ("Failed to create int resampler state");
       
  1373     return FALSE;
       
  1374   }
       
  1375 
       
  1376   /* Benchmark */
       
  1377   for (i = 0; i < 10; i++) {
       
  1378     oil_profile_start (&a);
       
  1379     if (!_benchmark_int_float (sta))
       
  1380       goto error;
       
  1381     oil_profile_stop (&a);
       
  1382   }
       
  1383 
       
  1384   /* Benchmark */
       
  1385   for (i = 0; i < 10; i++) {
       
  1386     oil_profile_start (&b);
       
  1387     if (!_benchmark_int_int (stb))
       
  1388       goto error;
       
  1389     oil_profile_stop (&b);
       
  1390   }
       
  1391 
       
  1392   /* Handle results */
       
  1393   oil_profile_get_ave_std (&a, &av, NULL);
       
  1394   oil_profile_get_ave_std (&b, &bv, NULL);
       
  1395 
       
  1396   /* Remember benchmark result in global variable */
       
  1397   gst_audio_resample_use_int = (av > bv);
       
  1398   resample_float_resampler_destroy (sta);
       
  1399   resample_int_resampler_destroy (stb);
       
  1400 
       
  1401   if (av > bv)
       
  1402     GST_INFO ("Using integer resampler if appropiate: %lf < %lf", bv, av);
       
  1403   else
       
  1404     GST_INFO ("Using float resampler for everything: %lf <= %lf", av, bv);
       
  1405 
       
  1406   return TRUE;
       
  1407 
       
  1408 error:
       
  1409   resample_float_resampler_destroy (sta);
       
  1410   resample_int_resampler_destroy (stb);
       
  1411 
       
  1412   return FALSE;
       
  1413 }
       
  1414 #endif
       
  1415 
   826 
  1416 static gboolean
   827 static gboolean
  1417 plugin_init (GstPlugin * plugin)
   828 plugin_init (GstPlugin * plugin)
  1418 {
   829 {
  1419   GST_DEBUG_CATEGORY_INIT (audio_resample_debug, "audioresample", 0,
   830   resample_init ();
  1420       "audio resampling element");
       
  1421 #if defined AUDIORESAMPLE_FORMAT_AUTO
       
  1422   oil_init ();
       
  1423 
       
  1424   if (!_benchmark_integer_resampling ())
       
  1425     return FALSE;
       
  1426 #endif
       
  1427 
   831 
  1428   if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
   832   if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY,
  1429           GST_TYPE_AUDIO_RESAMPLE)) {
   833           GST_TYPE_AUDIORESAMPLE)) {
  1430     return FALSE;
   834     return FALSE;
  1431   }
   835   }
  1432 
   836 
  1433   return TRUE;
   837   return TRUE;
  1434 }
   838 }