From 15e1fd9883b4a2898635212b4e167823755d1653 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 29 Dec 2015 16:52:16 +0100 Subject: avfilter/avf_showspectrum: add window overlap support Signed-off-by: Paul B Mahol --- doc/filters.texi | 5 ++++ libavfilter/avf_showspectrum.c | 58 +++++++++++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 92931aa0c6..8aa3b47fcf 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -14677,6 +14677,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}. + +@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 d1ac560169..53809943bf 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 + * Copyright (c) 2015 Paul B Mahol * * This file is part of FFmpeg. * @@ -28,9 +29,12 @@ #include #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) @@ -111,6 +118,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 } }; @@ -178,6 +186,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) @@ -217,6 +226,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; @@ -271,7 +281,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]; @@ -296,15 +313,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, @@ -317,6 +331,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; } @@ -516,6 +535,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } } + av_frame_make_writable(s->outpicref); /* copy to output */ if (s->orientation == VERTICAL) { if (s->sliding == SCROLL) { @@ -598,13 +618,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; } -- cgit v1.2.3