[FFmpeg-devel] [PATCH] avfilter/avf_showspectrum: add window overlap support

Paul B Mahol onemda at gmail.com
Tue Dec 29 17:13:50 CET 2015


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
 doc/filters.texi               |  5 ++++
 libavfilter/avf_showspectrum.c | 57 +++++++++++++++++++++++++++++++++++-------
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index e1b3c69..adcbd58 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -14669,6 +14669,11 @@ Default value is @code{hann}.
 @item orientation
 Set orientation of time vs frequency axis. Can be @code{vertical} or
 @code{horizontal}. Default is @code{vertical}.
+
+ at item overlap
+Set ratio of overlap window. Default value is @code{0}.
+When value is @code{1} overlap is set to recommended size for specific
+window function currently used.
 @end table
 
 The usage is very similar to the showwaves filter; see the examples in that
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 1872135..8ec6cd5 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2012-2013 Clément Bœsch
  * Copyright (c) 2013 Rudolf Polzer <divverent at xonotic.org>
+ * Copyright (c) 2015 Paul B Mahol
  *
  * This file is part of FFmpeg.
  *
@@ -28,9 +29,12 @@
 #include <math.h>
 
 #include "libavcodec/avfft.h"
+#include "libavutil/audio_fifo.h"
 #include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/opt.h"
+#include "audio.h"
+#include "video.h"
 #include "avfilter.h"
 #include "internal.h"
 #include "window_func.h"
@@ -62,7 +66,10 @@ typedef struct {
     int win_func;
     double win_scale;
     float overlap;
+    int skip_samples;
     float *combine_buffer;      ///< color combining buffer (3 * h items)
+    AVAudioFifo *fifo;
+    int64_t pts;
 } ShowSpectrumContext;
 
 #define OFFSET(x) offsetof(ShowSpectrumContext, x)
@@ -107,6 +114,7 @@ static const AVOption showspectrum_options[] = {
     { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
         { "vertical",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL},   0, 0, FLAGS, "orientation" },
         { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
+    { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS },
     { NULL }
 };
 
@@ -137,6 +145,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_freep(&s->rdft_data);
     av_freep(&s->window_func_lut);
     av_frame_free(&s->outpicref);
+    av_audio_fifo_free(s->fifo);
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -176,6 +185,7 @@ static int config_output(AVFilterLink *outlink)
     AVFilterLink *inlink = ctx->inputs[0];
     ShowSpectrumContext *s = ctx->priv;
     int i, rdft_bits, win_size, h, w;
+    float overlap;
 
     outlink->w = s->w;
     outlink->h = s->h;
@@ -230,7 +240,14 @@ static int config_output(AVFilterLink *outlink)
                          sizeof(*s->window_func_lut));
         if (!s->window_func_lut)
             return AVERROR(ENOMEM);
-        ff_generate_window_func(s->window_func_lut, win_size, s->win_func, &s->overlap);
+        ff_generate_window_func(s->window_func_lut, win_size, s->win_func, &overlap);
+        if (s->overlap == 1)
+            s->overlap = overlap;
+        s->skip_samples = (1. - s->overlap) * win_size;
+        if (s->skip_samples < 1) {
+            av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap);
+            return AVERROR(EINVAL);
+        }
 
         for (s->win_scale = 0, i = 0; i < win_size; i++) {
             s->win_scale += s->window_func_lut[i] * s->window_func_lut[i];
@@ -255,15 +272,12 @@ static int config_output(AVFilterLink *outlink)
         (s->orientation == HORIZONTAL && s->xpos >= outlink->h))
         s->xpos = 0;
 
-    outlink->frame_rate = av_make_q(inlink->sample_rate, win_size);
+    outlink->frame_rate = av_make_q(inlink->sample_rate, win_size * (1.-s->overlap));
     if (s->orientation == VERTICAL && s->sliding == FULLFRAME)
         outlink->frame_rate.den *= outlink->w;
     if (s->orientation == HORIZONTAL && s->sliding == FULLFRAME)
         outlink->frame_rate.den *= outlink->h;
 
-    inlink->min_samples = inlink->max_samples = inlink->partial_buf_size =
-        win_size;
-
     if (s->orientation == VERTICAL) {
         s->combine_buffer =
             av_realloc_f(s->combine_buffer, outlink->h * 3,
@@ -276,6 +290,11 @@ static int config_output(AVFilterLink *outlink)
 
     av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d RDFT window size:%d\n",
            s->w, s->h, win_size);
+
+    av_audio_fifo_free(s->fifo);
+    s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, win_size);
+    if (!s->fifo)
+        return AVERROR(ENOMEM);
     return 0;
 }
 
@@ -552,13 +571,33 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     AVFilterContext *ctx = inlink->dst;
     ShowSpectrumContext *s = ctx->priv;
     unsigned win_size = 1 << s->rdft_bits;
+    AVFrame *fin = NULL;
     int ret = 0;
 
-    av_assert0(insamples->nb_samples <= win_size);
-    if (insamples->nb_samples == win_size)
-        ret = plot_spectrum_column(inlink, insamples);
-
+    av_audio_fifo_write(s->fifo, (void **)insamples->extended_data, insamples->nb_samples);
     av_frame_free(&insamples);
+    while (av_audio_fifo_size(s->fifo) >= win_size) {
+        fin = ff_get_audio_buffer(inlink, win_size);
+        if (!fin) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+
+        fin->pts = s->pts;
+        s->pts += s->skip_samples;
+        ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, win_size);
+        if (ret < 0)
+            goto fail;
+
+        ret = plot_spectrum_column(inlink, fin);
+        av_frame_free(&fin);
+        av_audio_fifo_drain(s->fifo, s->skip_samples);
+        if (ret < 0)
+            goto fail;
+    }
+
+fail:
+    av_frame_free(&fin);
     return ret;
 }
 
-- 
1.9.1



More information about the ffmpeg-devel mailing list