Add resample element based on the Speex resampling algorithm.

Original commit message from CVS:
* configure.ac:
* gst/speexresample/arch.h:
* gst/speexresample/fixed_generic.h:
* gst/speexresample/gstspeexresample.c:
(gst_speex_resample_base_init), (gst_speex_resample_class_init),
(gst_speex_resample_init), (gst_speex_resample_start),
(gst_speex_resample_stop), (gst_speex_resample_get_unit_size),
(gst_speex_resample_transform_caps),
(gst_speex_resample_init_state), (gst_speex_resample_update_state),
(gst_speex_resample_reset_state), (gst_speex_resample_parse_caps),
(gst_speex_resample_transform_size), (gst_speex_resample_set_caps),
(gst_speex_resample_event), (gst_speex_resample_check_discont),
(gst_speex_resample_process), (gst_speex_resample_transform),
(gst_speex_resample_set_property),
(gst_speex_resample_get_property), (plugin_init):
* gst/speexresample/gstspeexresample.h:
* gst/speexresample/resample.c: (speex_alloc), (speex_realloc),
(speex_free), (compute_func), (main), (sinc), (cubic_coef),
(resampler_basic_direct_single), (resampler_basic_direct_double),
(resampler_basic_interpolate_single),
(resampler_basic_interpolate_double), (update_filter),
(speex_resampler_init), (speex_resampler_init_frac),
(speex_resampler_destroy), (speex_resampler_process_native),
(speex_resampler_process_float), (speex_resampler_process_int),
(speex_resampler_process_interleaved_float),
(speex_resampler_process_interleaved_int),
(speex_resampler_set_rate), (speex_resampler_get_rate),
(speex_resampler_set_rate_frac), (speex_resampler_get_ratio),
(speex_resampler_set_quality), (speex_resampler_get_quality),
(speex_resampler_set_input_stride),
(speex_resampler_get_input_stride),
(speex_resampler_set_output_stride),
(speex_resampler_get_output_stride), (speex_resampler_skip_zeros),
(speex_resampler_reset_mem), (speex_resampler_strerror):
* gst/speexresample/speex_resampler.h:
* gst/speexresample/speex_resampler_float.c:
* gst/speexresample/speex_resampler_int.c:
* gst/speexresample/speex_resampler_wrapper.h:
Add resample element based on the Speex resampling algorithm.
This commit is contained in:
Sebastian Dröge 2007-11-20 07:02:45 +00:00
parent ac04e0124b
commit 644432907c
11 changed files with 2969 additions and 0 deletions

View file

@ -1,3 +1,45 @@
2007-11-20 Sebastian Dröge <slomo@circular-chaos.org>
* configure.ac:
* gst/speexresample/arch.h:
* gst/speexresample/fixed_generic.h:
* gst/speexresample/gstspeexresample.c:
(gst_speex_resample_base_init), (gst_speex_resample_class_init),
(gst_speex_resample_init), (gst_speex_resample_start),
(gst_speex_resample_stop), (gst_speex_resample_get_unit_size),
(gst_speex_resample_transform_caps),
(gst_speex_resample_init_state), (gst_speex_resample_update_state),
(gst_speex_resample_reset_state), (gst_speex_resample_parse_caps),
(gst_speex_resample_transform_size), (gst_speex_resample_set_caps),
(gst_speex_resample_event), (gst_speex_resample_check_discont),
(gst_speex_resample_process), (gst_speex_resample_transform),
(gst_speex_resample_set_property),
(gst_speex_resample_get_property), (plugin_init):
* gst/speexresample/gstspeexresample.h:
* gst/speexresample/resample.c: (speex_alloc), (speex_realloc),
(speex_free), (compute_func), (main), (sinc), (cubic_coef),
(resampler_basic_direct_single), (resampler_basic_direct_double),
(resampler_basic_interpolate_single),
(resampler_basic_interpolate_double), (update_filter),
(speex_resampler_init), (speex_resampler_init_frac),
(speex_resampler_destroy), (speex_resampler_process_native),
(speex_resampler_process_float), (speex_resampler_process_int),
(speex_resampler_process_interleaved_float),
(speex_resampler_process_interleaved_int),
(speex_resampler_set_rate), (speex_resampler_get_rate),
(speex_resampler_set_rate_frac), (speex_resampler_get_ratio),
(speex_resampler_set_quality), (speex_resampler_get_quality),
(speex_resampler_set_input_stride),
(speex_resampler_get_input_stride),
(speex_resampler_set_output_stride),
(speex_resampler_get_output_stride), (speex_resampler_skip_zeros),
(speex_resampler_reset_mem), (speex_resampler_strerror):
* gst/speexresample/speex_resampler.h:
* gst/speexresample/speex_resampler_float.c:
* gst/speexresample/speex_resampler_int.c:
* gst/speexresample/speex_resampler_wrapper.h:
Add resample element based on the Speex resampling algorithm.
2007-11-20 Edgard Lima <edgard.lima@indt.org.br> 2007-11-20 Edgard Lima <edgard.lima@indt.org.br>
* ext/metadata/gstmetadataparse.c: * ext/metadata/gstmetadataparse.c:

View file

@ -105,6 +105,7 @@ GST_PLUGINS_ALL="\
rtpmanager \ rtpmanager \
sdp \ sdp \
spectrum \ spectrum \
speexresample \
speed \ speed \
stereo \ stereo \
switch \ switch \
@ -1069,6 +1070,7 @@ gst/rtpmanager/Makefile
gst/sdp/Makefile gst/sdp/Makefile
gst/spectrum/Makefile gst/spectrum/Makefile
gst/speed/Makefile gst/speed/Makefile
gst/speexresample/Makefile
gst/stereo/Makefile gst/stereo/Makefile
gst/switch/Makefile gst/switch/Makefile
gst/tta/Makefile gst/tta/Makefile

243
gst/speexresample/arch.h Normal file
View file

@ -0,0 +1,243 @@
/* Copyright (C) 2003 Jean-Marc Valin */
/**
@file arch.h
@brief Various architecture definitions Speex
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ARCH_H
#define ARCH_H
#ifndef SPEEX_VERSION
#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
#endif
/* A couple test to catch stupid option combinations */
#ifdef FIXED_POINT
#ifdef FLOATING_POINT
#error You cannot compile as floating point and fixed point at the same time
#endif
#ifdef _USE_SSE
#error SSE is only for floating-point
#endif
#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
#error Make up your mind. What CPU do you have?
#endif
#ifdef VORBIS_PSYCHO
#error Vorbis-psy model currently not implemented in fixed-point
#endif
#else
#ifndef FLOATING_POINT
#error You now need to define either FIXED_POINT or FLOATING_POINT
#endif
#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
#endif
#ifdef FIXED_POINT_DEBUG
#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
#endif
#endif
#ifndef OUTSIDE_SPEEX
#include "speex/speex_types.h"
#endif
#ifndef ABS
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
#endif
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
#ifdef FIXED_POINT
typedef spx_int16_t spx_word16_t;
typedef spx_int32_t spx_word32_t;
typedef spx_word32_t spx_mem_t;
typedef spx_word16_t spx_coef_t;
typedef spx_word16_t spx_lsp_t;
typedef spx_word32_t spx_sig_t;
#define Q15ONE 32767
#define LPC_SCALING 8192
#define SIG_SCALING 16384
#define LSP_SCALING 8192.
#define GAMMA_SCALING 32768.
#define GAIN_SCALING 64
#define GAIN_SCALING_1 0.015625
#define LPC_SHIFT 13
#define LSP_SHIFT 13
#define SIG_SHIFT 14
#define GAIN_SHIFT 6
#define VERY_SMALL 0
#define VERY_LARGE32 ((spx_word32_t)2147483647)
#define VERY_LARGE16 ((spx_word16_t)32767)
#define Q15_ONE ((spx_word16_t)32767)
#ifdef FIXED_DEBUG
#include "fixed_debug.h"
#else
#include "fixed_generic.h"
#ifdef ARM5E_ASM
#include "fixed_arm5e.h"
#elif defined (ARM4_ASM)
#include "fixed_arm4.h"
#elif defined (ARM5E_ASM)
#include "fixed_arm5e.h"
#elif defined (BFIN_ASM)
#include "fixed_bfin.h"
#endif
#endif
#else
typedef float spx_mem_t;
typedef float spx_coef_t;
typedef float spx_lsp_t;
typedef float spx_sig_t;
typedef float spx_word16_t;
typedef float spx_word32_t;
#define Q15ONE 1.0f
#define LPC_SCALING 1.f
#define SIG_SCALING 1.f
#define LSP_SCALING 1.f
#define GAMMA_SCALING 1.f
#define GAIN_SCALING 1.f
#define GAIN_SCALING_1 1.f
#define VERY_SMALL 1e-15f
#define VERY_LARGE32 1e15f
#define VERY_LARGE16 1e15f
#define Q15_ONE ((spx_word16_t)1.f)
#define QCONST16(x,bits) (x)
#define QCONST32(x,bits) (x)
#define NEG16(x) (-(x))
#define NEG32(x) (-(x))
#define EXTRACT16(x) (x)
#define EXTEND32(x) (x)
#define SHR16(a,shift) (a)
#define SHL16(a,shift) (a)
#define SHR32(a,shift) (a)
#define SHL32(a,shift) (a)
#define PSHR16(a,shift) (a)
#define PSHR32(a,shift) (a)
#define VSHR32(a,shift) (a)
#define SATURATE16(x,a) (x)
#define SATURATE32(x,a) (x)
#define PSHR(a,shift) (a)
#define SHR(a,shift) (a)
#define SHL(a,shift) (a)
#define SATURATE(x,a) (x)
#define ADD16(a,b) ((a)+(b))
#define SUB16(a,b) ((a)-(b))
#define ADD32(a,b) ((a)+(b))
#define SUB32(a,b) ((a)-(b))
#define MULT16_16_16(a,b) ((a)*(b))
#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b))
#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
#define MULT16_32_Q11(a,b) ((a)*(b))
#define MULT16_32_Q13(a,b) ((a)*(b))
#define MULT16_32_Q14(a,b) ((a)*(b))
#define MULT16_32_Q15(a,b) ((a)*(b))
#define MULT16_32_P15(a,b) ((a)*(b))
#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b))
#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b))
#define MAC16_16_P13(c,a,b) ((c)+(a)*(b))
#define MULT16_16_Q11_32(a,b) ((a)*(b))
#define MULT16_16_Q13(a,b) ((a)*(b))
#define MULT16_16_Q14(a,b) ((a)*(b))
#define MULT16_16_Q15(a,b) ((a)*(b))
#define MULT16_16_P15(a,b) ((a)*(b))
#define MULT16_16_P13(a,b) ((a)*(b))
#define MULT16_16_P14(a,b) ((a)*(b))
#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
#endif
#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
/* 2 on TI C5x DSP */
#define BYTES_PER_CHAR 2
#define BITS_PER_CHAR 16
#define LOG2_BITS_PER_CHAR 4
#else
#define BYTES_PER_CHAR 1
#define BITS_PER_CHAR 8
#define LOG2_BITS_PER_CHAR 3
#endif
#ifdef FIXED_DEBUG
long long spx_mips=0;
#endif
#endif

View file

@ -0,0 +1,106 @@
/* Copyright (C) 2003 Jean-Marc Valin */
/**
@file fixed_generic.h
@brief Generic fixed-point operations
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FIXED_GENERIC_H
#define FIXED_GENERIC_H
#define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
#define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits))))
#define NEG16(x) (-(x))
#define NEG32(x) (-(x))
#define EXTRACT16(x) ((spx_word16_t)(x))
#define EXTEND32(x) ((spx_word32_t)(x))
#define SHR16(a,shift) ((a) >> (shift))
#define SHL16(a,shift) ((a) << (shift))
#define SHR32(a,shift) ((a) >> (shift))
#define SHL32(a,shift) ((a) << (shift))
#define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift))
#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift))
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift))
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
#define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
#define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
#define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
#define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
/* result fits in 16 bits */
#define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b))))
/* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
#define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
#define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11)))
#define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13)))
#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
#define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15))
#define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b))))
#define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b))))
#define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b)))
#define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b)))
#endif

View file

@ -0,0 +1,733 @@
/* GStreamer
* Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2003,2004 David A. Schleef <ds@schleef.org>
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:element-speexresample
*
* <refsect2>
* speexresample resamples raw audio buffers to different sample rates using
* a configurable windowing function to enhance quality.
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! speexresample ! audio/x-raw-int, rate=8000 ! alsasink
* </programlisting>
* Decode an Ogg/Vorbis downsample to 8Khz and play sound through alsa.
* To create the Ogg/Vorbis file refer to the documentation of vorbisenc.
* </para>
* </refsect2>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <math.h>
#include "gstspeexresample.h"
#include <gst/audio/audio.h>
#include <gst/base/gstbasetransform.h>
GST_DEBUG_CATEGORY (speex_resample_debug);
#define GST_CAT_DEFAULT speex_resample_debug
enum
{
PROP_0,
PROP_QUALITY
};
#define SUPPORTED_CAPS \
GST_STATIC_CAPS ( \
"audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 32; " \
"audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " \
"width = (int) 16, " \
"depth = (int) 16, " \
"signed = (boolean) true" \
)
static GstStaticPadTemplate gst_speex_resample_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
static GstStaticPadTemplate gst_speex_resample_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
static void gst_speex_resample_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_speex_resample_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
/* vmethods */
static gboolean gst_speex_resample_get_unit_size (GstBaseTransform * base,
GstCaps * caps, guint * size);
static GstCaps *gst_speex_resample_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps);
static gboolean gst_speex_resample_transform_size (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * incaps, guint insize,
GstCaps * outcaps, guint * outsize);
static gboolean gst_speex_resample_set_caps (GstBaseTransform * base,
GstCaps * incaps, GstCaps * outcaps);
static GstFlowReturn gst_speex_resample_transform (GstBaseTransform * base,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_speex_resample_event (GstBaseTransform * base,
GstEvent * event);
static gboolean gst_speex_resample_start (GstBaseTransform * base);
static gboolean gst_speex_resample_stop (GstBaseTransform * base);
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (speex_resample_debug, "speex_resample", 0, "audio resampling element");
GST_BOILERPLATE_FULL (GstSpeexResample, gst_speex_resample, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static void
gst_speex_resample_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_speex_resample_src_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_speex_resample_sink_template));
gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
"Filter/Converter/Audio", "Resamples audio",
"Sebastian Dröge <slomo@circular-chaos.org>");
}
static void
gst_speex_resample_class_init (GstSpeexResampleClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_speex_resample_set_property;
gobject_class->get_property = gst_speex_resample_get_property;
g_object_class_install_property (gobject_class, PROP_QUALITY,
g_param_spec_int ("quality", "Quality", "Resample quality with 0 being "
"the lowest and 10 being the best",
SPEEX_RESAMPLER_QUALITY_MIN, SPEEX_RESAMPLER_QUALITY_MAX,
SPEEX_RESAMPLER_QUALITY_DEFAULT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
GST_BASE_TRANSFORM_CLASS (klass)->start =
GST_DEBUG_FUNCPTR (gst_speex_resample_start);
GST_BASE_TRANSFORM_CLASS (klass)->stop =
GST_DEBUG_FUNCPTR (gst_speex_resample_stop);
GST_BASE_TRANSFORM_CLASS (klass)->transform_size =
GST_DEBUG_FUNCPTR (gst_speex_resample_transform_size);
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
GST_DEBUG_FUNCPTR (gst_speex_resample_get_unit_size);
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
GST_DEBUG_FUNCPTR (gst_speex_resample_transform_caps);
GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
GST_DEBUG_FUNCPTR (gst_speex_resample_set_caps);
GST_BASE_TRANSFORM_CLASS (klass)->transform =
GST_DEBUG_FUNCPTR (gst_speex_resample_transform);
GST_BASE_TRANSFORM_CLASS (klass)->event =
GST_DEBUG_FUNCPTR (gst_speex_resample_event);
GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
}
static void
gst_speex_resample_init (GstSpeexResample * resample,
GstSpeexResampleClass * klass)
{
resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
resample->need_discont = FALSE;
}
/* vmethods */
static gboolean
gst_speex_resample_start (GstBaseTransform * base)
{
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
resample->ts_offset = -1;
resample->offset = -1;
resample->next_ts = -1;
return TRUE;
}
static gboolean
gst_speex_resample_stop (GstBaseTransform * base)
{
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
if (resample->state) {
resample_resampler_destroy (resample->state);
resample->state = NULL;
}
gst_caps_replace (&resample->sinkcaps, NULL);
gst_caps_replace (&resample->srccaps, NULL);
return TRUE;
}
static gboolean
gst_speex_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
guint * size)
{
gint width, channels;
GstStructure *structure;
gboolean ret;
g_return_val_if_fail (size != NULL, FALSE);
/* this works for both float and int */
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", &width);
ret &= gst_structure_get_int (structure, "channels", &channels);
g_return_val_if_fail (ret, FALSE);
*size = width * channels / 8;
return TRUE;
}
static GstCaps *
gst_speex_resample_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps)
{
GstCaps *res;
GstStructure *structure;
/* transform caps gives one single caps so we can just replace
* the rate property with our range. */
res = gst_caps_copy (caps);
structure = gst_caps_get_structure (res, 0);
gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
return res;
}
static SpeexResamplerState *
gst_speex_resample_init_state (guint channels, guint inrate, guint outrate,
guint quality, gboolean fp)
{
SpeexResamplerState *ret = NULL;
gint err = RESAMPLER_ERR_SUCCESS;
if (fp)
ret =
resample_float_resampler_init (channels, inrate, outrate, quality,
&err);
else
ret =
resample_int_resampler_init (channels, inrate, outrate, quality, &err);
if (err != RESAMPLER_ERR_SUCCESS) {
GST_ERROR ("Failed to create resampler state: %s",
resample_resampler_strerror (err));
return NULL;
}
return ret;
}
static gboolean
gst_speex_resample_update_state (GstSpeexResample * resample, gint channels,
gint inrate, gint outrate, gint quality, gboolean fp)
{
gboolean ret = TRUE;
if (resample->state == NULL) {
ret = TRUE;
} else if (resample->channels != channels || fp != resample->fp) {
resample_resampler_destroy (resample->state);
resample->state =
gst_speex_resample_init_state (channels, inrate, outrate, quality, fp);
ret = (resample->state != NULL);
} else if (resample->inrate != inrate || resample->outrate != outrate) {
gint err = RESAMPLER_ERR_SUCCESS;
if (fp)
err =
resample_float_resampler_set_rate (resample->state, inrate, outrate);
else
err = resample_int_resampler_set_rate (resample->state, inrate, outrate);
if (err != RESAMPLER_ERR_SUCCESS)
GST_ERROR ("Failed to update rate: %s",
resample_resampler_strerror (err));
ret = (err == RESAMPLER_ERR_SUCCESS);
} else if (quality != resample->quality) {
gint err = RESAMPLER_ERR_SUCCESS;
if (fp)
err = resample_float_resampler_set_quality (resample->state, quality);
else
err = resample_int_resampler_set_quality (resample->state, quality);
if (err != RESAMPLER_ERR_SUCCESS)
GST_ERROR ("Failed to update quality: %s",
resample_resampler_strerror (err));
ret = (err == RESAMPLER_ERR_SUCCESS);
}
resample->channels = channels;
resample->fp = fp;
resample->quality = quality;
resample->inrate = inrate;
resample->outrate = outrate;
return ret;
}
static void
gst_speex_resample_reset_state (GstSpeexResample * resample)
{
if (resample->state && resample->fp)
resample_float_resampler_reset_mem (resample->state);
else if (resample->state && !resample->fp)
resample_int_resampler_reset_mem (resample->state);
}
static gboolean
gst_speex_resample_parse_caps (GstCaps * incaps,
GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate,
gboolean * fp)
{
GstStructure *structure;
gboolean ret;
gint myinrate, myoutrate, mychannels;
gboolean myfp;
GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
structure = gst_caps_get_structure (incaps, 0);
if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float"))
myfp = TRUE;
else
myfp = FALSE;
ret = gst_structure_get_int (structure, "rate", &myinrate);
ret &= gst_structure_get_int (structure, "channels", &mychannels);
if (!ret)
goto no_in_rate_channels;
structure = gst_caps_get_structure (outcaps, 0);
ret = gst_structure_get_int (structure, "rate", &myoutrate);
if (!ret)
goto no_out_rate;
if (channels)
*channels = mychannels;
if (inrate)
*inrate = myinrate;
if (outrate)
*outrate = myoutrate;
if (fp)
*fp = myfp;
return TRUE;
/* ERRORS */
no_in_rate_channels:
{
GST_DEBUG ("could not get input rate and channels");
return FALSE;
}
no_out_rate:
{
GST_DEBUG ("could not get output rate");
return FALSE;
}
}
static gboolean
gst_speex_resample_transform_size (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
guint * othersize)
{
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
SpeexResamplerState *state;
GstCaps *srccaps, *sinkcaps;
gboolean use_internal = FALSE; /* whether we use the internal state */
gboolean ret = TRUE;
guint32 ratio_den, ratio_num;
gboolean fp;
GST_LOG ("asked to transform size %d in direction %s",
size, direction == GST_PAD_SINK ? "SINK" : "SRC");
if (direction == GST_PAD_SINK) {
sinkcaps = caps;
srccaps = othercaps;
} else {
sinkcaps = othercaps;
srccaps = caps;
}
/* if the caps are the ones that _set_caps got called with; we can use
* our own state; otherwise we'll have to create a state */
if (resample->state && gst_caps_is_equal (sinkcaps, resample->sinkcaps) &&
gst_caps_is_equal (srccaps, resample->srccaps)) {
use_internal = TRUE;
state = resample->state;
fp = resample->fp;
} else {
gint inrate, outrate, channels;
GST_DEBUG ("Can't use internal state, creating state");
ret =
gst_speex_resample_parse_caps (caps, othercaps, &channels, &inrate,
&outrate, &fp);
if (!ret) {
GST_ERROR ("Wrong caps");
return FALSE;
}
state = gst_speex_resample_init_state (channels, inrate, outrate, 0, TRUE);
if (!state)
return FALSE;
}
if (resample->fp || use_internal)
resample_float_resampler_get_ratio (state, &ratio_num, &ratio_den);
else
resample_int_resampler_get_ratio (state, &ratio_num, &ratio_den);
if (direction == GST_PAD_SINK) {
gint fac = (fp) ? 4 : 2;
/* asked to convert size of an incoming buffer */
size /= fac;
*othersize = (size * ratio_den + (ratio_num >> 1)) / ratio_num;
*othersize *= fac;
} else {
gint fac = (fp) ? 4 : 2;
/* asked to convert size of an outgoing buffer */
size /= fac;
*othersize = (size * ratio_num + (ratio_den >> 1)) / ratio_den;
*othersize *= fac;
}
GST_LOG ("transformed size %d to %d", size, *othersize);
if (!use_internal)
resample_resampler_destroy (state);
return ret;
}
static gboolean
gst_speex_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps)
{
gboolean ret;
gint inrate = 0, outrate = 0, channels = 0;
gboolean fp = FALSE;
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
ret = gst_speex_resample_parse_caps (incaps, outcaps,
&channels, &inrate, &outrate, &fp);
g_return_val_if_fail (ret, FALSE);
ret =
gst_speex_resample_update_state (resample, channels, inrate, outrate,
resample->quality, fp);
g_return_val_if_fail (ret, FALSE);
/* save caps so we can short-circuit in the size_transform if the caps
* are the same */
gst_caps_replace (&resample->sinkcaps, incaps);
gst_caps_replace (&resample->srccaps, outcaps);
return TRUE;
}
static gboolean
gst_speex_resample_event (GstBaseTransform * base, GstEvent * event)
{
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
break;
case GST_EVENT_FLUSH_STOP:
case GST_EVENT_NEWSEGMENT:
gst_speex_resample_reset_state (resample);
resample->ts_offset = -1;
resample->next_ts = -1;
resample->offset = -1;
break;
case GST_EVENT_EOS:
gst_speex_resample_reset_state (resample);
break;
default:
break;
}
parent_class->event (base, event);
return TRUE;
}
static gboolean
gst_speex_resample_check_discont (GstSpeexResample * resample,
GstClockTime timestamp)
{
if (timestamp != GST_CLOCK_TIME_NONE &&
resample->prev_ts != GST_CLOCK_TIME_NONE &&
resample->prev_duration != GST_CLOCK_TIME_NONE &&
timestamp != resample->prev_ts + resample->prev_duration) {
/* Potentially a discontinuous buffer. However, it turns out that many
* elements generate imperfect streams due to rounding errors, so we permit
* a small error (up to one sample) without triggering a filter
* flush/restart (if triggered incorrectly, this will be audible) */
GstClockTimeDiff diff = timestamp -
(resample->prev_ts + resample->prev_duration);
if (ABS (diff) > GST_SECOND / resample->inrate) {
GST_WARNING ("encountered timestamp discontinuity of %" G_GINT64_FORMAT,
diff);
return TRUE;
}
}
return FALSE;
}
static GstFlowReturn
gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf,
GstBuffer * outbuf)
{
guint32 in_len, in_processed;
guint32 out_len, out_processed;
gint err = RESAMPLER_ERR_SUCCESS;
in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
if (resample->fp) {
in_len /= 4;
out_len /= 4;
} else {
in_len /= 2;
out_len /= 2;
}
in_processed = in_len;
out_processed = out_len;
if (resample->fp)
err = resample_float_resampler_process_interleaved_float (resample->state,
(const gfloat *) GST_BUFFER_DATA (inbuf), &in_processed,
(gfloat *) GST_BUFFER_DATA (outbuf), &out_processed);
else
err = resample_int_resampler_process_interleaved_int (resample->state,
(const gint16 *) GST_BUFFER_DATA (inbuf), &in_processed,
(gint16 *) GST_BUFFER_DATA (outbuf), &out_processed);
if (in_len != in_processed)
GST_WARNING ("Converted %d of %d input samples", in_processed, in_len);
if (out_len != out_processed)
GST_WARNING ("Converted to %d instead of %d output samples", out_processed,
out_len);
if (err != RESAMPLER_ERR_SUCCESS) {
GST_ERROR ("Failed to convert data: %s", resample_resampler_strerror (err));
return GST_FLOW_ERROR;
} else {
return GST_FLOW_OK;
}
}
static GstFlowReturn
gst_speex_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base);
guint8 *data;
gulong size;
GstClockTime timestamp;
gint outsamples;
if (resample->state == NULL)
if (!(resample->state = gst_speex_resample_init_state (resample->channels,
resample->inrate, resample->outrate, resample->quality,
resample->fp)))
return GST_FLOW_ERROR;
data = GST_BUFFER_DATA (inbuf);
size = GST_BUFFER_SIZE (inbuf);
timestamp = GST_BUFFER_TIMESTAMP (inbuf);
GST_LOG ("transforming buffer of %ld bytes, ts %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
size, GST_TIME_ARGS (timestamp),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
/* check for timestamp discontinuities and flush/reset if needed */
if (G_UNLIKELY (gst_speex_resample_check_discont (resample, timestamp)
|| GST_BUFFER_IS_DISCONT (inbuf))) {
/* Flush internal samples */
gst_speex_resample_reset_state (resample);
/* Inform downstream element about discontinuity */
resample->need_discont = TRUE;
/* We want to recalculate the offset */
resample->ts_offset = -1;
}
outsamples = GST_BUFFER_SIZE (outbuf) / resample->channels;
outsamples /= (resample->fp) ? 4 : 2;
if (resample->ts_offset == -1) {
/* if we don't know the initial offset yet, calculate it based on the
* input timestamp. */
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GstClockTime stime;
/* offset used to calculate the timestamps. We use the sample offset for
* this to make it more accurate. We want the first buffer to have the
* same timestamp as the incoming timestamp. */
resample->next_ts = timestamp;
resample->ts_offset =
gst_util_uint64_scale_int (timestamp, resample->outrate, GST_SECOND);
/* offset used to set as the buffer offset, this offset is always
* relative to the stream time, note that timestamp is not... */
stime = (timestamp - base->segment.start) + base->segment.time;
resample->offset =
gst_util_uint64_scale_int (stime, resample->outrate, GST_SECOND);
}
}
resample->prev_ts = timestamp;
resample->prev_duration = GST_BUFFER_DURATION (inbuf);
GST_BUFFER_OFFSET (outbuf) = resample->offset;
GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts;
if (resample->ts_offset != -1) {
resample->offset += outsamples;
resample->ts_offset += outsamples;
resample->next_ts =
gst_util_uint64_scale_int (resample->ts_offset, GST_SECOND,
resample->outrate);
GST_BUFFER_OFFSET_END (outbuf) = resample->offset;
/* we calculate DURATION as the difference between "next" timestamp
* and current timestamp so we ensure a contiguous stream, instead of
* having rounding errors. */
GST_BUFFER_DURATION (outbuf) = resample->next_ts -
GST_BUFFER_TIMESTAMP (outbuf);
} else {
/* no valid offset know, we can still sortof calculate the duration though */
GST_BUFFER_DURATION (outbuf) =
gst_util_uint64_scale_int (outsamples, GST_SECOND, resample->outrate);
}
if (G_UNLIKELY (resample->need_discont)) {
GST_DEBUG ("marking this buffer with the DISCONT flag");
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
resample->need_discont = FALSE;
}
return gst_speex_resample_process (resample, inbuf, outbuf);
}
static void
gst_speex_resample_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstSpeexResample *resample;
resample = GST_SPEEX_RESAMPLE (object);
switch (prop_id) {
case PROP_QUALITY:
resample->quality = g_value_get_int (value);
GST_DEBUG ("new quality %d", resample->quality);
gst_speex_resample_update_state (resample, resample->channels,
resample->inrate, resample->outrate, resample->quality, resample->fp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_speex_resample_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstSpeexResample *resample;
resample = GST_SPEEX_RESAMPLE (object);
switch (prop_id) {
case PROP_QUALITY:
g_value_set_int (value, resample->quality);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "speexresample", GST_RANK_NONE,
GST_TYPE_SPEEX_RESAMPLE)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"speexresample",
"Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN);

View file

@ -0,0 +1,80 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2007> Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __SPEEX_RESAMPLE_H__
#define __SPEEX_RESAMPLE_H__
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include "speex_resampler_wrapper.h"
G_BEGIN_DECLS
#define GST_TYPE_SPEEX_RESAMPLE \
(gst_speex_resample_get_type())
#define GST_SPEEX_RESAMPLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEEX_RESAMPLE,GstSpeexResample))
#define GST_SPEEX_RESAMPLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPEEX_RESAMPLE,GstSpeexResampleClass))
#define GST_IS_SPEEX_RESAMPLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEEX_RESAMPLE))
#define GST_IS_SPEEX_RESAMPLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEEX_RESAMPLE))
typedef struct _GstSpeexResample GstSpeexResample;
typedef struct _GstSpeexResampleClass GstSpeexResampleClass;
/**
* GstSpeexResample:
*
* Opaque data structure.
*/
struct _GstSpeexResample {
GstBaseTransform element;
GstCaps *srccaps, *sinkcaps;
gboolean need_discont;
guint64 offset;
guint64 ts_offset;
GstClockTime next_ts;
GstClockTime prev_ts, prev_duration;
gboolean fp;
int channels;
int inrate;
int outrate;
int quality;
SpeexResamplerState *state;
};
struct _GstSpeexResampleClass {
GstBaseTransformClass parent_class;
};
GType gst_speex_resample_get_type(void);
G_END_DECLS
#endif /* __SPEEX_RESAMPLE_H__ */

1310
gst/speexresample/resample.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,325 @@
/* Copyright (C) 2007 Jean-Marc Valin
File: speex_resampler.h
Resampling code
The design goals of this code are:
- Very fast algorithm
- Low memory requirement
- Good *perceptual* quality (and not best SNR)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SPEEX_RESAMPLER_H
#define SPEEX_RESAMPLER_H
#ifdef OUTSIDE_SPEEX
#include <glib.h>
/********* WARNING: MENTAL SANITY ENDS HERE *************/
/* If the resampler is defined outside of Speex, we change the symbol names so that
there won't be any clash if linking with Speex later on. */
#define CAT_PREFIX2(a,b) a ## b
#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
#define spx_int16_t gint16
#define spx_int32_t gint32
#define spx_uint16_t guint16
#define spx_uint32_t guint32
#else /* OUTSIDE_SPEEX */
#include "speex/speex_types.h"
#endif /* OUTSIDE_SPEEX */
#ifdef __cplusplus
extern "C" {
#endif
#define SPEEX_RESAMPLER_QUALITY_MAX 10
#define SPEEX_RESAMPLER_QUALITY_MIN 0
#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
#define SPEEX_RESAMPLER_QUALITY_VOIP 3
#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
enum {
RESAMPLER_ERR_SUCCESS = 0,
RESAMPLER_ERR_ALLOC_FAILED = 1,
RESAMPLER_ERR_BAD_STATE = 2,
RESAMPLER_ERR_INVALID_ARG = 3,
RESAMPLER_ERR_PTR_OVERLAP = 4,
RESAMPLER_ERR_MAX_ERROR
};
struct SpeexResamplerState_;
typedef struct SpeexResamplerState_ SpeexResamplerState;
/** Create a new resampler with integer input and output rates.
* @param nb_channels Number of channels to be processed
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state
* @retval NULL Error: not enough memory
*/
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
spx_uint32_t in_rate,
spx_uint32_t out_rate,
int quality,
int *err);
/** Create a new resampler with fractional input/output rates. The sampling
* rate ratio is an arbitrary rational number with both the numerator and
* denominator being 32-bit integers.
* @param nb_channels Number of channels to be processed
* @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state
* @retval NULL Error: not enough memory
*/
SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
spx_uint32_t ratio_num,
spx_uint32_t ratio_den,
spx_uint32_t in_rate,
spx_uint32_t out_rate,
int quality,
int *err);
/** Destroy a resampler state.
* @param st Resampler state
*/
void speex_resampler_destroy(SpeexResamplerState *st);
/** Resample a float array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the
* number of samples processed
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written
*/
int speex_resampler_process_float(SpeexResamplerState *st,
spx_uint32_t channel_index,
const float *in,
spx_uint32_t *in_len,
float *out,
spx_uint32_t *out_len);
/** Resample an int array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written
*/
int speex_resampler_process_int(SpeexResamplerState *st,
spx_uint32_t channel_index,
const spx_int16_t *in,
spx_uint32_t *in_len,
spx_int16_t *out,
spx_uint32_t *out_len);
/** Resample an interleaved float array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/
int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
const float *in,
spx_uint32_t *in_len,
float *out,
spx_uint32_t *out_len);
/** Resample an interleaved int array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/
int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
const spx_int16_t *in,
spx_uint32_t *in_len,
spx_int16_t *out,
spx_uint32_t *out_len);
/** Set (change) the input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
*/
int speex_resampler_set_rate(SpeexResamplerState *st,
spx_uint32_t in_rate,
spx_uint32_t out_rate);
/** Get the current input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz) copied.
* @param out_rate Output sampling rate (integer number of Hz) copied.
*/
void speex_resampler_get_rate(SpeexResamplerState *st,
spx_uint32_t *in_rate,
spx_uint32_t *out_rate);
/** Set (change) the input/output sampling rates and resampling ratio
* (fractional values in Hz supported).
* @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
*/
int speex_resampler_set_rate_frac(SpeexResamplerState *st,
spx_uint32_t ratio_num,
spx_uint32_t ratio_den,
spx_uint32_t in_rate,
spx_uint32_t out_rate);
/** Get the current resampling ratio. This will be reduced to the least
* common denominator.
* @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio copied
* @param ratio_den Denominator of the sampling rate ratio copied
*/
void speex_resampler_get_ratio(SpeexResamplerState *st,
spx_uint32_t *ratio_num,
spx_uint32_t *ratio_den);
/** Set (change) the conversion quality.
* @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/
int speex_resampler_set_quality(SpeexResamplerState *st,
int quality);
/** Get the conversion quality.
* @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/
void speex_resampler_get_quality(SpeexResamplerState *st,
int *quality);
/** Set (change) the input stride.
* @param st Resampler state
* @param stride Input stride
*/
void speex_resampler_set_input_stride(SpeexResamplerState *st,
spx_uint32_t stride);
/** Get the input stride.
* @param st Resampler state
* @param stride Input stride copied
*/
void speex_resampler_get_input_stride(SpeexResamplerState *st,
spx_uint32_t *stride);
/** Set (change) the output stride.
* @param st Resampler state
* @param stride Output stride
*/
void speex_resampler_set_output_stride(SpeexResamplerState *st,
spx_uint32_t stride);
/** Get the output stride.
* @param st Resampler state copied
* @param stride Output stride
*/
void speex_resampler_get_output_stride(SpeexResamplerState *st,
spx_uint32_t *stride);
/** Make sure that the first samples to go out of the resamplers don't have
* leading zeros. This is only useful before starting to use a newly created
* resampler. It is recommended to use that when resampling an audio file, as
* it will generate a file with the same length. For real-time processing,
* it is probably easier not to use this call (so that the output duration
* is the same for the first frame).
* @param st Resampler state
*/
int speex_resampler_skip_zeros(SpeexResamplerState *st);
/** Reset a resampler so a new (unrelated) stream can be processed.
* @param st Resampler state
*/
int speex_resampler_reset_mem(SpeexResamplerState *st);
/** Returns the English meaning for an error code
* @param err Error code
* @return English string
*/
const char *speex_resampler_strerror(int err);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,24 @@
/* GStreamer
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define FLOATING_POINT
#define OUTSIDE_SPEEX
#define RANDOM_PREFIX resample_float
#include "resample.c"

View file

@ -0,0 +1,24 @@
/* GStreamer
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#define FIXED_POINT 1
#define OUTSIDE_SPEEX 1
#define RANDOM_PREFIX resample_int
#include "resample.c"

View file

@ -0,0 +1,80 @@
/* GStreamer
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __SPEEX_RESAMPLER_WRAPPER_H__
#define __SPEEX_RESAMPLER_WRAPPER_H__
#define SPEEX_RESAMPLER_QUALITY_MAX 10
#define SPEEX_RESAMPLER_QUALITY_MIN 0
#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
#define SPEEX_RESAMPLER_QUALITY_VOIP 3
#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
enum
{
RESAMPLER_ERR_SUCCESS = 0,
RESAMPLER_ERR_ALLOC_FAILED = 1,
RESAMPLER_ERR_BAD_STATE = 2,
RESAMPLER_ERR_INVALID_ARG = 3,
RESAMPLER_ERR_PTR_OVERLAP = 4,
RESAMPLER_ERR_MAX_ERROR
};
typedef struct SpeexResamplerState_ SpeexResamplerState;
SpeexResamplerState *resample_float_resampler_init (guint32 nb_channels,
guint32 in_rate, guint32 out_rate, gint quality, gint * err);
SpeexResamplerState *resample_int_resampler_init (guint32 nb_channels,
guint32 in_rate, guint32 out_rate, gint quality, gint * err);
#define resample_resampler_destroy resample_int_resampler_destroy
void resample_resampler_destroy (SpeexResamplerState * st);
int resample_float_resampler_process_interleaved_float (SpeexResamplerState *
st, const gfloat * in, guint32 * in_len, gfloat * out, guint32 * out_len);
int resample_int_resampler_process_interleaved_int (SpeexResamplerState * st,
const gint16 * in, guint32 * in_len, gint16 * out, guint32 * out_len);
int resample_float_resampler_set_rate (SpeexResamplerState * st,
guint32 in_rate, guint32 out_rate);
int resample_int_resampler_set_rate (SpeexResamplerState * st,
guint32 in_rate, guint32 out_rate);
void resample_float_resampler_get_rate (SpeexResamplerState * st,
guint32 * in_rate, guint32 * out_rate);
void resample_int_resampler_get_rate (SpeexResamplerState * st,
guint32 * in_rate, guint32 * out_rate);
void resample_float_resampler_get_ratio (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
void resample_int_resampler_get_ratio (SpeexResamplerState * st,
guint32 * ratio_num, guint32 * ratio_den);
int resample_float_resampler_set_quality (SpeexResamplerState * st,
gint quality);
int resample_int_resampler_set_quality (SpeexResamplerState * st, gint quality);
int resample_float_resampler_reset_mem (SpeexResamplerState * st);
int resample_int_resampler_reset_mem (SpeexResamplerState * st);
#define resample_resampler_strerror resample_int_resampler_strerror
const char *resample_resampler_strerror (gint err);
#endif /* __SPEEX_RESAMPLER_WRAPPER_H__ */