avfilter/avf_showspectrum: add posibility to display phase
authorPaul B Mahol <onemda@gmail.com>
Sun, 10 Jan 2016 13:20:59 +0000 (14:20 +0100)
committerPaul B Mahol <onemda@gmail.com>
Tue, 12 Jan 2016 20:21:50 +0000 (21:21 +0100)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
doc/filters.texi
libavfilter/avf_showspectrum.c

index efb050d..45d22f4 100644 (file)
@@ -14712,6 +14712,9 @@ window function currently used.
 @item gain
 Set scale gain for calculating intensity color values.
 Default value is @code{1}.
 @item gain
 Set scale gain for calculating intensity color values.
 Default value is @code{1}.
+
+@item data
+Set which data to display. Can be @code{magnitude}, default or @code{phase}.
 @end table
 
 The usage is very similar to the showwaves filter; see the examples in that
 @end table
 
 The usage is very similar to the showwaves filter; see the examples in that
index 36cbdb2..7fd0ea9 100644 (file)
@@ -42,6 +42,7 @@
 #include "window_func.h"
 
 enum DisplayMode  { COMBINED, SEPARATE, NB_MODES };
 #include "window_func.h"
 
 enum DisplayMode  { COMBINED, SEPARATE, NB_MODES };
+enum DataMode     { D_MAGNITUDE, D_PHASE, NB_DMODES };
 enum DisplayScale { LINEAR, SQRT, CBRT, LOG, FOURTHRT, FIFTHRT, NB_SCALES };
 enum ColorMode    { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, NB_CLMODES };
 enum SlideMode    { REPLACE, SCROLL, FULLFRAME, RSCROLL, NB_SLIDES };
 enum DisplayScale { LINEAR, SQRT, CBRT, LOG, FOURTHRT, FIFTHRT, NB_SCALES };
 enum ColorMode    { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, NB_CLMODES };
 enum SlideMode    { REPLACE, SCROLL, FULLFRAME, RSCROLL, NB_SLIDES };
@@ -60,12 +61,14 @@ typedef struct {
     int color_mode;             ///< display color scheme
     int scale;
     float saturation;           ///< color saturation multiplier
     int color_mode;             ///< display color scheme
     int scale;
     float saturation;           ///< color saturation multiplier
+    int data;
     int xpos;                   ///< x position (current column)
     FFTContext *fft;            ///< Fast Fourier Transform context
     int fft_bits;               ///< number of bits (FFT window size = 1<<fft_bits)
     FFTComplex **fft_data;      ///< bins holder for each (displayed) channels
     float *window_func_lut;     ///< Window function LUT
     float **magnitudes;
     int xpos;                   ///< x position (current column)
     FFTContext *fft;            ///< Fast Fourier Transform context
     int fft_bits;               ///< number of bits (FFT window size = 1<<fft_bits)
     FFTComplex **fft_data;      ///< bins holder for each (displayed) channels
     float *window_func_lut;     ///< Window function LUT
     float **magnitudes;
+    float **phases;
     int win_func;
     int win_size;
     double win_scale;
     int win_func;
     int win_size;
     double win_scale;
@@ -134,6 +137,9 @@ static const AVOption showspectrum_options[] = {
         { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
     { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS },
     { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
         { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
     { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS },
     { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
+    { "data", "set data mode", OFFSET(data), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_DMODES-1, FLAGS, "data" },
+        { "magnitude", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_MAGNITUDE}, 0, 0, FLAGS, "data" },
+        { "phase",     NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_PHASE},     0, 0, FLAGS, "data" },
     { NULL }
 };
 
     { NULL }
 };
 
@@ -231,6 +237,11 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_freep(&s->magnitudes);
     av_frame_free(&s->outpicref);
     av_audio_fifo_free(s->fifo);
     av_freep(&s->magnitudes);
     av_frame_free(&s->outpicref);
     av_audio_fifo_free(s->fifo);
+    if (s->phases) {
+        for (i = 0; i < s->nb_display_channels; i++)
+            av_freep(&s->phases[i]);
+    }
+    av_freep(&s->phases);
 }
 
 static int query_formats(AVFilterContext *ctx)
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -329,6 +340,15 @@ static int config_output(AVFilterLink *outlink)
                 return AVERROR(ENOMEM);
         }
 
                 return AVERROR(ENOMEM);
         }
 
+        s->phases = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes));
+        if (!s->phases)
+            return AVERROR(ENOMEM);
+        for (i = 0; i < s->nb_display_channels; i++) {
+            s->phases[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->phases));
+            if (!s->phases[i])
+                return AVERROR(ENOMEM);
+        }
+
         s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data));
         if (!s->fft_data)
             return AVERROR(ENOMEM);
         s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data));
         if (!s->fft_data)
             return AVERROR(ENOMEM);
@@ -427,6 +447,7 @@ static void run_fft(ShowSpectrumContext *s, AVFrame *fin)
 #define RE(y, ch) s->fft_data[ch][y].re
 #define IM(y, ch) s->fft_data[ch][y].im
 #define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch))
 #define RE(y, ch) s->fft_data[ch][y].re
 #define IM(y, ch) s->fft_data[ch][y].im
 #define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch))
+#define PHASE(y, ch) atan2(IM(y, ch), RE(y, ch))
 
 static void calc_magnitudes(ShowSpectrumContext *s)
 {
 
 static void calc_magnitudes(ShowSpectrumContext *s)
 {
@@ -440,6 +461,18 @@ static void calc_magnitudes(ShowSpectrumContext *s)
     }
 }
 
     }
 }
 
+static void calc_phases(ShowSpectrumContext *s)
+{
+    int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
+
+    for (ch = 0; ch < s->nb_display_channels; ch++) {
+        float *phases = s->phases[ch];
+
+        for (y = 0; y < h; y++)
+            phases[y] = (PHASE(y, ch) / M_PI + 1) / 2;
+    }
+}
+
 static void acalc_magnitudes(ShowSpectrumContext *s)
 {
     int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
 static void acalc_magnitudes(ShowSpectrumContext *s)
 {
     int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
@@ -578,7 +611,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
     AVFilterLink *outlink = ctx->outputs[0];
     ShowSpectrumContext *s = ctx->priv;
     AVFrame *outpicref = s->outpicref;
     AVFilterLink *outlink = ctx->outputs[0];
     ShowSpectrumContext *s = ctx->priv;
     AVFrame *outpicref = s->outpicref;
-    const double w = s->win_scale;
+    const double w = s->data == D_PHASE ? 1 : s->win_scale;
     const float g = s->gain;
     int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
 
     const float g = s->gain;
     int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
 
@@ -590,6 +623,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
 
     for (ch = 0; ch < s->nb_display_channels; ch++) {
         float *magnitudes = s->magnitudes[ch];
 
     for (ch = 0; ch < s->nb_display_channels; ch++) {
         float *magnitudes = s->magnitudes[ch];
+        float *phases = s->phases[ch];
         float yf, uf, vf;
 
         /* decide color range */
         float yf, uf, vf;
 
         /* decide color range */
@@ -599,9 +633,20 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
         for (y = 0; y < h; y++) {
             int row = (s->mode == COMBINED) ? y : ch * h + y;
             float *out = &s->combine_buffer[3 * row];
         for (y = 0; y < h; y++) {
             int row = (s->mode == COMBINED) ? y : ch * h + y;
             float *out = &s->combine_buffer[3 * row];
+            float a;
 
 
-            /* get magnitude */
-            float a = g * w * magnitudes[y];
+            switch (s->data) {
+            case D_MAGNITUDE:
+                /* get magnitude */
+                a = g * w * magnitudes[y];
+                break;
+            case D_PHASE:
+                /* get phase */
+                a = phases[y];
+                break;
+            default:
+                av_assert0(0);
+            }
 
             /* apply scale */
             switch (s->scale) {
 
             /* apply scale */
             switch (s->scale) {
@@ -766,7 +811,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
         av_assert0(fin->nb_samples == s->win_size);
 
         run_fft(s, fin);
         av_assert0(fin->nb_samples == s->win_size);
 
         run_fft(s, fin);
-        calc_magnitudes(s);
+        if (s->data == D_MAGNITUDE)
+            calc_magnitudes(s);
+        if (s->data == D_PHASE)
+            calc_phases(s);
 
         ret = plot_spectrum_column(inlink, fin);
         av_frame_free(&fin);
 
         ret = plot_spectrum_column(inlink, fin);
         av_frame_free(&fin);