Created
January 31, 2013 16:39
-
-
Save anonymous/4684199 to your computer and use it in GitHub Desktop.
stdin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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