avfilter/af_silenceremove: add median silence detector

This commit is contained in:
Paul B Mahol 2023-05-26 14:10:38 +02:00
parent 68d0b881de
commit 5a13b133f8
3 changed files with 74 additions and 3 deletions

View File

@ -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

View File

@ -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;

View File

@ -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++) {