mirror of https://git.ffmpeg.org/ffmpeg.git
swr: resampling: add filter type and Kaiser window beta to AVOptions
This commit is contained in:
parent
a7ac05ce2f
commit
7e15df7551
|
@ -29,9 +29,6 @@
|
||||||
#include "libavutil/avassert.h"
|
#include "libavutil/avassert.h"
|
||||||
#include "swresample_internal.h"
|
#include "swresample_internal.h"
|
||||||
|
|
||||||
#define WINDOW_TYPE 9
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ResampleContext {
|
typedef struct ResampleContext {
|
||||||
const AVClass *av_class;
|
const AVClass *av_class;
|
||||||
|
@ -47,6 +44,8 @@ typedef struct ResampleContext {
|
||||||
int phase_shift;
|
int phase_shift;
|
||||||
int phase_mask;
|
int phase_mask;
|
||||||
int linear;
|
int linear;
|
||||||
|
enum SwrFilterType filter_type;
|
||||||
|
int kaiser_beta;
|
||||||
double factor;
|
double factor;
|
||||||
enum AVSampleFormat format;
|
enum AVSampleFormat format;
|
||||||
int felem_size;
|
int felem_size;
|
||||||
|
@ -87,10 +86,12 @@ static double bessel(double x){
|
||||||
* builds a polyphase filterbank.
|
* builds a polyphase filterbank.
|
||||||
* @param factor resampling factor
|
* @param factor resampling factor
|
||||||
* @param scale wanted sum of coefficients for each filter
|
* @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
|
* @param filter_type filter type
|
||||||
|
* @param kaiser_beta kaiser window beta
|
||||||
* @return 0 on success, negative on error
|
* @return 0 on success, negative on error
|
||||||
*/
|
*/
|
||||||
static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale, int type){
|
static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale,
|
||||||
|
int filter_type, int kaiser_beta){
|
||||||
int ph, i;
|
int ph, i;
|
||||||
double x, y, w;
|
double x, y, w;
|
||||||
double *tab = av_malloc(tap_count * sizeof(*tab));
|
double *tab = av_malloc(tap_count * sizeof(*tab));
|
||||||
|
@ -109,21 +110,23 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap
|
||||||
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
|
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
|
||||||
if (x == 0) y = 1.0;
|
if (x == 0) y = 1.0;
|
||||||
else y = sin(x) / x;
|
else y = sin(x) / x;
|
||||||
switch(type){
|
switch(filter_type){
|
||||||
case 0:{
|
case SWR_FILTER_TYPE_CUBIC:{
|
||||||
const float d= -0.5; //first order derivative = -0.5
|
const float d= -0.5; //first order derivative = -0.5
|
||||||
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
|
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
|
||||||
if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
|
if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
|
||||||
else y= d*(-4 + 8*x - 5*x*x + x*x*x);
|
else y= d*(-4 + 8*x - 5*x*x + x*x*x);
|
||||||
break;}
|
break;}
|
||||||
case 1:
|
case SWR_FILTER_TYPE_BLACKMAN_NUTTALL:
|
||||||
w = 2.0*x / (factor*tap_count) + M_PI;
|
w = 2.0*x / (factor*tap_count) + M_PI;
|
||||||
y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
|
y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
|
||||||
break;
|
break;
|
||||||
default:
|
case SWR_FILTER_TYPE_KAISER:
|
||||||
w = 2.0*x / (factor*tap_count*M_PI);
|
w = 2.0*x / (factor*tap_count*M_PI);
|
||||||
y *= bessel(type*sqrt(FFMAX(1-w*w, 0)));
|
y *= bessel(kaiser_beta*sqrt(FFMAX(1-w*w, 0)));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
av_assert0(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
tab[i] = y;
|
tab[i] = y;
|
||||||
|
@ -191,12 +194,14 @@ static int build_filter(ResampleContext *c, void *filter, double factor, int tap
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResampleContext *swri_resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat format){
|
ResampleContext *swri_resample_init(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, int kaiser_beta){
|
||||||
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
|
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
|
||||||
int phase_count= 1<<phase_shift;
|
int phase_count= 1<<phase_shift;
|
||||||
|
|
||||||
if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor
|
if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor
|
||||||
|| c->filter_length != FFMAX((int)ceil(filter_size/factor), 1) || c->format != format) {
|
|| 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));
|
c = av_mallocz(sizeof(*c));
|
||||||
if (!c)
|
if (!c)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -228,9 +233,11 @@ ResampleContext *swri_resample_init(ResampleContext *c, int out_rate, int in_rat
|
||||||
c->filter_length = FFMAX((int)ceil(filter_size/factor), 1);
|
c->filter_length = FFMAX((int)ceil(filter_size/factor), 1);
|
||||||
c->filter_alloc = FFALIGN(c->filter_length, 8);
|
c->filter_alloc = FFALIGN(c->filter_length, 8);
|
||||||
c->filter_bank = av_mallocz(c->filter_alloc*(phase_count+1)*c->felem_size);
|
c->filter_bank = av_mallocz(c->filter_alloc*(phase_count+1)*c->felem_size);
|
||||||
|
c->filter_type = filter_type;
|
||||||
|
c->kaiser_beta = kaiser_beta;
|
||||||
if (!c->filter_bank)
|
if (!c->filter_bank)
|
||||||
goto error;
|
goto error;
|
||||||
if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, WINDOW_TYPE))
|
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))
|
||||||
goto error;
|
goto error;
|
||||||
memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size);
|
memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size);
|
||||||
memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size);
|
memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size);
|
||||||
|
|
|
@ -88,6 +88,11 @@ static const AVOption options[]={
|
||||||
, OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM },
|
, OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM },
|
||||||
{"max_soft_comp" , "Maximum factor by which data is stretched/squeezed to make it match the timestamps."
|
{"max_soft_comp" , "Maximum factor by which data is stretched/squeezed to make it match the timestamps."
|
||||||
, OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM },
|
, OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM },
|
||||||
|
{ "filter_type" , "Filter Type" , OFFSET(filter_type) , AV_OPT_TYPE_INT , { SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, "filter_type" },
|
||||||
|
{ "cubic" , "Cubic" , 0 , AV_OPT_TYPE_CONST, { SWR_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" },
|
||||||
|
{ "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0 , AV_OPT_TYPE_CONST, { SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" },
|
||||||
|
{ "kaiser" , "Kaiser Windowed Sinc" , 0 , AV_OPT_TYPE_CONST, { SWR_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" },
|
||||||
|
{ "kaiser_beta" , "Kaiser Window Beta" ,OFFSET(kaiser_beta) , AV_OPT_TYPE_INT , {.dbl=9 }, 2 , 16 , PARAM },
|
||||||
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
@ -244,7 +249,7 @@ int swr_init(struct SwrContext *s){
|
||||||
set_audiodata_fmt(&s->out, s->out_sample_fmt);
|
set_audiodata_fmt(&s->out, s->out_sample_fmt);
|
||||||
|
|
||||||
if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){
|
if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){
|
||||||
s->resample = swri_resample_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->resample = swri_resample_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);
|
||||||
}else
|
}else
|
||||||
swri_resample_free(&s->resample);
|
swri_resample_free(&s->resample);
|
||||||
if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P
|
if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P
|
||||||
|
|
|
@ -53,6 +53,13 @@ enum SwrDitherType {
|
||||||
SWR_DITHER_NB, ///< not part of API/ABI
|
SWR_DITHER_NB, ///< not part of API/ABI
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Resampling Filter Types */
|
||||||
|
enum SwrFilterType {
|
||||||
|
SWR_FILTER_TYPE_CUBIC, /**< Cubic */
|
||||||
|
SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */
|
||||||
|
SWR_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct SwrContext SwrContext;
|
typedef struct SwrContext SwrContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -63,6 +63,8 @@ struct SwrContext {
|
||||||
int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
|
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 linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */
|
||||||
double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */
|
double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */
|
||||||
|
enum SwrFilterType filter_type; /**< resampling filter type */
|
||||||
|
int kaiser_beta; /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
|
||||||
|
|
||||||
float min_compensation; ///< minimum below which no compensation will happen
|
float min_compensation; ///< minimum below which no compensation will happen
|
||||||
float min_hard_compensation; ///< minimum below which no silence inject / sample drop will happen
|
float min_hard_compensation; ///< minimum below which no silence inject / sample drop will happen
|
||||||
|
@ -109,7 +111,7 @@ struct SwrContext {
|
||||||
/* TODO: callbacks for ASM optimizations */
|
/* TODO: callbacks for ASM optimizations */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResampleContext *swri_resample_init(struct ResampleContext *, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat);
|
struct ResampleContext *swri_resample_init(struct ResampleContext *, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat, enum SwrFilterType, int kaiser_beta);
|
||||||
void swri_resample_free(struct ResampleContext **c);
|
void swri_resample_free(struct ResampleContext **c);
|
||||||
int swri_multiple_resample(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed);
|
int swri_multiple_resample(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed);
|
||||||
void swri_resample_compensate(struct ResampleContext *c, int sample_delta, int compensation_distance);
|
void swri_resample_compensate(struct ResampleContext *c, int sample_delta, int compensation_distance);
|
||||||
|
|
Loading…
Reference in New Issue