Message ID | 20201105123644.13223-1-onemda@gmail.com |
---|---|
State | Accepted |
Commit | ee4a04654014e24f47f5a31265fb3bde6fad8ce6 |
Headers | show |
Series | [FFmpeg-devel] avfilter/af_asoftclip: add oversampling support | expand |
Context | Check | Description |
---|---|---|
andriy/x86_make | success | Make finished |
andriy/x86_make_fate | success | Make fate finished |
andriy/PPC64_make | success | Make finished |
andriy/PPC64_make_fate | success | Make fate finished |
Will apply soon. On Thu, Nov 5, 2020 at 1:36 PM Paul B Mahol <onemda@gmail.com> wrote: > Signed-off-by: Paul B Mahol <onemda@gmail.com> > --- > configure | 1 + > doc/filters.texi | 3 ++ > libavfilter/af_asoftclip.c | 106 ++++++++++++++++++++++++++++++++++--- > 3 files changed, 103 insertions(+), 7 deletions(-) > > diff --git a/configure b/configure > index 8a9e9b3cd7..2f02d7f5c8 100755 > --- a/configure > +++ b/configure > @@ -3501,6 +3501,7 @@ afir_filter_deps="avcodec" > afir_filter_select="rdft" > amovie_filter_deps="avcodec avformat" > aresample_filter_deps="swresample" > +asoftclip_filter_deps="swresample" > asr_filter_deps="pocketsphinx" > ass_filter_deps="libass" > atempo_filter_deps="avcodec" > diff --git a/doc/filters.texi b/doc/filters.texi > index 40f8f614fe..8380f6cac2 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -2356,6 +2356,9 @@ It accepts the following values: > > @item param > Set additional parameter which controls sigmoid function. > + > +@item oversample > +Set oversampling factor. > @end table > > @subsection Commands > diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c > index ce1f7ea96a..aaae3c6d4b 100644 > --- a/libavfilter/af_asoftclip.c > +++ b/libavfilter/af_asoftclip.c > @@ -21,6 +21,7 @@ > #include "libavutil/avassert.h" > #include "libavutil/channel_layout.h" > #include "libavutil/opt.h" > +#include "libswresample/swresample.h" > #include "avfilter.h" > #include "audio.h" > #include "formats.h" > @@ -42,14 +43,22 @@ typedef struct ASoftClipContext { > const AVClass *class; > > int type; > + int oversample; > + int64_t delay; > double param; > > + SwrContext *up_ctx; > + SwrContext *down_ctx; > + > + AVFrame *frame; > + > void (*filter)(struct ASoftClipContext *s, void **dst, const void > **src, > int nb_samples, int channels, int start, int end); > } ASoftClipContext; > > #define OFFSET(x) offsetof(ASoftClipContext, x) > #define A > AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM > +#define F AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM > > static const AVOption asoftclip_options[] = { > { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT, > {.i64=0}, -1, NB_TYPES-1, A, "types" }, > @@ -63,6 +72,7 @@ static const AVOption asoftclip_options[] = { > { "sin", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=ASC_SIN}, 0, 0, A, "types" }, > { "erf", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=ASC_ERF}, 0, 0, A, "types" }, > { "param", "set softclip parameter", OFFSET(param), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 3, A }, > + { "oversample", "set oversample factor", OFFSET(oversample), > AV_OPT_TYPE_INT, {.i64=1}, 1, 32, F }, > { NULL } > }; > > @@ -242,6 +252,7 @@ static int config_input(AVFilterLink *inlink) > { > AVFilterContext *ctx = inlink->dst; > ASoftClipContext *s = ctx->priv; > + int ret; > > switch (inlink->format) { > case AV_SAMPLE_FMT_FLT: > @@ -251,6 +262,38 @@ static int config_input(AVFilterLink *inlink) > default: av_assert0(0); > } > > + if (s->oversample <= 1) > + return 0; > + > + s->up_ctx = swr_alloc(); > + s->down_ctx = swr_alloc(); > + if (!s->up_ctx || !s->down_ctx) > + return AVERROR(ENOMEM); > + > + av_opt_set_int(s->up_ctx, "in_channel_layout", > inlink->channel_layout, 0); > + av_opt_set_int(s->up_ctx, "in_sample_rate", > inlink->sample_rate, 0); > + av_opt_set_sample_fmt(s->up_ctx, "in_sample_fmt", inlink->format, 0); > + > + av_opt_set_int(s->up_ctx, "out_channel_layout", > inlink->channel_layout, 0); > + av_opt_set_int(s->up_ctx, "out_sample_rate", > inlink->sample_rate * s->oversample, 0); > + av_opt_set_sample_fmt(s->up_ctx, "out_sample_fmt", inlink->format, 0); > + > + av_opt_set_int(s->down_ctx, "in_channel_layout", > inlink->channel_layout, 0); > + av_opt_set_int(s->down_ctx, "in_sample_rate", > inlink->sample_rate * s->oversample, 0); > + av_opt_set_sample_fmt(s->down_ctx, "in_sample_fmt", inlink->format, > 0); > + > + av_opt_set_int(s->down_ctx, "out_channel_layout", > inlink->channel_layout, 0); > + av_opt_set_int(s->down_ctx, "out_sample_rate", > inlink->sample_rate, 0); > + av_opt_set_sample_fmt(s->down_ctx, "out_sample_fmt", inlink->format, > 0); > + > + ret = swr_init(s->up_ctx); > + if (ret < 0) > + return ret; > + > + ret = swr_init(s->down_ctx); > + if (ret < 0) > + return ret; > + > return 0; > } > > @@ -280,8 +323,9 @@ static int filter_channels(AVFilterContext *ctx, void > *arg, int jobnr, int nb_jo > static int filter_frame(AVFilterLink *inlink, AVFrame *in) > { > AVFilterContext *ctx = inlink->dst; > + ASoftClipContext *s = ctx->priv; > AVFilterLink *outlink = ctx->outputs[0]; > - int nb_samples, channels; > + int ret, nb_samples, channels; > ThreadData td; > AVFrame *out; > > @@ -304,17 +348,64 @@ static int filter_frame(AVFilterLink *inlink, > AVFrame *in) > channels = 1; > } > > - td.in = in; > - td.out = out; > - td.nb_samples = nb_samples; > - td.channels = channels; > - ctx->internal->execute(ctx, filter_channels, &td, NULL, > FFMIN(channels, > - > ff_filter_get_nb_threads(ctx))); > + if (s->oversample > 1) { > + s->frame = ff_get_audio_buffer(outlink, in->nb_samples * > s->oversample); > + if (!s->frame) { > + ret = AVERROR(ENOMEM); > + goto fail; > + } > + > + ret = swr_convert(s->up_ctx, (uint8_t**)s->frame->extended_data, > in->nb_samples * s->oversample, > + (const uint8_t **)in->extended_data, > in->nb_samples); > + if (ret < 0) > + goto fail; > + > + td.in = s->frame; > + td.out = s->frame; > + td.nb_samples = av_sample_fmt_is_planar(in->format) ? ret : ret * > in->channels; > + td.channels = channels; > + ctx->internal->execute(ctx, filter_channels, &td, NULL, > FFMIN(channels, > + > ff_filter_get_nb_threads(ctx))); > + > + ret = swr_convert(s->down_ctx, (uint8_t**)out->extended_data, > out->nb_samples, > + (const uint8_t **)s->frame->extended_data, ret); > + if (ret < 0) > + goto fail; > + > + if (out->pts) > + out->pts -= s->delay; > + s->delay += in->nb_samples - ret; > + out->nb_samples = ret; > + > + av_frame_free(&s->frame); > + } else { > + td.in = in; > + td.out = out; > + td.nb_samples = nb_samples; > + td.channels = channels; > + ctx->internal->execute(ctx, filter_channels, &td, NULL, > FFMIN(channels, > + > ff_filter_get_nb_threads(ctx))); > + } > > if (out != in) > av_frame_free(&in); > > return ff_filter_frame(outlink, out); > +fail: > + if (out != in) > + av_frame_free(&out); > + av_frame_free(&in); > + av_frame_free(&s->frame); > + > + return ret; > +} > + > +static av_cold void uninit(AVFilterContext *ctx) > +{ > + ASoftClipContext *s = ctx->priv; > + > + swr_free(&s->up_ctx); > + swr_free(&s->down_ctx); > } > > static const AVFilterPad inputs[] = { > @@ -343,6 +434,7 @@ AVFilter ff_af_asoftclip = { > .priv_class = &asoftclip_class, > .inputs = inputs, > .outputs = outputs, > + .uninit = uninit, > .process_command = ff_filter_process_command, > .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | > AVFILTER_FLAG_SLICE_THREADS, > -- > 2.17.1 > >
diff --git a/configure b/configure index 8a9e9b3cd7..2f02d7f5c8 100755 --- a/configure +++ b/configure @@ -3501,6 +3501,7 @@ afir_filter_deps="avcodec" afir_filter_select="rdft" amovie_filter_deps="avcodec avformat" aresample_filter_deps="swresample" +asoftclip_filter_deps="swresample" asr_filter_deps="pocketsphinx" ass_filter_deps="libass" atempo_filter_deps="avcodec" diff --git a/doc/filters.texi b/doc/filters.texi index 40f8f614fe..8380f6cac2 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2356,6 +2356,9 @@ It accepts the following values: @item param Set additional parameter which controls sigmoid function. + +@item oversample +Set oversampling factor. @end table @subsection Commands diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c index ce1f7ea96a..aaae3c6d4b 100644 --- a/libavfilter/af_asoftclip.c +++ b/libavfilter/af_asoftclip.c @@ -21,6 +21,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" +#include "libswresample/swresample.h" #include "avfilter.h" #include "audio.h" #include "formats.h" @@ -42,14 +43,22 @@ typedef struct ASoftClipContext { const AVClass *class; int type; + int oversample; + int64_t delay; double param; + SwrContext *up_ctx; + SwrContext *down_ctx; + + AVFrame *frame; + void (*filter)(struct ASoftClipContext *s, void **dst, const void **src, int nb_samples, int channels, int start, int end); } ASoftClipContext; #define OFFSET(x) offsetof(ASoftClipContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM +#define F AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption asoftclip_options[] = { { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=0}, -1, NB_TYPES-1, A, "types" }, @@ -63,6 +72,7 @@ static const AVOption asoftclip_options[] = { { "sin", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_SIN}, 0, 0, A, "types" }, { "erf", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ERF}, 0, 0, A, "types" }, { "param", "set softclip parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 3, A }, + { "oversample", "set oversample factor", OFFSET(oversample), AV_OPT_TYPE_INT, {.i64=1}, 1, 32, F }, { NULL } }; @@ -242,6 +252,7 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; ASoftClipContext *s = ctx->priv; + int ret; switch (inlink->format) { case AV_SAMPLE_FMT_FLT: @@ -251,6 +262,38 @@ static int config_input(AVFilterLink *inlink) default: av_assert0(0); } + if (s->oversample <= 1) + return 0; + + s->up_ctx = swr_alloc(); + s->down_ctx = swr_alloc(); + if (!s->up_ctx || !s->down_ctx) + return AVERROR(ENOMEM); + + av_opt_set_int(s->up_ctx, "in_channel_layout", inlink->channel_layout, 0); + av_opt_set_int(s->up_ctx, "in_sample_rate", inlink->sample_rate, 0); + av_opt_set_sample_fmt(s->up_ctx, "in_sample_fmt", inlink->format, 0); + + av_opt_set_int(s->up_ctx, "out_channel_layout", inlink->channel_layout, 0); + av_opt_set_int(s->up_ctx, "out_sample_rate", inlink->sample_rate * s->oversample, 0); + av_opt_set_sample_fmt(s->up_ctx, "out_sample_fmt", inlink->format, 0); + + av_opt_set_int(s->down_ctx, "in_channel_layout", inlink->channel_layout, 0); + av_opt_set_int(s->down_ctx, "in_sample_rate", inlink->sample_rate * s->oversample, 0); + av_opt_set_sample_fmt(s->down_ctx, "in_sample_fmt", inlink->format, 0); + + av_opt_set_int(s->down_ctx, "out_channel_layout", inlink->channel_layout, 0); + av_opt_set_int(s->down_ctx, "out_sample_rate", inlink->sample_rate, 0); + av_opt_set_sample_fmt(s->down_ctx, "out_sample_fmt", inlink->format, 0); + + ret = swr_init(s->up_ctx); + if (ret < 0) + return ret; + + ret = swr_init(s->down_ctx); + if (ret < 0) + return ret; + return 0; } @@ -280,8 +323,9 @@ static int filter_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; + ASoftClipContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int nb_samples, channels; + int ret, nb_samples, channels; ThreadData td; AVFrame *out; @@ -304,17 +348,64 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) channels = 1; } - td.in = in; - td.out = out; - td.nb_samples = nb_samples; - td.channels = channels; - ctx->internal->execute(ctx, filter_channels, &td, NULL, FFMIN(channels, - ff_filter_get_nb_threads(ctx))); + if (s->oversample > 1) { + s->frame = ff_get_audio_buffer(outlink, in->nb_samples * s->oversample); + if (!s->frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = swr_convert(s->up_ctx, (uint8_t**)s->frame->extended_data, in->nb_samples * s->oversample, + (const uint8_t **)in->extended_data, in->nb_samples); + if (ret < 0) + goto fail; + + td.in = s->frame; + td.out = s->frame; + td.nb_samples = av_sample_fmt_is_planar(in->format) ? ret : ret * in->channels; + td.channels = channels; + ctx->internal->execute(ctx, filter_channels, &td, NULL, FFMIN(channels, + ff_filter_get_nb_threads(ctx))); + + ret = swr_convert(s->down_ctx, (uint8_t**)out->extended_data, out->nb_samples, + (const uint8_t **)s->frame->extended_data, ret); + if (ret < 0) + goto fail; + + if (out->pts) + out->pts -= s->delay; + s->delay += in->nb_samples - ret; + out->nb_samples = ret; + + av_frame_free(&s->frame); + } else { + td.in = in; + td.out = out; + td.nb_samples = nb_samples; + td.channels = channels; + ctx->internal->execute(ctx, filter_channels, &td, NULL, FFMIN(channels, + ff_filter_get_nb_threads(ctx))); + } if (out != in) av_frame_free(&in); return ff_filter_frame(outlink, out); +fail: + if (out != in) + av_frame_free(&out); + av_frame_free(&in); + av_frame_free(&s->frame); + + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + ASoftClipContext *s = ctx->priv; + + swr_free(&s->up_ctx); + swr_free(&s->down_ctx); } static const AVFilterPad inputs[] = { @@ -343,6 +434,7 @@ AVFilter ff_af_asoftclip = { .priv_class = &asoftclip_class, .inputs = inputs, .outputs = outputs, + .uninit = uninit, .process_command = ff_filter_process_command, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
Signed-off-by: Paul B Mahol <onemda@gmail.com> --- configure | 1 + doc/filters.texi | 3 ++ libavfilter/af_asoftclip.c | 106 ++++++++++++++++++++++++++++++++++--- 3 files changed, 103 insertions(+), 7 deletions(-)