mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-28 12:32:17 +02:00
avfilter/af_afreqshift: add fltp sample format support
This commit is contained in:
parent
5148740e79
commit
bf4b9e933f
@ -34,7 +34,8 @@ typedef struct AFreqShift {
|
|||||||
double shift;
|
double shift;
|
||||||
double level;
|
double level;
|
||||||
|
|
||||||
double c[NB_COEFS];
|
double cd[NB_COEFS];
|
||||||
|
float cf[NB_COEFS];
|
||||||
|
|
||||||
int64_t in_samples;
|
int64_t in_samples;
|
||||||
|
|
||||||
@ -42,11 +43,8 @@ typedef struct AFreqShift {
|
|||||||
AVFrame *i2, *o2;
|
AVFrame *i2, *o2;
|
||||||
|
|
||||||
void (*filter_channel)(AVFilterContext *ctx,
|
void (*filter_channel)(AVFilterContext *ctx,
|
||||||
int nb_samples,
|
int channel,
|
||||||
int sample_rate,
|
AVFrame *in, AVFrame *out);
|
||||||
const double *src, double *dst,
|
|
||||||
double *i1, double *o1,
|
|
||||||
double *i2, double *o2);
|
|
||||||
} AFreqShift;
|
} AFreqShift;
|
||||||
|
|
||||||
static int query_formats(AVFilterContext *ctx)
|
static int query_formats(AVFilterContext *ctx)
|
||||||
@ -54,6 +52,7 @@ static int query_formats(AVFilterContext *ctx)
|
|||||||
AVFilterFormats *formats = NULL;
|
AVFilterFormats *formats = NULL;
|
||||||
AVFilterChannelLayouts *layouts = NULL;
|
AVFilterChannelLayouts *layouts = NULL;
|
||||||
static const enum AVSampleFormat sample_fmts[] = {
|
static const enum AVSampleFormat sample_fmts[] = {
|
||||||
|
AV_SAMPLE_FMT_FLTP,
|
||||||
AV_SAMPLE_FMT_DBLP,
|
AV_SAMPLE_FMT_DBLP,
|
||||||
AV_SAMPLE_FMT_NONE
|
AV_SAMPLE_FMT_NONE
|
||||||
};
|
};
|
||||||
@ -78,89 +77,105 @@ static int query_formats(AVFilterContext *ctx)
|
|||||||
return ff_set_common_samplerates(ctx, formats);
|
return ff_set_common_samplerates(ctx, formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pfilter_channel(AVFilterContext *ctx,
|
#define PFILTER(name, type, sin, cos, cc) \
|
||||||
int nb_samples,
|
static void pfilter_channel_## name(AVFilterContext *ctx, \
|
||||||
int sample_rate,
|
int ch, \
|
||||||
const double *src, double *dst,
|
AVFrame *in, AVFrame *out) \
|
||||||
double *i1, double *o1,
|
{ \
|
||||||
double *i2, double *o2)
|
AFreqShift *s = ctx->priv; \
|
||||||
{
|
const int nb_samples = in->nb_samples; \
|
||||||
AFreqShift *s = ctx->priv;
|
const type *src = (const type *)in->extended_data[ch]; \
|
||||||
const double *c = s->c;
|
type *dst = (type *)out->extended_data[ch]; \
|
||||||
const double level = s->level;
|
type *i1 = (type *)s->i1->extended_data[ch]; \
|
||||||
double shift = s->shift * M_PI;
|
type *o1 = (type *)s->o1->extended_data[ch]; \
|
||||||
double cos_theta = cos(shift);
|
type *i2 = (type *)s->i2->extended_data[ch]; \
|
||||||
double sin_theta = sin(shift);
|
type *o2 = (type *)s->o2->extended_data[ch]; \
|
||||||
|
const type *c = s->cc; \
|
||||||
for (int n = 0; n < nb_samples; n++) {
|
const type level = s->level; \
|
||||||
double xn1 = src[n], xn2 = src[n];
|
type shift = s->shift * M_PI; \
|
||||||
double I, Q;
|
type cos_theta = cos(shift); \
|
||||||
|
type sin_theta = sin(shift); \
|
||||||
for (int j = 0; j < NB_COEFS / 2; j++) {
|
\
|
||||||
I = c[j] * (xn1 + o2[j]) - i2[j];
|
for (int n = 0; n < nb_samples; n++) { \
|
||||||
i2[j] = i1[j];
|
type xn1 = src[n], xn2 = src[n]; \
|
||||||
i1[j] = xn1;
|
type I, Q; \
|
||||||
o2[j] = o1[j];
|
\
|
||||||
o1[j] = I;
|
for (int j = 0; j < NB_COEFS / 2; j++) { \
|
||||||
xn1 = I;
|
I = c[j] * (xn1 + o2[j]) - i2[j]; \
|
||||||
}
|
i2[j] = i1[j]; \
|
||||||
|
i1[j] = xn1; \
|
||||||
for (int j = NB_COEFS / 2; j < NB_COEFS; j++) {
|
o2[j] = o1[j]; \
|
||||||
Q = c[j] * (xn2 + o2[j]) - i2[j];
|
o1[j] = I; \
|
||||||
i2[j] = i1[j];
|
xn1 = I; \
|
||||||
i1[j] = xn2;
|
} \
|
||||||
o2[j] = o1[j];
|
\
|
||||||
o1[j] = Q;
|
for (int j = NB_COEFS / 2; j < NB_COEFS; j++) { \
|
||||||
xn2 = Q;
|
Q = c[j] * (xn2 + o2[j]) - i2[j]; \
|
||||||
}
|
i2[j] = i1[j]; \
|
||||||
Q = o2[NB_COEFS - 1];
|
i1[j] = xn2; \
|
||||||
|
o2[j] = o1[j]; \
|
||||||
dst[n] = (I * cos_theta - Q * sin_theta) * level;
|
o1[j] = Q; \
|
||||||
}
|
xn2 = Q; \
|
||||||
|
} \
|
||||||
|
Q = o2[NB_COEFS - 1]; \
|
||||||
|
\
|
||||||
|
dst[n] = (I * cos_theta - Q * sin_theta) * level; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ffilter_channel(AVFilterContext *ctx,
|
PFILTER(flt, float, sin, cos, cf)
|
||||||
int nb_samples,
|
PFILTER(dbl, double, sin, cos, cd)
|
||||||
int sample_rate,
|
|
||||||
const double *src, double *dst,
|
|
||||||
double *i1, double *o1,
|
|
||||||
double *i2, double *o2)
|
|
||||||
{
|
|
||||||
AFreqShift *s = ctx->priv;
|
|
||||||
const double *c = s->c;
|
|
||||||
const double level = s->level;
|
|
||||||
double ts = 1. / sample_rate;
|
|
||||||
double shift = s->shift;
|
|
||||||
int64_t N = s->in_samples;
|
|
||||||
|
|
||||||
for (int n = 0; n < nb_samples; n++) {
|
#define FFILTER(name, type, sin, cos, fmod, cc) \
|
||||||
double xn1 = src[n], xn2 = src[n];
|
static void ffilter_channel_## name(AVFilterContext *ctx, \
|
||||||
double I, Q, theta;
|
int ch, \
|
||||||
|
AVFrame *in, AVFrame *out) \
|
||||||
for (int j = 0; j < NB_COEFS / 2; j++) {
|
{ \
|
||||||
I = c[j] * (xn1 + o2[j]) - i2[j];
|
AFreqShift *s = ctx->priv; \
|
||||||
i2[j] = i1[j];
|
const int nb_samples = in->nb_samples; \
|
||||||
i1[j] = xn1;
|
const type *src = (const type *)in->extended_data[ch]; \
|
||||||
o2[j] = o1[j];
|
type *dst = (type *)out->extended_data[ch]; \
|
||||||
o1[j] = I;
|
type *i1 = (type *)s->i1->extended_data[ch]; \
|
||||||
xn1 = I;
|
type *o1 = (type *)s->o1->extended_data[ch]; \
|
||||||
}
|
type *i2 = (type *)s->i2->extended_data[ch]; \
|
||||||
|
type *o2 = (type *)s->o2->extended_data[ch]; \
|
||||||
for (int j = NB_COEFS / 2; j < NB_COEFS; j++) {
|
const type *c = s->cc; \
|
||||||
Q = c[j] * (xn2 + o2[j]) - i2[j];
|
const type level = s->level; \
|
||||||
i2[j] = i1[j];
|
type ts = 1. / in->sample_rate; \
|
||||||
i1[j] = xn2;
|
type shift = s->shift; \
|
||||||
o2[j] = o1[j];
|
int64_t N = s->in_samples; \
|
||||||
o1[j] = Q;
|
\
|
||||||
xn2 = Q;
|
for (int n = 0; n < nb_samples; n++) { \
|
||||||
}
|
type xn1 = src[n], xn2 = src[n]; \
|
||||||
Q = o2[NB_COEFS - 1];
|
type I, Q, theta; \
|
||||||
|
\
|
||||||
theta = 2. * M_PI * fmod(shift * (N + n) * ts, 1.);
|
for (int j = 0; j < NB_COEFS / 2; j++) { \
|
||||||
dst[n] = (I * cos(theta) - Q * sin(theta)) * level;
|
I = c[j] * (xn1 + o2[j]) - i2[j]; \
|
||||||
}
|
i2[j] = i1[j]; \
|
||||||
|
i1[j] = xn1; \
|
||||||
|
o2[j] = o1[j]; \
|
||||||
|
o1[j] = I; \
|
||||||
|
xn1 = I; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
for (int j = NB_COEFS / 2; j < NB_COEFS; j++) { \
|
||||||
|
Q = c[j] * (xn2 + o2[j]) - i2[j]; \
|
||||||
|
i2[j] = i1[j]; \
|
||||||
|
i1[j] = xn2; \
|
||||||
|
o2[j] = o1[j]; \
|
||||||
|
o1[j] = Q; \
|
||||||
|
xn2 = Q; \
|
||||||
|
} \
|
||||||
|
Q = o2[NB_COEFS - 1]; \
|
||||||
|
\
|
||||||
|
theta = 2. * M_PI * fmod(shift * (N + n) * ts, 1.); \
|
||||||
|
dst[n] = (I * cos(theta) - Q * sin(theta)) * level; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FFILTER(flt, float, sinf, cosf, fmodf, cf)
|
||||||
|
FFILTER(dbl, double, sin, cos, fmod, cd)
|
||||||
|
|
||||||
static void compute_transition_param(double *K, double *Q, double transition)
|
static void compute_transition_param(double *K, double *Q, double transition)
|
||||||
{
|
{
|
||||||
double kksqrt, e, e2, e4, k, q;
|
double kksqrt, e, e2, e4, k, q;
|
||||||
@ -243,15 +258,19 @@ static double compute_coef(int index, double k, double q, int order)
|
|||||||
return coef;
|
return coef;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compute_coefs(double *coef_arr, int nbr_coefs, double transition)
|
static void compute_coefs(double *coef_arrd, float *coef_arrf, int nbr_coefs, double transition)
|
||||||
{
|
{
|
||||||
const int order = nbr_coefs * 2 + 1;
|
const int order = nbr_coefs * 2 + 1;
|
||||||
double k, q;
|
double k, q;
|
||||||
|
|
||||||
compute_transition_param(&k, &q, transition);
|
compute_transition_param(&k, &q, transition);
|
||||||
|
|
||||||
for (int n = 0; n < nbr_coefs; n++)
|
for (int n = 0; n < nbr_coefs; n++) {
|
||||||
coef_arr[(n / 2) + (n & 1) * nbr_coefs / 2] = compute_coef(n, k, q, order);
|
const int idx = (n / 2) + (n & 1) * nbr_coefs / 2;
|
||||||
|
|
||||||
|
coef_arrd[idx] = compute_coef(n, k, q, order);
|
||||||
|
coef_arrf[idx] = coef_arrd[idx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int config_input(AVFilterLink *inlink)
|
static int config_input(AVFilterLink *inlink)
|
||||||
@ -259,7 +278,7 @@ static int config_input(AVFilterLink *inlink)
|
|||||||
AVFilterContext *ctx = inlink->dst;
|
AVFilterContext *ctx = inlink->dst;
|
||||||
AFreqShift *s = ctx->priv;
|
AFreqShift *s = ctx->priv;
|
||||||
|
|
||||||
compute_coefs(s->c, NB_COEFS, 2. * 20. / inlink->sample_rate);
|
compute_coefs(s->cd, s->cf, NB_COEFS, 2. * 20. / inlink->sample_rate);
|
||||||
|
|
||||||
s->i1 = ff_get_audio_buffer(inlink, NB_COEFS);
|
s->i1 = ff_get_audio_buffer(inlink, NB_COEFS);
|
||||||
s->o1 = ff_get_audio_buffer(inlink, NB_COEFS);
|
s->o1 = ff_get_audio_buffer(inlink, NB_COEFS);
|
||||||
@ -268,10 +287,17 @@ static int config_input(AVFilterLink *inlink)
|
|||||||
if (!s->i1 || !s->o1 || !s->i2 || !s->o2)
|
if (!s->i1 || !s->o1 || !s->i2 || !s->o2)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
if (!strcmp(ctx->filter->name, "afreqshift"))
|
if (inlink->format == AV_SAMPLE_FMT_DBLP) {
|
||||||
s->filter_channel = ffilter_channel;
|
if (!strcmp(ctx->filter->name, "afreqshift"))
|
||||||
else
|
s->filter_channel = ffilter_channel_dbl;
|
||||||
s->filter_channel = pfilter_channel;
|
else
|
||||||
|
s->filter_channel = pfilter_channel_dbl;
|
||||||
|
} else {
|
||||||
|
if (!strcmp(ctx->filter->name, "afreqshift"))
|
||||||
|
s->filter_channel = ffilter_channel_flt;
|
||||||
|
else
|
||||||
|
s->filter_channel = pfilter_channel_flt;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -289,16 +315,8 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo
|
|||||||
const int start = (in->channels * jobnr) / nb_jobs;
|
const int start = (in->channels * jobnr) / nb_jobs;
|
||||||
const int end = (in->channels * (jobnr+1)) / nb_jobs;
|
const int end = (in->channels * (jobnr+1)) / nb_jobs;
|
||||||
|
|
||||||
for (int ch = start; ch < end; ch++) {
|
for (int ch = start; ch < end; ch++)
|
||||||
s->filter_channel(ctx, in->nb_samples,
|
s->filter_channel(ctx, ch, in, out);
|
||||||
in->sample_rate,
|
|
||||||
(const double *)in->extended_data[ch],
|
|
||||||
(double *)out->extended_data[ch],
|
|
||||||
(double *)s->i1->extended_data[ch],
|
|
||||||
(double *)s->o1->extended_data[ch],
|
|
||||||
(double *)s->i2->extended_data[ch],
|
|
||||||
(double *)s->o2->extended_data[ch]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user