[FFmpeg-cvslog] avfilter/af_silenceremove: add median silence detector

Paul B Mahol git at videolan.org
Sat May 27 01:35:39 EEST 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Fri May 26 14:10:38 2023 +0200| [5a13b133f8effe2a2bac07b17f591d8ca7f6c1de] | committer: Paul B Mahol

avfilter/af_silenceremove: add median silence detector

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=5a13b133f8effe2a2bac07b17f591d8ca7f6c1de
---

 doc/filters.texi                     |  2 +-
 libavfilter/af_silenceremove.c       |  6 ++++
 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++) {



More information about the ffmpeg-cvslog mailing list