aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2014-08-14 19:42:34 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-08-14 19:42:38 +0200
commitc6c345ea928bafc4097a1b99a8ce18556a38473e (patch)
treea4789362ce5d3ac4333a79c6fbf0cf3970119065
parent37bfeca78cf3e00934427e59350441ca097de84c (diff)
parent638eec2ac34b7f65a8e84203ea4292440bc8fe50 (diff)
downloadffmpeg-c6c345ea928bafc4097a1b99a8ce18556a38473e.tar.gz
Merge remote-tracking branch 'cigaes/master'
* cigaes/master: lavfi/avf_showspectrum: check RDFT context init. lavfi/avf_showspectrum: add full frame sliding mode. lavfi/avf_showspectrum: use automatic framing. lavfi/avf_showspectrum: do not push the frame at EOF. lavfi/avf_showspectrum: fix output pts computation. lavfi/avf_showspectrum: set output frame rate. Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--doc/filters.texi15
-rw-r--r--libavfilter/avf_showspectrum.c105
2 files changed, 68 insertions, 52 deletions
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 4a4b4f4c7a..bd4d818d6b 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;
@@ -55,8 +56,6 @@ typedef struct {
RDFTContext *rdft; ///< Real Discrete Fourier Transform context
int rdft_bits; ///< number of bits (RDFT window size = 1<<rdft_bits)
FFTSample **rdft_data; ///< bins holder for each (displayed) channels
- int filled; ///< number of samples (per channel) filled in current rdft_buffer
- int consumed; ///< number of samples (per channel) consumed from the input frame
float *window_func_lut; ///< Window function LUT
enum WindowFunc win_func;
float *combine_buffer; ///< color combining buffer (3 * h items)
@@ -68,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" },
@@ -175,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.
@@ -199,7 +206,6 @@ static int config_output(AVFilterLink *outlink)
if (!s->rdft_data[i])
return AVERROR(ENOMEM);
}
- s->filled = 0;
/* pre-calc windowing function */
s->window_func_lut =
@@ -246,6 +252,13 @@ 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);
+ if (s->sliding == FULLFRAME)
+ outlink->frame_rate.den *= outlink->w;
+
+ 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));
@@ -255,36 +268,33 @@ 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->filled = 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);
- if (ret == AVERROR_EOF && s->outpicref)
- push_frame(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 +307,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++)
@@ -445,7 +450,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb
}
/* 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] +
@@ -465,32 +470,32 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb
}
}
- outpicref->pts = insamples->pts +
- av_rescale_q(s->consumed,
- (AVRational){ 1, inlink->sample_rate },
- outlink->time_base);
- 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 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;