diff options
author | Paul B Mahol <onemda@gmail.com> | 2023-05-26 14:10:38 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2023-05-27 00:34:37 +0200 |
commit | 5a13b133f8effe2a2bac07b17f591d8ca7f6c1de (patch) | |
tree | 4566d6141fadb23db355c99de8d1786b3d73aa8f | |
parent | 68d0b881dea35960275fb168030ae1f19dcf1a0f (diff) | |
download | ffmpeg-5a13b133f8effe2a2bac07b17f591d8ca7f6c1de.tar.gz |
avfilter/af_silenceremove: add median silence detector
-rw-r--r-- | doc/filters.texi | 2 | ||||
-rw-r--r-- | libavfilter/af_silenceremove.c | 6 | ||||
-rw-r--r-- | libavfilter/silenceremove_template.c | 69 |
3 files changed, 74 insertions, 3 deletions
diff --git a/doc/filters.texi b/doc/filters.texi index 6f15b54d10..ea42c127da 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -6461,7 +6461,7 @@ With @var{all}, only if all channels are detected as non-silence will cause stopped trimming of silence. @item detection -Set how is silence detected. Can be @code{avg}, @code{rms} or @code{peak}. +Set how is silence detected. Can be @code{avg}, @code{rms}, @code{median} or @code{peak}. Default value is @code{rms}. @item window diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index a3ad0eea13..fa182fc9f3 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -36,6 +36,7 @@ enum SilenceDetect { D_AVG, D_RMS, D_PEAK, + D_MEDIAN, D_NB }; @@ -132,6 +133,7 @@ static const AVOption silenceremove_options[] = { { "avg", "use mean absolute values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_AVG}, 0, 0, AF, "detection" }, { "rms", "use root mean squared values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_RMS}, 0, 0, AF, "detection" }, { "peak", "use max absolute values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_PEAK},0, 0, AF, "detection" }, + { "median", "use median of absolute values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_MEDIAN},0, 0, AF, "detection" }, { "window", "set duration of window for silence detection", OFFSET(window_duration_opt), AV_OPT_TYPE_DURATION, {.i64=20000}, 0, 100000000, AF }, { NULL } }; @@ -234,6 +236,10 @@ static int config_output(AVFilterLink *outlink) s->compute_flt = compute_avg_flt; s->compute_dbl = compute_avg_dbl; break; + case D_MEDIAN: + s->compute_flt = compute_median_flt; + s->compute_dbl = compute_median_dbl; + break; case D_PEAK: s->compute_flt = compute_peak_flt; s->compute_dbl = compute_peak_dbl; diff --git a/libavfilter/silenceremove_template.c b/libavfilter/silenceremove_template.c index be51beb300..143d399f9e 100644 --- a/libavfilter/silenceremove_template.c +++ b/libavfilter/silenceremove_template.c @@ -22,6 +22,7 @@ #undef SAMPLE_FORMAT #undef SQRT #undef ZERO +#undef ONE #if DEPTH == 32 #define SAMPLE_FORMAT flt #define SQRT sqrtf @@ -29,6 +30,7 @@ #define FABS fabsf #define ftype float #define ZERO 0.f +#define ONE 1.f #else #define SAMPLE_FORMAT dbl #define SQRT sqrt @@ -36,6 +38,7 @@ #define FABS fabs #define ftype double #define ZERO 0.0 +#define ONE 1.0 #endif #define fn3(a,b) a##_##b @@ -111,6 +114,68 @@ static ftype fn(compute_avg)(ftype *cache, ftype sample, ftype wsample, return r / window_size; } +static ftype fn(compute_median)(ftype *peak, ftype sample, ftype wsample, + int size, int *ffront, int *bback) +{ + ftype r, abs_sample = FABS(sample); + int front = *ffront; + int back = *bback; + int empty = front == back && peak[front] == -ONE; + int idx; + + if (!empty && FABS(wsample) == peak[front]) { + peak[front] = -ONE; + if (back != front) { + front--; + if (front < 0) + front = size - 1; + } + empty = front == back; + } + + if (!empty && abs_sample > peak[front]) { + while (1) { + peak[front] = -ONE; + if (back == front) { + empty = 1; + break; + } + front--; + if (front < 0) + front = size - 1; + } + } + + while (!empty && abs_sample > peak[back]) { + peak[back] = -ONE; + if (back == front) { + empty = 1; + break; + } + back++; + if (back >= size) + back = 0; + } + + if (!empty) { + back--; + if (back < 0) + back = size - 1; + } + + peak[back] = abs_sample; + idx = (back <= front) ? back + (front - back + 1) / 2 : back + (size + front - back + 1) / 2; + if (idx >= size) + idx -= size; + av_assert2(idx >= 0 && idx < size); + r = peak[idx]; + + *ffront = front; + *bback = back; + + return r; +} + static ftype fn(compute_peak)(ftype *peak, ftype sample, ftype wsample, int size, int *ffront, int *bback) { @@ -216,7 +281,7 @@ static void fn(filter_start)(AVFilterContext *ctx, if (s->start_found_periods < 0) goto skip; - if (s->detection != D_PEAK) + if (s->detection != D_PEAK && s->detection != D_MEDIAN) window_size = s->start_window_size; for (int ch = 0; ch < nb_channels; ch++) { @@ -308,7 +373,7 @@ static void fn(filter_stop)(AVFilterContext *ctx, stop_nb_samples, stop_window_nb_samples); - if (s->detection != D_PEAK) + if (s->detection != D_PEAK && s->detection != D_MEDIAN) window_size = s->stop_window_size; for (int ch = 0; ch < nb_channels; ch++) { |