[FFmpeg-devel] [PATCH 1/2] swresample: fix phase_count calculation
Muhammad Faiz
mfcc64 at gmail.com
Wed Jun 15 19:31:03 CEST 2016
support odd phase_count
stick to low phase_count until set_compensation is called
Signed-off-by: Muhammad Faiz <mfcc64 at 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
More information about the ffmpeg-devel
mailing list