From: Paul B Mahol <onemda@gmail.com>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH] new audio filter and misc improvements
Date: Wed, 9 Aug 2023 23:36:16 +0200
Message-ID: <CAPYw7P5SYPrr=t=Nn9nNp9rp5DeyNP+MmjBJC33JKafBuLkBWQ@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 18 bytes --]
Patches attached.
[-- Attachment #2: 0003-avfilter-af_adeclick-do-not-output-pointless-message.patch --]
[-- Type: text/x-patch, Size: 1198 bytes --]
From 2d8c330f543397642fa1afe0a01a67155008d4e1 Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 21:53:04 +0200
Subject: [PATCH 3/3] avfilter/af_adeclick: do not output pointless message
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
libavfilter/af_adeclick.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index fd0438d252..3401028c6b 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -721,9 +721,10 @@ static av_cold void uninit(AVFilterContext *ctx)
{
AudioDeclickContext *s = ctx->priv;
- av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
- filter_modes[s->mode], s->detected_errors,
- s->nb_samples, 100. * s->detected_errors / s->nb_samples);
+ if (s->nb_samples > 0)
+ av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
+ filter_modes[s->mode], s->detected_errors,
+ s->nb_samples, 100. * s->detected_errors / s->nb_samples);
av_audio_fifo_free(s->fifo);
av_audio_fifo_free(s->efifo);
--
2.39.1
[-- Attachment #3: 0002-avfilter-af_adeclick-refactor-and-cleanup.patch --]
[-- Type: text/x-patch, Size: 15328 bytes --]
From 0a6de9b1482ece4402b1c7274501b43e43f5f56a Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 21:49:19 +0200
Subject: [PATCH 2/3] avfilter/af_adeclick: refactor and cleanup
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
libavfilter/af_adeclick.c | 136 +++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 69 deletions(-)
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index 1137dbe25b..fd0438d252 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -119,7 +119,6 @@ static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
AudioDeclickContext *s = ctx->priv;
- int i;
s->pts = AV_NOPTS_VALUE;
s->window_size = inlink->sample_rate * s->w / 1000.;
@@ -134,7 +133,7 @@ static int config_input(AVFilterLink *inlink)
s->window_func_lut = av_calloc(s->window_size, sizeof(*s->window_func_lut));
if (!s->window_func_lut)
return AVERROR(ENOMEM);
- for (i = 0; i < s->window_size; i++)
+ for (int i = 0; i < s->window_size; i++)
s->window_func_lut[i] = sin(M_PI * i / s->window_size) *
(1. - (s->overlap / 100.)) * M_PI_2;
@@ -167,7 +166,7 @@ static int config_input(AVFilterLink *inlink)
if (!s->chan)
return AVERROR(ENOMEM);
- for (i = 0; i < inlink->ch_layout.nb_channels; i++) {
+ for (int i = 0; i < inlink->ch_layout.nb_channels; i++) {
DeclickChannel *c = &s->chan[i];
c->detection = av_calloc(s->window_size, sizeof(*c->detection));
@@ -189,13 +188,13 @@ static int config_input(AVFilterLink *inlink)
static void autocorrelation(const double *input, int order, int size,
double *output, double scale)
{
- int i, j;
-
- for (i = 0; i <= order; i++) {
+ for (int i = 0; i <= order; i++) {
+ const double *ninput = input + i;
+ const int isize = size - i;
double value = 0.;
- for (j = i; j < size; j++)
- value += input[j] * input[j - i];
+ for (int j = 0; j < isize; j++)
+ value += ninput[j] * input[j];
output[i] = value * scale;
}
@@ -205,7 +204,6 @@ static double autoregression(const double *samples, int ar_order,
int nb_samples, double *k, double *r, double *a)
{
double alpha;
- int i, j;
memset(a, 0, ar_order * sizeof(*a));
@@ -214,23 +212,23 @@ static double autoregression(const double *samples, int ar_order,
/* Levinson-Durbin algorithm */
k[0] = a[0] = -r[1] / r[0];
alpha = r[0] * (1. - k[0] * k[0]);
- for (i = 1; i < ar_order; i++) {
+ for (int i = 1; i < ar_order; i++) {
double epsilon = 0.;
- for (j = 0; j < i; j++)
+ for (int j = 0; j < i; j++)
epsilon += a[j] * r[i - j];
epsilon += r[i + 1];
k[i] = -epsilon / alpha;
alpha *= (1. - k[i] * k[i]);
- for (j = i - 1; j >= 0; j--)
+ for (int j = i - 1; j >= 0; j--)
k[j] = a[j] + k[i] * a[i - j - 1];
- for (j = 0; j <= i; j++)
+ for (int j = 0; j <= i; j++)
a[j] = k[j];
}
k[0] = 1.;
- for (i = 1; i <= ar_order; i++)
+ for (int i = 1; i <= ar_order; i++)
k[i] = a[i - 1];
return sqrt(alpha);
@@ -238,9 +236,7 @@ static double autoregression(const double *samples, int ar_order,
static int isfinite_array(double *samples, int nb_samples)
{
- int i;
-
- for (i = 0; i < nb_samples; i++)
+ for (int i = 0; i < nb_samples; i++)
if (!isfinite(samples[i]))
return 0;
@@ -272,14 +268,12 @@ static int find_index(int *index, int value, int size)
static int factorization(double *matrix, int n)
{
- int i, j, k;
-
- for (i = 0; i < n; i++) {
+ for (int i = 0; i < n; i++) {
const int in = i * n;
double value;
value = matrix[in + i];
- for (j = 0; j < i; j++)
+ for (int j = 0; j < i; j++)
value -= matrix[j * n + j] * matrix[in + j] * matrix[in + j];
if (value == 0.) {
@@ -287,12 +281,12 @@ static int factorization(double *matrix, int n)
}
matrix[in + i] = value;
- for (j = i + 1; j < n; j++) {
+ for (int j = i + 1; j < n; j++) {
const int jn = j * n;
double x;
x = matrix[jn + i];
- for (k = 0; k < i; k++)
+ for (int k = 0; k < i; k++)
x -= matrix[k * n + k] * matrix[in + k] * matrix[jn + k];
matrix[jn + i] = x / matrix[in + i];
}
@@ -304,8 +298,8 @@ static int factorization(double *matrix, int n)
static int do_interpolation(DeclickChannel *c, double *matrix,
double *vector, int n, double *out)
{
- int i, j, ret;
double *y;
+ int ret;
ret = factorization(matrix, n);
if (ret < 0)
@@ -316,19 +310,19 @@ static int do_interpolation(DeclickChannel *c, double *matrix,
if (!y)
return AVERROR(ENOMEM);
- for (i = 0; i < n; i++) {
+ for (int i = 0; i < n; i++) {
const int in = i * n;
double value;
value = vector[i];
- for (j = 0; j < i; j++)
+ for (int j = 0; j < i; j++)
value -= matrix[in + j] * y[j];
y[i] = value;
}
- for (i = n - 1; i >= 0; i--) {
+ for (int i = n - 1; i >= 0; i--) {
out[i] = y[i] / matrix[i * n + i];
- for (j = i + 1; j < n; j++)
+ for (int j = i + 1; j < n; j++)
out[i] -= matrix[j * n + i] * out[j];
}
@@ -340,7 +334,6 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
double *auxiliary, double *interpolated)
{
double *vector, *matrix;
- int i, j;
av_fast_malloc(&c->matrix, &c->matrix_size, nb_errors * nb_errors * sizeof(*c->matrix));
matrix = c->matrix;
@@ -354,10 +347,10 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
autocorrelation(acoefficients, ar_order, ar_order + 1, auxiliary, 1.);
- for (i = 0; i < nb_errors; i++) {
+ for (int i = 0; i < nb_errors; i++) {
const int im = i * nb_errors;
- for (j = i; j < nb_errors; j++) {
+ for (int j = i; j < nb_errors; j++) {
if (abs(index[j] - index[i]) <= ar_order) {
matrix[j * nb_errors + i] = matrix[im + j] = auxiliary[abs(index[j] - index[i])];
} else {
@@ -366,10 +359,10 @@ static int interpolation(DeclickChannel *c, const double *src, int ar_order,
}
}
- for (i = 0; i < nb_errors; i++) {
+ for (int i = 0; i < nb_errors; i++) {
double value = 0.;
- for (j = -ar_order; j <= ar_order; j++)
+ for (int j = -ar_order; j <= ar_order; j++)
if (find_index(index, index[i] - j, nb_errors))
value -= src[index[i] - j] * auxiliary[abs(j)];
@@ -386,9 +379,11 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
const double *src, double *dst)
{
const double threshold = s->threshold;
+ const int window_size = s->window_size;
+ const int ar_order = s->ar_order;
double max_amplitude = 0;
unsigned *histogram;
- int i, nb_clips = 0;
+ int nb_clips = 0;
av_fast_malloc(&c->histogram, &c->histogram_size, s->nb_hbins * sizeof(*c->histogram));
if (!c->histogram)
@@ -396,7 +391,7 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
histogram = c->histogram;
memset(histogram, 0, sizeof(*histogram) * s->nb_hbins);
- for (i = 0; i < s->window_size; i++) {
+ for (int i = 0; i < window_size; i++) {
const unsigned index = fmin(fabs(src[i]), 1) * (s->nb_hbins - 1);
histogram[index]++;
@@ -404,7 +399,7 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
clip[i] = 0;
}
- for (i = s->nb_hbins - 1; i > 1; i--) {
+ for (int i = s->nb_hbins - 1; i > 1; i--) {
if (histogram[i]) {
if (histogram[i] / (double)FFMAX(histogram[i - 1], 1) > threshold) {
max_amplitude = i / (double)s->nb_hbins;
@@ -414,15 +409,15 @@ static int detect_clips(AudioDeclickContext *s, DeclickChannel *c,
}
if (max_amplitude > 0.) {
- for (i = 0; i < s->window_size; i++) {
+ for (int i = 0; i < window_size; i++) {
clip[i] = fabs(src[i]) >= max_amplitude;
}
}
- memset(clip, 0, s->ar_order * sizeof(*clip));
- memset(clip + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*clip));
+ memset(clip, 0, ar_order * sizeof(*clip));
+ memset(clip + (window_size - ar_order), 0, ar_order * sizeof(*clip));
- for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+ for (int i = ar_order; i < window_size - ar_order; i++)
if (clip[i])
index[nb_clips++] = i;
@@ -436,35 +431,37 @@ static int detect_clicks(AudioDeclickContext *s, DeclickChannel *c,
const double *src, double *dst)
{
const double threshold = s->threshold;
- int i, j, nb_clicks = 0, prev = -1;
+ const int window_size = s->window_size;
+ int nb_clicks = 0, prev = -1;
+ const int ar_order = s->ar_order;
- memset(detection, 0, s->window_size * sizeof(*detection));
+ memset(detection, 0, window_size * sizeof(*detection));
- for (i = s->ar_order; i < s->window_size; i++) {
- for (j = 0; j <= s->ar_order; j++) {
+ for (int i = ar_order; i < window_size; i++) {
+ for (int j = 0; j <= ar_order; j++) {
detection[i] += acoefficients[j] * src[i - j];
}
}
- for (i = 0; i < s->window_size; i++) {
+ for (int i = 0; i < window_size; i++) {
click[i] = fabs(detection[i]) > sigmae * threshold;
dst[i] = src[i];
}
- for (i = 0; i < s->window_size; i++) {
+ for (int i = 0; i < window_size; i++) {
if (!click[i])
continue;
if (prev >= 0 && (i > prev + 1) && (i <= s->nb_burst_samples + prev))
- for (j = prev + 1; j < i; j++)
+ for (int j = prev + 1; j < i; j++)
click[j] = 1;
prev = i;
}
- memset(click, 0, s->ar_order * sizeof(*click));
- memset(click + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*click));
+ memset(click, 0, ar_order * sizeof(*click));
+ memset(click + (window_size - ar_order), 0, ar_order * sizeof(*click));
- for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+ for (int i = ar_order; i < window_size - ar_order; i++)
if (click[i])
index[nb_clicks++] = i;
@@ -478,33 +475,35 @@ static int detect_surges(AudioDeclickContext *s, DeclickChannel *c,
const double *src, double *dst)
{
const double threshold = s->threshold;
+ const int window_size = s->window_size;
const int size = s->nb_surge_samples * 2;
- int i, j, nb_surges = 0;
+ const int ar_order = s->ar_order;
+ int nb_surges = 0;
- memset(detection, 0, s->window_size * sizeof(*detection));
+ memset(detection, 0, window_size * sizeof(*detection));
- for (i = s->ar_order; i < s->window_size; i++) {
- for (j = 0; j <= s->ar_order; j++) {
+ for (int i = ar_order; i < window_size; i++) {
+ for (int j = 0; j <= ar_order; j++) {
detection[i] += acoefficients[j] * src[i - j];
}
}
- for (i = 0; i < s->window_size; i++) {
+ for (int i = 0; i < window_size; i++) {
surge[i] = fabs(detection[i]) > sigmae * threshold;
dst[i] = src[i];
}
- for (i = 0; i < s->window_size;) {
+ for (int i = 0; i < window_size;) {
if (!surge[i++])
continue;
- memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, s->window_size - i));
+ memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, window_size - i));
i += size/2;
}
- memset(surge, 0, s->ar_order * sizeof(*surge));
- memset(surge + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*surge));
+ memset(surge, 0, ar_order * sizeof(*surge));
+ memset(surge + (window_size - ar_order), 0, ar_order * sizeof(*surge));
- for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+ for (int i = ar_order; i < window_size - ar_order; i++)
if (surge[i])
index[nb_surges++] = i;
@@ -528,7 +527,7 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
const double *w = s->window_func_lut;
DeclickChannel *c = &s->chan[ch];
double sigmae;
- int j, ret;
+ int ret;
sigmae = autoregression(src, s->ar_order, s->window_size, c->acoefficients, c->acorrelation, c->tmp);
@@ -549,7 +548,7 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
av_audio_fifo_peek(s->efifo, (void**)s->enabled->extended_data, s->window_size);
- for (j = 0; j < nb_errors; j++) {
+ for (int j = 0; j < nb_errors; j++) {
if (enabled[index[j]]) {
dst[index[j]] = interpolated[j];
is[index[j]] = 1;
@@ -561,15 +560,15 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
}
if (s->method == 0) {
- for (j = 0; j < s->window_size; j++)
+ for (int j = 0; j < s->window_size; j++)
buf[j] += dst[j] * w[j];
} else {
const int skip = s->overlap_skip;
- for (j = 0; j < s->hop_size; j++)
+ for (int j = 0; j < s->hop_size; j++)
buf[j] = dst[skip + j];
}
- for (j = 0; j < s->hop_size; j++)
+ for (int j = 0; j < s->hop_size; j++)
ptr[j] = buf[j];
memmove(buf, buf + s->hop_size, (s->window_size * 2 - s->hop_size) * sizeof(*buf));
@@ -586,7 +585,7 @@ static int filter_frame(AVFilterLink *inlink)
AVFilterLink *outlink = ctx->outputs[0];
AudioDeclickContext *s = ctx->priv;
AVFrame *out = NULL;
- int ret = 0, j, ch, detected_errors = 0;
+ int ret = 0, ch, detected_errors = 0;
ThreadData td;
out = ff_get_audio_buffer(outlink, s->hop_size);
@@ -606,7 +605,7 @@ static int filter_frame(AVFilterLink *inlink)
for (ch = 0; ch < s->in->ch_layout.nb_channels; ch++) {
double *is = (double *)s->is->extended_data[ch];
- for (j = 0; j < s->hop_size; j++) {
+ for (int j = 0; j < s->hop_size; j++) {
if (is[j])
detected_errors++;
}
@@ -721,7 +720,6 @@ static av_cold int init(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
{
AudioDeclickContext *s = ctx->priv;
- int i;
av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
filter_modes[s->mode], s->detected_errors,
@@ -737,7 +735,7 @@ static av_cold void uninit(AVFilterContext *ctx)
av_frame_free(&s->is);
if (s->chan) {
- for (i = 0; i < s->nb_channels; i++) {
+ for (int i = 0; i < s->nb_channels; i++) {
DeclickChannel *c = &s->chan[i];
av_freep(&c->detection);
--
2.39.1
[-- Attachment #4: 0001-avfilter-add-adesurge-filter.patch --]
[-- Type: text/x-patch, Size: 9480 bytes --]
From af565f57f733af327edc1e1724e31a3c5f1fe44f Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Wed, 9 Aug 2023 18:21:25 +0200
Subject: [PATCH 1/3] avfilter: add adesurge filter
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
doc/filters.texi | 51 ++++++++++++++++++++++
libavfilter/Makefile | 1 +
libavfilter/af_adeclick.c | 91 +++++++++++++++++++++++++++++++++++++--
libavfilter/allfilters.c | 1 +
4 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index b30ff8240b..e041adc40f 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -913,6 +913,57 @@ Compute derivative/integral of audio stream.
Applying both filters one after another produces original audio.
+@section adesurge
+Remove big surge in audio samples from input audio.
+
+Samples detected as instant increase or decrease of volume are replaced by
+interpolated samples using autoregressive modelling.
+
+@table @option
+@item window, w
+Set window size, in milliseconds. Allowed range is from @code{10} to
+@code{100}. Default value is @code{85} milliseconds.
+This sets size of window which will be processed at once.
+
+@item overlap, o
+Set window overlap, in percentage of window size. Allowed range is from
+@code{50} to @code{95}. Default value is @code{75} percent.
+Setting this to a very high value may increases surges removal but makes
+whole process much slower.
+
+@item arorder, a
+Set autoregression order, in percentage of window size. Allowed range is from
+@code{0} to @code{25}. Default value is @code{0.5} percent. This option also
+controls quality of interpolated samples using neighbour good samples.
+
+@item threshold, t
+Set threshold value. Allowed range is from @code{1} to @code{100}.
+Default value is @code{20}.
+This controls the strength of surges which is going to be removed.
+The lower value, the more samples will be detected as surges.
+
+@item surges, s
+Set surges size, in number of samples. Allowed range is @code{1} to
+@code{50}. Default value is @code{5}.
+For any sample detected as surge then also its surrounding samples of this size
+will be interpolated also.
+
+@item method, m
+Set overlap method.
+
+It accepts the following values:
+@table @option
+@item add, a
+Select overlap-add method. Even not interpolated samples are slightly
+changed with this method.
+
+@item save, s
+Select overlap-save method. Not interpolated samples remain unchanged.
+@end table
+
+Default value is @code{s}.
+@end table
+
@section adrc
Apply spectral dynamic range controller filter to input audio stream.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 30a0e22ef8..b26a85a7d2 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -49,6 +49,7 @@ OBJS-$(CONFIG_ADECORRELATE_FILTER) += af_adecorrelate.o
OBJS-$(CONFIG_ADELAY_FILTER) += af_adelay.o
OBJS-$(CONFIG_ADENORM_FILTER) += af_adenorm.o
OBJS-$(CONFIG_ADERIVATIVE_FILTER) += af_aderivative.o
+OBJS-$(CONFIG_ADESURGE_FILTER) += af_adesurge.o
OBJS-$(CONFIG_ADRC_FILTER) += af_adrc.o
OBJS-$(CONFIG_ADYNAMICEQUALIZER_FILTER) += af_adynamicequalizer.o
OBJS-$(CONFIG_ADYNAMICSMOOTH_FILTER) += af_adynamicsmooth.o
diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c
index 822f3065b8..1137dbe25b 100644
--- a/libavfilter/af_adeclick.c
+++ b/libavfilter/af_adeclick.c
@@ -25,6 +25,8 @@
#include "filters.h"
#include "internal.h"
+static const char *filter_modes[] = {"clicks", "clips", "surges" };
+
typedef struct DeclickChannel {
double *auxiliary;
double *detection;
@@ -55,8 +57,9 @@ typedef struct AudioDeclickContext {
int method;
int nb_hbins;
- int is_declip;
+ int mode;
int ar_order;
+ int nb_surge_samples;
int nb_burst_samples;
int window_size;
int hop_size;
@@ -468,6 +471,46 @@ static int detect_clicks(AudioDeclickContext *s, DeclickChannel *c,
return nb_clicks;
}
+static int detect_surges(AudioDeclickContext *s, DeclickChannel *c,
+ double sigmae,
+ double *detection, double *acoefficients,
+ uint8_t *surge, int *index,
+ const double *src, double *dst)
+{
+ const double threshold = s->threshold;
+ const int size = s->nb_surge_samples * 2;
+ int i, j, nb_surges = 0;
+
+ memset(detection, 0, s->window_size * sizeof(*detection));
+
+ for (i = s->ar_order; i < s->window_size; i++) {
+ for (j = 0; j <= s->ar_order; j++) {
+ detection[i] += acoefficients[j] * src[i - j];
+ }
+ }
+
+ for (i = 0; i < s->window_size; i++) {
+ surge[i] = fabs(detection[i]) > sigmae * threshold;
+ dst[i] = src[i];
+ }
+
+ for (i = 0; i < s->window_size;) {
+ if (!surge[i++])
+ continue;
+ memset(surge + FFMAX(i - size/2, 0), 1, FFMIN(size, s->window_size - i));
+ i += size/2;
+ }
+
+ memset(surge, 0, s->ar_order * sizeof(*surge));
+ memset(surge + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*surge));
+
+ for (i = s->ar_order; i < s->window_size - s->ar_order; i++)
+ if (surge[i])
+ index[nb_surges++] = i;
+
+ return nb_surges;
+}
+
typedef struct ThreadData {
AVFrame *out;
} ThreadData;
@@ -661,10 +704,14 @@ static av_cold int init(AVFilterContext *ctx)
{
AudioDeclickContext *s = ctx->priv;
- s->is_declip = !strcmp(ctx->filter->name, "adeclip");
- if (s->is_declip) {
+ if (!strcmp(ctx->filter->name, "adesurge")) {
+ s->mode = 2;
+ s->detector = detect_surges;
+ } else if (!strcmp(ctx->filter->name, "adeclip")) {
+ s->mode = 1;
s->detector = detect_clips;
} else {
+ s->mode = 0;
s->detector = detect_clicks;
}
@@ -677,7 +724,7 @@ static av_cold void uninit(AVFilterContext *ctx)
int i;
av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n",
- s->is_declip ? "clips" : "clicks", s->detected_errors,
+ filter_modes[s->mode], s->detected_errors,
s->nb_samples, 100. * s->detected_errors / s->nb_samples);
av_audio_fifo_free(s->fifo);
@@ -772,3 +819,39 @@ const AVFilter ff_af_adeclip = {
FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
.flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
};
+
+static const AVOption adesurge_options[] = {
+ { "window", "set window size", OFFSET(w), AV_OPT_TYPE_DOUBLE, {.dbl=85}, 10, 100, AF },
+ { "w", "set window size", OFFSET(w), AV_OPT_TYPE_DOUBLE, {.dbl=85}, 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=0.5}, 0, 25, AF },
+ { "a", "set autoregression order", OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 25, AF },
+ { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 100, AF },
+ { "t", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 1, 100, AF },
+ { "surges", "set surge size", OFFSET(nb_surge_samples), AV_OPT_TYPE_INT, {.i64=5}, 1, 50, AF },
+ { "s", "set surge size", OFFSET(nb_surge_samples), AV_OPT_TYPE_INT, {.i64=5}, 1, 50, AF },
+ { "method", "set overlap method", OFFSET(method), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "m" },
+ { "m", "set overlap method", OFFSET(method), AV_OPT_TYPE_INT, {.i64=1}, 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(adesurge);
+
+const AVFilter ff_af_adesurge = {
+ .name = "adesurge",
+ .description = NULL_IF_CONFIG_SMALL("Remove surges from input audio."),
+ .priv_size = sizeof(AudioDeclickContext),
+ .priv_class = &adesurge_class,
+ .init = init,
+ .activate = activate,
+ .uninit = uninit,
+ FILTER_INPUTS(inputs),
+ FILTER_OUTPUTS(ff_audio_default_filterpad),
+ FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
+ .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 089ad3a0ed..286e601799 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -35,6 +35,7 @@ extern const AVFilter ff_af_adecorrelate;
extern const AVFilter ff_af_adelay;
extern const AVFilter ff_af_adenorm;
extern const AVFilter ff_af_aderivative;
+extern const AVFilter ff_af_adesurge;
extern const AVFilter ff_af_adrc;
extern const AVFilter ff_af_adynamicequalizer;
extern const AVFilter ff_af_adynamicsmooth;
--
2.39.1
[-- Attachment #5: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next reply other threads:[~2023-08-09 21:29 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-09 21:36 Paul B Mahol [this message]
2023-08-10 9:47 ` Michael Niedermayer
2023-08-10 10:10 ` Paul B Mahol
2023-08-10 15:13 ` Michael Niedermayer
2023-08-10 16:49 ` Paul B Mahol
2023-08-12 10:09 ` Michael Niedermayer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAPYw7P5SYPrr=t=Nn9nNp9rp5DeyNP+MmjBJC33JKafBuLkBWQ@mail.gmail.com' \
--to=onemda@gmail.com \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git