Skip to content

Instantly share code, notes, and snippets.

Created January 31, 2013 16:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/4684199 to your computer and use it in GitHub Desktop.
Save anonymous/4684199 to your computer and use it in GitHub Desktop.
stdin
From d1d874dc11846f40c1b3060b67cd9e135166f9fb Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda at gmail.com>
Date: Thu, 31 Jan 2013 11:33:04 +0100
Subject: [PATCH 1/6] lavfi/showspectrum: display multiple channels in separate
row
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
doc/filters.texi | 4 +++
libavfilter/avf_showspectrum.c | 75 ++++++++++++++++++++++++++++++++----------
2 files changed, 62 insertions(+), 17 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 21e2cff..73674cb 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -5709,6 +5709,10 @@ Specify the video size for the output. Default value is @code{640x480}.
@item slide
Specify if the spectrum should slide along the window. Default value is
@code{0}.
+ at item compat
+Specify if the old mode, where up to 2 channels are displayed in same row,
+should be used. Default value is
+ at code{0}.
@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 977fca9..21c9561 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -37,11 +37,13 @@ typedef struct {
int w, h;
AVFilterBufferRef *outpicref;
int req_fullfilled;
+ int nb_display_channels;
+ int compat; ///< use old up to 2 channels display mode
int sliding; ///< 1 if sliding mode, 0 otherwise
int xpos; ///< x position (current column)
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
+ 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
@@ -54,6 +56,7 @@ static const AVOption showspectrum_options[] = {
{ "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "compat", "set compat mode", OFFSET(compat), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
{ NULL },
};
@@ -76,8 +79,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
static av_cold void uninit(AVFilterContext *ctx)
{
ShowSpectrumContext *showspectrum = ctx->priv;
+ int i;
av_rdft_end(showspectrum->rdft);
+ for (i = 0; i < showspectrum->nb_display_channels; i++)
+ av_freep(&showspectrum->rdft_data[i]);
av_freep(&showspectrum->rdft_data);
av_freep(&showspectrum->window_func_lut);
avfilter_unref_bufferp(&showspectrum->outpicref);
@@ -120,14 +126,17 @@ static int query_formats(AVFilterContext *ctx)
static int config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
ShowSpectrumContext *showspectrum = ctx->priv;
- int i, rdft_bits, win_size;
+ int i, rdft_bits, win_size, h;
outlink->w = showspectrum->w;
outlink->h = showspectrum->h;
+ h = showspectrum->compat ? outlink->h: outlink->h / inlink->channels;
+
/* RDFT window size (precision) according to the requested output frame height */
- for (rdft_bits = 1; 1<<rdft_bits < 2*outlink->h; rdft_bits++);
+ for (rdft_bits = 1; 1 << rdft_bits < 2 * h; rdft_bits++);
win_size = 1 << rdft_bits;
/* (re-)configuration if the video output changed (or first init) */
@@ -142,12 +151,26 @@ static int config_output(AVFilterLink *outlink)
/* RDFT buffers: x2 for each (display) channel buffer.
* Note: we use free and malloc instead of a realloc-like function to
* make sure the buffer is aligned in memory for the FFT functions. */
+ for (i = 0; i < showspectrum->nb_display_channels; i++)
+ av_freep(&showspectrum->rdft_data[i]);
av_freep(&showspectrum->rdft_data);
- if (av_size_mult(sizeof(*showspectrum->rdft_data), 2 * win_size, &rdft_size) < 0)
+ if (showspectrum->compat)
+ showspectrum->nb_display_channels = FFMIN(inlink->channels, 2);
+ else
+ showspectrum->nb_display_channels = inlink->channels;
+
+ if (av_size_mult(sizeof(*showspectrum->rdft_data),
+ showspectrum->nb_display_channels * win_size, &rdft_size) < 0)
return AVERROR(EINVAL);
- showspectrum->rdft_data = av_malloc(rdft_size);
+ showspectrum->rdft_data = av_malloc(showspectrum->nb_display_channels *
+ sizeof(*showspectrum->rdft_data));
if (!showspectrum->rdft_data)
return AVERROR(ENOMEM);
+ for (i = 0; i < showspectrum->nb_display_channels; i++) {
+ showspectrum->rdft_data[i] = av_malloc(rdft_size);
+ if (!showspectrum->rdft_data[i])
+ return AVERROR(ENOMEM);
+ }
showspectrum->filled = 0;
/* pre-calc windowing function (hann here) */
@@ -213,27 +236,24 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
AVFilterLink *outlink = ctx->outputs[0];
ShowSpectrumContext *showspectrum = ctx->priv;
AVFilterBufferRef *outpicref = showspectrum->outpicref;
- const int nb_channels = av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
/* nb_freq contains the power of two superior or equal to the output image
* height (or half the RDFT window size) */
const int nb_freq = 1 << (showspectrum->rdft_bits - 1);
const int win_size = nb_freq << 1;
+ const double w = 1. / sqrt(nb_freq);
int ch, n, y;
- FFTSample *data[2];
- const int nb_display_channels = FFMIN(nb_channels, 2);
const int start = showspectrum->filled;
const int add_samples = FFMIN(win_size - start, nb_samples);
/* fill RDFT input with the number of samples available */
- for (ch = 0; ch < nb_display_channels; ch++) {
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
const int16_t *p = (int16_t *)insamples->extended_data[ch];
p += showspectrum->consumed;
- data[ch] = showspectrum->rdft_data + win_size * ch; // select channel buffer
for (n = 0; n < add_samples; n++)
- data[ch][start + n] = p[n] * showspectrum->window_func_lut[start + n];
+ showspectrum->rdft_data[ch][start + n] = p[n] * showspectrum->window_func_lut[start + n];
}
showspectrum->filled += add_samples;
@@ -241,20 +261,20 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
if (showspectrum->filled == win_size) {
/* run RDFT on each samples set */
- for (ch = 0; ch < nb_display_channels; ch++)
- av_rdft_calc(showspectrum->rdft, data[ch]);
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++)
+ av_rdft_calc(showspectrum->rdft, showspectrum->rdft_data[ch]);
/* fill a new spectrum column */
-#define RE(ch) data[ch][2*y + 0]
-#define IM(ch) data[ch][2*y + 1]
+#define RE(ch) showspectrum->rdft_data[ch][2*y + 0]
+#define IM(ch) showspectrum->rdft_data[ch][2*y + 1]
#define MAGNITUDE(re, im) sqrt((re)*(re) + (im)*(im))
+ if (showspectrum->compat) {
for (y = 0; y < outlink->h; y++) {
// FIXME: bin[0] contains first and last bins
uint8_t *p = outpicref->data[0] + (outlink->h - y - 1) * outpicref->linesize[0];
- const double w = 1. / sqrt(nb_freq);
int a = sqrt(w * MAGNITUDE(RE(0), IM(0)));
- int b = nb_display_channels > 1 ? sqrt(w * MAGNITUDE(RE(1), IM(1))) : a;
+ int b = showspectrum->nb_display_channels > 1 ? sqrt(w * MAGNITUDE(RE(1), IM(1))) : a;
if (showspectrum->sliding) {
memmove(p, p + 3, (outlink->w - 1) * 3);
@@ -269,6 +289,27 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
p[1] = b;
p[2] = (a + b) / 2;
}
+ } else {
+ int h = outlink->h / showspectrum->nb_display_channels;
+
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
+ for (y = 0; y < h; y++) {
+ uint8_t *p = outpicref->data[0] +
+ (outlink->h - (ch * h + y) - 1) *
+ outpicref->linesize[0];
+ int a = sqrt(w * MAGNITUDE(RE(ch), IM(ch)));
+
+ if (showspectrum->sliding) {
+ memmove(p, p + 3, (outlink->w - 1) * 3);
+ p += (outlink->w - 1) * 3;
+ } else {
+ p += showspectrum->xpos * 3;
+ }
+
+ p[0] = p[1] = p[2] = a;
+ }
+ }
+ }
outpicref->pts = insamples->pts +
av_rescale_q(showspectrum->consumed,
(AVRational){ 1, inlink->sample_rate },
--
1.8.1.1
From 158a4b84004fc4d5035ebec841cf5178f290e060 Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Thu, 31 Jan 2013 14:11:02 +0100
Subject: [PATCH 2/6] lavfi/showspectrum: replace "compat" by "combined";
multichannel support
Channels now have colors! "combined" mode now overlaps all channels on
top of each other with their color. For stereo it looks very close to
ffplay's view.
Also, any channel count is supported now.
This commit also rewrites the separate channel display, to give separate
and combined display a mostly unified code path.
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
---
libavfilter/avf_showspectrum.c | 118 +++++++++++++++++++++++++----------------
1 file changed, 73 insertions(+), 45 deletions(-)
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 21c9561..4355b3b 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -38,8 +38,8 @@ typedef struct {
AVFilterBufferRef *outpicref;
int req_fullfilled;
int nb_display_channels;
- int compat; ///< use old up to 2 channels display mode
int sliding; ///< 1 if sliding mode, 0 otherwise
+ int combined; ///< use old-style combined channel display mode
int xpos; ///< x position (current column)
RDFTContext *rdft; ///< Real Discrete Fourier Transform context
int rdft_bits; ///< number of bits (RDFT window size = 1<<rdft_bits)
@@ -47,6 +47,7 @@ typedef struct {
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
+ float *combine_buffer; ///< color combining buffer (3 * h items)
} ShowSpectrumContext;
#define OFFSET(x) offsetof(ShowSpectrumContext, x)
@@ -56,7 +57,7 @@ static const AVOption showspectrum_options[] = {
{ "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
- { "compat", "set compat mode", OFFSET(compat), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "combined", "set combined mode", OFFSET(combined), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
{ NULL },
};
@@ -81,6 +82,7 @@ static av_cold void uninit(AVFilterContext *ctx)
ShowSpectrumContext *showspectrum = ctx->priv;
int i;
+ av_freep(&showspectrum->combine_buffer);
av_rdft_end(showspectrum->rdft);
for (i = 0; i < showspectrum->nb_display_channels; i++)
av_freep(&showspectrum->rdft_data[i]);
@@ -96,7 +98,7 @@ static int query_formats(AVFilterContext *ctx)
AVFilterLink *inlink = ctx->inputs[0];
AVFilterLink *outlink = ctx->outputs[0];
static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_NONE };
- static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE };
/* set input audio formats */
formats = ff_make_format_list(sample_fmts);
@@ -133,7 +135,7 @@ static int config_output(AVFilterLink *outlink)
outlink->w = showspectrum->w;
outlink->h = showspectrum->h;
- h = showspectrum->compat ? outlink->h: outlink->h / inlink->channels;
+ h = showspectrum->combined ? outlink->h : outlink->h / inlink->channels;
/* RDFT window size (precision) according to the requested output frame height */
for (rdft_bits = 1; 1 << rdft_bits < 2 * h; rdft_bits++);
@@ -154,10 +156,7 @@ static int config_output(AVFilterLink *outlink)
for (i = 0; i < showspectrum->nb_display_channels; i++)
av_freep(&showspectrum->rdft_data[i]);
av_freep(&showspectrum->rdft_data);
- if (showspectrum->compat)
- showspectrum->nb_display_channels = FFMIN(inlink->channels, 2);
- else
- showspectrum->nb_display_channels = inlink->channels;
+ showspectrum->nb_display_channels = inlink->channels;
if (av_size_mult(sizeof(*showspectrum->rdft_data),
showspectrum->nb_display_channels * win_size, &rdft_size) < 0)
@@ -196,6 +195,10 @@ static int config_output(AVFilterLink *outlink)
if (showspectrum->xpos >= outlink->w)
showspectrum->xpos = 0;
+ showspectrum->combine_buffer = av_realloc(showspectrum->combine_buffer,
+ outlink->h * 3 *
+ sizeof(*showspectrum->combine_buffer));
+
av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d RDFT window size:%d\n",
showspectrum->w, showspectrum->h, win_size);
return 0;
@@ -243,7 +246,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
const int win_size = nb_freq << 1;
const double w = 1. / sqrt(nb_freq);
- int ch, n, y;
+ int ch, plane, n, y;
const int start = showspectrum->filled;
const int add_samples = FFMIN(win_size - start, nb_samples);
@@ -260,56 +263,81 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
/* complete RDFT window size? */
if (showspectrum->filled == win_size) {
+ /* channel height */
+ int h = showspectrum->combined ? outlink->h : outlink->h / showspectrum->nb_display_channels;
+
/* run RDFT on each samples set */
for (ch = 0; ch < showspectrum->nb_display_channels; ch++)
av_rdft_calc(showspectrum->rdft, showspectrum->rdft_data[ch]);
/* fill a new spectrum column */
-#define RE(ch) showspectrum->rdft_data[ch][2*y + 0]
-#define IM(ch) showspectrum->rdft_data[ch][2*y + 1]
-#define MAGNITUDE(re, im) sqrt((re)*(re) + (im)*(im))
+#define RE(y,ch) showspectrum->rdft_data[ch][2*y + 0]
+#define IM(y,ch) showspectrum->rdft_data[ch][2*y + 1]
+#define CPLX_MAGNITUDE(re, im) sqrt((re)*(re) + (im)*(im)) /* is actually hypot(re, im) */
+#define MAGNITUDE(y,ch) CPLX_MAGNITUDE(RE(y,ch), IM(y,ch))
- if (showspectrum->compat) {
+ /* initialize buffer for combining to black */
for (y = 0; y < outlink->h; y++) {
- // FIXME: bin[0] contains first and last bins
- uint8_t *p = outpicref->data[0] + (outlink->h - y - 1) * outpicref->linesize[0];
- int a = sqrt(w * MAGNITUDE(RE(0), IM(0)));
- int b = showspectrum->nb_display_channels > 1 ? sqrt(w * MAGNITUDE(RE(1), IM(1))) : a;
-
- if (showspectrum->sliding) {
- memmove(p, p + 3, (outlink->w - 1) * 3);
- p += (outlink->w - 1) * 3;
+ showspectrum->combine_buffer[3*y] = 0;
+ showspectrum->combine_buffer[3*y+1] = 127.5;
+ showspectrum->combine_buffer[3*y+2] = 127.5;
+ }
+
+ for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
+ float yf, uf, vf;
+
+ /* decide channel colors */
+ if (showspectrum->combined) {
+ // reduce range by channel count
+ yf = 1.0f / showspectrum->nb_display_channels;
+ uf = yf;
+ vf = yf;
+ } else {
+ // full range
+ yf = 1.0f;
+ uf = 0.5f;
+ vf = 0.5f;
+ }
+ if (showspectrum->nb_display_channels >= 2) {
+ uf *= cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ vf *= sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
} else {
- p += showspectrum->xpos * 3;
+ uf = 0.0f;
+ vf = 0.0f;
}
- a = FFMIN(a, 255);
- b = FFMIN(b, 255);
- p[0] = a;
- p[1] = b;
- p[2] = (a + b) / 2;
+ /* draw the channel */
+ for (y = 0; y < h; y++) {
+ int row = showspectrum->combined ? y : ch * h + y;
+ float a = sqrt(w * MAGNITUDE(y, ch));
+ float *out = &showspectrum->combine_buffer[3 * row];
+ out[0] += a * yf;
+ out[1] += a * vf;
+ out[2] += a * uf;
+ }
}
- } else {
- int h = outlink->h / showspectrum->nb_display_channels;
-
- for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
- for (y = 0; y < h; y++) {
- uint8_t *p = outpicref->data[0] +
- (outlink->h - (ch * h + y) - 1) *
- outpicref->linesize[0];
- int a = sqrt(w * MAGNITUDE(RE(ch), IM(ch)));
-
- if (showspectrum->sliding) {
- memmove(p, p + 3, (outlink->w - 1) * 3);
- p += (outlink->w - 1) * 3;
- } else {
- p += showspectrum->xpos * 3;
- }
-
- p[0] = p[1] = p[2] = a;
+
+ /* copy to output */
+ if (showspectrum->sliding) {
+ for (plane = 0; plane < 3; plane++) {
+ for (y = 0; y < outlink->h; y++) {
+ uint8_t *p = outpicref->data[plane] +
+ y * outpicref->linesize[plane];
+ memmove(p, p + 1, outlink->w - 1);
}
}
+ showspectrum->xpos = outlink->w - 1;
}
+ for (plane = 0; plane < 3; plane++) {
+ uint8_t *p = outpicref->data[plane] +
+ (outlink->h - 1) * outpicref->linesize[plane] +
+ showspectrum->xpos;
+ for (y = 0; y < outlink->h; y++) {
+ *p = rint(FFMAX(0, FFMIN(showspectrum->combine_buffer[3*y + plane], 255)));
+ p -= outpicref->linesize[plane];
+ }
+ }
+
outpicref->pts = insamples->pts +
av_rescale_q(showspectrum->consumed,
(AVRational){ 1, inlink->sample_rate },
--
1.8.1.1
From 1f5c6e9a2ec45758a261a04b8da4f7d52bee9c9f Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Thu, 31 Jan 2013 14:11:24 +0100
Subject: [PATCH 3/6] lavfi/showspectrum: add a "saturation" option to tune
coloring
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
---
libavfilter/avf_showspectrum.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 4355b3b..59f9891 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -40,6 +40,7 @@ typedef struct {
int nb_display_channels;
int sliding; ///< 1 if sliding mode, 0 otherwise
int combined; ///< use old-style combined channel display mode
+ float saturation; ///< color saturation multiplier
int xpos; ///< x position (current column)
RDFTContext *rdft; ///< Real Discrete Fourier Transform context
int rdft_bits; ///< number of bits (RDFT window size = 1<<rdft_bits)
@@ -58,6 +59,7 @@ static const AVOption showspectrum_options[] = {
{ "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
{ "combined", "set combined mode", OFFSET(combined), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
{ NULL },
};
@@ -305,6 +307,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
uf = 0.0f;
vf = 0.0f;
}
+ uf *= showspectrum->saturation;
+ vf *= showspectrum->saturation;
/* draw the channel */
for (y = 0; y < h; y++) {
--
1.8.1.1
From b6349a3780dce0f01b2de829dc97efbd1a845ec8 Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Thu, 31 Jan 2013 14:03:39 +0100
Subject: [PATCH 4/6] lavfi/showspectrum: replace sqrt() using macro by a call
to hypot()
hypot() exists on most libcs even before C99, and thus shouldn't be a
problem to use. This avoids a bad case of multiple argument evaluation.
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
---
libavfilter/avf_showspectrum.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 59f9891..c15a158 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -275,8 +275,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
/* fill a new spectrum column */
#define RE(y,ch) showspectrum->rdft_data[ch][2*y + 0]
#define IM(y,ch) showspectrum->rdft_data[ch][2*y + 1]
-#define CPLX_MAGNITUDE(re, im) sqrt((re)*(re) + (im)*(im)) /* is actually hypot(re, im) */
-#define MAGNITUDE(y,ch) CPLX_MAGNITUDE(RE(y,ch), IM(y,ch))
+#define MAGNITUDE(y,ch) hypot(RE(y,ch), IM(y,ch))
/* initialize buffer for combining to black */
for (y = 0; y < outlink->h; y++) {
--
1.8.1.1
From a736194f5b1a54ece59cc7bdfe333426dfbe45f1 Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Thu, 31 Jan 2013 17:22:50 +0100
Subject: [PATCH 5/6] lavfi/showspectrum: logarithmic scale, intensity based
coloring
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
---
libavfilter/avf_showspectrum.c | 106 ++++++++++++++++++++++++++++++++++-------
1 file changed, 88 insertions(+), 18 deletions(-)
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index c15a158..80ec6e6 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -39,7 +39,9 @@ typedef struct {
int req_fullfilled;
int nb_display_channels;
int sliding; ///< 1 if sliding mode, 0 otherwise
- int combined; ///< use old-style combined channel display mode
+ int combined; ///< use combined channel display mode
+ int intensity_colors; ///< use intensity-based coloring
+ int logscale; ///< use logarithmic scale
float saturation; ///< color saturation multiplier
int xpos; ///< x position (current column)
RDFTContext *rdft; ///< Real Discrete Fourier Transform context
@@ -59,12 +61,30 @@ static const AVOption showspectrum_options[] = {
{ "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, FLAGS },
{ "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
{ "combined", "set combined mode", OFFSET(combined), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "intensity", "set intensity based coloring", OFFSET(intensity_colors), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "logscale", "set logarithmic scale", OFFSET(logscale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
{ "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
{ NULL },
};
AVFILTER_DEFINE_CLASS(showspectrum);
+struct intensity_color_table_item
+{
+ float a, y, u, v;
+};
+static const struct intensity_color_table_item intensity_color_table[] =
+{
+ { 0, 0, 0, 0 },
+ { 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 },
+ { 0.3, .1857228179456802, .1772436246393981, .1747555484041475 },
+ { 0.6, .2818498058365613, -.1593064119945782, .4713207455460892 },
+ { 0.73, .6583062117554781, -.3716070802232764, .2435275933125293 },
+ { 0.78, 0.763185357582429, -.4307467689263783, .1686649662231043 },
+ { 0.91, .9533636363636364, -.2045454545454546, .03313636363636363 },
+ { 1, 1, 0, 0 }
+};
+
static av_cold int init(AVFilterContext *ctx, const char *args)
{
ShowSpectrumContext *showspectrum = ctx->priv;
@@ -246,7 +266,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
* height (or half the RDFT window size) */
const int nb_freq = 1 << (showspectrum->rdft_bits - 1);
const int win_size = nb_freq << 1;
- const double w = 1. / sqrt(nb_freq);
+ const double w = 1. / sqrt(nb_freq) / 32768.;
int ch, plane, n, y;
const int start = showspectrum->filled;
@@ -287,36 +307,86 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
for (ch = 0; ch < showspectrum->nb_display_channels; ch++) {
float yf, uf, vf;
- /* decide channel colors */
+ /* decide color range */
if (showspectrum->combined) {
// reduce range by channel count
- yf = 1.0f / showspectrum->nb_display_channels;
+ yf = 256.0f / showspectrum->nb_display_channels;
uf = yf;
vf = yf;
- } else {
+ } else if (showspectrum->intensity_colors) {
// full range
- yf = 1.0f;
- uf = 0.5f;
- vf = 0.5f;
- }
- if (showspectrum->nb_display_channels >= 2) {
- uf *= cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
- vf *= sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ yf = 256.0f;
+ uf = 256.0f;
+ vf = 256.0f;
} else {
- uf = 0.0f;
- vf = 0.0f;
+ // full range
+ yf = 256.0f;
+ uf = 128.0f;
+ vf = 128.0f;
}
+
uf *= showspectrum->saturation;
vf *= showspectrum->saturation;
+ /* decide channel colors */
+ if (!showspectrum->intensity_colors) {
+ if (showspectrum->nb_display_channels >= 2) {
+ uf *= sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ vf *= cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ } else {
+ uf = 0.0f;
+ vf = 0.0f;
+ }
+ }
+
/* draw the channel */
for (y = 0; y < h; y++) {
int row = showspectrum->combined ? y : ch * h + y;
- float a = sqrt(w * MAGNITUDE(y, ch));
float *out = &showspectrum->combine_buffer[3 * row];
- out[0] += a * yf;
- out[1] += a * vf;
- out[2] += a * uf;
+
+ /* get magnitude */
+ float a = w * MAGNITUDE(y, ch);
+
+ /* apply scale */
+ if (showspectrum->logscale)
+ a = 1 - log(FFMAX(FFMIN(1, a), 1e-6)) / log(1e-6); // zero = -120dBFS
+ else
+ a = sqrt(a);
+
+ if (showspectrum->intensity_colors) {
+ float y, u, v;
+ int i;
+
+ for (i = 1; i < sizeof(intensity_color_table) / sizeof(*intensity_color_table) - 1; i++)
+ if (intensity_color_table[i].a >= a)
+ break;
+ // i now is the first item >= the color
+ // now we know to interpolate between item i-1 and i
+ if (a <= intensity_color_table[i-1].a) {
+ y = intensity_color_table[i-1].y;
+ u = intensity_color_table[i-1].u;
+ v = intensity_color_table[i-1].v;
+ } else if (a >= intensity_color_table[i].a) {
+ y = intensity_color_table[i].y;
+ u = intensity_color_table[i].u;
+ v = intensity_color_table[i].v;
+ } else {
+ float start = intensity_color_table[i-1].a;
+ float end = intensity_color_table[i].a;
+ float lerpfrac = (a - start) / (end - start);
+ y = intensity_color_table[i-1].y * (1.0f - lerpfrac) + intensity_color_table[i].y * lerpfrac;
+ u = intensity_color_table[i-1].u * (1.0f - lerpfrac) + intensity_color_table[i].u * lerpfrac;
+ v = intensity_color_table[i-1].v * (1.0f - lerpfrac) + intensity_color_table[i].v * lerpfrac;
+ }
+
+ out[0] += y * yf;
+ out[1] += u * uf;
+ out[2] += v * vf;
+ } else {
+ out[0] += a * yf;
+ out[1] += a * uf;
+ out[2] += a * vf;
+ }
}
}
--
1.8.1.1
From 28b085d26cfc111f92d9169e1e2e73525454f475 Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Thu, 31 Jan 2013 17:35:26 +0100
Subject: [PATCH 6/6] lavfi/showspectrum: simplify saturation logic
Signed-off-by: Rudolf Polzer <divverent@xonotic.org>
---
libavfilter/avf_showspectrum.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 80ec6e6..4798173 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -309,36 +309,38 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
/* decide color range */
if (showspectrum->combined) {
- // reduce range by channel count
+ /* reduce range by channel count */
yf = 256.0f / showspectrum->nb_display_channels;
uf = yf;
vf = yf;
- } else if (showspectrum->intensity_colors) {
- // full range
+ if (!showspectrum->intensity_colors) {
+ /* adjust saturation for mixed UV coloring */
+ /* this factor is correct for infinite channels, an approximation otherwise */
+ uf *= M_PI;
+ vf *= M_PI;
+ }
+ } else {
+ /* full range */
yf = 256.0f;
uf = 256.0f;
vf = 256.0f;
- } else {
- // full range
- yf = 256.0f;
- uf = 128.0f;
- vf = 128.0f;
}
- uf *= showspectrum->saturation;
- vf *= showspectrum->saturation;
-
/* decide channel colors */
if (!showspectrum->intensity_colors) {
if (showspectrum->nb_display_channels >= 2) {
- uf *= sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
- vf *= cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ uf *= 0.5 * sin((2 * M_PI * ch) / showspectrum->nb_display_channels);
+ vf *= 0.5 * cos((2 * M_PI * ch) / showspectrum->nb_display_channels);
} else {
uf = 0.0f;
vf = 0.0f;
}
}
+ /* apply saturation */
+ uf *= showspectrum->saturation;
+ vf *= showspectrum->saturation;
+
/* draw the channel */
for (y = 0; y < h; y++) {
int row = showspectrum->combined ? y : ch * h + y;
@@ -360,8 +362,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
for (i = 1; i < sizeof(intensity_color_table) / sizeof(*intensity_color_table) - 1; i++)
if (intensity_color_table[i].a >= a)
break;
- // i now is the first item >= the color
- // now we know to interpolate between item i-1 and i
+ /* i now is the first item >= the color */
+ /* now we know to interpolate between item i-1 and i */
if (a <= intensity_color_table[i-1].a) {
y = intensity_color_table[i-1].y;
u = intensity_color_table[i-1].u;
--
1.8.1.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment