On 01/06/12 21:42, Justin Ruggles wrote:
> Based partially on implementation by Michael Niedermayer <[email protected]> in
> libswresample in FFmpeg. See commits:
> 7f1ae79d38c4edba9dbd31d7bf797e525298ac55
> 24ab1abfb6d55bf330022df4b10d7aec80b3f116
> ---
>  libavresample/resample.c          |  205 
> +++++++++++++++++++++----------------
>  libavresample/resample_template.c |   65 ++++++++++++
>  libavresample/utils.c             |   22 ++++-
>  3 files changed, 204 insertions(+), 88 deletions(-)
>  create mode 100644 libavresample/resample_template.c
> 
> diff --git a/libavresample/resample.c b/libavresample/resample.c
> index da0e2c2..3f90d98 100644
> --- a/libavresample/resample.c
> +++ b/libavresample/resample.c
> @@ -24,34 +24,10 @@
>  #include "internal.h"
>  #include "audio_data.h"
>  
> -#ifdef CONFIG_RESAMPLE_FLT
> -/* float template */
> -#define FILTER_SHIFT  0
> -#define FELEM         float
> -#define FELEM2        float
> -#define FELEML        float
> -#elifdef CONFIG_RESAMPLE_S32
> -/* s32 template */
> -#define FILTER_SHIFT  30
> -#define FELEM         int32_t
> -#define FELEM2        int64_t
> -#define FELEML        int64_t
> -#define FELEM_MAX     INT32_MAX
> -#define FELEM_MIN     INT32_MIN
> -#else
> -/* s16 template */
> -#define FILTER_SHIFT  15
> -#define FELEM         int16_t
> -#define FELEM2        int32_t
> -#define FELEML        int64_t
> -#define FELEM_MAX     INT16_MAX
> -#define FELEM_MIN     INT16_MIN
> -#endif
> -
>  struct ResampleContext {
>      AVAudioResampleContext *avr;
>      AudioData *buffer;
> -    FELEM *filter_bank;
> +    uint8_t *filter_bank;
>      int filter_length;
>      int ideal_dst_incr;
>      int dst_incr;
> @@ -65,8 +41,74 @@ struct ResampleContext {
>      enum AVResampleFilterType filter_type;
>      int kaiser_beta;
>      double factor;
> +    void (*set_filter)(void *filter, double *tab, int phase, int tap_count);
> +    void (*resample_one)(struct ResampleContext *c, int no_filter, void 
> *dst0,
> +                         int dst_index, const void *src0, int src_size,
> +                         int index, int frac);
>  };
>  
> +/* double template */
> +#define RENAME(func)  func ## _ ## dbl
> +#define FILTER_SHIFT  0
> +#define FELEM         double
> +#define FELEM2        double
> +#define FELEML        double
> +#define OUT(d, v) d = v
> +#define DBL_TO_FELEM(d, v) d = v
> +#include "resample_template.c"
> +#undef RENAME
> +#undef FILTER_SHIFT
> +#undef FELEM
> +#undef FELEM2
> +#undef FELEML
> +#undef OUT
> +#undef DBL_TO_FELEM
> +
> +/* float template */
> +#define RENAME(func)  func ## _ ## flt
> +#define FILTER_SHIFT  0
> +#define FELEM         float
> +#define FELEM2        float
> +#define FELEML        float
> +#define OUT(d, v) d = v
> +#define DBL_TO_FELEM(d, v) d = v
> +#include "resample_template.c"
> +#undef RENAME
> +#undef FILTER_SHIFT
> +#undef FELEM
> +#undef FELEM2
> +#undef FELEML
> +#undef OUT
> +#undef DBL_TO_FELEM
> +
> +/* s32 template */
> +#define RENAME(func)  func ## _ ## s32
> +#define FILTER_SHIFT  30
> +#define FELEM         int32_t
> +#define FELEM2        int64_t
> +#define FELEML        int64_t
> +#define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30)
> +#define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 
> FILTER_SHIFT)));
> +#include "resample_template.c"
> +#undef RENAME
> +#undef FILTER_SHIFT
> +#undef FELEM
> +#undef FELEM2
> +#undef FELEML
> +#undef OUT
> +#undef DBL_TO_FELEM
> +
> +/* s16 template */
> +#define RENAME(func)  func ## _ ## s16
> +#define FILTER_SHIFT  15
> +#define FELEM         int16_t
> +#define FELEM2        int32_t
> +#define FELEML        int64_t
> +#define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15)
> +#define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << FILTER_SHIFT)))
> +#include "resample_template.c"
> +
> +
>  /**
>   * 0th order modified bessel function of the first kind.
>   */
> @@ -98,13 +140,13 @@ static double bessel(double x)
>   * @param      kaiser_beta  kaiser window beta
>   * @return                  0 on success, negative AVERROR code on failure
>   */
> -static int build_filter(FELEM *filter, double factor, int tap_count,
> -                        int phase_count, int scale, int filter_type,
> -                        int kaiser_beta)
> +static int build_filter(ResampleContext *c)
>  {
>      int ph, i;
> -    double x, y, w;
> +    double x, y, w, factor;
>      double *tab;
> +    int tap_count    = c->filter_length;
> +    int phase_count  = 1 << c->phase_shift;
>      const int center = (tap_count - 1) / 2;
>  
>      tab = av_malloc(tap_count * sizeof(*tab));
> @@ -112,8 +154,7 @@ static int build_filter(FELEM *filter, double factor, int 
> tap_count,
>          return AVERROR(ENOMEM);
>  
>      /* if upsampling, only need to interpolate, no filter */
> -    if (factor > 1.0)
> -        factor = 1.0;
> +    factor = FFMIN(c->factor, 1.0);
>  
>      for (ph = 0; ph < phase_count; ph++) {
>          double norm = 0;
> @@ -121,7 +162,7 @@ static int build_filter(FELEM *filter, double factor, int 
> tap_count,
>              x = M_PI * ((double)(i - center) - (double)ph / phase_count) * 
> factor;
>              if (x == 0) y = 1.0;
>              else        y = sin(x) / x;
> -            switch (filter_type) {
> +            switch (c->filter_type) {
>              case AV_FILTER_TYPE_CUBIC: {
>                  const float d = -0.5; //first order derivative = -0.5
>                  x = fabs(((double)(i - center) - (double)ph / phase_count) * 
> factor);
> @@ -137,23 +178,18 @@ static int build_filter(FELEM *filter, double factor, 
> int tap_count,
>                  break;
>              case AV_FILTER_TYPE_KAISER:
>                  w  = 2.0 * x / (factor * tap_count * M_PI);
> -                y *= bessel(kaiser_beta * sqrt(FFMAX(1 - w * w, 0)));
> +                y *= bessel(c->kaiser_beta * sqrt(FFMAX(1 - w * w, 0)));
>                  break;
>              }
>  
>              tab[i] = y;
>              norm  += y;
>          }
> -
>          /* normalize so that an uniform color remains the same */
> -        for (i = 0; i < tap_count; i++) {
> -#ifdef CONFIG_RESAMPLE_FLT
> -            filter[ph * tap_count + i] = tab[i] / norm;
> -#else
> -            filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / 
> norm),
> -                                                 FELEM_MIN, FELEM_MAX);
> -#endif
> -        }
> +        for (i = 0; i < tap_count; i++)
> +            tab[i] = tab[i] / norm;
> +
> +        c->set_filter(c->filter_bank, tab, ph, tap_count);
>      }
>  
>      av_free(tab);
> @@ -167,9 +203,12 @@ ResampleContext 
> *ff_audio_resample_init(AVAudioResampleContext *avr)
>      int in_rate     = avr->in_sample_rate;
>      double factor   = FFMIN(out_rate * avr->cutoff / in_rate, 1.0);
>      int phase_count = 1 << avr->phase_shift;
> +    int felem_size;
>  
> -    /* TODO: add support for s32 and float internal formats */
> -    if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) {
> +    if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
> +        avr->internal_sample_fmt != AV_SAMPLE_FMT_S32P &&
> +        avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP &&
> +        avr->internal_sample_fmt != AV_SAMPLE_FMT_DBLP) {
>          av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
>                 "resampling: %s\n",
>                 av_get_sample_fmt_name(avr->internal_sample_fmt));
> @@ -188,17 +227,37 @@ ResampleContext 
> *ff_audio_resample_init(AVAudioResampleContext *avr)
>      c->filter_type   = avr->filter_type;
>      c->kaiser_beta   = avr->kaiser_beta;
>  
> -    c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * 
> sizeof(FELEM));
> +    switch (avr->internal_sample_fmt) {
> +    case AV_SAMPLE_FMT_DBLP:
> +        c->resample_one  = resample_one_dbl;
> +        c->set_filter    = set_filter_dbl;
> +        break;
> +    case AV_SAMPLE_FMT_FLTP:
> +        c->resample_one  = resample_one_flt;
> +        c->set_filter    = set_filter_flt;
> +        break;
> +    case AV_SAMPLE_FMT_S32P:
> +        c->resample_one  = resample_one_s32;
> +        c->set_filter    = set_filter_s32;
> +        break;
> +    case AV_SAMPLE_FMT_S16P:
> +        c->resample_one  = resample_one_s16;
> +        c->set_filter    = set_filter_s16;
> +        break;
> +    }
> +
> +    felem_size = av_get_bytes_per_sample(avr->internal_sample_fmt);
> +    c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * 
> felem_size);
>      if (!c->filter_bank)
>          goto error;
>  
> -    if (build_filter(c->filter_bank, factor, c->filter_length, phase_count,
> -                     1 << FILTER_SHIFT, c->filter_type, c->kaiser_beta) < 0)
> +    if (build_filter(c) < 0)
>          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];
> +    memcpy(&c->filter_bank[(c->filter_length * phase_count + 1) * 
> felem_size],
> +           c->filter_bank, (c->filter_length - 1) * felem_size);
> +    memcpy(&c->filter_bank[c->filter_length * phase_count * felem_size],
> +           &c->filter_bank[(c->filter_length - 1) * felem_size], felem_size);
>  
>      c->compensation_distance = 0;
>      if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate,
> @@ -312,10 +371,10 @@ reinit_fail:
>      return ret;
>  }
>  
> -static int resample(ResampleContext *c, int16_t *dst, const int16_t *src,
> +static int resample(ResampleContext *c, void *dst, const void *src,
>                      int *consumed, int src_size, int dst_size, int 
> update_ctx)
>  {
> -    int dst_index, i;
> +    int dst_index;
>      int index         = c->index;
>      int frac          = c->frac;
>      int dst_incr_frac = c->dst_incr % c->src_incr;
> @@ -335,7 +394,7 @@ static int resample(ResampleContext *c, int16_t *dst, 
> const int16_t *src,
>  
>          if (dst) {
>              for(dst_index = 0; dst_index < dst_size; dst_index++) {
> -                dst[dst_index] = src[index2 >> 32];
> +                c->resample_one(c, 1, dst, dst_index, src, 0, index2 >> 32, 
> 0);
>                  index2 += incr;
>              }
>          } else {
> @@ -346,42 +405,14 @@ static int resample(ResampleContext *c, int16_t *dst, 
> const int16_t *src,
>          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);
>              int sample_index = index >> c->phase_shift;
>  
> -            if (!dst && (sample_index + c->filter_length > src_size ||
> -                         -sample_index >= src_size))
> +            if (sample_index + c->filter_length > src_size ||
> +                -sample_index >= src_size)
>                  break;
>  
> -            if (dst) {
> -                FELEM2 val = 0;
> -
> -                if (sample_index < 0) {
> -                    for (i = 0; i < c->filter_length; i++)
> -                        val += src[FFABS(sample_index + i) % src_size] *
> -                               (FELEM2)filter[i];
> -                } else if (sample_index + c->filter_length > src_size) {
> -                    break;
> -                } else if (c->linear) {
> -                    FELEM2 v2 = 0;
> -                    for (i = 0; i < c->filter_length; i++) {
> -                        val += src[abs(sample_index + i)] * 
> (FELEM2)filter[i];
> -                        v2  += src[abs(sample_index + i)] * (FELEM2)filter[i 
> + c->filter_length];
> -                    }
> -                    val += (v2 - val) * (FELEML)frac / c->src_incr;
> -                } else {
> -                    for (i = 0; i < c->filter_length; i++)
> -                        val += src[sample_index + i] * (FELEM2)filter[i];
> -                }
> -
> -#ifdef CONFIG_RESAMPLE_FLT
> -                dst[dst_index] = av_clip_int16(lrintf(val));
> -#else
> -                val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;
> -                dst[dst_index] = av_clip_int16(val);
> -#endif
> -            }
> +            if (dst)
> +                c->resample_one(c, 0, dst, dst_index, src, src_size, index, 
> frac);
>  
>              frac  += dst_incr_frac;
>              index += dst_incr;
> @@ -452,8 +483,8 @@ int ff_audio_resample(ResampleContext *c, AudioData *dst, 
> AudioData *src,
>  
>      /* resample each channel plane */
>      for (ch = 0; ch < c->buffer->channels; ch++) {
> -        out_samples = resample(c, (int16_t *)dst->data[ch],
> -                               (const int16_t *)c->buffer->data[ch], 
> consumed,
> +        out_samples = resample(c, (void *)dst->data[ch],
> +                               (const void *)c->buffer->data[ch], consumed,
>                                 c->buffer->nb_samples, dst->allocated_samples,
>                                 ch + 1 == c->buffer->channels);
>      }
> diff --git a/libavresample/resample_template.c 
> b/libavresample/resample_template.c
> new file mode 100644
> index 0000000..f0cfb45
> --- /dev/null
> +++ b/libavresample/resample_template.c

Not sure how a macro generator would be better than this contraption.
Experience with swscale probably makes me overly wary of this kind of
templating.

lu

-- 

Luca Barbato
Gentoo/linux
http://dev.gentoo.org/~lu_zero

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to