swresample: add exact_rational option
authorMuhammad Faiz <mfcc64@gmail.com>
Sat, 11 Jun 2016 22:19:20 +0000 (05:19 +0700)
committerMuhammad Faiz <mfcc64@gmail.com>
Mon, 13 Jun 2016 05:36:01 +0000 (12:36 +0700)
give high quality resampling
as good as with linear_interp=on
as fast as without linear_interp=on
tested visually with ffplay
ffplay -f lavfi "aevalsrc='sin(10000*t*t)', aresample=osr=48000, showcqt=gamma=5"
ffplay -f lavfi "aevalsrc='sin(10000*t*t)', aresample=osr=48000:linear_interp=on, showcqt=gamma=5"
ffplay -f lavfi "aevalsrc='sin(10000*t*t)', aresample=osr=48000:exact_rational=on, showcqt=gamma=5"

slightly speed improvement
for fair comparison with -cpuflags 0
audio.wav is ~ 1 hour 44100 stereo 16bit wav file
ffmpeg -i audio.wav -af aresample=osr=48000 -f null -
        old         new
real    13.498s     13.121s
user    13.364s     12.987s
sys      0.131s      0.129s

linear_interp=on
        old         new
real    23.035s     23.050s
user    22.907s     22.917s
sys      0.119s     0.125s

exact_rational=on
real    12.418s
user    12.298s
sys      0.114s

possibility to decrease memory usage if soft compensation is ignored

Signed-off-by: Muhammad Faiz <mfcc64@gmail.com>
libswresample/arm/resample_init.c
libswresample/options.c
libswresample/resample.c
libswresample/resample.h
libswresample/resample_template.c
libswresample/soxr_resample.c
libswresample/swresample.c
libswresample/swresample_internal.h
libswresample/version.h
libswresample/x86/resample_init.c

index 797c530..003fafd 100644 (file)
@@ -44,11 +44,15 @@ static int ff_resample_common_##TYPE##_neon(ResampleContext *c, void *dest, cons
     int dst_index;                                                                                \
     int index= c->index;                                                                          \
     int frac= c->frac;                                                                            \
-    int sample_index = index >> c->phase_shift;                                                   \
+    int sample_index = 0;                                                                         \
     int x4_aligned_filter_length = c->filter_length & ~3;                                         \
     int x8_aligned_filter_length = c->filter_length & ~7;                                         \
                                                                                                   \
-    index &= c->phase_mask;                                                                       \
+    while (index >= c->phase_count) {                                                             \
+        sample_index++;                                                                           \
+        index -= c->phase_count;                                                                  \
+    }                                                                                             \
+                                                                                                  \
     for (dst_index = 0; dst_index < n; dst_index++) {                                             \
         FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;                     \
                                                                                                   \
@@ -75,8 +79,11 @@ static int ff_resample_common_##TYPE##_neon(ResampleContext *c, void *dest, cons
             frac -= c->src_incr;                                                                  \
             index++;                                                                              \
         }                                                                                         \
-        sample_index += index >> c->phase_shift;                                                  \
-        index &= c->phase_mask;                                                                   \
+                                                                                                  \
+        while (index >= c->phase_count) {                                                         \
+            sample_index++;                                                                       \
+            index -= c->phase_count;                                                              \
+        }                                                                                         \
     }                                                                                             \
                                                                                                   \
     if(update_ctx){                                                                               \
index eac1a7c..816ce47 100644 (file)
@@ -85,6 +85,7 @@ static const AVOption options[]={
 {"filter_size"          , "set swr resampling filter size", OFFSET(filter_size)  , AV_OPT_TYPE_INT  , {.i64=32                    }, 0      , INT_MAX   , PARAM },
 {"phase_shift"          , "set swr resampling phase shift", OFFSET(phase_shift)  , AV_OPT_TYPE_INT  , {.i64=10                    }, 0      , 24        , PARAM },
 {"linear_interp"        , "enable linear interpolation" , OFFSET(linear_interp)  , AV_OPT_TYPE_BOOL , {.i64=0                     }, 0      , 1         , PARAM },
+{"exact_rational"       , "enable exact rational"       , OFFSET(exact_rational) , AV_OPT_TYPE_BOOL , {.i64=0                     }, 0      , 1         , PARAM },
 {"cutoff"               , "set cutoff frequency ratio"  , OFFSET(cutoff)         , AV_OPT_TYPE_DOUBLE,{.dbl=0.                    }, 0      , 1         , PARAM },
 
 /* duplicate option in order to work with avconv */
index d410432..1b1d83e 100644 (file)
@@ -297,13 +297,28 @@ fail:
 
 static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
                                     double cutoff0, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta,
-                                    double precision, int cheby)
+                                    double precision, int cheby, int exact_rational)
 {
     double cutoff = cutoff0? cutoff0 : 0.97;
     double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
     int phase_count= 1<<phase_shift;
 
-    if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor
+    if (exact_rational) {
+        int phase_count_exact, phase_count_exact_den;
+
+        av_reduce(&phase_count_exact, &phase_count_exact_den, out_rate, in_rate, INT_MAX);
+        /* FIXME this is not required, but build_filter needs even phase_count */
+        if (phase_count_exact & 1 && phase_count_exact > 1 && phase_count_exact < INT_MAX/2)
+            phase_count_exact *= 2;
+
+        if (phase_count_exact <= phase_count) {
+            /* FIXME this is not required when soft compensation is disabled */
+            phase_count_exact *= phase_count / phase_count_exact;
+            phase_count = phase_count_exact;
+        }
+    }
+
+    if (!c || c->phase_count != phase_count || c->linear!=linear || c->factor != factor
            || c->filter_length != FFMAX((int)ceil(filter_size/factor), 1) || c->format != format
            || c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) {
         c = av_mallocz(sizeof(*c));
@@ -337,6 +352,7 @@ static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_r
 
         c->phase_shift   = phase_shift;
         c->phase_mask    = phase_count - 1;
+        c->phase_count   = phase_count;
         c->linear        = linear;
         c->factor        = factor;
         c->filter_length = FFMAX((int)ceil(filter_size/factor), 1);
@@ -399,7 +415,7 @@ static int swri_resample(ResampleContext *c,
                          uint8_t *dst, const uint8_t *src, int *consumed,
                          int src_size, int dst_size, int update_ctx)
 {
-    if (c->filter_length == 1 && c->phase_shift == 0) {
+    if (c->filter_length == 1 && c->phase_count == 1) {
         int index= c->index;
         int frac= c->frac;
         int64_t index2= (1LL<<32)*c->frac/c->src_incr + (1LL<<32)*index;
@@ -418,7 +434,7 @@ static int swri_resample(ResampleContext *c,
             c->index = 0;
         }
     } else {
-        int64_t end_index = (1LL + src_size - c->filter_length) << c->phase_shift;
+        int64_t end_index = (1LL + src_size - c->filter_length) * c->phase_count;
         int64_t delta_frac = (end_index - c->index) * c->src_incr - c->frac;
         int delta_n = (delta_frac + c->dst_incr - 1) / c->dst_incr;
 
@@ -438,7 +454,7 @@ static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, A
     int av_unused mm_flags = av_get_cpu_flags();
     int need_emms = c->format == AV_SAMPLE_FMT_S16P && ARCH_X86_32 &&
                     (mm_flags & (AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE2)) == AV_CPU_FLAG_MMX2;
-    int64_t max_src_size = (INT64_MAX >> (c->phase_shift+1)) / c->src_incr;
+    int64_t max_src_size = (INT64_MAX/2 / c->phase_count) / c->src_incr;
 
     if (c->compensation_distance)
         dst_size = FFMIN(dst_size, c->compensation_distance);
@@ -466,11 +482,11 @@ static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, A
 static int64_t get_delay(struct SwrContext *s, int64_t base){
     ResampleContext *c = s->resample;
     int64_t num = s->in_buffer_count - (c->filter_length-1)/2;
-    num *= 1 << c->phase_shift;
+    num *= c->phase_count;
     num -= c->index;
     num *= c->src_incr;
     num -= c->frac;
-    return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr << c->phase_shift);
+    return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr * c->phase_count);
 }
 
 static int64_t get_out_samples(struct SwrContext *s, int in_samples) {
@@ -479,9 +495,9 @@ static int64_t get_out_samples(struct SwrContext *s, int in_samples) {
     // They also make it easier to proof that changes and optimizations do not
     // break the upper bound.
     int64_t num = s->in_buffer_count + 2LL + in_samples;
-    num *= 1 << c->phase_shift;
+    num *= c->phase_count;
     num -= c->index;
-    num = av_rescale_rnd(num, s->out_sample_rate, ((int64_t)s->in_sample_rate) << c->phase_shift, AV_ROUND_UP) + 2;
+    num = av_rescale_rnd(num, s->out_sample_rate, ((int64_t)s->in_sample_rate) * c->phase_count, AV_ROUND_UP) + 2;
 
     if (c->compensation_distance) {
         if (num > INT_MAX)
@@ -545,10 +561,13 @@ static int invert_initial_buffer(ResampleContext *c, AudioData *dst, const Audio
     }
 
     res = num - *out_sz;
-    *out_idx = c->filter_length + (c->index >> c->phase_shift);
+    *out_idx = c->filter_length;
+    while (c->index < 0) {
+        --*out_idx;
+        c->index += c->phase_count;
+    }
     *out_sz = FFMAX(*out_sz + c->filter_length,
                     1 + c->filter_length * 2) - *out_idx;
-    c->index &= c->phase_mask;
 
     return FFMAX(res, 0);
 }
index ca0cf2b..53788c4 100644 (file)
@@ -40,8 +40,10 @@ typedef struct ResampleContext {
     int frac;
     int src_incr;
     int compensation_distance;
-    int phase_shift;
-    int phase_mask;
+    /* TODO remove phase_shift and phase_mask */
+    attribute_deprecated int phase_shift;
+    attribute_deprecated int phase_mask;
+    int phase_count;
     int linear;
     enum SwrFilterType filter_type;
     double kaiser_beta;
index d71efd6..1636f4e 100644 (file)
@@ -92,9 +92,13 @@ static int RENAME(resample_common)(ResampleContext *c,
     int dst_index;
     int index= c->index;
     int frac= c->frac;
-    int sample_index = index >> c->phase_shift;
+    int sample_index = 0;
+
+    while (index >= c->phase_count) {
+        sample_index++;
+        index -= c->phase_count;
+    }
 
-    index &= c->phase_mask;
     for (dst_index = 0; dst_index < n; dst_index++) {
         FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;
 
@@ -111,8 +115,11 @@ static int RENAME(resample_common)(ResampleContext *c,
             frac -= c->src_incr;
             index++;
         }
-        sample_index += index >> c->phase_shift;
-        index &= c->phase_mask;
+
+        while (index >= c->phase_count) {
+            sample_index++;
+            index -= c->phase_count;
+        }
     }
 
     if(update_ctx){
@@ -132,12 +139,16 @@ static int RENAME(resample_linear)(ResampleContext *c,
     int dst_index;
     int index= c->index;
     int frac= c->frac;
-    int sample_index = index >> c->phase_shift;
+    int sample_index = 0;
 #if FILTER_SHIFT == 0
     double inv_src_incr = 1.0 / c->src_incr;
 #endif
 
-    index &= c->phase_mask;
+    while (index >= c->phase_count) {
+        sample_index++;
+        index -= c->phase_count;
+    }
+
     for (dst_index = 0; dst_index < n; dst_index++) {
         FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;
         FELEM2 val=0, v2 = 0;
@@ -164,8 +175,11 @@ static int RENAME(resample_linear)(ResampleContext *c,
             frac -= c->src_incr;
             index++;
         }
-        sample_index += index >> c->phase_shift;
-        index &= c->phase_mask;
+
+        while (index >= c->phase_count) {
+            sample_index++;
+            index -= c->phase_count;
+        }
     }
 
     if(update_ctx){
index 807f508..b9c6735 100644 (file)
@@ -30,7 +30,7 @@
 #include <soxr.h>
 
 static struct ResampleContext *create(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
-        double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby){
+        double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby, int exact_rational){
     soxr_error_t error;
 
     soxr_datatype_t type =
index e02ec81..351623b 100644 (file)
@@ -262,7 +262,7 @@ av_cold int swr_init(struct SwrContext *s){
     }
 
     if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){
-        s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby);
+        s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby, s->exact_rational);
         if (!s->resample) {
             av_log(s, AV_LOG_ERROR, "Failed to initialize resampler\n");
             return AVERROR(ENOMEM);
index 5d61de4..3828b72 100644 (file)
@@ -69,7 +69,7 @@ struct DitherContext {
 };
 
 typedef struct ResampleContext * (* resample_init_func)(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
-                                    double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby);
+                                    double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby, int exact_rational);
 typedef void    (* resample_free_func)(struct ResampleContext **c);
 typedef int     (* multiple_resample_func)(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed);
 typedef int     (* resample_flush_func)(struct SwrContext *c);
@@ -126,6 +126,7 @@ struct SwrContext {
     int filter_size;                                /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
     int phase_shift;                                /**< log2 of the number of entries in the resampling polyphase filterbank */
     int linear_interp;                              /**< if 1 then the resampling FIR filter will be linearly interpolated */
+    int exact_rational;                             /**< if 1 then enable non power of 2 phase_count */
     double cutoff;                                  /**< resampling cutoff frequency (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */
     int filter_type;                                /**< swr resampling filter type */
     double kaiser_beta;                                /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
index 830f00e..b8e32c0 100644 (file)
@@ -29,8 +29,8 @@
 #include "libavutil/avutil.h"
 
 #define LIBSWRESAMPLE_VERSION_MAJOR   2
-#define LIBSWRESAMPLE_VERSION_MINOR   0
-#define LIBSWRESAMPLE_VERSION_MICRO 101
+#define LIBSWRESAMPLE_VERSION_MINOR   1
+#define LIBSWRESAMPLE_VERSION_MICRO 100
 
 #define LIBSWRESAMPLE_VERSION_INT  AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \
                                                   LIBSWRESAMPLE_VERSION_MINOR, \
index 9d7d5cf..f05397f 100644 (file)
@@ -47,6 +47,10 @@ av_cold void swri_resample_dsp_x86_init(ResampleContext *c)
 {
     int av_unused mm_flags = av_get_cpu_flags();
 
+    /* FIXME use phase_count on asm */
+    if (c->phase_count != 1 << c->phase_shift)
+        return;
+
     switch(c->format){
     case AV_SAMPLE_FMT_S16P:
         if (ARCH_X86_32 && EXTERNAL_MMXEXT(mm_flags)) {