]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/af_adeclick.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / af_adeclick.c
index bf0b7cb40808042c76fbed2a4588866645a9f0d1..798838f522cb5f0f90b376bf6fef5cd39c956bb7 100644 (file)
@@ -22,7 +22,9 @@
 #include "libavutil/opt.h"
 #include "avfilter.h"
 #include "audio.h"
+#include "filters.h"
 #include "formats.h"
+#include "internal.h"
 
 typedef struct DeclickChannel {
     double *auxiliary;
@@ -61,6 +63,7 @@ typedef struct AudioDeclickContext {
     int hop_size;
     int overlap_skip;
 
+    AVFrame *enabled;
     AVFrame *in;
     AVFrame *out;
     AVFrame *buffer;
@@ -73,7 +76,9 @@ typedef struct AudioDeclickContext {
     uint64_t nb_samples;
     uint64_t detected_errors;
     int samples_left;
+    int eof;
 
+    AVAudioFifo *efifo;
     AVAudioFifo *fifo;
     double *window_func_lut;
 
@@ -87,13 +92,21 @@ typedef struct AudioDeclickContext {
 #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
 
 static const AVOption adeclick_options[] = {
+    { "window", "set window size",     OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=55}, 10,  100, AF },
     { "w", "set window size",          OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=55}, 10,  100, AF },
+    { "overlap", "set window overlap", OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75}, 50,   95, AF },
     { "o", "set window overlap",       OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75}, 50,   95, AF },
+    { "arorder", "set autoregression order", OFFSET(ar),  AV_OPT_TYPE_DOUBLE, {.dbl=2},   0,   25, AF },
     { "a", "set autoregression order", OFFSET(ar),        AV_OPT_TYPE_DOUBLE, {.dbl=2},   0,   25, AF },
+    { "threshold", "set threshold",    OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=2},   1,  100, AF },
     { "t", "set threshold",            OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=2},   1,  100, AF },
+    { "burst", "set burst fusion",     OFFSET(burst),     AV_OPT_TYPE_DOUBLE, {.dbl=2},   0,   10, AF },
     { "b", "set burst fusion",         OFFSET(burst),     AV_OPT_TYPE_DOUBLE, {.dbl=2},   0,   10, AF },
+    { "method", "set overlap method",  OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=0},   0,    1, AF, "m" },
     { "m", "set overlap method",       OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=0},   0,    1, AF, "m" },
+    { "add", "overlap-add",            0,                 AV_OPT_TYPE_CONST,  {.i64=0},   0,    0, AF, "m" },
     { "a", "overlap-add",              0,                 AV_OPT_TYPE_CONST,  {.i64=0},   0,    0, AF, "m" },
+    { "save", "overlap-save",          0,                 AV_OPT_TYPE_CONST,  {.i64=1},   0,    0, AF, "m" },
     { "s", "overlap-save",             0,                 AV_OPT_TYPE_CONST,  {.i64=1},   0,    0, AF, "m" },
     { NULL }
 };
@@ -156,13 +169,17 @@ static int config_input(AVFilterLink *inlink)
     av_frame_free(&s->out);
     av_frame_free(&s->buffer);
     av_frame_free(&s->is);
+    s->enabled = ff_get_audio_buffer(inlink, s->window_size);
     s->in = ff_get_audio_buffer(inlink, s->window_size);
     s->out = ff_get_audio_buffer(inlink, s->window_size);
     s->buffer = ff_get_audio_buffer(inlink, s->window_size * 2);
     s->is = ff_get_audio_buffer(inlink, s->window_size);
-    if (!s->in || !s->out || !s->buffer || !s->is)
+    if (!s->in || !s->out || !s->buffer || !s->is || !s->enabled)
         return AVERROR(ENOMEM);
 
+    s->efifo = av_audio_fifo_alloc(inlink->format, 1, s->window_size);
+    if (!s->efifo)
+        return AVERROR(ENOMEM);
     s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size);
     if (!s->fifo)
         return AVERROR(ENOMEM);
@@ -510,14 +527,20 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
         nb_errors = s->detector(s, c, sigmae, c->detection, c->acoefficients,
                                 c->click, index, src, dst);
         if (nb_errors > 0) {
+            double *enabled = (double *)s->enabled->extended_data[0];
+
             ret = interpolation(c, src, s->ar_order, c->acoefficients, index,
                                 nb_errors, c->auxiliary, interpolated);
             if (ret < 0)
                 return ret;
 
+            av_audio_fifo_peek(s->efifo, (void**)s->enabled->extended_data, s->window_size);
+
             for (j = 0; j < nb_errors; j++) {
-                dst[index[j]] = interpolated[j];
-                is[index[j]] = 1;
+                if (enabled[index[j]]) {
+                    dst[index[j]] = interpolated[j];
+                    is[index[j]] = 1;
+                }
             }
         }
     } else {
@@ -544,68 +567,58 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+static int filter_frame(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     AudioDeclickContext *s = ctx->priv;
     AVFrame *out = NULL;
-    int ret = 0;
-
-    if (s->pts == AV_NOPTS_VALUE)
-        s->pts = in->pts;
-
-    ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data,
-                              in->nb_samples);
-    av_frame_free(&in);
+    int ret = 0, j, ch, detected_errors = 0;
+    ThreadData td;
 
-    while (av_audio_fifo_size(s->fifo) >= s->window_size) {
-        int j, ch, detected_errors = 0;
-        ThreadData td;
-
-        out = ff_get_audio_buffer(outlink, s->hop_size);
-        if (!out)
-            return AVERROR(ENOMEM);
+    out = ff_get_audio_buffer(outlink, s->hop_size);
+    if (!out)
+        return AVERROR(ENOMEM);
 
-        ret = av_audio_fifo_peek(s->fifo, (void **)s->in->extended_data,
-                                 s->window_size);
-        if (ret < 0)
-            break;
+    ret = av_audio_fifo_peek(s->fifo, (void **)s->in->extended_data,
+                             s->window_size);
+    if (ret < 0)
+        goto fail;
 
-        td.out = out;
-        ret = ctx->internal->execute(ctx, filter_channel, &td, NULL, inlink->channels);
-        if (ret < 0)
-            goto fail;
+    td.out = out;
+    ret = ctx->internal->execute(ctx, filter_channel, &td, NULL, inlink->channels);
+    if (ret < 0)
+        goto fail;
 
-        for (ch = 0; ch < s->in->channels; ch++) {
-            double *is = (double *)s->is->extended_data[ch];
+    for (ch = 0; ch < s->in->channels; ch++) {
+        double *is = (double *)s->is->extended_data[ch];
 
-            for (j = 0; j < s->hop_size; j++) {
-                if (is[j])
-                    detected_errors++;
-            }
+        for (j = 0; j < s->hop_size; j++) {
+            if (is[j])
+                detected_errors++;
         }
+    }
 
-        av_audio_fifo_drain(s->fifo, s->hop_size);
+    av_audio_fifo_drain(s->fifo, s->hop_size);
+    av_audio_fifo_drain(s->efifo, s->hop_size);
 
-        if (s->samples_left > 0)
-            out->nb_samples = FFMIN(s->hop_size, s->samples_left);
+    if (s->samples_left > 0)
+        out->nb_samples = FFMIN(s->hop_size, s->samples_left);
 
-        out->pts = s->pts;
-        s->pts += s->hop_size;
+    out->pts = s->pts;
+    s->pts += av_rescale_q(s->hop_size, (AVRational){1, outlink->sample_rate}, outlink->time_base);
 
-        s->detected_errors += detected_errors;
-        s->nb_samples += out->nb_samples * inlink->channels;
+    s->detected_errors += detected_errors;
+    s->nb_samples += out->nb_samples * inlink->channels;
 
-        ret = ff_filter_frame(outlink, out);
-        if (ret < 0)
-            break;
+    ret = ff_filter_frame(outlink, out);
+    if (ret < 0)
+        return ret;
 
-        if (s->samples_left > 0) {
-            s->samples_left -= s->hop_size;
-            if (s->samples_left <= 0)
-                av_audio_fifo_drain(s->fifo, av_audio_fifo_size(s->fifo));
-        }
+    if (s->samples_left > 0) {
+        s->samples_left -= s->hop_size;
+        if (s->samples_left <= 0)
+            av_audio_fifo_drain(s->fifo, av_audio_fifo_size(s->fifo));
     }
 
 fail:
@@ -614,27 +627,64 @@ fail:
     return ret;
 }
 
-static int request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
 {
-    AVFilterContext *ctx = outlink->src;
+    AVFilterLink *inlink = ctx->inputs[0];
+    AVFilterLink *outlink = ctx->outputs[0];
     AudioDeclickContext *s = ctx->priv;
-    int ret = 0;
+    AVFrame *in;
+    int ret, status;
+    int64_t pts;
 
-    ret = ff_request_frame(ctx->inputs[0]);
+    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
 
-    if (ret == AVERROR_EOF && av_audio_fifo_size(s->fifo) > 0) {
-        if (!s->samples_left)
-            s->samples_left = av_audio_fifo_size(s->fifo) - s->overlap_skip;
+    ret = ff_inlink_consume_samples(inlink, s->window_size, s->window_size, &in);
+    if (ret < 0)
+        return ret;
+    if (ret > 0) {
+        double *e = (double *)s->enabled->extended_data[0];
+
+        if (s->pts == AV_NOPTS_VALUE)
+            s->pts = in->pts;
+
+        ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data,
+                                  in->nb_samples);
+        for (int i = 0; i < in->nb_samples; i++)
+            e[i] = !ctx->is_disabled;
+
+        av_audio_fifo_write(s->efifo, (void**)s->enabled->extended_data, in->nb_samples);
+        av_frame_free(&in);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (av_audio_fifo_size(s->fifo) >= s->window_size ||
+        s->samples_left > 0)
+        return filter_frame(inlink);
 
-        if (s->samples_left > 0) {
-            AVFrame *in = ff_get_audio_buffer(outlink, s->window_size - s->samples_left);
-            if (!in)
-                return AVERROR(ENOMEM);
-            ret = filter_frame(ctx->inputs[0], in);
+    if (av_audio_fifo_size(s->fifo) >= s->window_size) {
+        ff_filter_set_ready(ctx, 100);
+        return 0;
+    }
+
+    if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
+        if (status == AVERROR_EOF) {
+            s->eof = 1;
+            s->samples_left = av_audio_fifo_size(s->fifo) - s->overlap_skip;
+            ff_filter_set_ready(ctx, 100);
+            return 0;
         }
     }
 
-    return ret;
+    if (s->eof && s->samples_left <= 0) {
+        ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
+        return 0;
+    }
+
+    if (!s->eof)
+        FF_FILTER_FORWARD_WANTED(outlink, inlink);
+
+    return FFERROR_NOT_READY;
 }
 
 static av_cold int init(AVFilterContext *ctx)
@@ -661,7 +711,9 @@ static av_cold void uninit(AVFilterContext *ctx)
            s->nb_samples, 100. * s->detected_errors / s->nb_samples);
 
     av_audio_fifo_free(s->fifo);
+    av_audio_fifo_free(s->efifo);
     av_freep(&s->window_func_lut);
+    av_frame_free(&s->enabled);
     av_frame_free(&s->in);
     av_frame_free(&s->out);
     av_frame_free(&s->buffer);
@@ -697,7 +749,6 @@ static const AVFilterPad inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
-        .filter_frame = filter_frame,
         .config_props = config_input,
     },
     { NULL }
@@ -707,47 +758,56 @@ static const AVFilterPad outputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_AUDIO,
-        .request_frame = request_frame,
     },
     { NULL }
 };
 
-AVFilter ff_af_adeclick = {
+const AVFilter ff_af_adeclick = {
     .name          = "adeclick",
     .description   = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."),
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioDeclickContext),
     .priv_class    = &adeclick_class,
     .init          = init,
+    .activate      = activate,
     .uninit        = uninit,
     .inputs        = inputs,
     .outputs       = outputs,
-    .flags         = AVFILTER_FLAG_SLICE_THREADS,
+    .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
 
 static const AVOption adeclip_options[] = {
-    { "w", "set window size",          OFFSET(w),              AV_OPT_TYPE_DOUBLE, {.dbl=55},     10,  100, AF },
-    { "o", "set window overlap",       OFFSET(overlap),        AV_OPT_TYPE_DOUBLE, {.dbl=75},     50,   95, AF },
-    { "a", "set autoregression order", OFFSET(ar),             AV_OPT_TYPE_DOUBLE, {.dbl=8},       0,   25, AF },
-    { "t", "set threshold",            OFFSET(threshold),      AV_OPT_TYPE_DOUBLE, {.dbl=10},      1,  100, AF },
-    { "n", "set histogram size",       OFFSET(nb_hbins),       AV_OPT_TYPE_INT,    {.i64=1000},  100, 9999, AF },
-    { "m", "set overlap method",       OFFSET(method),         AV_OPT_TYPE_INT,    {.i64=0},       0,    1, AF, "m" },
-    { "a", "overlap-add",              0,                      AV_OPT_TYPE_CONST,  {.i64=0},       0,    0, AF, "m" },
-    { "s", "overlap-save",             0,                      AV_OPT_TYPE_CONST,  {.i64=1},       0,    0, AF, "m" },
+    { "window", "set window size",     OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=55},     10,  100, AF },
+    { "w", "set window size",          OFFSET(w),         AV_OPT_TYPE_DOUBLE, {.dbl=55},     10,  100, AF },
+    { "overlap", "set window overlap", OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75},     50,   95, AF },
+    { "o", "set window overlap",       OFFSET(overlap),   AV_OPT_TYPE_DOUBLE, {.dbl=75},     50,   95, AF },
+    { "arorder", "set autoregression order", OFFSET(ar),  AV_OPT_TYPE_DOUBLE, {.dbl=8},       0,   25, AF },
+    { "a", "set autoregression order", OFFSET(ar),        AV_OPT_TYPE_DOUBLE, {.dbl=8},       0,   25, AF },
+    { "threshold", "set threshold",    OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=10},      1,  100, AF },
+    { "t", "set threshold",            OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=10},      1,  100, AF },
+    { "hsize", "set histogram size",   OFFSET(nb_hbins),  AV_OPT_TYPE_INT,    {.i64=1000},  100, 9999, AF },
+    { "n", "set histogram size",       OFFSET(nb_hbins),  AV_OPT_TYPE_INT,    {.i64=1000},  100, 9999, AF },
+    { "method", "set overlap method",  OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=0},       0,    1, AF, "m" },
+    { "m", "set overlap method",       OFFSET(method),    AV_OPT_TYPE_INT,    {.i64=0},       0,    1, AF, "m" },
+    { "add", "overlap-add",            0,                 AV_OPT_TYPE_CONST,  {.i64=0},       0,    0, AF, "m" },
+    { "a", "overlap-add",              0,                 AV_OPT_TYPE_CONST,  {.i64=0},       0,    0, AF, "m" },
+    { "save", "overlap-save",          0,                 AV_OPT_TYPE_CONST,  {.i64=1},       0,    0, AF, "m" },
+    { "s", "overlap-save",             0,                 AV_OPT_TYPE_CONST,  {.i64=1},       0,    0, AF, "m" },
     { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(adeclip);
 
-AVFilter ff_af_adeclip = {
+const AVFilter ff_af_adeclip = {
     .name          = "adeclip",
     .description   = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."),
     .query_formats = query_formats,
     .priv_size     = sizeof(AudioDeclickContext),
     .priv_class    = &adeclip_class,
     .init          = init,
+    .activate      = activate,
     .uninit        = uninit,
     .inputs        = inputs,
     .outputs       = outputs,
-    .flags         = AVFILTER_FLAG_SLICE_THREADS,
+    .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };