[FFmpeg-devel] [PATCH] lavfi/showspectrum: display multiple channels in separate row

Paul B Mahol onemda at gmail.com
Tue Jan 29 19:59:54 CET 2013


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..272fd9d 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.7.11.4



More information about the ffmpeg-devel mailing list