[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