FFmpeg
avf_showspectrum.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2013 Clément Bœsch
3  * Copyright (c) 2013 Rudolf Polzer <divverent@xonotic.org>
4  * Copyright (c) 2015 Paul B Mahol
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * audio to spectrum (video) transmedia filter, based on ffplay rdft showmode
26  * (by Michael Niedermayer) and lavfi/avf_showwaves (by Stefano Sabatini).
27  */
28 
29 #include <math.h>
30 
31 #include "libavutil/tx.h"
32 #include "libavutil/audio_fifo.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/parseutils.h"
39 #include "audio.h"
40 #include "video.h"
41 #include "avfilter.h"
42 #include "filters.h"
43 #include "internal.h"
44 #include "window_func.h"
45 
53 
54 typedef struct ShowSpectrumContext {
55  const AVClass *class;
56  int w, h;
57  char *rate_str;
65  int sliding; ///< 1 if sliding mode, 0 otherwise
66  int mode; ///< channel display mode
67  int color_mode; ///< display color scheme
68  int scale;
69  int fscale;
70  float saturation; ///< color saturation multiplier
71  float rotation; ///< color rotation
72  int start, stop; ///< zoom mode
73  int data;
74  int xpos; ///< x position (current column)
75  AVTXContext **fft; ///< Fast Fourier Transform context
76  AVTXContext **ifft; ///< Inverse Fast Fourier Transform context
79  int fft_size; ///< number of coeffs (FFT window size)
80  AVComplexFloat **fft_in; ///< input FFT coeffs
81  AVComplexFloat **fft_data; ///< bins holder for each (displayed) channels
82  AVComplexFloat **fft_scratch;///< scratch buffers
83  float *window_func_lut; ///< Window function LUT
84  float **magnitudes;
85  float **phases;
86  int win_func;
87  int win_size;
88  int buf_size;
89  double win_scale;
90  float overlap;
91  float gain;
92  int consumed;
93  int hop_size;
94  float *combine_buffer; ///< color combining buffer (3 * h items)
95  float **color_buffer; ///< color buffer (3 * h * ch items)
97  int64_t pts;
98  int64_t old_pts;
99  int old_len;
101  int legend;
103  int (*plot_channel)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
105 
106 #define OFFSET(x) offsetof(ShowSpectrumContext, x)
107 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
108 
109 static const AVOption showspectrum_options[] = {
110  { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
111  { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
112  { "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_SLIDES-1, FLAGS, "slide" },
113  { "replace", "replace old columns with new", 0, AV_OPT_TYPE_CONST, {.i64=REPLACE}, 0, 0, FLAGS, "slide" },
114  { "scroll", "scroll from right to left", 0, AV_OPT_TYPE_CONST, {.i64=SCROLL}, 0, 0, FLAGS, "slide" },
115  { "fullframe", "return full frames", 0, AV_OPT_TYPE_CONST, {.i64=FULLFRAME}, 0, 0, FLAGS, "slide" },
116  { "rscroll", "scroll from left to right", 0, AV_OPT_TYPE_CONST, {.i64=RSCROLL}, 0, 0, FLAGS, "slide" },
117  { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, COMBINED, NB_MODES-1, FLAGS, "mode" },
118  { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
119  { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
120  { "color", "set channel coloring", OFFSET(color_mode), AV_OPT_TYPE_INT, {.i64=CHANNEL}, CHANNEL, NB_CLMODES-1, FLAGS, "color" },
121  { "channel", "separate color for each channel", 0, AV_OPT_TYPE_CONST, {.i64=CHANNEL}, 0, 0, FLAGS, "color" },
122  { "intensity", "intensity based coloring", 0, AV_OPT_TYPE_CONST, {.i64=INTENSITY}, 0, 0, FLAGS, "color" },
123  { "rainbow", "rainbow based coloring", 0, AV_OPT_TYPE_CONST, {.i64=RAINBOW}, 0, 0, FLAGS, "color" },
124  { "moreland", "moreland based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MORELAND}, 0, 0, FLAGS, "color" },
125  { "nebulae", "nebulae based coloring", 0, AV_OPT_TYPE_CONST, {.i64=NEBULAE}, 0, 0, FLAGS, "color" },
126  { "fire", "fire based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIRE}, 0, 0, FLAGS, "color" },
127  { "fiery", "fiery based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIERY}, 0, 0, FLAGS, "color" },
128  { "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
129  { "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
130  { "magma", "magma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MAGMA}, 0, 0, FLAGS, "color" },
131  { "green", "green based coloring", 0, AV_OPT_TYPE_CONST, {.i64=GREEN}, 0, 0, FLAGS, "color" },
132  { "viridis", "viridis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=VIRIDIS}, 0, 0, FLAGS, "color" },
133  { "plasma", "plasma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=PLASMA}, 0, 0, FLAGS, "color" },
134  { "cividis", "cividis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=CIVIDIS}, 0, 0, FLAGS, "color" },
135  { "terrain", "terrain based coloring", 0, AV_OPT_TYPE_CONST, {.i64=TERRAIN}, 0, 0, FLAGS, "color" },
136  { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=SQRT}, LINEAR, NB_SCALES-1, FLAGS, "scale" },
137  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
138  { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
139  { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
140  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
141  { "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
142  { "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
143  { "fscale", "set frequency scale", OFFSET(fscale), AV_OPT_TYPE_INT, {.i64=F_LINEAR}, 0, NB_FSCALES-1, FLAGS, "fscale" },
144  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=F_LINEAR}, 0, 0, FLAGS, "fscale" },
145  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=F_LOG}, 0, 0, FLAGS, "fscale" },
146  { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
147  { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" },
148  { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" },
149  { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" },
150  { "hann", "Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" },
151  { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" },
152  { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" },
153  { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" },
154  { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, FLAGS, "win_func" },
155  { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, FLAGS, "win_func" },
156  { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, FLAGS, "win_func" },
157  { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, FLAGS, "win_func" },
158  { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, FLAGS, "win_func" },
159  { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, FLAGS, "win_func" },
160  { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, FLAGS, "win_func" },
161  { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" },
162  { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" },
163  { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" },
164  { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" },
165  { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" },
166  { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" },
167  { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" },
168  { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, FLAGS, "win_func" },
169  { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
170  { "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
171  { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
172  { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS },
173  { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
174  { "data", "set data mode", OFFSET(data), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_DMODES-1, FLAGS, "data" },
175  { "magnitude", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_MAGNITUDE}, 0, 0, FLAGS, "data" },
176  { "phase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_PHASE}, 0, 0, FLAGS, "data" },
177  { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
178  { "start", "start frequency", OFFSET(start), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
179  { "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
180  { "fps", "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = "auto"}, 0, 0, FLAGS },
181  { "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
182  { NULL }
183 };
184 
185 AVFILTER_DEFINE_CLASS(showspectrum);
186 
187 static const struct ColorTable {
188  float a, y, u, v;
189 } color_table[][8] = {
190  [INTENSITY] = {
191  { 0, 0, 0, 0 },
192  { 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 },
193  { 0.30, .18572281794568020, .1772436246393981, .17475554840414750 },
194  { 0.60, .28184980583656130, -.1593064119945782, .47132074554608920 },
195  { 0.73, .65830621175547810, -.3716070802232764, .24352759331252930 },
196  { 0.78, .76318535758242900, -.4307467689263783, .16866496622310430 },
197  { 0.91, .95336363636363640, -.2045454545454546, .03313636363636363 },
198  { 1, 1, 0, 0 }},
199  [RAINBOW] = {
200  { 0, 0, 0, 0 },
201  { 0.13, 44/256., (189-128)/256., (138-128)/256. },
202  { 0.25, 29/256., (186-128)/256., (119-128)/256. },
203  { 0.38, 119/256., (194-128)/256., (53-128)/256. },
204  { 0.60, 111/256., (73-128)/256., (59-128)/256. },
205  { 0.73, 205/256., (19-128)/256., (149-128)/256. },
206  { 0.86, 135/256., (83-128)/256., (200-128)/256. },
207  { 1, 73/256., (95-128)/256., (225-128)/256. }},
208  [MORELAND] = {
209  { 0, 44/256., (181-128)/256., (112-128)/256. },
210  { 0.13, 126/256., (177-128)/256., (106-128)/256. },
211  { 0.25, 164/256., (163-128)/256., (109-128)/256. },
212  { 0.38, 200/256., (140-128)/256., (120-128)/256. },
213  { 0.60, 201/256., (117-128)/256., (141-128)/256. },
214  { 0.73, 177/256., (103-128)/256., (165-128)/256. },
215  { 0.86, 136/256., (100-128)/256., (183-128)/256. },
216  { 1, 68/256., (117-128)/256., (203-128)/256. }},
217  [NEBULAE] = {
218  { 0, 10/256., (134-128)/256., (132-128)/256. },
219  { 0.23, 21/256., (137-128)/256., (130-128)/256. },
220  { 0.45, 35/256., (134-128)/256., (134-128)/256. },
221  { 0.57, 51/256., (130-128)/256., (139-128)/256. },
222  { 0.67, 104/256., (116-128)/256., (162-128)/256. },
223  { 0.77, 120/256., (105-128)/256., (188-128)/256. },
224  { 0.87, 140/256., (105-128)/256., (188-128)/256. },
225  { 1, 1, 0, 0 }},
226  [FIRE] = {
227  { 0, 0, 0, 0 },
228  { 0.23, 44/256., (132-128)/256., (127-128)/256. },
229  { 0.45, 62/256., (116-128)/256., (140-128)/256. },
230  { 0.57, 75/256., (105-128)/256., (152-128)/256. },
231  { 0.67, 95/256., (91-128)/256., (166-128)/256. },
232  { 0.77, 126/256., (74-128)/256., (172-128)/256. },
233  { 0.87, 164/256., (73-128)/256., (162-128)/256. },
234  { 1, 1, 0, 0 }},
235  [FIERY] = {
236  { 0, 0, 0, 0 },
237  { 0.23, 36/256., (116-128)/256., (163-128)/256. },
238  { 0.45, 52/256., (102-128)/256., (200-128)/256. },
239  { 0.57, 116/256., (84-128)/256., (196-128)/256. },
240  { 0.67, 157/256., (67-128)/256., (181-128)/256. },
241  { 0.77, 193/256., (40-128)/256., (155-128)/256. },
242  { 0.87, 221/256., (101-128)/256., (134-128)/256. },
243  { 1, 1, 0, 0 }},
244  [FRUIT] = {
245  { 0, 0, 0, 0 },
246  { 0.20, 29/256., (136-128)/256., (119-128)/256. },
247  { 0.30, 60/256., (119-128)/256., (90-128)/256. },
248  { 0.40, 85/256., (91-128)/256., (85-128)/256. },
249  { 0.50, 116/256., (70-128)/256., (105-128)/256. },
250  { 0.60, 151/256., (50-128)/256., (146-128)/256. },
251  { 0.70, 191/256., (63-128)/256., (178-128)/256. },
252  { 1, 98/256., (80-128)/256., (221-128)/256. }},
253  [COOL] = {
254  { 0, 0, 0, 0 },
255  { .15, 0, .5, -.5 },
256  { 1, 1, -.5, .5 }},
257  [MAGMA] = {
258  { 0, 0, 0, 0 },
259  { 0.10, 23/256., (175-128)/256., (120-128)/256. },
260  { 0.23, 43/256., (158-128)/256., (144-128)/256. },
261  { 0.35, 85/256., (138-128)/256., (179-128)/256. },
262  { 0.48, 96/256., (128-128)/256., (189-128)/256. },
263  { 0.64, 128/256., (103-128)/256., (214-128)/256. },
264  { 0.92, 205/256., (80-128)/256., (152-128)/256. },
265  { 1, 1, 0, 0 }},
266  [GREEN] = {
267  { 0, 0, 0, 0 },
268  { .75, .5, 0, -.5 },
269  { 1, 1, 0, 0 }},
270  [VIRIDIS] = {
271  { 0, 0, 0, 0 },
272  { 0.10, 0x39/255., (0x9D -128)/255., (0x8F -128)/255. },
273  { 0.23, 0x5C/255., (0x9A -128)/255., (0x68 -128)/255. },
274  { 0.35, 0x69/255., (0x93 -128)/255., (0x57 -128)/255. },
275  { 0.48, 0x76/255., (0x88 -128)/255., (0x4B -128)/255. },
276  { 0.64, 0x8A/255., (0x72 -128)/255., (0x4F -128)/255. },
277  { 0.80, 0xA3/255., (0x50 -128)/255., (0x66 -128)/255. },
278  { 1, 0xCC/255., (0x2F -128)/255., (0x87 -128)/255. }},
279  [PLASMA] = {
280  { 0, 0, 0, 0 },
281  { 0.10, 0x27/255., (0xC2 -128)/255., (0x82 -128)/255. },
282  { 0.58, 0x5B/255., (0x9A -128)/255., (0xAE -128)/255. },
283  { 0.70, 0x89/255., (0x44 -128)/255., (0xAB -128)/255. },
284  { 0.80, 0xB4/255., (0x2B -128)/255., (0x9E -128)/255. },
285  { 0.91, 0xD2/255., (0x38 -128)/255., (0x92 -128)/255. },
286  { 1, 1, 0, 0. }},
287  [CIVIDIS] = {
288  { 0, 0, 0, 0 },
289  { 0.20, 0x28/255., (0x98 -128)/255., (0x6F -128)/255. },
290  { 0.50, 0x48/255., (0x95 -128)/255., (0x74 -128)/255. },
291  { 0.63, 0x69/255., (0x84 -128)/255., (0x7F -128)/255. },
292  { 0.76, 0x89/255., (0x75 -128)/255., (0x84 -128)/255. },
293  { 0.90, 0xCE/255., (0x35 -128)/255., (0x95 -128)/255. },
294  { 1, 1, 0, 0. }},
295  [TERRAIN] = {
296  { 0, 0, 0, 0 },
297  { 0.15, 0, .5, 0 },
298  { 0.60, 1, -.5, -.5 },
299  { 0.85, 1, -.5, .5 },
300  { 1, 1, 0, 0 }},
301 };
302 
304 {
305  ShowSpectrumContext *s = ctx->priv;
306  int i;
307 
308  av_freep(&s->combine_buffer);
309  if (s->fft) {
310  for (i = 0; i < s->nb_display_channels; i++)
311  av_tx_uninit(&s->fft[i]);
312  }
313  av_freep(&s->fft);
314  if (s->ifft) {
315  for (i = 0; i < s->nb_display_channels; i++)
316  av_tx_uninit(&s->ifft[i]);
317  }
318  av_freep(&s->ifft);
319  if (s->fft_data) {
320  for (i = 0; i < s->nb_display_channels; i++)
321  av_freep(&s->fft_data[i]);
322  }
323  av_freep(&s->fft_data);
324  if (s->fft_in) {
325  for (i = 0; i < s->nb_display_channels; i++)
326  av_freep(&s->fft_in[i]);
327  }
328  av_freep(&s->fft_in);
329  if (s->fft_scratch) {
330  for (i = 0; i < s->nb_display_channels; i++)
331  av_freep(&s->fft_scratch[i]);
332  }
333  av_freep(&s->fft_scratch);
334  if (s->color_buffer) {
335  for (i = 0; i < s->nb_display_channels; i++)
336  av_freep(&s->color_buffer[i]);
337  }
338  av_freep(&s->color_buffer);
339  av_freep(&s->window_func_lut);
340  if (s->magnitudes) {
341  for (i = 0; i < s->nb_display_channels; i++)
342  av_freep(&s->magnitudes[i]);
343  }
344  av_freep(&s->magnitudes);
345  av_frame_free(&s->outpicref);
346  av_audio_fifo_free(s->fifo);
347  if (s->phases) {
348  for (i = 0; i < s->nb_display_channels; i++)
349  av_freep(&s->phases[i]);
350  }
351  av_freep(&s->phases);
352 }
353 
355 {
358  AVFilterLink *inlink = ctx->inputs[0];
359  AVFilterLink *outlink = ctx->outputs[0];
362  int ret;
363 
364  /* set input audio formats */
366  if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0)
367  return ret;
368 
370  if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0)
371  return ret;
372 
374  if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0)
375  return ret;
376 
377  /* set output video format */
379  if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0)
380  return ret;
381 
382  return 0;
383 }
384 
385 static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
386 {
387  ShowSpectrumContext *s = ctx->priv;
388  AVFilterLink *inlink = ctx->inputs[0];
389  const float *window_func_lut = s->window_func_lut;
390  AVFrame *fin = arg;
391  const int ch = jobnr;
392  int n;
393 
394  /* fill FFT input with the number of samples available */
395  const float *p = (float *)fin->extended_data[ch];
396 
397  if (s->stop) {
398  float theta, phi, psi, a, b, S, c;
399  AVComplexFloat *f = s->fft_in[ch];
400  AVComplexFloat *g = s->fft_data[ch];
401  AVComplexFloat *h = s->fft_scratch[ch];
402  int L = s->buf_size;
403  int N = s->win_size;
404  int M = s->win_size / 2;
405 
406  for (n = 0; n < s->win_size; n++) {
407  s->fft_data[ch][n].re = p[n] * window_func_lut[n];
408  s->fft_data[ch][n].im = 0;
409  }
410 
411  phi = 2.f * M_PI * (s->stop - s->start) / (float)inlink->sample_rate / (M - 1);
412  theta = 2.f * M_PI * s->start / (float)inlink->sample_rate;
413 
414  for (int n = 0; n < M; n++) {
415  h[n].re = cosf(n * n / 2.f * phi);
416  h[n].im = sinf(n * n / 2.f * phi);
417  }
418 
419  for (int n = M; n < L; n++) {
420  h[n].re = 0.f;
421  h[n].im = 0.f;
422  }
423 
424  for (int n = L - N; n < L; n++) {
425  h[n].re = cosf((L - n) * (L - n) / 2.f * phi);
426  h[n].im = sinf((L - n) * (L - n) / 2.f * phi);
427  }
428 
429  for (int n = N; n < L; n++) {
430  g[n].re = 0.f;
431  g[n].im = 0.f;
432  }
433 
434  for (int n = 0; n < N; n++) {
435  psi = n * theta + n * n / 2.f * phi;
436  c = cosf(psi);
437  S = -sinf(psi);
438  a = c * g[n].re - S * g[n].im;
439  b = S * g[n].re + c * g[n].im;
440  g[n].re = a;
441  g[n].im = b;
442  }
443 
444  memcpy(f, h, s->buf_size * sizeof(*f));
445  s->tx_fn(s->fft[ch], h, f, sizeof(float));
446 
447  memcpy(f, g, s->buf_size * sizeof(*f));
448  s->tx_fn(s->fft[ch], g, f, sizeof(float));
449 
450  for (int n = 0; n < L; n++) {
451  c = g[n].re;
452  S = g[n].im;
453  a = c * h[n].re - S * h[n].im;
454  b = S * h[n].re + c * h[n].im;
455 
456  g[n].re = a / L;
457  g[n].im = b / L;
458  }
459 
460  memcpy(f, g, s->buf_size * sizeof(*f));
461  s->itx_fn(s->ifft[ch], g, f, sizeof(float));
462 
463  for (int k = 0; k < M; k++) {
464  psi = k * k / 2.f * phi;
465  c = cosf(psi);
466  S = -sinf(psi);
467  a = c * g[k].re - S * g[k].im;
468  b = S * g[k].re + c * g[k].im;
469  s->fft_data[ch][k].re = a;
470  s->fft_data[ch][k].im = b;
471  }
472  } else {
473  for (n = 0; n < s->win_size; n++) {
474  s->fft_in[ch][n].re = p[n] * window_func_lut[n];
475  s->fft_in[ch][n].im = 0;
476  }
477 
478  /* run FFT on each samples set */
479  s->tx_fn(s->fft[ch], s->fft_data[ch], s->fft_in[ch], sizeof(float));
480  }
481 
482  return 0;
483 }
484 
485 static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o)
486 {
487  const uint8_t *font;
488  int font_height;
489  int i;
490 
491  font = avpriv_cga_font, font_height = 8;
492 
493  for (i = 0; txt[i]; i++) {
494  int char_y, mask;
495 
496  if (o) {
497  for (char_y = font_height - 1; char_y >= 0; char_y--) {
498  uint8_t *p = pic->data[0] + (y + i * 10) * pic->linesize[0] + x;
499  for (mask = 0x80; mask; mask >>= 1) {
500  if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
501  p[char_y] = ~p[char_y];
502  p += pic->linesize[0];
503  }
504  }
505  } else {
506  uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8);
507  for (char_y = 0; char_y < font_height; char_y++) {
508  for (mask = 0x80; mask; mask >>= 1) {
509  if (font[txt[i] * font_height + char_y] & mask)
510  *p = ~(*p);
511  p++;
512  }
513  p += pic->linesize[0] - 8;
514  }
515  }
516  }
517 }
518 
519 static void color_range(ShowSpectrumContext *s, int ch,
520  float *yf, float *uf, float *vf)
521 {
522  switch (s->mode) {
523  case COMBINED:
524  // reduce range by channel count
525  *yf = 256.0f / s->nb_display_channels;
526  switch (s->color_mode) {
527  case RAINBOW:
528  case MORELAND:
529  case NEBULAE:
530  case FIRE:
531  case FIERY:
532  case FRUIT:
533  case COOL:
534  case GREEN:
535  case VIRIDIS:
536  case PLASMA:
537  case CIVIDIS:
538  case TERRAIN:
539  case MAGMA:
540  case INTENSITY:
541  *uf = *yf;
542  *vf = *yf;
543  break;
544  case CHANNEL:
545  /* adjust saturation for mixed UV coloring */
546  /* this factor is correct for infinite channels, an approximation otherwise */
547  *uf = *yf * M_PI;
548  *vf = *yf * M_PI;
549  break;
550  default:
551  av_assert0(0);
552  }
553  break;
554  case SEPARATE:
555  // full range
556  *yf = 256.0f;
557  *uf = 256.0f;
558  *vf = 256.0f;
559  break;
560  default:
561  av_assert0(0);
562  }
563 
564  if (s->color_mode == CHANNEL) {
565  if (s->nb_display_channels > 1) {
566  *uf *= 0.5f * sinf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
567  *vf *= 0.5f * cosf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
568  } else {
569  *uf *= 0.5f * sinf(M_PI * s->rotation);
570  *vf *= 0.5f * cosf(M_PI * s->rotation + M_PI_2);
571  }
572  } else {
573  *uf += *uf * sinf(M_PI * s->rotation);
574  *vf += *vf * cosf(M_PI * s->rotation + M_PI_2);
575  }
576 
577  *uf *= s->saturation;
578  *vf *= s->saturation;
579 }
580 
582  float yf, float uf, float vf,
583  float a, float *out)
584 {
585  if (s->color_mode > CHANNEL) {
586  const int cm = s->color_mode;
587  float y, u, v;
588  int i;
589 
590  for (i = 1; i < FF_ARRAY_ELEMS(color_table[cm]) - 1; i++)
591  if (color_table[cm][i].a >= a)
592  break;
593  // i now is the first item >= the color
594  // now we know to interpolate between item i - 1 and i
595  if (a <= color_table[cm][i - 1].a) {
596  y = color_table[cm][i - 1].y;
597  u = color_table[cm][i - 1].u;
598  v = color_table[cm][i - 1].v;
599  } else if (a >= color_table[cm][i].a) {
600  y = color_table[cm][i].y;
601  u = color_table[cm][i].u;
602  v = color_table[cm][i].v;
603  } else {
604  float start = color_table[cm][i - 1].a;
605  float end = color_table[cm][i].a;
606  float lerpfrac = (a - start) / (end - start);
607  y = color_table[cm][i - 1].y * (1.0f - lerpfrac)
608  + color_table[cm][i].y * lerpfrac;
609  u = color_table[cm][i - 1].u * (1.0f - lerpfrac)
610  + color_table[cm][i].u * lerpfrac;
611  v = color_table[cm][i - 1].v * (1.0f - lerpfrac)
612  + color_table[cm][i].v * lerpfrac;
613  }
614 
615  out[0] = y * yf;
616  out[1] = u * uf;
617  out[2] = v * vf;
618  } else {
619  out[0] = a * yf;
620  out[1] = a * uf;
621  out[2] = a * vf;
622  }
623 }
624 
625 static char *get_time(AVFilterContext *ctx, float seconds, int x)
626 {
627  char *units;
628 
629  if (x == 0)
630  units = av_asprintf("0");
631  else if (log10(seconds) > 6)
632  units = av_asprintf("%.2fh", seconds / (60 * 60));
633  else if (log10(seconds) > 3)
634  units = av_asprintf("%.2fm", seconds / 60);
635  else
636  units = av_asprintf("%.2fs", seconds);
637  return units;
638 }
639 
640 static float log_scale(const float value, const float min, const float max)
641 {
642  if (value < min)
643  return min;
644  if (value > max)
645  return max;
646 
647  {
648  const float b = logf(max / min) / (max - min);
649  const float a = max / expf(max * b);
650 
651  return expf(value * b) * a;
652  }
653 }
654 
655 static float get_log_hz(const int bin, const int num_bins, const float sample_rate)
656 {
657  const float max_freq = sample_rate / 2;
658  const float hz_per_bin = max_freq / num_bins;
659  const float freq = hz_per_bin * bin;
660  const float scaled_freq = log_scale(freq + 1, 21, max_freq) - 1;
661 
662  return num_bins * scaled_freq / max_freq;
663 }
664 
665 static float inv_log_scale(const float value, const float min, const float max)
666 {
667  if (value < min)
668  return min;
669  if (value > max)
670  return max;
671 
672  {
673  const float b = logf(max / min) / (max - min);
674  const float a = max / expf(max * b);
675 
676  return logf(value / a) / b;
677  }
678 }
679 
680 static float bin_pos(const int bin, const int num_bins, const float sample_rate)
681 {
682  const float max_freq = sample_rate / 2;
683  const float hz_per_bin = max_freq / num_bins;
684  const float freq = hz_per_bin * bin;
685  const float scaled_freq = inv_log_scale(freq + 1, 21, max_freq) - 1;
686 
687  return num_bins * scaled_freq / max_freq;
688 }
689 
691 {
692  ShowSpectrumContext *s = ctx->priv;
693  AVFilterLink *inlink = ctx->inputs[0];
694  AVFilterLink *outlink = ctx->outputs[0];
695  int ch, y, x = 0, sz = s->orientation == VERTICAL ? s->w : s->h;
696  int multi = (s->mode == SEPARATE && s->color_mode == CHANNEL);
697  float spp = samples / (float)sz;
698  char *text;
699  uint8_t *dst;
700  char chlayout_str[128];
701 
702  av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), inlink->channels,
703  inlink->channel_layout);
704 
705  text = av_asprintf("%d Hz | %s", inlink->sample_rate, chlayout_str);
706  if (!text)
707  return AVERROR(ENOMEM);
708 
709  drawtext(s->outpicref, 2, outlink->h - 10, "CREATED BY LIBAVFILTER", 0);
710  drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, outlink->h - 10, text, 0);
711  av_freep(&text);
712  if (s->stop) {
713  text = av_asprintf("Zoom: %d Hz - %d Hz", s->start, s->stop);
714  if (!text)
715  return AVERROR(ENOMEM);
716  drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, 3, text, 0);
717  av_freep(&text);
718  }
719 
720  dst = s->outpicref->data[0] + (s->start_y - 1) * s->outpicref->linesize[0] + s->start_x - 1;
721  for (x = 0; x < s->w + 1; x++)
722  dst[x] = 200;
723  dst = s->outpicref->data[0] + (s->start_y + s->h) * s->outpicref->linesize[0] + s->start_x - 1;
724  for (x = 0; x < s->w + 1; x++)
725  dst[x] = 200;
726  for (y = 0; y < s->h + 2; y++) {
727  dst = s->outpicref->data[0] + (y + s->start_y - 1) * s->outpicref->linesize[0];
728  dst[s->start_x - 1] = 200;
729  dst[s->start_x + s->w] = 200;
730  }
731  if (s->orientation == VERTICAL) {
732  int h = s->mode == SEPARATE ? s->h / s->nb_display_channels : s->h;
733  int hh = s->mode == SEPARATE ? -(s->h % s->nb_display_channels) + 1 : 1;
734  for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) {
735  for (y = 0; y < h; y += 20) {
736  dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0];
737  dst[s->start_x - 2] = 200;
738  dst[s->start_x + s->w + 1] = 200;
739  }
740  for (y = 0; y < h; y += 40) {
741  dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0];
742  dst[s->start_x - 3] = 200;
743  dst[s->start_x + s->w + 2] = 200;
744  }
745  dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x;
746  for (x = 0; x < s->w; x+=40)
747  dst[x] = 200;
748  dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x;
749  for (x = 0; x < s->w; x+=80)
750  dst[x] = 200;
751  dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x;
752  for (x = 0; x < s->w; x+=40) {
753  dst[x] = 200;
754  }
755  dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x;
756  for (x = 0; x < s->w; x+=80) {
757  dst[x] = 200;
758  }
759  for (y = 0; y < h; y += 40) {
760  float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
761  float bin = s->fscale == F_LINEAR ? y : get_log_hz(y, h, inlink->sample_rate);
762  float hertz = s->start + bin * range / (float)h;
763  char *units;
764 
765  if (hertz == 0)
766  units = av_asprintf("DC");
767  else
768  units = av_asprintf("%.2f", hertz);
769  if (!units)
770  return AVERROR(ENOMEM);
771 
772  drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, h * (ch + 1) + s->start_y - y - 4 - hh, units, 0);
773  av_free(units);
774  }
775  }
776 
777  for (x = 0; x < s->w && s->single_pic; x+=80) {
778  float seconds = x * spp / inlink->sample_rate;
779  char *units = get_time(ctx, seconds, x);
780  if (!units)
781  return AVERROR(ENOMEM);
782 
783  drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->h + s->start_y + 6, units, 0);
784  drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->start_y - 12, units, 0);
785  av_free(units);
786  }
787 
788  drawtext(s->outpicref, outlink->w / 2 - 4 * 4, outlink->h - s->start_y / 2, "TIME", 0);
789  drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 14 * 4, "FREQUENCY (Hz)", 1);
790  } else {
791  int w = s->mode == SEPARATE ? s->w / s->nb_display_channels : s->w;
792  for (y = 0; y < s->h; y += 20) {
793  dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0];
794  dst[s->start_x - 2] = 200;
795  dst[s->start_x + s->w + 1] = 200;
796  }
797  for (y = 0; y < s->h; y += 40) {
798  dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0];
799  dst[s->start_x - 3] = 200;
800  dst[s->start_x + s->w + 2] = 200;
801  }
802  for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) {
803  dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x + w * ch;
804  for (x = 0; x < w; x+=40)
805  dst[x] = 200;
806  dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x + w * ch;
807  for (x = 0; x < w; x+=80)
808  dst[x] = 200;
809  dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x + w * ch;
810  for (x = 0; x < w; x+=40) {
811  dst[x] = 200;
812  }
813  dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x + w * ch;
814  for (x = 0; x < w; x+=80) {
815  dst[x] = 200;
816  }
817  for (x = 0; x < w - 79; x += 80) {
818  float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
819  float bin = s->fscale == F_LINEAR ? x : get_log_hz(x, w, inlink->sample_rate);
820  float hertz = s->start + bin * range / (float)w;
821  char *units;
822 
823  if (hertz == 0)
824  units = av_asprintf("DC");
825  else
826  units = av_asprintf("%.2f", hertz);
827  if (!units)
828  return AVERROR(ENOMEM);
829 
830  drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->start_y - 12, units, 0);
831  drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->h + s->start_y + 6, units, 0);
832  av_free(units);
833  }
834  }
835  for (y = 0; y < s->h && s->single_pic; y+=40) {
836  float seconds = y * spp / inlink->sample_rate;
837  char *units = get_time(ctx, seconds, x);
838  if (!units)
839  return AVERROR(ENOMEM);
840 
841  drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, s->start_y + y - 4, units, 0);
842  av_free(units);
843  }
844  drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 4 * 4, "TIME", 1);
845  drawtext(s->outpicref, outlink->w / 2 - 14 * 4, outlink->h - s->start_y / 2, "FREQUENCY (Hz)", 0);
846  }
847 
848  for (ch = 0; ch < (multi ? s->nb_display_channels : 1); ch++) {
849  int h = multi ? s->h / s->nb_display_channels : s->h;
850 
851  for (y = 0; y < h; y++) {
852  float out[3] = { 0., 127.5, 127.5};
853  int chn;
854 
855  for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) {
856  float yf, uf, vf;
857  int channel = (multi) ? s->nb_display_channels - ch - 1 : chn;
858  float lout[3];
859 
860  color_range(s, channel, &yf, &uf, &vf);
861  pick_color(s, yf, uf, vf, y / (float)h, lout);
862  out[0] += lout[0];
863  out[1] += lout[1];
864  out[2] += lout[2];
865  }
866  memset(s->outpicref->data[0]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0] + s->w + s->start_x + 20, av_clip_uint8(out[0]), 10);
867  memset(s->outpicref->data[1]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[1] + s->w + s->start_x + 20, av_clip_uint8(out[1]), 10);
868  memset(s->outpicref->data[2]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[2] + s->w + s->start_x + 20, av_clip_uint8(out[2]), 10);
869  }
870 
871  for (y = 0; ch == 0 && y < h; y += h / 10) {
872  float value = 120.f * log10f(1.f - y / (float)h);
873  char *text;
874 
875  if (value < -120)
876  break;
877  text = av_asprintf("%.0f dB", value);
878  if (!text)
879  continue;
880  drawtext(s->outpicref, s->w + s->start_x + 35, s->start_y + y - 5, text, 0);
881  av_free(text);
882  }
883  }
884 
885  return 0;
886 }
887 
888 static float get_value(AVFilterContext *ctx, int ch, int y)
889 {
890  ShowSpectrumContext *s = ctx->priv;
891  float *magnitudes = s->magnitudes[ch];
892  float *phases = s->phases[ch];
893  float a;
894 
895  switch (s->data) {
896  case D_MAGNITUDE:
897  /* get magnitude */
898  a = magnitudes[y];
899  break;
900  case D_PHASE:
901  /* get phase */
902  a = phases[y];
903  break;
904  default:
905  av_assert0(0);
906  }
907 
908  /* apply scale */
909  switch (s->scale) {
910  case LINEAR:
911  a = av_clipf(a, 0, 1);
912  break;
913  case SQRT:
914  a = av_clipf(sqrtf(a), 0, 1);
915  break;
916  case CBRT:
917  a = av_clipf(cbrtf(a), 0, 1);
918  break;
919  case FOURTHRT:
920  a = av_clipf(sqrtf(sqrtf(a)), 0, 1);
921  break;
922  case FIFTHRT:
923  a = av_clipf(powf(a, 0.20), 0, 1);
924  break;
925  case LOG:
926  a = 1.f + log10f(av_clipf(a, 1e-6, 1)) / 6.f; // zero = -120dBFS
927  break;
928  default:
929  av_assert0(0);
930  }
931 
932  return a;
933 }
934 
935 static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
936 {
937  ShowSpectrumContext *s = ctx->priv;
938  const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
939  const int ch = jobnr;
940  float yf, uf, vf;
941  int y;
942 
943  /* decide color range */
944  color_range(s, ch, &yf, &uf, &vf);
945 
946  /* draw the channel */
947  for (y = 0; y < h; y++) {
948  int row = (s->mode == COMBINED) ? y : ch * h + y;
949  float *out = &s->color_buffer[ch][3 * row];
950  float a = get_value(ctx, ch, y);
951 
952  pick_color(s, yf, uf, vf, a, out);
953  }
954 
955  return 0;
956 }
957 
958 static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
959 {
960  ShowSpectrumContext *s = ctx->priv;
961  AVFilterLink *inlink = ctx->inputs[0];
962  const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
963  const int ch = jobnr;
964  float y, yf, uf, vf;
965  int yy = 0;
966 
967  /* decide color range */
968  color_range(s, ch, &yf, &uf, &vf);
969 
970  /* draw the channel */
971  for (y = 0; y < h && yy < h; yy++) {
972  float pos0 = bin_pos(yy+0, h, inlink->sample_rate);
973  float pos1 = bin_pos(yy+1, h, inlink->sample_rate);
974  float delta = pos1 - pos0;
975  float a0, a1;
976 
977  a0 = get_value(ctx, ch, yy+0);
978  a1 = get_value(ctx, ch, FFMIN(yy+1, h-1));
979  for (float j = pos0; j < pos1 && y + j - pos0 < h; j++) {
980  float row = (s->mode == COMBINED) ? av_clipf(y + j - pos0, 0, h - 1) : ch * h + av_clipf(y + j - pos0, 0, h - 1);
981  float *out = &s->color_buffer[ch][3 * lrintf(row)];
982  float lerpfrac = (j - pos0) / delta;
983 
984  pick_color(s, yf, uf, vf, lerpfrac * a1 + (1.f-lerpfrac) * a0, out);
985  }
986  y += delta;
987  }
988 
989  return 0;
990 }
991 
992 static int config_output(AVFilterLink *outlink)
993 {
994  AVFilterContext *ctx = outlink->src;
995  AVFilterLink *inlink = ctx->inputs[0];
996  ShowSpectrumContext *s = ctx->priv;
997  int i, fft_size, h, w, ret;
998  float overlap;
999 
1000  switch (s->fscale) {
1001  case F_LINEAR: s->plot_channel = plot_channel_lin; break;
1002  case F_LOG: s->plot_channel = plot_channel_log; break;
1003  default: return AVERROR_BUG;
1004  }
1005 
1006  s->stop = FFMIN(s->stop, inlink->sample_rate / 2);
1007  if ((s->stop || s->start) && s->stop <= s->start) {
1008  av_log(ctx, AV_LOG_ERROR, "Stop frequency should be greater than start.\n");
1009  return AVERROR(EINVAL);
1010  }
1011 
1012  if (!strcmp(ctx->filter->name, "showspectrumpic"))
1013  s->single_pic = 1;
1014 
1015  outlink->w = s->w;
1016  outlink->h = s->h;
1017  outlink->sample_aspect_ratio = (AVRational){1,1};
1018 
1019  if (s->legend) {
1020  s->start_x = (log10(inlink->sample_rate) + 1) * 25;
1021  s->start_y = 64;
1022  outlink->w += s->start_x * 2;
1023  outlink->h += s->start_y * 2;
1024  }
1025 
1026  h = (s->mode == COMBINED || s->orientation == HORIZONTAL) ? s->h : s->h / inlink->channels;
1027  w = (s->mode == COMBINED || s->orientation == VERTICAL) ? s->w : s->w / inlink->channels;
1028  s->channel_height = h;
1029  s->channel_width = w;
1030 
1031  if (s->orientation == VERTICAL) {
1032  /* FFT window size (precision) according to the requested output frame height */
1033  fft_size = h * 2;
1034  } else {
1035  /* FFT window size (precision) according to the requested output frame width */
1036  fft_size = w * 2;
1037  }
1038 
1039  s->win_size = fft_size;
1040  s->buf_size = FFALIGN(s->win_size << (!!s->stop), 512);
1041 
1042  if (!s->fft) {
1043  s->fft = av_calloc(inlink->channels, sizeof(*s->fft));
1044  if (!s->fft)
1045  return AVERROR(ENOMEM);
1046  }
1047 
1048  if (s->stop) {
1049  if (!s->ifft) {
1050  s->ifft = av_calloc(inlink->channels, sizeof(*s->ifft));
1051  if (!s->ifft)
1052  return AVERROR(ENOMEM);
1053  }
1054  }
1055 
1056  /* (re-)configuration if the video output changed (or first init) */
1057  if (fft_size != s->fft_size) {
1058  AVFrame *outpicref;
1059 
1060  s->fft_size = fft_size;
1061 
1062  /* FFT buffers: x2 for each (display) channel buffer.
1063  * Note: we use free and malloc instead of a realloc-like function to
1064  * make sure the buffer is aligned in memory for the FFT functions. */
1065  for (i = 0; i < s->nb_display_channels; i++) {
1066  if (s->stop) {
1067  av_tx_uninit(&s->ifft[i]);
1068  av_freep(&s->fft_scratch[i]);
1069  }
1070  av_tx_uninit(&s->fft[i]);
1071  av_freep(&s->fft_in[i]);
1072  av_freep(&s->fft_data[i]);
1073  }
1074  av_freep(&s->fft_data);
1075 
1076  s->nb_display_channels = inlink->channels;
1077  for (i = 0; i < s->nb_display_channels; i++) {
1078  float scale;
1079 
1080  ret = av_tx_init(&s->fft[i], &s->tx_fn, AV_TX_FLOAT_FFT, 0, fft_size << (!!s->stop), &scale, 0);
1081  if (s->stop) {
1082  ret = av_tx_init(&s->ifft[i], &s->itx_fn, AV_TX_FLOAT_FFT, 1, fft_size << (!!s->stop), &scale, 0);
1083  if (ret < 0) {
1084  av_log(ctx, AV_LOG_ERROR, "Unable to create Inverse FFT context. "
1085  "The window size might be too high.\n");
1086  return ret;
1087  }
1088  }
1089  if (ret < 0) {
1090  av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. "
1091  "The window size might be too high.\n");
1092  return ret;
1093  }
1094  }
1095 
1096  s->magnitudes = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes));
1097  if (!s->magnitudes)
1098  return AVERROR(ENOMEM);
1099  for (i = 0; i < s->nb_display_channels; i++) {
1100  s->magnitudes[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->magnitudes));
1101  if (!s->magnitudes[i])
1102  return AVERROR(ENOMEM);
1103  }
1104 
1105  s->phases = av_calloc(s->nb_display_channels, sizeof(*s->phases));
1106  if (!s->phases)
1107  return AVERROR(ENOMEM);
1108  for (i = 0; i < s->nb_display_channels; i++) {
1109  s->phases[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->phases));
1110  if (!s->phases[i])
1111  return AVERROR(ENOMEM);
1112  }
1113 
1114  av_freep(&s->color_buffer);
1115  s->color_buffer = av_calloc(s->nb_display_channels, sizeof(*s->color_buffer));
1116  if (!s->color_buffer)
1117  return AVERROR(ENOMEM);
1118  for (i = 0; i < s->nb_display_channels; i++) {
1119  s->color_buffer[i] = av_calloc(s->orientation == VERTICAL ? s->h * 3 : s->w * 3, sizeof(**s->color_buffer));
1120  if (!s->color_buffer[i])
1121  return AVERROR(ENOMEM);
1122  }
1123 
1124  s->fft_in = av_calloc(s->nb_display_channels, sizeof(*s->fft_in));
1125  if (!s->fft_in)
1126  return AVERROR(ENOMEM);
1127  s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data));
1128  if (!s->fft_data)
1129  return AVERROR(ENOMEM);
1130  s->fft_scratch = av_calloc(s->nb_display_channels, sizeof(*s->fft_scratch));
1131  if (!s->fft_scratch)
1132  return AVERROR(ENOMEM);
1133  for (i = 0; i < s->nb_display_channels; i++) {
1134  s->fft_in[i] = av_calloc(s->buf_size, sizeof(**s->fft_in));
1135  if (!s->fft_in[i])
1136  return AVERROR(ENOMEM);
1137 
1138  s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data));
1139  if (!s->fft_data[i])
1140  return AVERROR(ENOMEM);
1141 
1142  s->fft_scratch[i] = av_calloc(s->buf_size, sizeof(**s->fft_scratch));
1143  if (!s->fft_scratch[i])
1144  return AVERROR(ENOMEM);
1145  }
1146 
1147  /* pre-calc windowing function */
1148  s->window_func_lut =
1149  av_realloc_f(s->window_func_lut, s->win_size,
1150  sizeof(*s->window_func_lut));
1151  if (!s->window_func_lut)
1152  return AVERROR(ENOMEM);
1153  generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap);
1154  if (s->overlap == 1)
1155  s->overlap = overlap;
1156  s->hop_size = (1.f - s->overlap) * s->win_size;
1157  if (s->hop_size < 1) {
1158  av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap);
1159  return AVERROR(EINVAL);
1160  }
1161 
1162  for (s->win_scale = 0, i = 0; i < s->win_size; i++) {
1163  s->win_scale += s->window_func_lut[i] * s->window_func_lut[i];
1164  }
1165  s->win_scale = 1.f / sqrtf(s->win_scale);
1166 
1167  /* prepare the initial picref buffer (black frame) */
1168  av_frame_free(&s->outpicref);
1169  s->outpicref = outpicref =
1170  ff_get_video_buffer(outlink, outlink->w, outlink->h);
1171  if (!outpicref)
1172  return AVERROR(ENOMEM);
1173  outpicref->sample_aspect_ratio = (AVRational){1,1};
1174  for (i = 0; i < outlink->h; i++) {
1175  memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w);
1176  memset(outpicref->data[1] + i * outpicref->linesize[1], 128, outlink->w);
1177  memset(outpicref->data[2] + i * outpicref->linesize[2], 128, outlink->w);
1178  }
1179  outpicref->color_range = AVCOL_RANGE_JPEG;
1180 
1181  if (!s->single_pic && s->legend)
1182  draw_legend(ctx, 0);
1183  }
1184 
1185  if ((s->orientation == VERTICAL && s->xpos >= s->w) ||
1186  (s->orientation == HORIZONTAL && s->xpos >= s->h))
1187  s->xpos = 0;
1188 
1189  s->auto_frame_rate = av_make_q(inlink->sample_rate, s->hop_size);
1190  if (s->orientation == VERTICAL && s->sliding == FULLFRAME)
1191  s->auto_frame_rate.den *= s->w;
1192  if (s->orientation == HORIZONTAL && s->sliding == FULLFRAME)
1193  s->auto_frame_rate.den *= s->h;
1194  if (!s->single_pic && strcmp(s->rate_str, "auto")) {
1195  int ret = av_parse_video_rate(&s->frame_rate, s->rate_str);
1196  if (ret < 0)
1197  return ret;
1198  } else {
1199  s->frame_rate = s->auto_frame_rate;
1200  }
1201  outlink->frame_rate = s->frame_rate;
1202  outlink->time_base = av_inv_q(outlink->frame_rate);
1203 
1204  if (s->orientation == VERTICAL) {
1205  s->combine_buffer =
1206  av_realloc_f(s->combine_buffer, s->h * 3,
1207  sizeof(*s->combine_buffer));
1208  } else {
1209  s->combine_buffer =
1210  av_realloc_f(s->combine_buffer, s->w * 3,
1211  sizeof(*s->combine_buffer));
1212  }
1213 
1214  av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d FFT window size:%d\n",
1215  s->w, s->h, s->win_size);
1216 
1217  av_audio_fifo_free(s->fifo);
1218  s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size);
1219  if (!s->fifo)
1220  return AVERROR(ENOMEM);
1221  return 0;
1222 }
1223 
1224 #define RE(y, ch) s->fft_data[ch][y].re
1225 #define IM(y, ch) s->fft_data[ch][y].im
1226 #define MAGNITUDE(y, ch) hypotf(RE(y, ch), IM(y, ch))
1227 #define PHASE(y, ch) atan2f(IM(y, ch), RE(y, ch))
1228 
1229 static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1230 {
1231  ShowSpectrumContext *s = ctx->priv;
1232  const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1);
1233  int y, h = s->orientation == VERTICAL ? s->h : s->w;
1234  const float f = s->gain * w;
1235  const int ch = jobnr;
1236  float *magnitudes = s->magnitudes[ch];
1237 
1238  for (y = 0; y < h; y++)
1239  magnitudes[y] = MAGNITUDE(y, ch) * f;
1240 
1241  return 0;
1242 }
1243 
1244 static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1245 {
1246  ShowSpectrumContext *s = ctx->priv;
1247  const int h = s->orientation == VERTICAL ? s->h : s->w;
1248  const int ch = jobnr;
1249  float *phases = s->phases[ch];
1250  int y;
1251 
1252  for (y = 0; y < h; y++)
1253  phases[y] = (PHASE(y, ch) / M_PI + 1) / 2;
1254 
1255  return 0;
1256 }
1257 
1259 {
1260  const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1);
1261  int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
1262  const float f = s->gain * w;
1263 
1264  for (ch = 0; ch < s->nb_display_channels; ch++) {
1265  float *magnitudes = s->magnitudes[ch];
1266 
1267  for (y = 0; y < h; y++)
1268  magnitudes[y] += MAGNITUDE(y, ch) * f;
1269  }
1270 }
1271 
1272 static void scale_magnitudes(ShowSpectrumContext *s, float scale)
1273 {
1274  int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
1275 
1276  for (ch = 0; ch < s->nb_display_channels; ch++) {
1277  float *magnitudes = s->magnitudes[ch];
1278 
1279  for (y = 0; y < h; y++)
1280  magnitudes[y] *= scale;
1281  }
1282 }
1283 
1285 {
1286  int y;
1287 
1288  for (y = 0; y < size; y++) {
1289  s->combine_buffer[3 * y ] = 0;
1290  s->combine_buffer[3 * y + 1] = 127.5;
1291  s->combine_buffer[3 * y + 2] = 127.5;
1292  }
1293 }
1294 
1296 {
1297  AVFilterContext *ctx = inlink->dst;
1298  AVFilterLink *outlink = ctx->outputs[0];
1299  ShowSpectrumContext *s = ctx->priv;
1300  AVFrame *outpicref = s->outpicref;
1301  int ret, plane, x, y, z = s->orientation == VERTICAL ? s->h : s->w;
1302 
1303  /* fill a new spectrum column */
1304  /* initialize buffer for combining to black */
1305  clear_combine_buffer(s, z);
1306 
1307  ctx->internal->execute(ctx, s->plot_channel, NULL, NULL, s->nb_display_channels);
1308 
1309  for (y = 0; y < z * 3; y++) {
1310  for (x = 0; x < s->nb_display_channels; x++) {
1311  s->combine_buffer[y] += s->color_buffer[x][y];
1312  }
1313  }
1314 
1315  av_frame_make_writable(s->outpicref);
1316  /* copy to output */
1317  if (s->orientation == VERTICAL) {
1318  if (s->sliding == SCROLL) {
1319  for (plane = 0; plane < 3; plane++) {
1320  for (y = 0; y < s->h; y++) {
1321  uint8_t *p = outpicref->data[plane] + s->start_x +
1322  (y + s->start_y) * outpicref->linesize[plane];
1323  memmove(p, p + 1, s->w - 1);
1324  }
1325  }
1326  s->xpos = s->w - 1;
1327  } else if (s->sliding == RSCROLL) {
1328  for (plane = 0; plane < 3; plane++) {
1329  for (y = 0; y < s->h; y++) {
1330  uint8_t *p = outpicref->data[plane] + s->start_x +
1331  (y + s->start_y) * outpicref->linesize[plane];
1332  memmove(p + 1, p, s->w - 1);
1333  }
1334  }
1335  s->xpos = 0;
1336  }
1337  for (plane = 0; plane < 3; plane++) {
1338  uint8_t *p = outpicref->data[plane] + s->start_x +
1339  (outlink->h - 1 - s->start_y) * outpicref->linesize[plane] +
1340  s->xpos;
1341  for (y = 0; y < s->h; y++) {
1342  *p = lrintf(av_clipf(s->combine_buffer[3 * y + plane], 0, 255));
1343  p -= outpicref->linesize[plane];
1344  }
1345  }
1346  } else {
1347  if (s->sliding == SCROLL) {
1348  for (plane = 0; plane < 3; plane++) {
1349  for (y = 1; y < s->h; y++) {
1350  memmove(outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x,
1351  outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x,
1352  s->w);
1353  }
1354  }
1355  s->xpos = s->h - 1;
1356  } else if (s->sliding == RSCROLL) {
1357  for (plane = 0; plane < 3; plane++) {
1358  for (y = s->h - 1; y >= 1; y--) {
1359  memmove(outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x,
1360  outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x,
1361  s->w);
1362  }
1363  }
1364  s->xpos = 0;
1365  }
1366  for (plane = 0; plane < 3; plane++) {
1367  uint8_t *p = outpicref->data[plane] + s->start_x +
1368  (s->xpos + s->start_y) * outpicref->linesize[plane];
1369  for (x = 0; x < s->w; x++) {
1370  *p = lrintf(av_clipf(s->combine_buffer[3 * x + plane], 0, 255));
1371  p++;
1372  }
1373  }
1374  }
1375 
1376  if (s->sliding != FULLFRAME || s->xpos == 0)
1377  outpicref->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base);
1378 
1379  s->xpos++;
1380  if (s->orientation == VERTICAL && s->xpos >= s->w)
1381  s->xpos = 0;
1382  if (s->orientation == HORIZONTAL && s->xpos >= s->h)
1383  s->xpos = 0;
1384  if (!s->single_pic && (s->sliding != FULLFRAME || s->xpos == 0)) {
1385  if (s->old_pts < outpicref->pts) {
1386  AVFrame *clone;
1387 
1388  if (s->legend) {
1389  char *units = get_time(ctx, insamples->pts /(float)inlink->sample_rate, x);
1390  if (!units)
1391  return AVERROR(ENOMEM);
1392 
1393  if (s->orientation == VERTICAL) {
1394  for (y = 0; y < 10; y++) {
1395  memset(s->outpicref->data[0] + outlink->w / 2 - 4 * s->old_len +
1396  (outlink->h - s->start_y / 2 - 20 + y) * s->outpicref->linesize[0], 0, 10 * s->old_len);
1397  }
1398  drawtext(s->outpicref,
1399  outlink->w / 2 - 4 * strlen(units),
1400  outlink->h - s->start_y / 2 - 20,
1401  units, 0);
1402  } else {
1403  for (y = 0; y < 10 * s->old_len; y++) {
1404  memset(s->outpicref->data[0] + s->start_x / 7 + 20 +
1405  (outlink->h / 2 - 4 * s->old_len + y) * s->outpicref->linesize[0], 0, 10);
1406  }
1407  drawtext(s->outpicref,
1408  s->start_x / 7 + 20,
1409  outlink->h / 2 - 4 * strlen(units),
1410  units, 1);
1411  }
1412  s->old_len = strlen(units);
1413  av_free(units);
1414  }
1415  s->old_pts = outpicref->pts;
1416  clone = av_frame_clone(s->outpicref);
1417  if (!clone)
1418  return AVERROR(ENOMEM);
1419  ret = ff_filter_frame(outlink, clone);
1420  if (ret < 0)
1421  return ret;
1422  return 0;
1423  }
1424  }
1425 
1426  return 1;
1427 }
1428 
1429 #if CONFIG_SHOWSPECTRUM_FILTER
1430 
1431 static int activate(AVFilterContext *ctx)
1432 {
1433  AVFilterLink *inlink = ctx->inputs[0];
1434  AVFilterLink *outlink = ctx->outputs[0];
1435  ShowSpectrumContext *s = ctx->priv;
1436  int ret;
1437 
1439 
1440  if (av_audio_fifo_size(s->fifo) < s->win_size) {
1441  AVFrame *frame = NULL;
1442 
1444  if (ret < 0)
1445  return ret;
1446  if (ret > 0) {
1447  s->pts = frame->pts;
1448  s->consumed = 0;
1449 
1450  av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples);
1451  av_frame_free(&frame);
1452  }
1453  }
1454 
1455  if (s->outpicref && (av_audio_fifo_size(s->fifo) >= s->win_size ||
1457  AVFrame *fin = ff_get_audio_buffer(inlink, s->win_size);
1458  if (!fin)
1459  return AVERROR(ENOMEM);
1460 
1461  fin->pts = s->pts + s->consumed;
1462  s->consumed += s->hop_size;
1463  ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data,
1464  FFMIN(s->win_size, av_audio_fifo_size(s->fifo)));
1465  if (ret < 0) {
1466  av_frame_free(&fin);
1467  return ret;
1468  }
1469 
1470  av_assert0(fin->nb_samples == s->win_size);
1471 
1472  ctx->internal->execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
1473 
1474  if (s->data == D_MAGNITUDE)
1475  ctx->internal->execute(ctx, calc_channel_magnitudes, NULL, NULL, s->nb_display_channels);
1476 
1477  if (s->data == D_PHASE)
1478  ctx->internal->execute(ctx, calc_channel_phases, NULL, NULL, s->nb_display_channels);
1479 
1481 
1482  av_frame_free(&fin);
1483  av_audio_fifo_drain(s->fifo, s->hop_size);
1484  if (ret <= 0 && !ff_outlink_get_status(inlink))
1485  return ret;
1486  }
1487 
1489  s->sliding == FULLFRAME &&
1490  s->xpos > 0 && s->outpicref) {
1491  int64_t pts;
1492 
1493  if (s->orientation == VERTICAL) {
1494  for (int i = 0; i < outlink->h; i++) {
1495  memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos);
1496  memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos);
1497  memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos);
1498  }
1499  } else {
1500  for (int i = s->xpos; i < outlink->h; i++) {
1501  memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w);
1502  memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w);
1503  memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w);
1504  }
1505  }
1506  s->outpicref->pts += s->consumed;
1507  pts = s->outpicref->pts;
1508  ret = ff_filter_frame(outlink, s->outpicref);
1509  s->outpicref = NULL;
1511  return 0;
1512  }
1513 
1514  FF_FILTER_FORWARD_STATUS(inlink, outlink);
1515  if (av_audio_fifo_size(s->fifo) >= s->win_size ||
1517  ff_filter_set_ready(ctx, 10);
1518  return 0;
1519  }
1520 
1521  if (ff_outlink_frame_wanted(outlink) && av_audio_fifo_size(s->fifo) < s->win_size &&
1524  return 0;
1525  }
1526 
1527  return FFERROR_NOT_READY;
1528 }
1529 
1530 static const AVFilterPad showspectrum_inputs[] = {
1531  {
1532  .name = "default",
1533  .type = AVMEDIA_TYPE_AUDIO,
1534  },
1535  { NULL }
1536 };
1537 
1538 static const AVFilterPad showspectrum_outputs[] = {
1539  {
1540  .name = "default",
1541  .type = AVMEDIA_TYPE_VIDEO,
1542  .config_props = config_output,
1543  },
1544  { NULL }
1545 };
1546 
1547 const AVFilter ff_avf_showspectrum = {
1548  .name = "showspectrum",
1549  .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."),
1550  .uninit = uninit,
1551  .query_formats = query_formats,
1552  .priv_size = sizeof(ShowSpectrumContext),
1553  .inputs = showspectrum_inputs,
1554  .outputs = showspectrum_outputs,
1555  .activate = activate,
1556  .priv_class = &showspectrum_class,
1558 };
1559 #endif // CONFIG_SHOWSPECTRUM_FILTER
1560 
1561 #if CONFIG_SHOWSPECTRUMPIC_FILTER
1562 
1563 static const AVOption showspectrumpic_options[] = {
1564  { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "4096x2048"}, 0, 0, FLAGS },
1565  { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "4096x2048"}, 0, 0, FLAGS },
1566  { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, 0, NB_MODES-1, FLAGS, "mode" },
1567  { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
1568  { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
1569  { "color", "set channel coloring", OFFSET(color_mode), AV_OPT_TYPE_INT, {.i64=INTENSITY}, 0, NB_CLMODES-1, FLAGS, "color" },
1570  { "channel", "separate color for each channel", 0, AV_OPT_TYPE_CONST, {.i64=CHANNEL}, 0, 0, FLAGS, "color" },
1571  { "intensity", "intensity based coloring", 0, AV_OPT_TYPE_CONST, {.i64=INTENSITY}, 0, 0, FLAGS, "color" },
1572  { "rainbow", "rainbow based coloring", 0, AV_OPT_TYPE_CONST, {.i64=RAINBOW}, 0, 0, FLAGS, "color" },
1573  { "moreland", "moreland based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MORELAND}, 0, 0, FLAGS, "color" },
1574  { "nebulae", "nebulae based coloring", 0, AV_OPT_TYPE_CONST, {.i64=NEBULAE}, 0, 0, FLAGS, "color" },
1575  { "fire", "fire based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIRE}, 0, 0, FLAGS, "color" },
1576  { "fiery", "fiery based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIERY}, 0, 0, FLAGS, "color" },
1577  { "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
1578  { "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
1579  { "magma", "magma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MAGMA}, 0, 0, FLAGS, "color" },
1580  { "green", "green based coloring", 0, AV_OPT_TYPE_CONST, {.i64=GREEN}, 0, 0, FLAGS, "color" },
1581  { "viridis", "viridis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=VIRIDIS}, 0, 0, FLAGS, "color" },
1582  { "plasma", "plasma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=PLASMA}, 0, 0, FLAGS, "color" },
1583  { "cividis", "cividis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=CIVIDIS}, 0, 0, FLAGS, "color" },
1584  { "terrain", "terrain based coloring", 0, AV_OPT_TYPE_CONST, {.i64=TERRAIN}, 0, 0, FLAGS, "color" },
1585  { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=LOG}, 0, NB_SCALES-1, FLAGS, "scale" },
1586  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
1587  { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
1588  { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
1589  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
1590  { "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
1591  { "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
1592  { "fscale", "set frequency scale", OFFSET(fscale), AV_OPT_TYPE_INT, {.i64=F_LINEAR}, 0, NB_FSCALES-1, FLAGS, "fscale" },
1593  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=F_LINEAR}, 0, 0, FLAGS, "fscale" },
1594  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=F_LOG}, 0, 0, FLAGS, "fscale" },
1595  { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
1596  { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" },
1597  { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" },
1598  { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" },
1599  { "hann", "Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" },
1600  { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" },
1601  { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" },
1602  { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" },
1603  { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, FLAGS, "win_func" },
1604  { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, FLAGS, "win_func" },
1605  { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, FLAGS, "win_func" },
1606  { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, FLAGS, "win_func" },
1607  { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, FLAGS, "win_func" },
1608  { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, FLAGS, "win_func" },
1609  { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, FLAGS, "win_func" },
1610  { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" },
1611  { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" },
1612  { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" },
1613  { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" },
1614  { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" },
1615  { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" },
1616  { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" },
1617  { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, FLAGS, "win_func" },
1618  { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
1619  { "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
1620  { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
1621  { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
1622  { "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
1623  { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
1624  { "start", "start frequency", OFFSET(start), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
1625  { "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
1626  { NULL }
1627 };
1628 
1629 AVFILTER_DEFINE_CLASS(showspectrumpic);
1630 
1631 static int showspectrumpic_request_frame(AVFilterLink *outlink)
1632 {
1633  AVFilterContext *ctx = outlink->src;
1634  ShowSpectrumContext *s = ctx->priv;
1635  AVFilterLink *inlink = ctx->inputs[0];
1636  int ret, samples;
1637 
1639  samples = av_audio_fifo_size(s->fifo);
1640  if (ret == AVERROR_EOF && s->outpicref && samples > 0) {
1641  int consumed = 0;
1642  int x = 0, sz = s->orientation == VERTICAL ? s->w : s->h;
1643  int ch, spf, spb;
1644  AVFrame *fin;
1645 
1646  spf = s->win_size * (samples / ((s->win_size * sz) * ceil(samples / (float)(s->win_size * sz))));
1647  spf = FFMAX(1, spf);
1648 
1649  spb = (samples / (spf * sz)) * spf;
1650 
1651  fin = ff_get_audio_buffer(inlink, s->win_size);
1652  if (!fin)
1653  return AVERROR(ENOMEM);
1654 
1655  while (x < sz) {
1656  ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size);
1657  if (ret < 0) {
1658  av_frame_free(&fin);
1659  return ret;
1660  }
1661 
1662  av_audio_fifo_drain(s->fifo, spf);
1663 
1664  if (ret < s->win_size) {
1665  for (ch = 0; ch < s->nb_display_channels; ch++) {
1666  memset(fin->extended_data[ch] + ret * sizeof(float), 0,
1667  (s->win_size - ret) * sizeof(float));
1668  }
1669  }
1670 
1671  ctx->internal->execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
1673 
1674  consumed += spf;
1675  if (consumed >= spb) {
1676  int h = s->orientation == VERTICAL ? s->h : s->w;
1677 
1678  scale_magnitudes(s, 1.f / (consumed / spf));
1680  consumed = 0;
1681  x++;
1682  for (ch = 0; ch < s->nb_display_channels; ch++)
1683  memset(s->magnitudes[ch], 0, h * sizeof(float));
1684  }
1685  }
1686 
1687  av_frame_free(&fin);
1688  s->outpicref->pts = 0;
1689 
1690  if (s->legend)
1692 
1693  ret = ff_filter_frame(outlink, s->outpicref);
1694  s->outpicref = NULL;
1695  }
1696 
1697  return ret;
1698 }
1699 
1700 static int showspectrumpic_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
1701 {
1702  AVFilterContext *ctx = inlink->dst;
1703  ShowSpectrumContext *s = ctx->priv;
1704  int ret;
1705 
1706  ret = av_audio_fifo_write(s->fifo, (void **)insamples->extended_data, insamples->nb_samples);
1707  av_frame_free(&insamples);
1708  return ret;
1709 }
1710 
1711 static const AVFilterPad showspectrumpic_inputs[] = {
1712  {
1713  .name = "default",
1714  .type = AVMEDIA_TYPE_AUDIO,
1715  .filter_frame = showspectrumpic_filter_frame,
1716  },
1717  { NULL }
1718 };
1719 
1720 static const AVFilterPad showspectrumpic_outputs[] = {
1721  {
1722  .name = "default",
1723  .type = AVMEDIA_TYPE_VIDEO,
1724  .config_props = config_output,
1725  .request_frame = showspectrumpic_request_frame,
1726  },
1727  { NULL }
1728 };
1729 
1731  .name = "showspectrumpic",
1732  .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."),
1733  .uninit = uninit,
1734  .query_formats = query_formats,
1735  .priv_size = sizeof(ShowSpectrumContext),
1736  .inputs = showspectrumpic_inputs,
1737  .outputs = showspectrumpic_outputs,
1738  .priv_class = &showspectrumpic_class,
1740 };
1741 
1742 #endif // CONFIG_SHOWSPECTRUMPIC_FILTER
M
#define M(a, b)
Definition: vp3dsp.c:48
av_audio_fifo_free
void av_audio_fifo_free(AVAudioFifo *af)
Free an AVAudioFifo.
Definition: audio_fifo.c:45
formats
formats
Definition: signature.h:48
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:97
ff_get_audio_buffer
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:86
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
ShowSpectrumContext::win_size
int win_size
Definition: avf_showspectrum.c:87
AVFilterChannelLayouts
A list of supported channel layouts.
Definition: formats.h:85
AVFrame::color_range
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition: frame.h:530
plot_channel_lin
static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:935
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
SCROLL
@ SCROLL
Definition: avf_showspectrum.c:51
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: avf_showspectrum.c:303
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
ShowSpectrumContext::data
int data
Definition: avf_showspectrum.c:73
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
ShowSpectrumContext::frame_rate
AVRational frame_rate
Definition: avf_showspectrum.c:59
out
FILE * out
Definition: movenc.c:54
ff_avf_showspectrum
const AVFilter ff_avf_showspectrum
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:264
FrequencyScale
FrequencyScale
Definition: avf_showfreqs.c:42
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:978
sample_fmts
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:948
pick_color
static void pick_color(ShowSpectrumContext *s, float yf, float uf, float vf, float a, float *out)
Definition: avf_showspectrum.c:581
ff_channel_layouts_ref
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:454
layouts
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
FFERROR_NOT_READY
return FFERROR_NOT_READY
Definition: filter_design.txt:204
ShowSpectrumContext::xpos
int xpos
x position (current column)
Definition: avf_showspectrum.c:74
ShowSpectrumContext::mode
int mode
channel display mode
Definition: avf_showspectrum.c:66
ShowSpectrumContext::overlap
float overlap
Definition: avf_showspectrum.c:90
AVTXContext
Definition: tx_priv.h:110
ShowSpectrumContext::gain
float gain
Definition: avf_showspectrum.c:91
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:112
SQRT
@ SQRT
Definition: avf_showspectrum.c:49
PHASE
#define PHASE(y, ch)
Definition: avf_showspectrum.c:1227
ShowSpectrumContext::old_len
int old_len
Definition: avf_showspectrum.c:99
ColorTable::y
float y
Definition: avf_showspectrum.c:188
av_get_channel_layout_string
void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout)
Return a description of a channel layout.
Definition: channel_layout.c:217
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:303
av_frame_make_writable
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:490
ShowSpectrumContext::w
int w
Definition: avf_showspectrum.c:56
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:396
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:576
M_PI_2
#define M_PI_2
Definition: mathematics.h:55
calc_channel_magnitudes
static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:1229
AVOption
AVOption.
Definition: opt.h:247
clear_combine_buffer
static void clear_combine_buffer(ShowSpectrumContext *s, int size)
Definition: avf_showspectrum.c:1284
b
#define b
Definition: input.c:40
GREEN
@ GREEN
Definition: avf_showspectrum.c:50
config_output
static int config_output(AVFilterLink *outlink)
Definition: avf_showspectrum.c:992
data
const char data[16]
Definition: mxf.c:143
expf
#define expf(x)
Definition: libm.h:283
ff_request_frame
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:395
ShowSpectrumContext::ifft
AVTXContext ** ifft
Inverse Fast Fourier Transform context.
Definition: avf_showspectrum.c:76
ShowSpectrumContext::hop_size
int hop_size
Definition: avf_showspectrum.c:93
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVComplexFloat
Definition: tx.h:27
ShowSpectrumContext::saturation
float saturation
color saturation multiplier
Definition: avf_showspectrum.c:70
max
#define max(a, b)
Definition: cuda_runtime.h:33
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:149
COOL
@ COOL
Definition: avf_showspectrum.c:50
ShowSpectrumContext::channel_width
int channel_width
Definition: avf_showspectrum.c:63
OFFSET
#define OFFSET(x)
Definition: avf_showspectrum.c:106
video.h
AVFormatContext::internal
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1565
FF_FILTER_FORWARD_STATUS_BACK
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition: filters.h:199
acalc_magnitudes
static void acalc_magnitudes(ShowSpectrumContext *s)
Definition: avf_showspectrum.c:1258
WFUNC_FLATTOP
@ WFUNC_FLATTOP
Definition: window_func.h:29
sample_rate
sample_rate
Definition: ffmpeg_filter.c:156
FIFTHRT
@ FIFTHRT
Definition: avf_showspectrum.c:49
scale_magnitudes
static void scale_magnitudes(ShowSpectrumContext *s, float scale)
Definition: avf_showspectrum.c:1272
av_tx_init
av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, int inv, int len, const void *scale, uint64_t flags)
Initialize a transform context with the given configuration (i)MDCTs with an odd length are currently...
Definition: tx.c:227
get_value
static float get_value(AVFilterContext *ctx, int ch, int y)
Definition: avf_showspectrum.c:888
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:317
ShowSpectrumContext::magnitudes
float ** magnitudes
Definition: avf_showspectrum.c:84
MORELAND
@ MORELAND
Definition: avf_showspectrum.c:50
ShowSpectrumContext::fifo
AVAudioFifo * fifo
Definition: avf_showspectrum.c:96
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:64
S
#define S(s, c, i)
Definition: flacdsp_template.c:46
ShowSpectrumContext::win_func
int win_func
Definition: avf_showspectrum.c:86
ShowSpectrumContext::outpicref
AVFrame * outpicref
Definition: avf_showspectrum.c:60
ShowSpectrumContext::rotation
float rotation
color rotation
Definition: avf_showspectrum.c:71
ff_inlink_consume_frame
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition: avfilter.c:1376
ShowSpectrumContext::fft_scratch
AVComplexFloat ** fft_scratch
scratch buffers
Definition: avf_showspectrum.c:82
WFUNC_BLACKMAN
@ WFUNC_BLACKMAN
Definition: af_firequalizer.c:37
WFUNC_PARZEN
@ WFUNC_PARZEN
Definition: window_func.h:32
calc_channel_phases
static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:1244
ShowSpectrumContext::fft_in
AVComplexFloat ** fft_in
input FFT coeffs
Definition: avf_showspectrum.c:80
AVAudioFifo
Context for an Audio FIFO Buffer.
Definition: audio_fifo.c:34
log_scale
static float log_scale(const float value, const float min, const float max)
Definition: avf_showspectrum.c:640
ColorMode
ColorMode
Definition: avf_showspectrum.c:50
cosf
#define cosf(x)
Definition: libm.h:78
ShowSpectrumContext::color_mode
int color_mode
display color scheme
Definition: avf_showspectrum.c:67
av_audio_fifo_drain
int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples)
Drain data from an AVAudioFifo.
Definition: audio_fifo.c:201
log10f
#define log10f(x)
Definition: libm.h:414
ShowSpectrumContext::color_buffer
float ** color_buffer
color buffer (3 * h * ch items)
Definition: avf_showspectrum.c:95
ShowSpectrumContext::window_func_lut
float * window_func_lut
Window function LUT.
Definition: avf_showspectrum.c:83
FULLFRAME
@ FULLFRAME
Definition: avf_showspectrum.c:51
NB_FSCALES
@ NB_FSCALES
Definition: avf_showspectrum.c:48
pts
static int64_t pts
Definition: transcode_aac.c:653
RAINBOW
@ RAINBOW
Definition: avf_showspectrum.c:50
ShowSpectrumContext::buf_size
int buf_size
Definition: avf_showspectrum.c:88
WFUNC_BHANN
@ WFUNC_BHANN
Definition: window_func.h:31
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
a1
#define a1
Definition: regdef.h:47
D_PHASE
@ D_PHASE
Definition: avf_showspectrum.c:47
FIERY
@ FIERY
Definition: avf_showspectrum.c:50
INTENSITY
@ INTENSITY
Definition: avf_showspectrum.c:50
avassert.h
ceil
static __device__ float ceil(float a)
Definition: cuda_runtime.h:176
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
WFUNC_DOLPH
@ WFUNC_DOLPH
Definition: window_func.h:32
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
av_tx_fn
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.
Definition: tx.h:102
mask
static const uint16_t mask[17]
Definition: lzw.c:38
WFUNC_NUTTALL
@ WFUNC_NUTTALL
Definition: af_firequalizer.c:40
ff_outlink_set_status
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition: filters.h:189
NB_DMODES
@ NB_DMODES
Definition: avf_showspectrum.c:47
ff_inlink_request_frame
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1502
s
#define s(width, name)
Definition: cbs_vp9.c:257
Orientation
Orientation
Definition: avf_showspectrum.c:52
FRUIT
@ FRUIT
Definition: avf_showspectrum.c:50
CHANNEL
@ CHANNEL
Definition: avf_showspectrum.c:50
g
const char * g
Definition: vf_curves.c:117
VIRIDIS
@ VIRIDIS
Definition: avf_showspectrum.c:50
av_audio_fifo_write
int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples)
Write data to an AVAudioFifo.
Definition: audio_fifo.c:112
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
ff_formats_ref
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:459
draw_legend
static int draw_legend(AVFilterContext *ctx, int samples)
Definition: avf_showspectrum.c:690
ShowSpectrumContext::h
int h
Definition: avf_showspectrum.c:56
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
WFUNC_LANCZOS
@ WFUNC_LANCZOS
Definition: window_func.h:31
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
filters.h
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:290
plot_channel_log
static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:958
AV_TX_FLOAT_FFT
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type AVComplexFloat.
Definition: tx.h:45
ShowSpectrumContext::fft
AVTXContext ** fft
Fast Fourier Transform context.
Definition: avf_showspectrum.c:75
WFUNC_RECT
@ WFUNC_RECT
Definition: window_func.h:28
ctx
AVFormatContext * ctx
Definition: movenc.c:48
WFUNC_BHARRIS
@ WFUNC_BHARRIS
Definition: af_firequalizer.c:42
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:424
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:141
color_range
color_range
Definition: vf_selectivecolor.c:44
VERTICAL
@ VERTICAL
Definition: avf_showspectrum.c:52
f
#define f(width, name)
Definition: cbs_vp9.c:255
AV_PIX_FMT_YUVJ444P
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition: pixfmt.h:80
TERRAIN
@ TERRAIN
Definition: avf_showspectrum.c:50
arg
const char * arg
Definition: jacosubdec.c:67
COMBINED
@ COMBINED
Definition: avf_showspectrum.c:46
if
if(ret)
Definition: filter_design.txt:179
av_realloc_f
#define av_realloc_f(p, o, n)
Definition: tableprint_vlc.h:33
ShowSpectrumContext::win_scale
double win_scale
Definition: avf_showspectrum.c:89
ShowSpectrumContext::combine_buffer
float * combine_buffer
color combining buffer (3 * h items)
Definition: avf_showspectrum.c:94
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
NB_SLIDES
@ NB_SLIDES
Definition: avf_showspectrum.c:51
inv_log_scale
static float inv_log_scale(const float value, const float min, const float max)
Definition: avf_showspectrum.c:665
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_audio_fifo_alloc
AVAudioFifo * av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, int nb_samples)
Allocate an AVAudioFifo.
Definition: audio_fifo.c:59
WFUNC_HAMMING
@ WFUNC_HAMMING
Definition: af_firequalizer.c:36
ShowSpectrumContext::fft_data
AVComplexFloat ** fft_data
bins holder for each (displayed) channels
Definition: avf_showspectrum.c:81
activate
filter_frame For filters that do not use the activate() callback
AV_OPT_TYPE_IMAGE_SIZE
@ AV_OPT_TYPE_IMAGE_SIZE
offset must point to two consecutive integers
Definition: opt.h:234
av_clipf
#define av_clipf
Definition: common.h:144
CIVIDIS
@ CIVIDIS
Definition: avf_showspectrum.c:50
parseutils.h
ShowSpectrumContext::start
int start
Definition: avf_showspectrum.c:72
get_time
static char * get_time(AVFilterContext *ctx, float seconds, int x)
Definition: avf_showspectrum.c:625
MAGNITUDE
#define MAGNITUDE(y, ch)
Definition: avf_showspectrum.c:1226
generate_window_func
static void generate_window_func(float *lut, int N, int win_func, float *overlap)
Definition: window_func.h:36
SEPARATE
@ SEPARATE
Definition: avf_showspectrum.c:46
WFUNC_HANNING
@ WFUNC_HANNING
Definition: window_func.h:28
WFUNC_BARTLETT
@ WFUNC_BARTLETT
Definition: window_func.h:29
sinf
#define sinf(x)
Definition: libm.h:419
WFUNC_BOHMAN
@ WFUNC_BOHMAN
Definition: window_func.h:33
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ShowSpectrumContext::auto_frame_rate
AVRational auto_frame_rate
Definition: avf_showspectrum.c:58
for
for(j=16;j >0;--j)
Definition: h264pred_template.c:469
ShowSpectrumContext::pts
int64_t pts
Definition: avf_showspectrum.c:97
ShowSpectrumContext::consumed
int consumed
Definition: avf_showspectrum.c:92
ShowSpectrumContext::single_pic
int single_pic
Definition: avf_showspectrum.c:100
DataMode
DataMode
Definition: avf_showfreqs.c:39
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:116
powf
#define powf(x, y)
Definition: libm.h:50
RSCROLL
@ RSCROLL
Definition: avf_showspectrum.c:51
D_MAGNITUDE
@ D_MAGNITUDE
Definition: avf_showspectrum.c:47
get_log_hz
static float get_log_hz(const int bin, const int num_bins, const float sample_rate)
Definition: avf_showspectrum.c:655
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
size
int size
Definition: twinvq_data.h:10344
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
PLASMA
@ PLASMA
Definition: avf_showspectrum.c:50
WFUNC_TUKEY
@ WFUNC_TUKEY
Definition: af_firequalizer.c:43
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
ColorTable::a
float a
Definition: avf_showspectrum.c:188
xga_font_data.h
N
#define N
Definition: af_mcompand.c:53
ff_all_channel_layouts
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout (w...
Definition: formats.c:420
av_audio_fifo_size
int av_audio_fifo_size(AVAudioFifo *af)
Get the current number of samples in the AVAudioFifo available for reading.
Definition: audio_fifo.c:228
a0
#define a0
Definition: regdef.h:46
M_PI
#define M_PI
Definition: mathematics.h:52
ShowSpectrumContext::nb_display_channels
int nb_display_channels
Definition: avf_showspectrum.c:61
av_tx_uninit
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets ctx to NULL, does nothing when ctx == NULL.
Definition: tx.c:212
ff_avf_showspectrumpic
const AVFilter ff_avf_showspectrumpic
internal.h
ShowSpectrumContext::scale
int scale
Definition: avf_showspectrum.c:68
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:227
plot_spectrum_column
static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
Definition: avf_showspectrum.c:1295
ShowSpectrumContext::rate_str
char * rate_str
Definition: avf_showspectrum.c:57
av_parse_video_rate
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition: parseutils.c:179
ShowSpectrumContext::old_pts
int64_t old_pts
Definition: avf_showspectrum.c:98
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:369
ShowSpectrumContext::phases
float ** phases
Definition: avf_showspectrum.c:85
i
int i
Definition: input.c:406
lrintf
#define lrintf(x)
Definition: libm_mips.h:72
FLAGS
#define FLAGS
Definition: avf_showspectrum.c:107
ShowSpectrumContext::channel_height
int channel_height
Definition: avf_showspectrum.c:64
ShowSpectrumContext
Definition: avf_showspectrum.c:54
AVFrame::extended_data
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:350
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
delta
float delta
Definition: vorbis_enc_data.h:430
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
cbrtf
static av_always_inline float cbrtf(float x)
Definition: libm.h:61
audio_fifo.h
av_inv_q
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
NB_CLMODES
@ NB_CLMODES
Definition: avf_showspectrum.c:50
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
HORIZONTAL
@ HORIZONTAL
Definition: avf_showspectrum.c:52
F_LINEAR
@ F_LINEAR
Definition: avf_showspectrum.c:48
AVFilter
Filter definition.
Definition: avfilter.h:145
ret
ret
Definition: filter_design.txt:187
NB_ORIENTATIONS
@ NB_ORIENTATIONS
Definition: avf_showspectrum.c:52
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
color_range
static void color_range(ShowSpectrumContext *s, int ch, float *yf, float *uf, float *vf)
Definition: avf_showspectrum.c:519
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(showspectrum)
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:391
ShowSpectrumContext::legend
int legend
Definition: avf_showspectrum.c:101
run_channel_fft
static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:385
ShowSpectrumContext::fscale
int fscale
Definition: avf_showspectrum.c:69
L
#define L(x)
Definition: vp56_arith.h:36
window_func.h
NEBULAE
@ NEBULAE
Definition: avf_showspectrum.c:50
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: avf_showspectrum.c:354
ShowSpectrumContext::start_x
int start_x
Definition: avf_showspectrum.c:102
ShowSpectrumContext::stop
int stop
zoom mode
Definition: avf_showspectrum.c:72
NB_WFUNC
@ NB_WFUNC
Definition: af_firequalizer.c:44
ff_all_samplerates
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:414
ShowSpectrumContext::orientation
int orientation
Definition: avf_showspectrum.c:62
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:251
channel_layout.h
WFUNC_SINE
@ WFUNC_SINE
Definition: window_func.h:30
WFUNC_CAUCHY
@ WFUNC_CAUCHY
Definition: window_func.h:32
mode
mode
Definition: ebur128.h:83
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
LOG
@ LOG
Definition: avf_showspectrum.c:49
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
ShowSpectrumContext::fft_size
int fft_size
number of coeffs (FFT window size)
Definition: avf_showspectrum.c:79
avfilter.h
FOURTHRT
@ FOURTHRT
Definition: avf_showspectrum.c:49
NB_MODES
@ NB_MODES
Definition: avf_showspectrum.c:46
cm
#define cm
Definition: dvbsubdec.c:38
F_LOG
@ F_LOG
Definition: avf_showspectrum.c:48
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
av_clip_uint8
#define av_clip_uint8
Definition: common.h:102
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
ff_outlink_get_status
int ff_outlink_get_status(AVFilterLink *link)
Get the status on an output link.
Definition: avfilter.c:1525
AVFilterContext
An instance of a filter.
Definition: avfilter.h:333
DisplayMode
DisplayMode
Definition: avf_ahistogram.c:34
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
WFUNC_GAUSS
@ WFUNC_GAUSS
Definition: window_func.h:31
ColorTable::v
float v
Definition: avf_showspectrum.c:188
LINEAR
@ LINEAR
Definition: avf_showspectrum.c:49
WFUNC_BNUTTALL
@ WFUNC_BNUTTALL
Definition: af_firequalizer.c:41
audio.h
ShowSpectrumContext::start_y
int start_y
Definition: avf_showspectrum.c:102
AVFilterFormatsConfig::formats
AVFilterFormats * formats
List of supported formats (pixel or sample).
Definition: avfilter.h:437
WFUNC_POISSON
@ WFUNC_POISSON
Definition: window_func.h:32
DisplayScale
DisplayScale
Definition: avf_ahistogram.c:31
ShowSpectrumContext::itx_fn
av_tx_fn itx_fn
Definition: avf_showspectrum.c:78
ShowSpectrumContext::tx_fn
av_tx_fn tx_fn
Definition: avf_showspectrum.c:77
avpriv_cga_font
const uint8_t avpriv_cga_font[2048]
Definition: xga_font_data.c:29
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FF_FILTER_FORWARD_STATUS
FF_FILTER_FORWARD_STATUS(inlink, outlink)
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
NB_SCALES
@ NB_SCALES
Definition: avf_showspectrum.c:49
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
ShowSpectrumContext::sliding
int sliding
1 if sliding mode, 0 otherwise
Definition: avf_showspectrum.c:65
bin_pos
static float bin_pos(const int bin, const int num_bins, const float sample_rate)
Definition: avf_showspectrum.c:680
ColorTable::u
float u
Definition: avf_showspectrum.c:188
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:334
CBRT
@ CBRT
Definition: avf_showspectrum.c:49
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
h
h
Definition: vp9dsp_template.c:2038
MAGMA
@ MAGMA
Definition: avf_showspectrum.c:50
ff_outlink_frame_wanted
the definition of that something depends on the semantic of the filter The callback must examine the status of the filter s links and proceed accordingly The status of output links is stored in the status_in and status_out fields and tested by the ff_outlink_frame_wanted() function. If this function returns true
color_table
static const struct ColorTable color_table[][8]
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:228
showspectrum_options
static const AVOption showspectrum_options[]
Definition: avf_showspectrum.c:109
ColorTable
Definition: avf_showspectrum.c:187
int
int
Definition: ffmpeg_filter.c:156
av_audio_fifo_peek
int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples)
Peek data from an AVAudioFifo.
Definition: audio_fifo.c:138
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
REPLACE
@ REPLACE
Definition: avf_showspectrum.c:51
FIRE
@ FIRE
Definition: avf_showspectrum.c:50
drawtext
static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o)
Definition: avf_showspectrum.c:485
WFUNC_WELCH
@ WFUNC_WELCH
Definition: window_func.h:29
channel
channel
Definition: ebur128.h:39
SlideMode
SlideMode
Definition: avf_ahistogram.c:33
ff_filter_set_ready
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition: avfilter.c:186
tx.h
min
float min
Definition: vorbis_enc_data.h:429
ShowSpectrumContext::plot_channel
int(* plot_channel)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:103