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