Message ID | 20171118104410.1508-1-onemda@gmail.com |
---|---|
State | New |
Headers | show |
On 18 November 2017 at 10:44, Paul B Mahol <onemda@gmail.com> wrote: > Signed-off-by: Paul B Mahol <onemda@gmail.com> > --- > doc/filters.texi | 10 +++ > libavfilter/Makefile | 1 + > libavfilter/af_acontrast.c | 219 ++++++++++++++++++++++++++++++ > +++++++++++++++ > libavfilter/allfilters.c | 1 + > 4 files changed, 231 insertions(+) > create mode 100644 libavfilter/af_acontrast.c > > diff --git a/doc/filters.texi b/doc/filters.texi > index 5d99437871..e35952510b 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -429,6 +429,16 @@ How much to use compressed signal in output. Default > is 1. > Range is between 0 and 1. > @end table > > +@section acontrast > +Simple audio dynamic range commpression/expansion filter. > + > +The filter accepts the following options: > + > +@table @option > +@item c > +Set contrast. Default is 33. Allowed range is between 0 and 100. > +@end table > + > @section acopy > > Copy the input audio source unchanged to the output. This is mainly > useful for > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 9acae3ff5b..71c6333a52 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -31,6 +31,7 @@ OBJS-$(CONFIG_QSVVPP) += qsvvpp.o > # audio filters > OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o > OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o > +OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o > OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o > OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o > OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o > diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c > new file mode 100644 > index 0000000000..38de08ffe5 > --- /dev/null > +++ b/libavfilter/af_acontrast.c > @@ -0,0 +1,219 @@ > +/* > + * Copyright (c) 2008 Rob Sykes > + * Copyright (c) 2017 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/channel_layout.h" > +#include "libavutil/opt.h" > +#include "avfilter.h" > +#include "audio.h" > +#include "formats.h" > + > +typedef struct AudioContrastContext { > + const AVClass *class; > + float contrast; > + void (*filter)(void **dst, const void **src, > + int nb_samples, int channels, float contrast); > +} AudioContrastContext; > + > +#define OFFSET(x) offsetof(AudioContrastContext, x) > +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM > + > +static const AVOption acontrast_options[] = { > + { "c", "set contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, > {.dbl=33}, 0, 100, A }, > "contrast" instead of "c"? Not sure if single letter options are a good idea. > + { NULL } > +}; > + > +AVFILTER_DEFINE_CLASS(acontrast); > + > +static int query_formats(AVFilterContext *ctx) > +{ > + AVFilterFormats *formats = NULL; > + AVFilterChannelLayouts *layouts = NULL; > + static const enum AVSampleFormat sample_fmts[] = { > + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, > + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, > + AV_SAMPLE_FMT_NONE > + }; > + int 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; > + > + 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_all_samplerates(); > + return ff_set_common_samplerates(ctx, formats); > +} > + > +static void filter_flt(void **d, const void **s, > + int nb_samples, int channels, > + float contrast) > +{ > + const float *src = s[0]; > + float *dst = d[0]; > + int n, c; > + > + for (n = 0; n < nb_samples; n++) { > + for (c = 0; c < channels; c++) { > + double d = src[c] * M_PI_2; > + > + dst[c] = sin(d + contrast * sin(d * 4)); > sinf() instead of sin() > + } > + > + dst += c; > + src += c; > + } > +} > + > +static void filter_dbl(void **d, const void **s, > + int nb_samples, int channels, > + float contrast) > +{ > + const double *src = s[0]; > + double *dst = d[0]; > + int n, c; > + > + for (n = 0; n < nb_samples; n++) { > + for (c = 0; c < channels; c++) { > + double d = src[c] * M_PI_2; > + > + dst[c] = sin(d + contrast * sin(d * 4)); > + } > + > + dst += c; > + src += c; > + } > +} > + > +static void filter_fltp(void **d, const void **s, > + int nb_samples, int channels, > + float contrast) > +{ > + int n, c; > + > + for (c = 0; c < channels; c++) { > + const float *src = s[c]; > + float *dst = d[c]; > + > + for (n = 0; n < nb_samples; n++) { > + double d = src[n] * M_PI_2; > + > + dst[n] = sin(d + contrast * sin(d * 4)); > sinf() instead of sin() > + } > + } > +} > + > +static void filter_dblp(void **d, const void **s, > + int nb_samples, int channels, > + float contrast) > +{ > + int n, c; > + > + for (c = 0; c < channels; c++) { > + const double *src = s[c]; > + double *dst = d[c]; > + > + for (n = 0; n < nb_samples; n++) { > + double d = src[n] * M_PI_2; > + > + dst[n] = sin(d + contrast * sin(d * 4)); > + } > + } > +} > Could you do the filtering in-place? Via av_frame_make_writeable? > + > +static int config_input(AVFilterLink *inlink) > +{ > + AVFilterContext *ctx = inlink->dst; > + AudioContrastContext *s = ctx->priv; > + > + switch (inlink->format) { > + case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; > + case AV_SAMPLE_FMT_DBL: s->filter = filter_dbl; break; > + case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break; > + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break; > + } > + > + return 0; > +} > + > +static int filter_frame(AVFilterLink *inlink, AVFrame *in) > +{ > + AVFilterContext *ctx = inlink->dst; > + AVFilterLink *outlink = ctx->outputs[0]; > + AudioContrastContext *s = ctx->priv; > + AVFrame *out; > + > + if (av_frame_is_writable(in)) { > + out = in; > + } else { > + out = ff_get_audio_buffer(inlink, in->nb_samples); > + if (!out) { > + av_frame_free(&in); > + return AVERROR(ENOMEM); > + } > + av_frame_copy_props(out, in); > + } > + > + s->filter((void **)out->extended_data, (const void > **)in->extended_data, > + in->nb_samples, in->channels, s->contrast / 750); > Divide s->contrast by 750 during init? > + > + if (out != in) > + av_frame_free(&in); > + > + return ff_filter_frame(outlink, out); > +} > + > +static const AVFilterPad inputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_AUDIO, > + .filter_frame = filter_frame, > + .config_props = config_input, > + }, > + { NULL } > +}; > + > +static const AVFilterPad outputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_AUDIO, > + }, > + { NULL } > +}; > + > +AVFilter ff_af_acontrast = { > + .name = "acontrast", > + .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range > compression/expansion filter."), > + .query_formats = query_formats, > + .priv_size = sizeof(AudioContrastContext), > + .priv_class = &acontrast_class, > + .inputs = inputs, > + .outputs = outputs, > +}; > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index a838309569..6d92b3ab5a 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -42,6 +42,7 @@ static void register_all(void) > { > REGISTER_FILTER(ABENCH, abench, af); > REGISTER_FILTER(ACOMPRESSOR, acompressor, af); > + REGISTER_FILTER(ACONTRAST, acontrast, af); > REGISTER_FILTER(ACOPY, acopy, af); > REGISTER_FILTER(ACROSSFADE, acrossfade, af); > REGISTER_FILTER(ACRUSHER, acrusher, af); > -- > 2.11.0 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > Apart from that lgtm
On 11/18/17, Rostislav Pehlivanov <atomnuker@gmail.com> wrote: > On 18 November 2017 at 10:44, Paul B Mahol <onemda@gmail.com> wrote: > >> Signed-off-by: Paul B Mahol <onemda@gmail.com> >> --- >> doc/filters.texi | 10 +++ >> libavfilter/Makefile | 1 + >> libavfilter/af_acontrast.c | 219 ++++++++++++++++++++++++++++++ >> +++++++++++++++ >> libavfilter/allfilters.c | 1 + >> 4 files changed, 231 insertions(+) >> create mode 100644 libavfilter/af_acontrast.c >> >> diff --git a/doc/filters.texi b/doc/filters.texi >> index 5d99437871..e35952510b 100644 >> --- a/doc/filters.texi >> +++ b/doc/filters.texi >> @@ -429,6 +429,16 @@ How much to use compressed signal in output. Default >> is 1. >> Range is between 0 and 1. >> @end table >> >> +@section acontrast >> +Simple audio dynamic range commpression/expansion filter. >> + >> +The filter accepts the following options: >> + >> +@table @option >> +@item c >> +Set contrast. Default is 33. Allowed range is between 0 and 100. >> +@end table >> + >> @section acopy >> >> Copy the input audio source unchanged to the output. This is mainly >> useful for >> diff --git a/libavfilter/Makefile b/libavfilter/Makefile >> index 9acae3ff5b..71c6333a52 100644 >> --- a/libavfilter/Makefile >> +++ b/libavfilter/Makefile >> @@ -31,6 +31,7 @@ OBJS-$(CONFIG_QSVVPP) += qsvvpp.o >> # audio filters >> OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o >> OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o >> +OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o >> OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o >> OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o >> OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o >> diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c >> new file mode 100644 >> index 0000000000..38de08ffe5 >> --- /dev/null >> +++ b/libavfilter/af_acontrast.c >> @@ -0,0 +1,219 @@ >> +/* >> + * Copyright (c) 2008 Rob Sykes >> + * Copyright (c) 2017 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/channel_layout.h" >> +#include "libavutil/opt.h" >> +#include "avfilter.h" >> +#include "audio.h" >> +#include "formats.h" >> + >> +typedef struct AudioContrastContext { >> + const AVClass *class; >> + float contrast; >> + void (*filter)(void **dst, const void **src, >> + int nb_samples, int channels, float contrast); >> +} AudioContrastContext; >> + >> +#define OFFSET(x) offsetof(AudioContrastContext, x) >> +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM >> + >> +static const AVOption acontrast_options[] = { >> + { "c", "set contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, >> {.dbl=33}, 0, 100, A }, >> > > "contrast" instead of "c"? Not sure if single letter options are a good > idea. > > > >> + { NULL } >> +}; >> + >> +AVFILTER_DEFINE_CLASS(acontrast); >> + >> +static int query_formats(AVFilterContext *ctx) >> +{ >> + AVFilterFormats *formats = NULL; >> + AVFilterChannelLayouts *layouts = NULL; >> + static const enum AVSampleFormat sample_fmts[] = { >> + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, >> + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, >> + AV_SAMPLE_FMT_NONE >> + }; >> + int 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; >> + >> + 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_all_samplerates(); >> + return ff_set_common_samplerates(ctx, formats); >> +} >> + >> +static void filter_flt(void **d, const void **s, >> + int nb_samples, int channels, >> + float contrast) >> +{ >> + const float *src = s[0]; >> + float *dst = d[0]; >> + int n, c; >> + >> + for (n = 0; n < nb_samples; n++) { >> + for (c = 0; c < channels; c++) { >> + double d = src[c] * M_PI_2; >> + >> + dst[c] = sin(d + contrast * sin(d * 4)); >> > > sinf() instead of sin() ok > > > >> + } >> + >> + dst += c; >> + src += c; >> + } >> +} >> + >> +static void filter_dbl(void **d, const void **s, >> + int nb_samples, int channels, >> + float contrast) >> +{ >> + const double *src = s[0]; >> + double *dst = d[0]; >> + int n, c; >> + >> + for (n = 0; n < nb_samples; n++) { >> + for (c = 0; c < channels; c++) { >> + double d = src[c] * M_PI_2; >> + >> + dst[c] = sin(d + contrast * sin(d * 4)); >> + } >> + >> + dst += c; >> + src += c; >> + } >> +} >> + >> +static void filter_fltp(void **d, const void **s, >> + int nb_samples, int channels, >> + float contrast) >> +{ >> + int n, c; >> + >> + for (c = 0; c < channels; c++) { >> + const float *src = s[c]; >> + float *dst = d[c]; >> + >> + for (n = 0; n < nb_samples; n++) { >> + double d = src[n] * M_PI_2; >> + >> + dst[n] = sin(d + contrast * sin(d * 4)); >> > > sinf() instead of sin() > ok > > >> + } >> + } >> +} >> + >> +static void filter_dblp(void **d, const void **s, >> + int nb_samples, int channels, >> + float contrast) >> +{ >> + int n, c; >> + >> + for (c = 0; c < channels; c++) { >> + const double *src = s[c]; >> + double *dst = d[c]; >> + >> + for (n = 0; n < nb_samples; n++) { >> + double d = src[n] * M_PI_2; >> + >> + dst[n] = sin(d + contrast * sin(d * 4)); >> + } >> + } >> +} >> > > Could you do the filtering in-place? Via av_frame_make_writeable? > Both are supported. > > >> + >> +static int config_input(AVFilterLink *inlink) >> +{ >> + AVFilterContext *ctx = inlink->dst; >> + AudioContrastContext *s = ctx->priv; >> + >> + switch (inlink->format) { >> + case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; >> + case AV_SAMPLE_FMT_DBL: s->filter = filter_dbl; break; >> + case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break; >> + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break; >> + } >> + >> + return 0; >> +} >> + >> +static int filter_frame(AVFilterLink *inlink, AVFrame *in) >> +{ >> + AVFilterContext *ctx = inlink->dst; >> + AVFilterLink *outlink = ctx->outputs[0]; >> + AudioContrastContext *s = ctx->priv; >> + AVFrame *out; >> + >> + if (av_frame_is_writable(in)) { >> + out = in; >> + } else { >> + out = ff_get_audio_buffer(inlink, in->nb_samples); >> + if (!out) { >> + av_frame_free(&in); >> + return AVERROR(ENOMEM); >> + } >> + av_frame_copy_props(out, in); >> + } >> + >> + s->filter((void **)out->extended_data, (const void >> **)in->extended_data, >> + in->nb_samples, in->channels, s->contrast / 750); >> > > Divide s->contrast by 750 during init? Doesn't cost much, and also it is less lines this way.
diff --git a/doc/filters.texi b/doc/filters.texi index 5d99437871..e35952510b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -429,6 +429,16 @@ How much to use compressed signal in output. Default is 1. Range is between 0 and 1. @end table +@section acontrast +Simple audio dynamic range commpression/expansion filter. + +The filter accepts the following options: + +@table @option +@item c +Set contrast. Default is 33. Allowed range is between 0 and 100. +@end table + @section acopy Copy the input audio source unchanged to the output. This is mainly useful for diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 9acae3ff5b..71c6333a52 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -31,6 +31,7 @@ OBJS-$(CONFIG_QSVVPP) += qsvvpp.o # audio filters OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o +OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c new file mode 100644 index 0000000000..38de08ffe5 --- /dev/null +++ b/libavfilter/af_acontrast.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008 Rob Sykes + * Copyright (c) 2017 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/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +typedef struct AudioContrastContext { + const AVClass *class; + float contrast; + void (*filter)(void **dst, const void **src, + int nb_samples, int channels, float contrast); +} AudioContrastContext; + +#define OFFSET(x) offsetof(AudioContrastContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption acontrast_options[] = { + { "c", "set contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, {.dbl=33}, 0, 100, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(acontrast); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int 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; + + 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_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static void filter_flt(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const float *src = s[0]; + float *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + double d = src[c] * M_PI_2; + + dst[c] = sin(d + contrast * sin(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_dbl(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const double *src = s[0]; + double *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + double d = src[c] * M_PI_2; + + dst[c] = sin(d + contrast * sin(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_fltp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const float *src = s[c]; + float *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + double d = src[n] * M_PI_2; + + dst[n] = sin(d + contrast * sin(d * 4)); + } + } +} + +static void filter_dblp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const double *src = s[c]; + double *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + double d = src[n] * M_PI_2; + + dst[n] = sin(d + contrast * sin(d * 4)); + } + } +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioContrastContext *s = ctx->priv; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; + case AV_SAMPLE_FMT_DBL: s->filter = filter_dbl; break; + case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break; + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioContrastContext *s = ctx->priv; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(inlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + s->filter((void **)out->extended_data, (const void **)in->extended_data, + in->nb_samples, in->channels, s->contrast / 750); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_acontrast = { + .name = "acontrast", + .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), + .query_formats = query_formats, + .priv_size = sizeof(AudioContrastContext), + .priv_class = &acontrast_class, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index a838309569..6d92b3ab5a 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -42,6 +42,7 @@ static void register_all(void) { REGISTER_FILTER(ABENCH, abench, af); REGISTER_FILTER(ACOMPRESSOR, acompressor, af); + REGISTER_FILTER(ACONTRAST, acontrast, af); REGISTER_FILTER(ACOPY, acopy, af); REGISTER_FILTER(ACROSSFADE, acrossfade, af); REGISTER_FILTER(ACRUSHER, acrusher, af);
Signed-off-by: Paul B Mahol <onemda@gmail.com> --- doc/filters.texi | 10 +++ libavfilter/Makefile | 1 + libavfilter/af_acontrast.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 231 insertions(+) create mode 100644 libavfilter/af_acontrast.c