support odd phase_count stick to low phase_count until set_compensation is called
Signed-off-by: Muhammad Faiz <mfc...@gmail.com> --- libswresample/resample.c | 83 +++++++++++++++++++++++++++++++++++++++++------- libswresample/resample.h | 1 + 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/libswresample/resample.c b/libswresample/resample.c index 1b1d83e..3b01408 100644 --- a/libswresample/resample.c +++ b/libswresample/resample.c @@ -144,9 +144,10 @@ static double bessel(double x) { static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale, int filter_type, double kaiser_beta){ int ph, i; + int ph_nb = phase_count % 2 ? phase_count : phase_count / 2 + 1; double x, y, w, t, s; double *tab = av_malloc_array(tap_count+1, sizeof(*tab)); - double *sin_lut = av_malloc_array(phase_count / 2 + 1, sizeof(*sin_lut)); + double *sin_lut = av_malloc_array(ph_nb, sizeof(*sin_lut)); const int center= (tap_count-1)/2; if (!tab || !sin_lut) @@ -156,13 +157,11 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap if (factor > 1.0) factor = 1.0; - av_assert0(phase_count == 1 || phase_count % 2 == 0); - if (factor == 1.0) { - for (ph = 0; ph <= phase_count / 2; ph++) + for (ph = 0; ph < ph_nb; ph++) sin_lut[ph] = sin(M_PI * ph / phase_count); } - for(ph = 0; ph <= phase_count / 2; ph++) { + for(ph = 0; ph < ph_nb; ph++) { double norm = 0; s = sin_lut[ph]; for(i=0;i<=tap_count;i++) { @@ -203,6 +202,7 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap case AV_SAMPLE_FMT_S16P: for(i=0;i<tap_count;i++) ((int16_t*)filter)[ph * alloc + i] = av_clip_int16(lrintf(tab[i] * scale / norm)); + if (phase_count % 2) break; if (tap_count % 2 == 0 || tap_count == 1) { for (i = 0; i < tap_count; i++) ((int16_t*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((int16_t*)filter)[ph * alloc + i]; @@ -216,6 +216,7 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap case AV_SAMPLE_FMT_S32P: for(i=0;i<tap_count;i++) ((int32_t*)filter)[ph * alloc + i] = av_clipl_int32(llrint(tab[i] * scale / norm)); + if (phase_count % 2) break; if (tap_count % 2 == 0 || tap_count == 1) { for (i = 0; i < tap_count; i++) ((int32_t*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((int32_t*)filter)[ph * alloc + i]; @@ -229,6 +230,7 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap case AV_SAMPLE_FMT_FLTP: for(i=0;i<tap_count;i++) ((float*)filter)[ph * alloc + i] = tab[i] * scale / norm; + if (phase_count % 2) break; if (tap_count % 2 == 0 || tap_count == 1) { for (i = 0; i < tap_count; i++) ((float*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((float*)filter)[ph * alloc + i]; @@ -241,6 +243,7 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap case AV_SAMPLE_FMT_DBLP: for(i=0;i<tap_count;i++) ((double*)filter)[ph * alloc + i] = tab[i] * scale / norm; + if (phase_count % 2) break; if (tap_count % 2 == 0 || tap_count == 1) { for (i = 0; i < tap_count; i++) ((double*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((double*)filter)[ph * alloc + i]; @@ -302,18 +305,14 @@ static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_r double cutoff = cutoff0? cutoff0 : 0.97; double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); int phase_count= 1<<phase_shift; + int phase_count_comp = phase_count; 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_comp = phase_count_exact * (phase_count / phase_count_exact); phase_count = phase_count_exact; } } @@ -360,6 +359,7 @@ static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_r c->filter_bank = av_calloc(c->filter_alloc, (phase_count+1)*c->felem_size); c->filter_type = filter_type; c->kaiser_beta = kaiser_beta; + c->phase_count_comp = phase_count_comp; if (!c->filter_bank) goto error; if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, filter_type, kaiser_beta)) @@ -382,6 +382,9 @@ static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_r c->index= -phase_count*((c->filter_length-1)/2); c->frac= 0; + /*av_log(NULL, AV_LOG_ERROR, "phase_count = %d, dst_incr = %d (%d + %d/%d)\n", + c->phase_count, c->dst_incr, c->dst_incr_div, c->dst_incr_mod, c->src_incr);*/ + swri_resample_dsp_init(c); return c; @@ -398,7 +401,65 @@ static void resample_free(ResampleContext **c){ av_freep(c); } +static int rebuild_filter_bank_with_compensation(ResampleContext *c) +{ + uint8_t *new_filter_bank; + int new_src_incr, new_dst_incr; + int phase_count = c->phase_count_comp; + int ret; + + if (phase_count == c->phase_count) + return 0; + + av_assert0(!c->frac && !c->dst_incr_mod && !c->compensation_distance); + + new_filter_bank = av_calloc(c->filter_alloc, (phase_count + 1) * c->felem_size); + if (!new_filter_bank) + return AVERROR(ENOMEM); + + ret = build_filter(c, new_filter_bank, c->factor, c->filter_length, c->filter_alloc, + phase_count, 1 << c->filter_shift, c->filter_type, c->kaiser_beta); + if (ret < 0) { + av_freep(&new_filter_bank); + return ret; + } + memcpy(new_filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, new_filter_bank, (c->filter_alloc-1)*c->felem_size); + memcpy(new_filter_bank + (c->filter_alloc*phase_count )*c->felem_size, new_filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); + + if (!av_reduce(&new_src_incr, &new_dst_incr, c->src_incr, + c->dst_incr * (int64_t)(c->phase_count_comp/c->phase_count), INT32_MAX/2)) + { + av_freep(&new_filter_bank); + return AVERROR(EINVAL); + } + + c->src_incr = new_src_incr; + c->dst_incr = new_dst_incr; + while (c->dst_incr < (1<<20) && c->src_incr < (1<<20)) { + c->dst_incr *= 2; + c->src_incr *= 2; + } + c->ideal_dst_incr = c->dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + c->index *= c->phase_count_comp/c->phase_count; + c->phase_count = c->phase_count_comp; + av_freep(&c->filter_bank); + c->filter_bank = new_filter_bank; + /*av_log(NULL, AV_LOG_ERROR, "phase_count = %d, dst_incr = %d (%d + %d/%d)\n", + c->phase_count, c->dst_incr, c->dst_incr_div, c->dst_incr_mod, c->src_incr);*/ + return 0; +} + static int set_compensation(ResampleContext *c, int sample_delta, int compensation_distance){ + int ret; + + if (compensation_distance) { + ret = rebuild_filter_bank_with_compensation(c); + if (ret < 0) + return ret; + } + c->compensation_distance= compensation_distance; if (compensation_distance) c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; diff --git a/libswresample/resample.h b/libswresample/resample.h index 53788c4..2c29959 100644 --- a/libswresample/resample.h +++ b/libswresample/resample.h @@ -51,6 +51,7 @@ typedef struct ResampleContext { enum AVSampleFormat format; int felem_size; int filter_shift; + int phase_count_comp; struct { void (*resample_one)(void *dst, const void *src, -- 2.5.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel