[pulseaudio-discuss] [PATCH] core: Update ffmpeg resampler
Peter Meerwald
pmeerw at pmeerw.net
Mon Jul 23 02:15:09 PDT 2012
From: Peter Meerwald <p.meerwald at bct-electronic.com>
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
More information about the pulseaudio-discuss
mailing list