From a3aaaec8916b8fae810ad35ff3ca299336f0bda0 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 16:23:18 +0200 Subject: lavfi/avf_showspectrum: set output frame rate. --- libavfilter/avf_showspectrum.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libavfilter') diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 4a4b4f4c7a..e3ae6ea045 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -246,6 +246,8 @@ static int config_output(AVFilterLink *outlink) if (s->xpos >= outlink->w) s->xpos = 0; + outlink->frame_rate = av_make_q(inlink->sample_rate, win_size); + s->combine_buffer = av_realloc_f(s->combine_buffer, outlink->h * 3, sizeof(*s->combine_buffer)); -- cgit v1.2.3 From 65b284a4aef68fc88c80d970a41339113293dc18 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 16:23:37 +0200 Subject: lavfi/avf_showspectrum: fix output pts computation. --- libavfilter/avf_showspectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libavfilter') diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index e3ae6ea045..28db8b1009 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -468,7 +468,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb } outpicref->pts = insamples->pts + - av_rescale_q(s->consumed, + av_rescale_q(s->consumed + add_samples - win_size, (AVRational){ 1, inlink->sample_rate }, outlink->time_base); ret = push_frame(outlink); -- cgit v1.2.3 From d4de6d4fadcc70fb96ba0f3793e7ebaf4ddc3da9 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 16:40:54 +0200 Subject: lavfi/avf_showspectrum: do not push the frame at EOF. It is always identical to the last pushed frame. The samples in the last incomplete window were ignored, this is unchanged. Possible enhancement: pad the last incomplete window with silence. --- libavfilter/avf_showspectrum.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 28db8b1009..e92555627d 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -281,8 +281,6 @@ static int request_frame(AVFilterLink *outlink) ret = ff_request_frame(inlink); } while (!s->req_fullfilled && ret >= 0); - if (ret == AVERROR_EOF && s->outpicref) - push_frame(outlink); return ret; } -- cgit v1.2.3 From ec33df60457d95e174c51666cb799e48c55facb0 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 16:58:27 +0200 Subject: lavfi/avf_showspectrum: use automatic framing. The framework can ensure that each input frame has exactly the correct number of samples, except the last one. --- libavfilter/avf_showspectrum.c | 48 +++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) (limited to 'libavfilter') diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index e92555627d..5a4ab271fa 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -55,8 +55,6 @@ typedef struct { RDFTContext *rdft; ///< Real Discrete Fourier Transform context int rdft_bits; ///< number of bits (RDFT window size = 1<rdft_data[i]) return AVERROR(ENOMEM); } - s->filled = 0; /* pre-calc windowing function */ s->window_func_lut = @@ -248,6 +245,9 @@ static int config_output(AVFilterLink *outlink) outlink->frame_rate = av_make_q(inlink->sample_rate, win_size); + inlink->min_samples = inlink->max_samples = inlink->partial_buf_size = + win_size; + s->combine_buffer = av_realloc_f(s->combine_buffer, outlink->h * 3, sizeof(*s->combine_buffer)); @@ -264,7 +264,6 @@ inline static int push_frame(AVFilterLink *outlink) s->xpos++; if (s->xpos >= outlink->w) s->xpos = 0; - s->filled = 0; s->req_fullfilled = 1; return ff_filter_frame(outlink, av_frame_clone(s->outpicref)); @@ -284,7 +283,7 @@ static int request_frame(AVFilterLink *outlink) return ret; } -static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb_samples) +static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) { int ret; AVFilterContext *ctx = inlink->dst; @@ -297,26 +296,21 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb const int nb_freq = 1 << (s->rdft_bits - 1); const int win_size = nb_freq << 1; const double w = 1. / (sqrt(nb_freq) * 32768.); + int h = s->channel_height; int ch, plane, n, y; - const int start = s->filled; - const int add_samples = FFMIN(win_size - start, nb_samples); + + av_assert0(insamples->nb_samples == win_size); /* fill RDFT input with the number of samples available */ for (ch = 0; ch < s->nb_display_channels; ch++) { const int16_t *p = (int16_t *)insamples->extended_data[ch]; - p += s->consumed; - for (n = 0; n < add_samples; n++) - s->rdft_data[ch][start + n] = p[n] * s->window_func_lut[start + n]; + for (n = 0; n < win_size; n++) + s->rdft_data[ch][n] = p[n] * s->window_func_lut[n]; } - s->filled += add_samples; - /* complete RDFT window size? */ - if (s->filled == win_size) { - - /* channel height */ - int h = s->channel_height; + /* TODO reindent */ /* run RDFT on each samples set */ for (ch = 0; ch < s->nb_display_channels; ch++) @@ -465,32 +459,24 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb } } - outpicref->pts = insamples->pts + - av_rescale_q(s->consumed + add_samples - win_size, - (AVRational){ 1, inlink->sample_rate }, - outlink->time_base); + outpicref->pts = insamples->pts; ret = push_frame(outlink); if (ret < 0) return ret; - } - return add_samples; + return win_size; } static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { AVFilterContext *ctx = inlink->dst; ShowSpectrumContext *s = ctx->priv; - int ret = 0, left_samples = insamples->nb_samples; + unsigned win_size = 1 << s->rdft_bits; + int ret = 0; - s->consumed = 0; - while (left_samples) { - int ret = plot_spectrum_column(inlink, insamples, left_samples); - if (ret < 0) - break; - s->consumed += ret; - left_samples -= ret; - } + av_assert0(insamples->nb_samples <= win_size); + if (insamples->nb_samples == win_size) + ret = plot_spectrum_column(inlink, insamples); av_frame_free(&insamples); return ret; -- cgit v1.2.3 From 7c10e32ae5a1e6e1ab654c5f84a0522500de773d Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 19:30:04 +0200 Subject: lavfi/avf_showspectrum: add full frame sliding mode. --- doc/filters.texi | 15 +++++++++++-- libavfilter/avf_showspectrum.c | 50 +++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 20 deletions(-) (limited to 'libavfilter') diff --git a/doc/filters.texi b/doc/filters.texi index a3e4d81197..0ca1d6fd5b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -10687,8 +10687,19 @@ the "Video size" section in the ffmpeg-utils manual. Default value is @code{640x512}. @item slide -Specify if the spectrum should slide along the window. Default value is -@code{0}. +Specify how the spectrum should slide along the window. + +It accepts the following values: +@table @samp +@item replace +the samples start again on the left when they reach the right +@item scroll +the samples scroll from right to left +@item fullframe +frames are only produced when the samples reach the right +@end table + +Default value is @code{replace}. @item mode Specify display mode. diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 5a4ab271fa..9130f6f4ab 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -38,6 +38,7 @@ enum DisplayMode { COMBINED, SEPARATE, NB_MODES }; enum DisplayScale { LINEAR, SQRT, CBRT, LOG, NB_SCALES }; enum ColorMode { CHANNEL, INTENSITY, NB_CLMODES }; enum WindowFunc { WFUNC_NONE, WFUNC_HANN, WFUNC_HAMMING, WFUNC_BLACKMAN, NB_WFUNC }; +enum SlideMode { REPLACE, SCROLL, FULLFRAME, NB_SLIDES }; typedef struct { const AVClass *class; @@ -66,7 +67,10 @@ typedef struct { static const AVOption showspectrum_options[] = { { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS }, { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS }, - { "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS }, + { "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_SLIDES, FLAGS, "slide" }, + { "replace", "replace old colums with new", 0, AV_OPT_TYPE_CONST, {.i64=REPLACE}, 0, 0, FLAGS, "slide" }, + { "scroll", "scroll from right to left", 0, AV_OPT_TYPE_CONST, {.i64=SCROLL}, 0, 0, FLAGS, "slide" }, + { "fullframe", "return full frames", 0, AV_OPT_TYPE_CONST, {.i64=FULLFRAME}, 0, 0, FLAGS, "slide" }, { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, COMBINED, NB_MODES-1, FLAGS, "mode" }, { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" }, { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" }, @@ -244,6 +248,8 @@ static int config_output(AVFilterLink *outlink) s->xpos = 0; outlink->frame_rate = av_make_q(inlink->sample_rate, win_size); + if (s->sliding == FULLFRAME) + outlink->frame_rate.den *= outlink->w; inlink->min_samples = inlink->max_samples = inlink->partial_buf_size = win_size; @@ -257,27 +263,27 @@ static int config_output(AVFilterLink *outlink) return 0; } -inline static int push_frame(AVFilterLink *outlink) -{ - ShowSpectrumContext *s = outlink->src->priv; - - s->xpos++; - if (s->xpos >= outlink->w) - s->xpos = 0; - s->req_fullfilled = 1; - - return ff_filter_frame(outlink, av_frame_clone(s->outpicref)); -} - static int request_frame(AVFilterLink *outlink) { ShowSpectrumContext *s = outlink->src->priv; AVFilterLink *inlink = outlink->src->inputs[0]; + unsigned i; int ret; s->req_fullfilled = 0; do { ret = ff_request_frame(inlink); + if (ret == AVERROR_EOF && s->sliding == FULLFRAME && s->xpos > 0 && + s->outpicref) { + for (i = 0; i < outlink->h; i++) { + memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos); + memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos); + memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos); + } + ret = ff_filter_frame(outlink, s->outpicref); + s->outpicref = NULL; + s->req_fullfilled = 1; + } } while (!s->req_fullfilled && ret >= 0); return ret; @@ -439,7 +445,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } /* copy to output */ - if (s->sliding) { + if (s->sliding == SCROLL) { for (plane = 0; plane < 3; plane++) { for (y = 0; y < outlink->h; y++) { uint8_t *p = outpicref->data[plane] + @@ -459,10 +465,18 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } } - outpicref->pts = insamples->pts; - ret = push_frame(outlink); - if (ret < 0) - return ret; + if (s->sliding != FULLFRAME || s->xpos == 0) + outpicref->pts = insamples->pts; + + s->xpos++; + if (s->xpos >= outlink->w) + s->xpos = 0; + if (s->sliding != FULLFRAME || s->xpos == 0) { + s->req_fullfilled = 1; + ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref)); + if (ret < 0) + return ret; + } return win_size; } -- cgit v1.2.3 From 638eec2ac34b7f65a8e84203ea4292440bc8fe50 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 3 Aug 2014 20:39:59 +0200 Subject: lavfi/avf_showspectrum: check RDFT context init. Fix a segfault with large window size. --- libavfilter/avf_showspectrum.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libavfilter') diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 9130f6f4ab..bd4d818d6b 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -177,6 +177,11 @@ static int config_output(AVFilterLink *outlink) av_rdft_end(s->rdft); s->rdft = av_rdft_init(rdft_bits, DFT_R2C); + if (!s->rdft) { + av_log(ctx, AV_LOG_ERROR, "Unable to create RDFT context. " + "The window size might be too high.\n"); + return AVERROR(EINVAL); + } s->rdft_bits = rdft_bits; /* RDFT buffers: x2 for each (display) channel buffer. -- cgit v1.2.3