On 2 January 2018 at 16:18, Paul B Mahol <one...@gmail.com> wrote: > Signed-off-by: Paul B Mahol <one...@gmail.com> > --- > doc/filters.texi | 14 +++ > libavfilter/Makefile | 1 + > libavfilter/af_aiir.c | 232 ++++++++++++++++++++++++++++++ > +++++++++++++++++ > libavfilter/allfilters.c | 1 + > 4 files changed, 248 insertions(+) > create mode 100644 libavfilter/af_aiir.c > > diff --git a/doc/filters.texi b/doc/filters.texi > index f651f1234d..ff911ad92e 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -1059,6 +1059,20 @@ the reduction. > Default is @code{average}. Can be @code{average} or @code{maximum}. > @end table > > +@section aiir > + > +Apply an arbitrary Infinite Impulse Response filter. > + > +It accepts the following parameters: > + > +@table @option > +@item a > +Set denominator coefficients. > + > +@item b > +Set nominator coefficients. > +@end table > + > @section alimiter > > The limiter prevents an input signal from rising over a desired threshold. > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 8bde542163..1fe58ed3d2 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -43,6 +43,7 @@ OBJS-$(CONFIG_AFFTFILT_FILTER) += > af_afftfilt.o > OBJS-$(CONFIG_AFIR_FILTER) += af_afir.o > OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o > OBJS-$(CONFIG_AGATE_FILTER) += af_agate.o > +OBJS-$(CONFIG_AIIR_FILTER) += af_aiir.o > OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o > OBJS-$(CONFIG_ALIMITER_FILTER) += af_alimiter.o > OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o > diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c > new file mode 100644 > index 0000000000..d1be9afa5e > --- /dev/null > +++ b/libavfilter/af_aiir.c > @@ -0,0 +1,232 @@ > +/* > + * Copyright (c) 2018 Paul B Mahol > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > 02110-1301 USA > + */ > + > +#include "libavutil/avassert.h" > +#include "libavutil/avstring.h" > +#include "libavutil/opt.h" > +#include "audio.h" > +#include "avfilter.h" > +#include "internal.h" > + > +typedef struct AudioIIRContext { > + const AVClass *class; > + char *a_str, *b_str; > + > + int nb_a, nb_b; > + double *a, *b; > + AVFrame *input, *output; > +} AudioIIRContext; > + > +static int query_formats(AVFilterContext *ctx) > +{ > + AVFilterFormats *formats; > + AVFilterChannelLayouts *layouts; > + static const enum AVSampleFormat sample_fmts[] = { > + AV_SAMPLE_FMT_DBLP, > + AV_SAMPLE_FMT_NONE > + }; > + int ret; > + > + layouts = ff_all_channel_counts(); > + if (!layouts) > + return AVERROR(ENOMEM); > + ret = ff_set_common_channel_layouts(ctx, layouts); > + if (ret < 0) > + return ret; > + > + formats = ff_make_format_list(sample_fmts); > + if (!formats) > + return AVERROR(ENOMEM); > + ret = ff_set_common_formats(ctx, formats); > + if (ret < 0) > + return ret; > + > + formats = ff_all_samplerates(); > + if (!formats) > + return AVERROR(ENOMEM); > + return ff_set_common_samplerates(ctx, formats); > +} > + > +static int config_output(AVFilterLink *outlink) > +{ > + AVFilterContext *ctx = outlink->src; > + AudioIIRContext *s = ctx->priv; > + AVFilterLink *inlink = ctx->inputs[0]; > + > + s->input = ff_get_audio_buffer(inlink, s->nb_b); > + s->output = ff_get_audio_buffer(inlink, s->nb_a); > + if (!s->input || !s->output) > + return AVERROR(ENOMEM); > + return 0; > +} > + > +static int filter_frame(AVFilterLink *inlink, AVFrame *in) > +{ > + AVFilterContext *ctx = inlink->dst; > + AudioIIRContext *s = ctx->priv; > + AVFilterLink *outlink = ctx->outputs[0]; > + AVFrame *out; > + int ch, n; > + > + if (av_frame_is_writable(in)) { > + out = in; > + } else { > + out = ff_get_audio_buffer(outlink, in->nb_samples); > + if (!out) { > + av_frame_free(&in); > + return AVERROR(ENOMEM); > + } > + av_frame_copy_props(out, in); > + } > + > + for (ch = 0; ch < out->channels; ch++) { > + const double *src = (const double *)in->extended_data[ch]; > + double *ic = (double *)s->input->extended_data[ch]; > + double *oc = (double *)s->output->extended_data[ch]; > + double *dst = (double *)out->extended_data[ch]; > + const double *a = s->a; > + const double *b = s->b; > + > + for (n = 0; n < in->nb_samples; n++) { > + double sample = 0.; > + int x; > + > + memmove(&ic[1], &ic[0], (s->nb_b - 1) * sizeof(*ic)); > + memmove(&oc[1], &oc[0], (s->nb_a - 1) * sizeof(*oc)); > + ic[0] = src[n]; > + for (x = 0; x < s->nb_b; x++) > + sample += b[x] * ic[x]; > + > + for (x = 1; x < s->nb_a; x++) > + sample -= a[x] * oc[x]; > + > + oc[0] = dst[n] = sample; > + } > + } > + > + if (in != out) > + av_frame_free(&in); > + > + return ff_filter_frame(outlink, out); > +} > + > +static void count_items(char *item_str, int *nb_items) > +{ > + char *p; > + > + *nb_items = 1; > + for (p = item_str; *p; p++) { > + if (*p == ' ' || *p == '|') > + (*nb_items)++; > + } > +} > + > +static int read_items(char *item_str, int nb_items, double *dst) > +{ > + char *p, *arg, *saveptr = NULL; > + int i; > + > + p = item_str; > + for (i = 0; i < nb_items; i++) { > + if (!(arg = av_strtok(p, " |", &saveptr))) > + break; > + > + p = NULL; > + sscanf(arg, "%lf", &dst[i]); > + } > + > + return 0; > +} > + > +static av_cold int init(AVFilterContext *ctx) > +{ > + AudioIIRContext *s = ctx->priv; > + int i; > + > + count_items(s->a_str, &s->nb_a); > + count_items(s->b_str, &s->nb_b); > + > + s->a = av_calloc(s->nb_a, sizeof(*s->a)); > + s->b = av_calloc(s->nb_b, sizeof(*s->b)); > + if (!s->a || !s->b) > + return AVERROR(ENOMEM); > + > + read_items(s->a_str, s->nb_a, s->a); > + read_items(s->b_str, s->nb_b, s->b); > + > + for (i = 1; i < s->nb_a; i++) > + s->a[i] /= s->a[0]; > + > + for (i = 0; i < s->nb_b; i++) > + s->b[i] /= s->a[0]; > + > + return 0; > +} > + > +static av_cold void uninit(AVFilterContext *ctx) > +{ > + AudioIIRContext *s = ctx->priv; > + > + av_freep(&s->a); > + av_freep(&s->b); > + av_frame_free(&s->input); > + av_frame_free(&s->output); > +} > + > +static const AVFilterPad inputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_AUDIO, > + .filter_frame = filter_frame, > + }, > + { NULL } > +}; > + > +static const AVFilterPad outputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_AUDIO, > + .config_props = config_output, > + }, > + { NULL } > +}; > + > +#define OFFSET(x) offsetof(AudioIIRContext, x) > +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM > + > +static const AVOption aiir_options[] = { > + { "a", "set A coefficients", OFFSET(a_str), AV_OPT_TYPE_STRING, > {.str="1 1"}, 0, 0, .flags = FLAGS }, > + { "b", "set B coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, > {.str="1 1"}, 0, 0, .flags = FLAGS }, > + { NULL }, > +}; > + > +AVFILTER_DEFINE_CLASS(aiir); > + > +AVFilter ff_af_aiir = { > + .name = "aiir", > + .description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse > Response filter with supplied coefficients."), > + .priv_size = sizeof(AudioIIRContext), > + .init = init, > + .uninit = uninit, > + .query_formats = query_formats, > + .inputs = inputs, > + .outputs = outputs, > + .priv_class = &aiir_class, > +}; > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index 67c073091f..705c03c22c 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -54,6 +54,7 @@ static void register_all(void) > REGISTER_FILTER(AFIR, afir, af); > REGISTER_FILTER(AFORMAT, aformat, af); > REGISTER_FILTER(AGATE, agate, af); > + REGISTER_FILTER(AIIR, aiir, af); > REGISTER_FILTER(AINTERLEAVE, ainterleave, af); > REGISTER_FILTER(ALIMITER, alimiter, af); > REGISTER_FILTER(ALLPASS, allpass, af); > -- > 2.11.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
lavc has an IIR filter (libavcodec/iirfilter.h), couldn't you reuse it? _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel