From: Peter Meerwald <p.meerwald@xxxxxxxxxxxxxxxxxx> maybe use the libavresample.h interface provided by very recent ffmpeg? commit c8af852b97447491823ff9b91413e32415e2babf Author: Justin Ruggles <justin.ruggles at gmail.com> Date: Fri Mar 23 17:42:17 2012 -0400 Add libavresample This is a new library for audio sample format, channel layout, and sample rate conversion. Signed-off-by: Peter Meerwald <p.meerwald at bct-electronic.com> --- src/Makefile.am | 2 +- src/pulsecore/ffmpeg/avcodec.h | 98 ++++++++++++++++++++++++++++- src/pulsecore/ffmpeg/libavutil/avassert.h | 24 +++++++ src/pulsecore/ffmpeg/resample2.c | 47 ++++++++++---- 4 files changed, 157 insertions(+), 14 deletions(-) create mode 100644 src/pulsecore/ffmpeg/libavutil/avassert.h diff --git a/src/Makefile.am b/src/Makefile.am index 63ad837..a46aaad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2018,7 +2018,7 @@ massif: pulseaudio libtool --mode=execute valgrind --tool=massif --depth=6 --alloc-fn=pa_xmalloc --alloc-fn=pa_xmalloc0 --alloc-fn=pa_xrealloc --alloc-fn=dbus_realloc --alloc-fn=pa_xnew0_internal --alloc-fn=pa_xnew_internal ./pulseaudio update-ffmpeg: - wget -O pulsecore/ffmpeg/resample2.c http://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec/resample2.c?view=co + wget -O pulsecore/ffmpeg/resample2.c --no-check-certificate https://raw.github.com/FFmpeg/FFmpeg/master/libavcodec/resample2.c # We get things twice here, because sometimes gitweb will us just give a "Generating..." otherwise. update-sbc: diff --git a/src/pulsecore/ffmpeg/avcodec.h b/src/pulsecore/ffmpeg/avcodec.h index 696fc98..6d9da6c 100644 --- a/src/pulsecore/ffmpeg/avcodec.h +++ b/src/pulsecore/ffmpeg/avcodec.h @@ -35,6 +35,8 @@ #include <string.h> #include <stdlib.h> #include <assert.h> +#include <errno.h> +#include "libavutil/avassert.h" #define av_mallocz(l) calloc(1, (l)) #define av_malloc(l) malloc(l) @@ -70,7 +72,6 @@ struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); void av_resample_close(struct AVResampleContext *c); -void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type); /* * crude lrintf for non-C99 systems. @@ -79,4 +80,99 @@ void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_co #define lrintf(x) ((long int)(x)) #endif +/* + * Copyright (c) 2003 Michael Niedermayer <michaelni at gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* taken from libavutil/log.h */ + +typedef struct AVClass { +} AVClass; + +/* taken from libavutil/error.h */ + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +/* taken from libavutil/mathematics.c */ + +int64_t av_gcd(int64_t a, int64_t b){ + if(b) return av_gcd(b, a%b); + else return a; +} + +/* taken from libavutil/rational.h */ + +typedef struct AVRational{ + int num; ///< numerator + int den; ///< denominator +} AVRational; + +int av_reduce(int *dst_num, int *dst_den, + int64_t num, int64_t den, int64_t max) +{ + AVRational a0 = { 0, 1 }, a1 = { 1, 0 }; + int sign = (num < 0) ^ (den < 0); + int64_t gcd = av_gcd(FFABS(num), FFABS(den)); + + if (gcd) { + num = FFABS(num) / gcd; + den = FFABS(den) / gcd; + } + if (num <= max && den <= max) { + a1 = (AVRational) { num, den }; + den = 0; + } + + while (den) { + uint64_t x = num / den; + int64_t next_den = num - den * x; + int64_t a2n = x * a1.num + a0.num; + int64_t a2d = x * a1.den + a0.den; + + if (a2n > max || a2d > max) { + if (a1.num) x = (max - a0.num) / a1.num; + if (a1.den) x = FFMIN(x, (max - a0.den) / a1.den); + + if (den * (2 * x * a1.den + a0.den) > num * a1.den) + a1 = (AVRational) { x * a1.num + a0.num, x * a1.den + a0.den }; + break; + } + + a0 = a1; + a1 = (AVRational) { a2n, a2d }; + num = den; + den = next_den; + } + av_assert2(av_gcd(a1.num, a1.den) <= 1U); + + *dst_num = sign ? -a1.num : a1.num; + *dst_den = a1.den; + + return den == 0; +} + #endif /* AVCODEC_H */ diff --git a/src/pulsecore/ffmpeg/libavutil/avassert.h b/src/pulsecore/ffmpeg/libavutil/avassert.h new file mode 100644 index 0000000..c74ee2f --- /dev/null +++ b/src/pulsecore/ffmpeg/libavutil/avassert.h @@ -0,0 +1,24 @@ +/* + * copyright (c) 2010 Michael Niedermayer <michaelni at gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* taken from libavutil/avassert.h */ + +/* assert() equivalent, that does lie in speed critical code. */ +#define av_assert2(cond) ((void)0) diff --git a/src/pulsecore/ffmpeg/resample2.c b/src/pulsecore/ffmpeg/resample2.c index ac9db73..f82b405 100644 --- a/src/pulsecore/ffmpeg/resample2.c +++ b/src/pulsecore/ffmpeg/resample2.c @@ -20,11 +20,12 @@ */ /** - * @file libavcodec/resample2.c + * @file * audio resampling * @author Michael Niedermayer <michaelni at gmx.at> */ +#include "libavutil/avassert.h" #include "avcodec.h" #include "dsputil.h" @@ -57,6 +58,7 @@ typedef struct AVResampleContext{ + const AVClass *av_class; FELEM *filter_bank; int filter_length; int ideal_dst_incr; @@ -75,11 +77,13 @@ typedef struct AVResampleContext{ */ static double bessel(double x){ double v=1; + double lastv=0; double t=1; int i; x= x*x/4; - for(i=1; i<50; i++){ + for(i=1; v != lastv; i++){ + lastv=v; t *= x/(i*i); v += t; } @@ -87,16 +91,21 @@ static double bessel(double x){ } /** - * builds a polyphase filterbank. + * Build a polyphase filterbank. * @param factor resampling factor * @param scale wanted sum of coefficients for each filter * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 + * @return 0 on success, negative on error */ -void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ +static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ int ph, i; - double x, y, w, tab[tap_count]; + double x, y, w; + double *tab = av_malloc(tap_count * sizeof(*tab)); const int center= (tap_count-1)/2; + if (!tab) + return AVERROR(ENOMEM); + /* if upsampling, only need to interpolate, no filter */ if (factor > 1.0) factor = 1.0; @@ -173,6 +182,9 @@ void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_coun } } #endif + + av_free(tab); + return 0; } AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){ @@ -180,21 +192,33 @@ AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size, double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); int phase_count= 1<<phase_shift; + if (!c) + return NULL; + c->phase_shift= phase_shift; c->phase_mask= phase_count-1; c->linear= linear; c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM)); - av_build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE); + if (!c->filter_bank) + goto error; + if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE)) + goto error; memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; - c->src_incr= out_rate; - c->ideal_dst_incr= c->dst_incr= in_rate * phase_count; + if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) + goto error; + c->ideal_dst_incr= c->dst_incr; + c->index= -phase_count*((c->filter_length-1)/2); return c; +error: + av_free(c->filter_bank); + av_free(c); + return NULL; } void av_resample_close(AVResampleContext *c){ @@ -225,10 +249,9 @@ int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int dst[dst_index] = src[index2>>32]; index2 += incr; } - frac += dst_index * dst_incr_frac; index += dst_index * dst_incr; - index += frac / c->src_incr; - frac %= c->src_incr; + index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; + frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; }else{ for(dst_index=0; dst_index < dst_size; dst_index++){ FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); @@ -279,7 +302,7 @@ int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int if(compensation_distance){ compensation_distance -= dst_index; - assert(compensation_distance > 0); + av_assert2(compensation_distance > 0); } if(update_ctx){ c->frac= frac; -- 1.7.5.4