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 <float.h>
30 #include <math.h>
31 
32 #include "libavutil/tx.h"
33 #include "libavutil/audio_fifo.h"
34 #include "libavutil/avassert.h"
35 #include "libavutil/avstring.h"
37 #include "libavutil/cpu.h"
38 #include "libavutil/opt.h"
39 #include "libavutil/parseutils.h"
41 #include "audio.h"
42 #include "video.h"
43 #include "avfilter.h"
44 #include "filters.h"
45 #include "internal.h"
46 #include "window_func.h"
47 
55 
56 typedef struct ShowSpectrumContext {
57  const AVClass *class;
58  int w, h;
59  char *rate_str;
67  int sliding; ///< 1 if sliding mode, 0 otherwise
68  int mode; ///< channel display mode
69  int color_mode; ///< display color scheme
70  int scale;
71  int fscale;
72  float saturation; ///< color saturation multiplier
73  float rotation; ///< color rotation
74  int start, stop; ///< zoom mode
75  int data;
76  int xpos; ///< x position (current column)
77  AVTXContext **fft; ///< Fast Fourier Transform context
78  AVTXContext **ifft; ///< Inverse Fast Fourier Transform context
81  int fft_size; ///< number of coeffs (FFT window size)
82  AVComplexFloat **fft_in; ///< input FFT coeffs
83  AVComplexFloat **fft_data; ///< bins holder for each (displayed) channels
84  AVComplexFloat **fft_scratch;///< scratch buffers
85  float *window_func_lut; ///< Window function LUT
86  float **magnitudes;
87  float **phases;
88  int win_func;
89  int win_size;
90  int buf_size;
91  double win_scale;
92  float overlap;
93  float gain;
94  int consumed;
95  int hop_size;
96  float *combine_buffer; ///< color combining buffer (3 * h items)
97  float **color_buffer; ///< color buffer (3 * h * ch items)
99  int64_t pts;
100  int64_t old_pts;
101  int old_len;
103  int legend;
105  float drange, limit;
106  float dmin, dmax;
107  int (*plot_channel)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
109 
110 #define OFFSET(x) offsetof(ShowSpectrumContext, x)
111 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
112 
113 static const AVOption showspectrum_options[] = {
114  { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
115  { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
116  { "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_SLIDES-1, FLAGS, "slide" },
117  { "replace", "replace old columns with new", 0, AV_OPT_TYPE_CONST, {.i64=REPLACE}, 0, 0, FLAGS, "slide" },
118  { "scroll", "scroll from right to left", 0, AV_OPT_TYPE_CONST, {.i64=SCROLL}, 0, 0, FLAGS, "slide" },
119  { "fullframe", "return full frames", 0, AV_OPT_TYPE_CONST, {.i64=FULLFRAME}, 0, 0, FLAGS, "slide" },
120  { "rscroll", "scroll from left to right", 0, AV_OPT_TYPE_CONST, {.i64=RSCROLL}, 0, 0, FLAGS, "slide" },
121  { "lreplace", "replace from right to left", 0, AV_OPT_TYPE_CONST, {.i64=LREPLACE}, 0, 0, FLAGS, "slide" },
122  { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, COMBINED, NB_MODES-1, FLAGS, "mode" },
123  { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
124  { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
125  { "color", "set channel coloring", OFFSET(color_mode), AV_OPT_TYPE_INT, {.i64=CHANNEL}, CHANNEL, NB_CLMODES-1, FLAGS, "color" },
126  { "channel", "separate color for each channel", 0, AV_OPT_TYPE_CONST, {.i64=CHANNEL}, 0, 0, FLAGS, "color" },
127  { "intensity", "intensity based coloring", 0, AV_OPT_TYPE_CONST, {.i64=INTENSITY}, 0, 0, FLAGS, "color" },
128  { "rainbow", "rainbow based coloring", 0, AV_OPT_TYPE_CONST, {.i64=RAINBOW}, 0, 0, FLAGS, "color" },
129  { "moreland", "moreland based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MORELAND}, 0, 0, FLAGS, "color" },
130  { "nebulae", "nebulae based coloring", 0, AV_OPT_TYPE_CONST, {.i64=NEBULAE}, 0, 0, FLAGS, "color" },
131  { "fire", "fire based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIRE}, 0, 0, FLAGS, "color" },
132  { "fiery", "fiery based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIERY}, 0, 0, FLAGS, "color" },
133  { "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
134  { "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
135  { "magma", "magma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MAGMA}, 0, 0, FLAGS, "color" },
136  { "green", "green based coloring", 0, AV_OPT_TYPE_CONST, {.i64=GREEN}, 0, 0, FLAGS, "color" },
137  { "viridis", "viridis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=VIRIDIS}, 0, 0, FLAGS, "color" },
138  { "plasma", "plasma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=PLASMA}, 0, 0, FLAGS, "color" },
139  { "cividis", "cividis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=CIVIDIS}, 0, 0, FLAGS, "color" },
140  { "terrain", "terrain based coloring", 0, AV_OPT_TYPE_CONST, {.i64=TERRAIN}, 0, 0, FLAGS, "color" },
141  { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=SQRT}, LINEAR, NB_SCALES-1, FLAGS, "scale" },
142  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
143  { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
144  { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
145  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
146  { "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
147  { "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
148  { "fscale", "set frequency scale", OFFSET(fscale), AV_OPT_TYPE_INT, {.i64=F_LINEAR}, 0, NB_FSCALES-1, FLAGS, "fscale" },
149  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=F_LINEAR}, 0, 0, FLAGS, "fscale" },
150  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=F_LOG}, 0, 0, FLAGS, "fscale" },
151  { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
152  WIN_FUNC_OPTION("win_func", OFFSET(win_func), FLAGS, WFUNC_HANNING),
153  { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
154  { "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
155  { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
156  { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, 1, FLAGS },
157  { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
158  { "data", "set data mode", OFFSET(data), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_DMODES-1, FLAGS, "data" },
159  { "magnitude", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_MAGNITUDE}, 0, 0, FLAGS, "data" },
160  { "phase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_PHASE}, 0, 0, FLAGS, "data" },
161  { "uphase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=D_UPHASE}, 0, 0, FLAGS, "data" },
162  { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
163  { "start", "start frequency", OFFSET(start), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
164  { "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
165  { "fps", "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = "auto"}, 0, 0, FLAGS },
166  { "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
167  { "drange", "set dynamic range in dBFS", OFFSET(drange), AV_OPT_TYPE_FLOAT, {.dbl = 120}, 10, 200, FLAGS },
168  { "limit", "set upper limit in dBFS", OFFSET(limit), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -100, 100, FLAGS },
169  { NULL }
170 };
171 
172 AVFILTER_DEFINE_CLASS(showspectrum);
173 
174 static const struct ColorTable {
175  float a, y, u, v;
176 } color_table[][8] = {
177  [INTENSITY] = {
178  { 0, 0, 0, 0 },
179  { 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 },
180  { 0.30, .18572281794568020, .1772436246393981, .17475554840414750 },
181  { 0.60, .28184980583656130, -.1593064119945782, .47132074554608920 },
182  { 0.73, .65830621175547810, -.3716070802232764, .24352759331252930 },
183  { 0.78, .76318535758242900, -.4307467689263783, .16866496622310430 },
184  { 0.91, .95336363636363640, -.2045454545454546, .03313636363636363 },
185  { 1, 1, 0, 0 }},
186  [RAINBOW] = {
187  { 0, 0, 0, 0 },
188  { 0.13, 44/256., (189-128)/256., (138-128)/256. },
189  { 0.25, 29/256., (186-128)/256., (119-128)/256. },
190  { 0.38, 119/256., (194-128)/256., (53-128)/256. },
191  { 0.60, 111/256., (73-128)/256., (59-128)/256. },
192  { 0.73, 205/256., (19-128)/256., (149-128)/256. },
193  { 0.86, 135/256., (83-128)/256., (200-128)/256. },
194  { 1, 73/256., (95-128)/256., (225-128)/256. }},
195  [MORELAND] = {
196  { 0, 44/256., (181-128)/256., (112-128)/256. },
197  { 0.13, 126/256., (177-128)/256., (106-128)/256. },
198  { 0.25, 164/256., (163-128)/256., (109-128)/256. },
199  { 0.38, 200/256., (140-128)/256., (120-128)/256. },
200  { 0.60, 201/256., (117-128)/256., (141-128)/256. },
201  { 0.73, 177/256., (103-128)/256., (165-128)/256. },
202  { 0.86, 136/256., (100-128)/256., (183-128)/256. },
203  { 1, 68/256., (117-128)/256., (203-128)/256. }},
204  [NEBULAE] = {
205  { 0, 10/256., (134-128)/256., (132-128)/256. },
206  { 0.23, 21/256., (137-128)/256., (130-128)/256. },
207  { 0.45, 35/256., (134-128)/256., (134-128)/256. },
208  { 0.57, 51/256., (130-128)/256., (139-128)/256. },
209  { 0.67, 104/256., (116-128)/256., (162-128)/256. },
210  { 0.77, 120/256., (105-128)/256., (188-128)/256. },
211  { 0.87, 140/256., (105-128)/256., (188-128)/256. },
212  { 1, 1, 0, 0 }},
213  [FIRE] = {
214  { 0, 0, 0, 0 },
215  { 0.23, 44/256., (132-128)/256., (127-128)/256. },
216  { 0.45, 62/256., (116-128)/256., (140-128)/256. },
217  { 0.57, 75/256., (105-128)/256., (152-128)/256. },
218  { 0.67, 95/256., (91-128)/256., (166-128)/256. },
219  { 0.77, 126/256., (74-128)/256., (172-128)/256. },
220  { 0.87, 164/256., (73-128)/256., (162-128)/256. },
221  { 1, 1, 0, 0 }},
222  [FIERY] = {
223  { 0, 0, 0, 0 },
224  { 0.23, 36/256., (116-128)/256., (163-128)/256. },
225  { 0.45, 52/256., (102-128)/256., (200-128)/256. },
226  { 0.57, 116/256., (84-128)/256., (196-128)/256. },
227  { 0.67, 157/256., (67-128)/256., (181-128)/256. },
228  { 0.77, 193/256., (40-128)/256., (155-128)/256. },
229  { 0.87, 221/256., (101-128)/256., (134-128)/256. },
230  { 1, 1, 0, 0 }},
231  [FRUIT] = {
232  { 0, 0, 0, 0 },
233  { 0.20, 29/256., (136-128)/256., (119-128)/256. },
234  { 0.30, 60/256., (119-128)/256., (90-128)/256. },
235  { 0.40, 85/256., (91-128)/256., (85-128)/256. },
236  { 0.50, 116/256., (70-128)/256., (105-128)/256. },
237  { 0.60, 151/256., (50-128)/256., (146-128)/256. },
238  { 0.70, 191/256., (63-128)/256., (178-128)/256. },
239  { 1, 98/256., (80-128)/256., (221-128)/256. }},
240  [COOL] = {
241  { 0, 0, 0, 0 },
242  { .15, 0, .5, -.5 },
243  { 1, 1, -.5, .5 }},
244  [MAGMA] = {
245  { 0, 0, 0, 0 },
246  { 0.10, 23/256., (175-128)/256., (120-128)/256. },
247  { 0.23, 43/256., (158-128)/256., (144-128)/256. },
248  { 0.35, 85/256., (138-128)/256., (179-128)/256. },
249  { 0.48, 96/256., (128-128)/256., (189-128)/256. },
250  { 0.64, 128/256., (103-128)/256., (214-128)/256. },
251  { 0.92, 205/256., (80-128)/256., (152-128)/256. },
252  { 1, 1, 0, 0 }},
253  [GREEN] = {
254  { 0, 0, 0, 0 },
255  { .75, .5, 0, -.5 },
256  { 1, 1, 0, 0 }},
257  [VIRIDIS] = {
258  { 0, 0, 0, 0 },
259  { 0.10, 0x39/255., (0x9D -128)/255., (0x8F -128)/255. },
260  { 0.23, 0x5C/255., (0x9A -128)/255., (0x68 -128)/255. },
261  { 0.35, 0x69/255., (0x93 -128)/255., (0x57 -128)/255. },
262  { 0.48, 0x76/255., (0x88 -128)/255., (0x4B -128)/255. },
263  { 0.64, 0x8A/255., (0x72 -128)/255., (0x4F -128)/255. },
264  { 0.80, 0xA3/255., (0x50 -128)/255., (0x66 -128)/255. },
265  { 1, 0xCC/255., (0x2F -128)/255., (0x87 -128)/255. }},
266  [PLASMA] = {
267  { 0, 0, 0, 0 },
268  { 0.10, 0x27/255., (0xC2 -128)/255., (0x82 -128)/255. },
269  { 0.58, 0x5B/255., (0x9A -128)/255., (0xAE -128)/255. },
270  { 0.70, 0x89/255., (0x44 -128)/255., (0xAB -128)/255. },
271  { 0.80, 0xB4/255., (0x2B -128)/255., (0x9E -128)/255. },
272  { 0.91, 0xD2/255., (0x38 -128)/255., (0x92 -128)/255. },
273  { 1, 1, 0, 0. }},
274  [CIVIDIS] = {
275  { 0, 0, 0, 0 },
276  { 0.20, 0x28/255., (0x98 -128)/255., (0x6F -128)/255. },
277  { 0.50, 0x48/255., (0x95 -128)/255., (0x74 -128)/255. },
278  { 0.63, 0x69/255., (0x84 -128)/255., (0x7F -128)/255. },
279  { 0.76, 0x89/255., (0x75 -128)/255., (0x84 -128)/255. },
280  { 0.90, 0xCE/255., (0x35 -128)/255., (0x95 -128)/255. },
281  { 1, 1, 0, 0. }},
282  [TERRAIN] = {
283  { 0, 0, 0, 0 },
284  { 0.15, 0, .5, 0 },
285  { 0.60, 1, -.5, -.5 },
286  { 0.85, 1, -.5, .5 },
287  { 1, 1, 0, 0 }},
288 };
289 
291 {
292  ShowSpectrumContext *s = ctx->priv;
293  int i;
294 
295  av_freep(&s->combine_buffer);
296  if (s->fft) {
297  for (i = 0; i < s->nb_display_channels; i++)
298  av_tx_uninit(&s->fft[i]);
299  }
300  av_freep(&s->fft);
301  if (s->ifft) {
302  for (i = 0; i < s->nb_display_channels; i++)
303  av_tx_uninit(&s->ifft[i]);
304  }
305  av_freep(&s->ifft);
306  if (s->fft_data) {
307  for (i = 0; i < s->nb_display_channels; i++)
308  av_freep(&s->fft_data[i]);
309  }
310  av_freep(&s->fft_data);
311  if (s->fft_in) {
312  for (i = 0; i < s->nb_display_channels; i++)
313  av_freep(&s->fft_in[i]);
314  }
315  av_freep(&s->fft_in);
316  if (s->fft_scratch) {
317  for (i = 0; i < s->nb_display_channels; i++)
318  av_freep(&s->fft_scratch[i]);
319  }
320  av_freep(&s->fft_scratch);
321  if (s->color_buffer) {
322  for (i = 0; i < s->nb_display_channels; i++)
323  av_freep(&s->color_buffer[i]);
324  }
325  av_freep(&s->color_buffer);
326  av_freep(&s->window_func_lut);
327  if (s->magnitudes) {
328  for (i = 0; i < s->nb_display_channels; i++)
329  av_freep(&s->magnitudes[i]);
330  }
331  av_freep(&s->magnitudes);
332  av_frame_free(&s->outpicref);
333  av_audio_fifo_free(s->fifo);
334  if (s->phases) {
335  for (i = 0; i < s->nb_display_channels; i++)
336  av_freep(&s->phases[i]);
337  }
338  av_freep(&s->phases);
339 }
340 
342 {
345  AVFilterLink *inlink = ctx->inputs[0];
346  AVFilterLink *outlink = ctx->outputs[0];
349  int ret;
350 
351  /* set input audio formats */
353  if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0)
354  return ret;
355 
357  if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0)
358  return ret;
359 
361  if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0)
362  return ret;
363 
364  /* set output video format */
366  if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0)
367  return ret;
368 
369  return 0;
370 }
371 
372 static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
373 {
374  ShowSpectrumContext *s = ctx->priv;
375  AVFilterLink *inlink = ctx->inputs[0];
376  const float *window_func_lut = s->window_func_lut;
377  AVFrame *fin = arg;
378  const int ch = jobnr;
379  int n;
380 
381  /* fill FFT input with the number of samples available */
382  const float *p = (float *)fin->extended_data[ch];
383 
384  if (s->stop) {
385  float theta, phi, psi, a, b, S, c;
386  AVComplexFloat *f = s->fft_in[ch];
387  AVComplexFloat *g = s->fft_data[ch];
388  AVComplexFloat *h = s->fft_scratch[ch];
389  int L = s->buf_size;
390  int N = s->win_size;
391  int M = s->win_size / 2;
392 
393  for (n = 0; n < s->win_size; n++) {
394  s->fft_data[ch][n].re = p[n] * window_func_lut[n];
395  s->fft_data[ch][n].im = 0;
396  }
397 
398  phi = 2.f * M_PI * (s->stop - s->start) / (float)inlink->sample_rate / (M - 1);
399  theta = 2.f * M_PI * s->start / (float)inlink->sample_rate;
400 
401  for (int n = 0; n < M; n++) {
402  h[n].re = cosf(n * n / 2.f * phi);
403  h[n].im = sinf(n * n / 2.f * phi);
404  }
405 
406  for (int n = M; n < L; n++) {
407  h[n].re = 0.f;
408  h[n].im = 0.f;
409  }
410 
411  for (int n = L - N; n < L; n++) {
412  h[n].re = cosf((L - n) * (L - n) / 2.f * phi);
413  h[n].im = sinf((L - n) * (L - n) / 2.f * phi);
414  }
415 
416  for (int n = N; n < L; n++) {
417  g[n].re = 0.f;
418  g[n].im = 0.f;
419  }
420 
421  for (int n = 0; n < N; n++) {
422  psi = n * theta + n * n / 2.f * phi;
423  c = cosf(psi);
424  S = -sinf(psi);
425  a = c * g[n].re - S * g[n].im;
426  b = S * g[n].re + c * g[n].im;
427  g[n].re = a;
428  g[n].im = b;
429  }
430 
431  memcpy(f, h, s->buf_size * sizeof(*f));
432  s->tx_fn(s->fft[ch], h, f, sizeof(float));
433 
434  memcpy(f, g, s->buf_size * sizeof(*f));
435  s->tx_fn(s->fft[ch], g, f, sizeof(float));
436 
437  for (int n = 0; n < L; n++) {
438  c = g[n].re;
439  S = g[n].im;
440  a = c * h[n].re - S * h[n].im;
441  b = S * h[n].re + c * h[n].im;
442 
443  g[n].re = a / L;
444  g[n].im = b / L;
445  }
446 
447  memcpy(f, g, s->buf_size * sizeof(*f));
448  s->itx_fn(s->ifft[ch], g, f, sizeof(float));
449 
450  for (int k = 0; k < M; k++) {
451  psi = k * k / 2.f * phi;
452  c = cosf(psi);
453  S = -sinf(psi);
454  a = c * g[k].re - S * g[k].im;
455  b = S * g[k].re + c * g[k].im;
456  s->fft_data[ch][k].re = a;
457  s->fft_data[ch][k].im = b;
458  }
459  } else {
460  for (n = 0; n < s->win_size; n++) {
461  s->fft_in[ch][n].re = p[n] * window_func_lut[n];
462  s->fft_in[ch][n].im = 0;
463  }
464 
465  /* run FFT on each samples set */
466  s->tx_fn(s->fft[ch], s->fft_data[ch], s->fft_in[ch], sizeof(float));
467  }
468 
469  return 0;
470 }
471 
472 static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o)
473 {
474  const uint8_t *font;
475  int font_height;
476  int i;
477 
478  font = avpriv_cga_font, font_height = 8;
479 
480  for (i = 0; txt[i]; i++) {
481  int char_y, mask;
482 
483  if (o) {
484  for (char_y = font_height - 1; char_y >= 0; char_y--) {
485  uint8_t *p = pic->data[0] + (y + i * 10) * pic->linesize[0] + x;
486  for (mask = 0x80; mask; mask >>= 1) {
487  if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
488  p[char_y] = ~p[char_y];
489  p += pic->linesize[0];
490  }
491  }
492  } else {
493  uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8);
494  for (char_y = 0; char_y < font_height; char_y++) {
495  for (mask = 0x80; mask; mask >>= 1) {
496  if (font[txt[i] * font_height + char_y] & mask)
497  *p = ~(*p);
498  p++;
499  }
500  p += pic->linesize[0] - 8;
501  }
502  }
503  }
504 }
505 
506 static void color_range(ShowSpectrumContext *s, int ch,
507  float *yf, float *uf, float *vf)
508 {
509  switch (s->mode) {
510  case COMBINED:
511  // reduce range by channel count
512  *yf = 256.0f / s->nb_display_channels;
513  switch (s->color_mode) {
514  case RAINBOW:
515  case MORELAND:
516  case NEBULAE:
517  case FIRE:
518  case FIERY:
519  case FRUIT:
520  case COOL:
521  case GREEN:
522  case VIRIDIS:
523  case PLASMA:
524  case CIVIDIS:
525  case TERRAIN:
526  case MAGMA:
527  case INTENSITY:
528  *uf = *yf;
529  *vf = *yf;
530  break;
531  case CHANNEL:
532  /* adjust saturation for mixed UV coloring */
533  /* this factor is correct for infinite channels, an approximation otherwise */
534  *uf = *yf * M_PI;
535  *vf = *yf * M_PI;
536  break;
537  default:
538  av_assert0(0);
539  }
540  break;
541  case SEPARATE:
542  // full range
543  *yf = 256.0f;
544  *uf = 256.0f;
545  *vf = 256.0f;
546  break;
547  default:
548  av_assert0(0);
549  }
550 
551  if (s->color_mode == CHANNEL) {
552  if (s->nb_display_channels > 1) {
553  *uf *= 0.5f * sinf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
554  *vf *= 0.5f * cosf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation);
555  } else {
556  *uf *= 0.5f * sinf(M_PI * s->rotation);
557  *vf *= 0.5f * cosf(M_PI * s->rotation + M_PI_2);
558  }
559  } else {
560  *uf += *uf * sinf(M_PI * s->rotation);
561  *vf += *vf * cosf(M_PI * s->rotation + M_PI_2);
562  }
563 
564  *uf *= s->saturation;
565  *vf *= s->saturation;
566 }
567 
569  float yf, float uf, float vf,
570  float a, float *out)
571 {
572  if (s->color_mode > CHANNEL) {
573  const int cm = s->color_mode;
574  float y, u, v;
575  int i;
576 
577  for (i = 1; i < FF_ARRAY_ELEMS(color_table[cm]) - 1; i++)
578  if (color_table[cm][i].a >= a)
579  break;
580  // i now is the first item >= the color
581  // now we know to interpolate between item i - 1 and i
582  if (a <= color_table[cm][i - 1].a) {
583  y = color_table[cm][i - 1].y;
584  u = color_table[cm][i - 1].u;
585  v = color_table[cm][i - 1].v;
586  } else if (a >= color_table[cm][i].a) {
587  y = color_table[cm][i].y;
588  u = color_table[cm][i].u;
589  v = color_table[cm][i].v;
590  } else {
591  float start = color_table[cm][i - 1].a;
592  float end = color_table[cm][i].a;
593  float lerpfrac = (a - start) / (end - start);
594  y = color_table[cm][i - 1].y * (1.0f - lerpfrac)
595  + color_table[cm][i].y * lerpfrac;
596  u = color_table[cm][i - 1].u * (1.0f - lerpfrac)
597  + color_table[cm][i].u * lerpfrac;
598  v = color_table[cm][i - 1].v * (1.0f - lerpfrac)
599  + color_table[cm][i].v * lerpfrac;
600  }
601 
602  out[0] = y * yf;
603  out[1] = u * uf;
604  out[2] = v * vf;
605  } else {
606  out[0] = a * yf;
607  out[1] = a * uf;
608  out[2] = a * vf;
609  }
610 }
611 
612 static char *get_time(AVFilterContext *ctx, float seconds, int x)
613 {
614  char *units;
615 
616  if (x == 0)
617  units = av_asprintf("0");
618  else if (log10(seconds) > 6)
619  units = av_asprintf("%.2fh", seconds / (60 * 60));
620  else if (log10(seconds) > 3)
621  units = av_asprintf("%.2fm", seconds / 60);
622  else
623  units = av_asprintf("%.2fs", seconds);
624  return units;
625 }
626 
627 static float log_scale(const float bin,
628  const float bmin, const float bmax,
629  const float min, const float max)
630 {
631  return exp2f(((bin - bmin) / (bmax - bmin)) * (log2f(max) - log2f(min)) + log2f(min));
632 }
633 
634 static float get_hz(const float bin, const float bmax,
635  const float min, const float max,
636  int fscale)
637 {
638  switch (fscale) {
639  case F_LINEAR:
640  return min + (bin / bmax) * (max - min);
641  case F_LOG:
642  return min + log_scale(bin, 0, bmax, 20.f, max - min);
643  default:
644  return 0.f;
645  }
646 }
647 
648 static float inv_log_scale(float bin,
649  float bmin, float bmax,
650  float min, float max)
651 {
652  return (min * exp2f((bin * (log2f(max) - log2f(20.f))) / bmax) + min) * bmax / max;
653 }
654 
655 static float bin_pos(const int bin, const int num_bins, const float min, const float max)
656 {
657  return inv_log_scale(bin, 0.f, num_bins, 20.f, max - min);
658 }
659 
660 static float get_scale(AVFilterContext *ctx, int scale, float a)
661 {
662  ShowSpectrumContext *s = ctx->priv;
663  const float dmin = s->dmin;
664  const float dmax = s->dmax;
665 
666  a = av_clipf(a, dmin, dmax);
667  if (scale != LOG)
668  a = (a - dmin) / (dmax - dmin);
669 
670  switch (scale) {
671  case LINEAR:
672  break;
673  case SQRT:
674  a = sqrtf(a);
675  break;
676  case CBRT:
677  a = cbrtf(a);
678  break;
679  case FOURTHRT:
680  a = sqrtf(sqrtf(a));
681  break;
682  case FIFTHRT:
683  a = powf(a, 0.2f);
684  break;
685  case LOG:
686  a = (s->drange - s->limit + log10f(a) * 20.f) / s->drange;
687  break;
688  default:
689  av_assert0(0);
690  }
691 
692  return a;
693 }
694 
695 static float get_iscale(AVFilterContext *ctx, int scale, float a)
696 {
697  ShowSpectrumContext *s = ctx->priv;
698  const float dmin = s->dmin;
699  const float dmax = s->dmax;
700 
701  switch (scale) {
702  case LINEAR:
703  break;
704  case SQRT:
705  a = a * a;
706  break;
707  case CBRT:
708  a = a * a * a;
709  break;
710  case FOURTHRT:
711  a = a * a * a * a;
712  break;
713  case FIFTHRT:
714  a = a * a * a * a * a;
715  break;
716  case LOG:
717  a = expf(M_LN10 * (a * s->drange - s->drange + s->limit) / 20.f);
718  break;
719  default:
720  av_assert0(0);
721  }
722 
723  if (scale != LOG)
724  a = a * (dmax - dmin) + dmin;
725 
726  return a;
727 }
728 
730 {
731  ShowSpectrumContext *s = ctx->priv;
732  AVFilterLink *inlink = ctx->inputs[0];
733  AVFilterLink *outlink = ctx->outputs[0];
734  int ch, y, x = 0, sz = s->orientation == VERTICAL ? s->w : s->h;
735  int multi = (s->mode == SEPARATE && s->color_mode == CHANNEL);
736  float spp = samples / (float)sz;
737  char *text;
738  uint8_t *dst;
739  char chlayout_str[128];
740 
741  av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), inlink->channels,
742  inlink->channel_layout);
743 
744  text = av_asprintf("%d Hz | %s", inlink->sample_rate, chlayout_str);
745  if (!text)
746  return AVERROR(ENOMEM);
747 
748  drawtext(s->outpicref, 2, outlink->h - 10, "CREATED BY LIBAVFILTER", 0);
749  drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, outlink->h - 10, text, 0);
750  av_freep(&text);
751  if (s->stop) {
752  text = av_asprintf("Zoom: %d Hz - %d Hz", s->start, s->stop);
753  if (!text)
754  return AVERROR(ENOMEM);
755  drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, 3, text, 0);
756  av_freep(&text);
757  }
758 
759  dst = s->outpicref->data[0] + (s->start_y - 1) * s->outpicref->linesize[0] + s->start_x - 1;
760  for (x = 0; x < s->w + 1; x++)
761  dst[x] = 200;
762  dst = s->outpicref->data[0] + (s->start_y + s->h) * s->outpicref->linesize[0] + s->start_x - 1;
763  for (x = 0; x < s->w + 1; x++)
764  dst[x] = 200;
765  for (y = 0; y < s->h + 2; y++) {
766  dst = s->outpicref->data[0] + (y + s->start_y - 1) * s->outpicref->linesize[0];
767  dst[s->start_x - 1] = 200;
768  dst[s->start_x + s->w] = 200;
769  }
770  if (s->orientation == VERTICAL) {
771  int h = s->mode == SEPARATE ? s->h / s->nb_display_channels : s->h;
772  int hh = s->mode == SEPARATE ? -(s->h % s->nb_display_channels) + 1 : 1;
773  for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) {
774  for (y = 0; y < h; y += 20) {
775  dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0];
776  dst[s->start_x - 2] = 200;
777  dst[s->start_x + s->w + 1] = 200;
778  }
779  for (y = 0; y < h; y += 40) {
780  dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0];
781  dst[s->start_x - 3] = 200;
782  dst[s->start_x + s->w + 2] = 200;
783  }
784  dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x;
785  for (x = 0; x < s->w; x+=40)
786  dst[x] = 200;
787  dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x;
788  for (x = 0; x < s->w; x+=80)
789  dst[x] = 200;
790  dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x;
791  for (x = 0; x < s->w; x+=40) {
792  dst[x] = 200;
793  }
794  dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x;
795  for (x = 0; x < s->w; x+=80) {
796  dst[x] = 200;
797  }
798  for (y = 0; y < h; y += 40) {
799  float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
800  float hertz = get_hz(y, h, s->start, s->start + range, s->fscale);
801  char *units;
802 
803  if (hertz == 0)
804  units = av_asprintf("DC");
805  else
806  units = av_asprintf("%.2f", hertz);
807  if (!units)
808  return AVERROR(ENOMEM);
809 
810  drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, h * (ch + 1) + s->start_y - y - 4 - hh, units, 0);
811  av_free(units);
812  }
813  }
814 
815  for (x = 0; x < s->w && s->single_pic; x+=80) {
816  float seconds = x * spp / inlink->sample_rate;
817  char *units = get_time(ctx, seconds, x);
818  if (!units)
819  return AVERROR(ENOMEM);
820 
821  drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->h + s->start_y + 6, units, 0);
822  drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->start_y - 12, units, 0);
823  av_free(units);
824  }
825 
826  drawtext(s->outpicref, outlink->w / 2 - 4 * 4, outlink->h - s->start_y / 2, "TIME", 0);
827  drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 14 * 4, "FREQUENCY (Hz)", 1);
828  } else {
829  int w = s->mode == SEPARATE ? s->w / s->nb_display_channels : s->w;
830  for (y = 0; y < s->h; y += 20) {
831  dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0];
832  dst[s->start_x - 2] = 200;
833  dst[s->start_x + s->w + 1] = 200;
834  }
835  for (y = 0; y < s->h; y += 40) {
836  dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0];
837  dst[s->start_x - 3] = 200;
838  dst[s->start_x + s->w + 2] = 200;
839  }
840  for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) {
841  dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x + w * ch;
842  for (x = 0; x < w; x+=40)
843  dst[x] = 200;
844  dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x + w * ch;
845  for (x = 0; x < w; x+=80)
846  dst[x] = 200;
847  dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x + w * ch;
848  for (x = 0; x < w; x+=40) {
849  dst[x] = 200;
850  }
851  dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x + w * ch;
852  for (x = 0; x < w; x+=80) {
853  dst[x] = 200;
854  }
855  for (x = 0; x < w - 79; x += 80) {
856  float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
857  float hertz = get_hz(x, w, s->start, s->start + range, s->fscale);
858  char *units;
859 
860  if (hertz == 0)
861  units = av_asprintf("DC");
862  else
863  units = av_asprintf("%.2f", hertz);
864  if (!units)
865  return AVERROR(ENOMEM);
866 
867  drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->start_y - 12, units, 0);
868  drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->h + s->start_y + 6, units, 0);
869  av_free(units);
870  }
871  }
872  for (y = 0; y < s->h && s->single_pic; y+=40) {
873  float seconds = y * spp / inlink->sample_rate;
874  char *units = get_time(ctx, seconds, x);
875  if (!units)
876  return AVERROR(ENOMEM);
877 
878  drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, s->start_y + y - 4, units, 0);
879  av_free(units);
880  }
881  drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 4 * 4, "TIME", 1);
882  drawtext(s->outpicref, outlink->w / 2 - 14 * 4, outlink->h - s->start_y / 2, "FREQUENCY (Hz)", 0);
883  }
884 
885  for (ch = 0; ch < (multi ? s->nb_display_channels : 1); ch++) {
886  int h = multi ? s->h / s->nb_display_channels : s->h;
887 
888  for (y = 0; y < h; y++) {
889  float out[3] = { 0., 127.5, 127.5};
890  int chn;
891 
892  for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) {
893  float yf, uf, vf;
894  int channel = (multi) ? s->nb_display_channels - ch - 1 : chn;
895  float lout[3];
896 
897  color_range(s, channel, &yf, &uf, &vf);
898  pick_color(s, yf, uf, vf, y / (float)h, lout);
899  out[0] += lout[0];
900  out[1] += lout[1];
901  out[2] += lout[2];
902  }
903  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);
904  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);
905  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);
906  }
907 
908  for (y = 0; ch == 0 && y < h + 5; y += 25) {
909  static const char *log_fmt = "%.0f";
910  static const char *lin_fmt = "%.3f";
911  const float a = av_clipf(1.f - y / (float)(h - 1), 0.f, 1.f);
912  const float value = s->scale == LOG ? log10f(get_iscale(ctx, s->scale, a)) * 20.f : get_iscale(ctx, s->scale, a);
913  char *text;
914 
915  text = av_asprintf(s->scale == LOG ? log_fmt : lin_fmt, value);
916  if (!text)
917  continue;
918  drawtext(s->outpicref, s->w + s->start_x + 35, s->start_y + y - 3, text, 0);
919  av_free(text);
920  }
921  }
922 
923  if (s->scale == LOG)
924  drawtext(s->outpicref, s->w + s->start_x + 22, s->start_y + s->h + 20, "dBFS", 0);
925 
926  return 0;
927 }
928 
929 static float get_value(AVFilterContext *ctx, int ch, int y)
930 {
931  ShowSpectrumContext *s = ctx->priv;
932  float *magnitudes = s->magnitudes[ch];
933  float *phases = s->phases[ch];
934  float a;
935 
936  switch (s->data) {
937  case D_MAGNITUDE:
938  /* get magnitude */
939  a = magnitudes[y];
940  break;
941  case D_UPHASE:
942  case D_PHASE:
943  /* get phase */
944  a = phases[y];
945  break;
946  default:
947  av_assert0(0);
948  }
949 
950  return av_clipf(get_scale(ctx, s->scale, a), 0.f, 1.f);
951 }
952 
953 static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
954 {
955  ShowSpectrumContext *s = ctx->priv;
956  const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
957  const int ch = jobnr;
958  float yf, uf, vf;
959  int y;
960 
961  /* decide color range */
962  color_range(s, ch, &yf, &uf, &vf);
963 
964  /* draw the channel */
965  for (y = 0; y < h; y++) {
966  int row = (s->mode == COMBINED) ? y : ch * h + y;
967  float *out = &s->color_buffer[ch][3 * row];
968  float a = get_value(ctx, ch, y);
969 
970  pick_color(s, yf, uf, vf, a, out);
971  }
972 
973  return 0;
974 }
975 
976 static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
977 {
978  ShowSpectrumContext *s = ctx->priv;
979  AVFilterLink *inlink = ctx->inputs[0];
980  const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
981  const int ch = jobnr;
982  float yf, uf, vf;
983 
984  /* decide color range */
985  color_range(s, ch, &yf, &uf, &vf);
986 
987  /* draw the channel */
988  for (int yy = 0; yy < h; yy++) {
989  float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
990  float pos = bin_pos(yy, h, s->start, s->start + range);
991  float delta = pos - floorf(pos);
992  float a0, a1;
993 
994  a0 = get_value(ctx, ch, av_clip(pos, 0, h-1));
995  a1 = get_value(ctx, ch, av_clip(pos+1, 0, h-1));
996  {
997  int row = (s->mode == COMBINED) ? yy : ch * h + yy;
998  float *out = &s->color_buffer[ch][3 * row];
999 
1000  pick_color(s, yf, uf, vf, delta * a1 + (1.f - delta) * a0, out);
1001  }
1002  }
1003 
1004  return 0;
1005 }
1006 
1007 static int config_output(AVFilterLink *outlink)
1008 {
1009  AVFilterContext *ctx = outlink->src;
1010  AVFilterLink *inlink = ctx->inputs[0];
1011  ShowSpectrumContext *s = ctx->priv;
1012  int i, fft_size, h, w, ret;
1013  float overlap;
1014 
1015  s->dmax = expf(s->limit * M_LN10 / 20.f);
1016  s->dmin = expf((s->limit - s->drange) * M_LN10 / 20.f);
1017 
1018  switch (s->fscale) {
1019  case F_LINEAR: s->plot_channel = plot_channel_lin; break;
1020  case F_LOG: s->plot_channel = plot_channel_log; break;
1021  default: return AVERROR_BUG;
1022  }
1023 
1024  s->stop = FFMIN(s->stop, inlink->sample_rate / 2);
1025  if ((s->stop || s->start) && s->stop <= s->start) {
1026  av_log(ctx, AV_LOG_ERROR, "Stop frequency should be greater than start.\n");
1027  return AVERROR(EINVAL);
1028  }
1029 
1030  if (!strcmp(ctx->filter->name, "showspectrumpic"))
1031  s->single_pic = 1;
1032 
1033  outlink->w = s->w;
1034  outlink->h = s->h;
1035  outlink->sample_aspect_ratio = (AVRational){1,1};
1036 
1037  if (s->legend) {
1038  s->start_x = (log10(inlink->sample_rate) + 1) * 25;
1039  s->start_y = 64;
1040  outlink->w += s->start_x * 2;
1041  outlink->h += s->start_y * 2;
1042  }
1043 
1044  h = (s->mode == COMBINED || s->orientation == HORIZONTAL) ? s->h : s->h / inlink->channels;
1045  w = (s->mode == COMBINED || s->orientation == VERTICAL) ? s->w : s->w / inlink->channels;
1046  s->channel_height = h;
1047  s->channel_width = w;
1048 
1049  if (s->orientation == VERTICAL) {
1050  /* FFT window size (precision) according to the requested output frame height */
1051  fft_size = h * 2;
1052  } else {
1053  /* FFT window size (precision) according to the requested output frame width */
1054  fft_size = w * 2;
1055  }
1056 
1057  s->win_size = fft_size;
1058  s->buf_size = FFALIGN(s->win_size << (!!s->stop), av_cpu_max_align());
1059 
1060  if (!s->fft) {
1061  s->fft = av_calloc(inlink->channels, sizeof(*s->fft));
1062  if (!s->fft)
1063  return AVERROR(ENOMEM);
1064  }
1065 
1066  if (s->stop) {
1067  if (!s->ifft) {
1068  s->ifft = av_calloc(inlink->channels, sizeof(*s->ifft));
1069  if (!s->ifft)
1070  return AVERROR(ENOMEM);
1071  }
1072  }
1073 
1074  /* (re-)configuration if the video output changed (or first init) */
1075  if (fft_size != s->fft_size) {
1076  AVFrame *outpicref;
1077 
1078  s->fft_size = fft_size;
1079 
1080  /* FFT buffers: x2 for each (display) channel buffer.
1081  * Note: we use free and malloc instead of a realloc-like function to
1082  * make sure the buffer is aligned in memory for the FFT functions. */
1083  for (i = 0; i < s->nb_display_channels; i++) {
1084  if (s->stop) {
1085  av_tx_uninit(&s->ifft[i]);
1086  av_freep(&s->fft_scratch[i]);
1087  }
1088  av_tx_uninit(&s->fft[i]);
1089  av_freep(&s->fft_in[i]);
1090  av_freep(&s->fft_data[i]);
1091  }
1092  av_freep(&s->fft_data);
1093 
1094  s->nb_display_channels = inlink->channels;
1095  for (i = 0; i < s->nb_display_channels; i++) {
1096  float scale;
1097 
1098  ret = av_tx_init(&s->fft[i], &s->tx_fn, AV_TX_FLOAT_FFT, 0, fft_size << (!!s->stop), &scale, 0);
1099  if (s->stop) {
1100  ret = av_tx_init(&s->ifft[i], &s->itx_fn, AV_TX_FLOAT_FFT, 1, fft_size << (!!s->stop), &scale, 0);
1101  if (ret < 0) {
1102  av_log(ctx, AV_LOG_ERROR, "Unable to create Inverse FFT context. "
1103  "The window size might be too high.\n");
1104  return ret;
1105  }
1106  }
1107  if (ret < 0) {
1108  av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. "
1109  "The window size might be too high.\n");
1110  return ret;
1111  }
1112  }
1113 
1114  s->magnitudes = av_calloc(s->nb_display_channels, sizeof(*s->magnitudes));
1115  if (!s->magnitudes)
1116  return AVERROR(ENOMEM);
1117  for (i = 0; i < s->nb_display_channels; i++) {
1118  s->magnitudes[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->magnitudes));
1119  if (!s->magnitudes[i])
1120  return AVERROR(ENOMEM);
1121  }
1122 
1123  s->phases = av_calloc(s->nb_display_channels, sizeof(*s->phases));
1124  if (!s->phases)
1125  return AVERROR(ENOMEM);
1126  for (i = 0; i < s->nb_display_channels; i++) {
1127  s->phases[i] = av_calloc(s->orientation == VERTICAL ? s->h : s->w, sizeof(**s->phases));
1128  if (!s->phases[i])
1129  return AVERROR(ENOMEM);
1130  }
1131 
1132  av_freep(&s->color_buffer);
1133  s->color_buffer = av_calloc(s->nb_display_channels, sizeof(*s->color_buffer));
1134  if (!s->color_buffer)
1135  return AVERROR(ENOMEM);
1136  for (i = 0; i < s->nb_display_channels; i++) {
1137  s->color_buffer[i] = av_calloc(s->orientation == VERTICAL ? s->h * 3 : s->w * 3, sizeof(**s->color_buffer));
1138  if (!s->color_buffer[i])
1139  return AVERROR(ENOMEM);
1140  }
1141 
1142  s->fft_in = av_calloc(s->nb_display_channels, sizeof(*s->fft_in));
1143  if (!s->fft_in)
1144  return AVERROR(ENOMEM);
1145  s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data));
1146  if (!s->fft_data)
1147  return AVERROR(ENOMEM);
1148  s->fft_scratch = av_calloc(s->nb_display_channels, sizeof(*s->fft_scratch));
1149  if (!s->fft_scratch)
1150  return AVERROR(ENOMEM);
1151  for (i = 0; i < s->nb_display_channels; i++) {
1152  s->fft_in[i] = av_calloc(s->buf_size, sizeof(**s->fft_in));
1153  if (!s->fft_in[i])
1154  return AVERROR(ENOMEM);
1155 
1156  s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data));
1157  if (!s->fft_data[i])
1158  return AVERROR(ENOMEM);
1159 
1160  s->fft_scratch[i] = av_calloc(s->buf_size, sizeof(**s->fft_scratch));
1161  if (!s->fft_scratch[i])
1162  return AVERROR(ENOMEM);
1163  }
1164 
1165  /* pre-calc windowing function */
1166  s->window_func_lut =
1167  av_realloc_f(s->window_func_lut, s->win_size,
1168  sizeof(*s->window_func_lut));
1169  if (!s->window_func_lut)
1170  return AVERROR(ENOMEM);
1171  generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap);
1172  if (s->overlap == 1)
1173  s->overlap = overlap;
1174  s->hop_size = (1.f - s->overlap) * s->win_size;
1175  if (s->hop_size < 1) {
1176  av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap);
1177  return AVERROR(EINVAL);
1178  }
1179 
1180  for (s->win_scale = 0, i = 0; i < s->win_size; i++) {
1181  s->win_scale += s->window_func_lut[i] * s->window_func_lut[i];
1182  }
1183  s->win_scale = 1.f / sqrtf(s->win_scale);
1184 
1185  /* prepare the initial picref buffer (black frame) */
1186  av_frame_free(&s->outpicref);
1187  s->outpicref = outpicref =
1188  ff_get_video_buffer(outlink, outlink->w, outlink->h);
1189  if (!outpicref)
1190  return AVERROR(ENOMEM);
1191  outpicref->sample_aspect_ratio = (AVRational){1,1};
1192  for (i = 0; i < outlink->h; i++) {
1193  memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w);
1194  memset(outpicref->data[1] + i * outpicref->linesize[1], 128, outlink->w);
1195  memset(outpicref->data[2] + i * outpicref->linesize[2], 128, outlink->w);
1196  }
1197  outpicref->color_range = AVCOL_RANGE_JPEG;
1198 
1199  if (!s->single_pic && s->legend)
1200  draw_legend(ctx, 0);
1201  }
1202 
1203  if ((s->orientation == VERTICAL && s->xpos >= s->w) ||
1204  (s->orientation == HORIZONTAL && s->xpos >= s->h))
1205  s->xpos = 0;
1206 
1207  if (s->sliding == LREPLACE) {
1208  if (s->orientation == VERTICAL)
1209  s->xpos = s->w - 1;
1210  if (s->orientation == HORIZONTAL)
1211  s->xpos = s->h - 1;
1212  }
1213 
1214  s->auto_frame_rate = av_make_q(inlink->sample_rate, s->hop_size);
1215  if (s->orientation == VERTICAL && s->sliding == FULLFRAME)
1216  s->auto_frame_rate = av_mul_q(s->auto_frame_rate, av_make_q(1, s->w));
1217  if (s->orientation == HORIZONTAL && s->sliding == FULLFRAME)
1218  s->auto_frame_rate = av_mul_q(s->auto_frame_rate, av_make_q(1, s->h));
1219  if (!s->single_pic && strcmp(s->rate_str, "auto")) {
1220  int ret = av_parse_video_rate(&s->frame_rate, s->rate_str);
1221  if (ret < 0)
1222  return ret;
1223  } else {
1224  s->frame_rate = s->auto_frame_rate;
1225  }
1226  outlink->frame_rate = s->frame_rate;
1227  outlink->time_base = av_inv_q(outlink->frame_rate);
1228 
1229  if (s->orientation == VERTICAL) {
1230  s->combine_buffer =
1231  av_realloc_f(s->combine_buffer, s->h * 3,
1232  sizeof(*s->combine_buffer));
1233  } else {
1234  s->combine_buffer =
1235  av_realloc_f(s->combine_buffer, s->w * 3,
1236  sizeof(*s->combine_buffer));
1237  }
1238 
1239  av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d FFT window size:%d\n",
1240  s->w, s->h, s->win_size);
1241 
1242  av_audio_fifo_free(s->fifo);
1243  s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size);
1244  if (!s->fifo)
1245  return AVERROR(ENOMEM);
1246  return 0;
1247 }
1248 
1249 #define RE(y, ch) s->fft_data[ch][y].re
1250 #define IM(y, ch) s->fft_data[ch][y].im
1251 #define MAGNITUDE(y, ch) hypotf(RE(y, ch), IM(y, ch))
1252 #define PHASE(y, ch) atan2f(IM(y, ch), RE(y, ch))
1253 
1254 static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1255 {
1256  ShowSpectrumContext *s = ctx->priv;
1257  const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1);
1258  int y, h = s->orientation == VERTICAL ? s->h : s->w;
1259  const float f = s->gain * w;
1260  const int ch = jobnr;
1261  float *magnitudes = s->magnitudes[ch];
1262 
1263  for (y = 0; y < h; y++)
1264  magnitudes[y] = MAGNITUDE(y, ch) * f;
1265 
1266  return 0;
1267 }
1268 
1269 static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1270 {
1271  ShowSpectrumContext *s = ctx->priv;
1272  const int h = s->orientation == VERTICAL ? s->h : s->w;
1273  const int ch = jobnr;
1274  float *phases = s->phases[ch];
1275  int y;
1276 
1277  for (y = 0; y < h; y++)
1278  phases[y] = (PHASE(y, ch) / M_PI + 1) / 2;
1279 
1280  return 0;
1281 }
1282 
1283 static void unwrap(float *x, int N, float tol, float *mi, float *ma)
1284 {
1285  const float rng = 2.f * M_PI;
1286  float prev_p = 0.f;
1287  float max = -FLT_MAX;
1288  float min = FLT_MAX;
1289 
1290  for (int i = 0; i < N; i++) {
1291  const float d = x[FFMIN(i + 1, N)] - x[i];
1292  const float p = ceilf(fabsf(d) / rng) * rng * (((d < tol) > 0.f) - ((d > -tol) > 0.f));
1293 
1294  x[i] += p + prev_p;
1295  prev_p += p;
1296  max = fmaxf(x[i], max);
1297  min = fminf(x[i], min);
1298  }
1299 
1300  *mi = min;
1301  *ma = max;
1302 }
1303 
1304 static int calc_channel_uphases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
1305 {
1306  ShowSpectrumContext *s = ctx->priv;
1307  const int h = s->orientation == VERTICAL ? s->h : s->w;
1308  const int ch = jobnr;
1309  float *phases = s->phases[ch];
1310  float min, max, scale;
1311  int y;
1312 
1313  for (y = 0; y < h; y++)
1314  phases[y] = PHASE(y, ch);
1315  unwrap(phases, h, M_PI, &min, &max);
1316  scale = 1.f / (max - min + FLT_MIN);
1317  for (y = 0; y < h; y++)
1318  phases[y] = fabsf((phases[y] - min) * scale);
1319 
1320  return 0;
1321 }
1322 
1324 {
1325  const double w = s->win_scale * (s->scale == LOG ? s->win_scale : 1);
1326  int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
1327  const float f = s->gain * w;
1328 
1329  for (ch = 0; ch < s->nb_display_channels; ch++) {
1330  float *magnitudes = s->magnitudes[ch];
1331 
1332  for (y = 0; y < h; y++)
1333  magnitudes[y] += MAGNITUDE(y, ch) * f;
1334  }
1335 }
1336 
1338 {
1339  int ch, y, h = s->orientation == VERTICAL ? s->h : s->w;
1340 
1341  for (ch = 0; ch < s->nb_display_channels; ch++) {
1342  float *magnitudes = s->magnitudes[ch];
1343 
1344  for (y = 0; y < h; y++)
1345  magnitudes[y] *= scale;
1346  }
1347 }
1348 
1350 {
1351  int y;
1352 
1353  for (y = 0; y < size; y++) {
1354  s->combine_buffer[3 * y ] = 0;
1355  s->combine_buffer[3 * y + 1] = 127.5;
1356  s->combine_buffer[3 * y + 2] = 127.5;
1357  }
1358 }
1359 
1361 {
1362  AVFilterContext *ctx = inlink->dst;
1363  AVFilterLink *outlink = ctx->outputs[0];
1364  ShowSpectrumContext *s = ctx->priv;
1365  AVFrame *outpicref = s->outpicref;
1366  int ret, plane, x, y, z = s->orientation == VERTICAL ? s->h : s->w;
1367 
1368  /* fill a new spectrum column */
1369  /* initialize buffer for combining to black */
1370  clear_combine_buffer(s, z);
1371 
1372  ff_filter_execute(ctx, s->plot_channel, NULL, NULL, s->nb_display_channels);
1373 
1374  for (y = 0; y < z * 3; y++) {
1375  for (x = 0; x < s->nb_display_channels; x++) {
1376  s->combine_buffer[y] += s->color_buffer[x][y];
1377  }
1378  }
1379 
1380  av_frame_make_writable(s->outpicref);
1381  /* copy to output */
1382  if (s->orientation == VERTICAL) {
1383  if (s->sliding == SCROLL) {
1384  for (plane = 0; plane < 3; plane++) {
1385  for (y = 0; y < s->h; y++) {
1386  uint8_t *p = outpicref->data[plane] + s->start_x +
1387  (y + s->start_y) * outpicref->linesize[plane];
1388  memmove(p, p + 1, s->w - 1);
1389  }
1390  }
1391  s->xpos = s->w - 1;
1392  } else if (s->sliding == RSCROLL) {
1393  for (plane = 0; plane < 3; plane++) {
1394  for (y = 0; y < s->h; y++) {
1395  uint8_t *p = outpicref->data[plane] + s->start_x +
1396  (y + s->start_y) * outpicref->linesize[plane];
1397  memmove(p + 1, p, s->w - 1);
1398  }
1399  }
1400  s->xpos = 0;
1401  }
1402  for (plane = 0; plane < 3; plane++) {
1403  uint8_t *p = outpicref->data[plane] + s->start_x +
1404  (outlink->h - 1 - s->start_y) * outpicref->linesize[plane] +
1405  s->xpos;
1406  for (y = 0; y < s->h; y++) {
1407  *p = lrintf(av_clipf(s->combine_buffer[3 * y + plane], 0, 255));
1408  p -= outpicref->linesize[plane];
1409  }
1410  }
1411  } else {
1412  if (s->sliding == SCROLL) {
1413  for (plane = 0; plane < 3; plane++) {
1414  for (y = 1; y < s->h; y++) {
1415  memmove(outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x,
1416  outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x,
1417  s->w);
1418  }
1419  }
1420  s->xpos = s->h - 1;
1421  } else if (s->sliding == RSCROLL) {
1422  for (plane = 0; plane < 3; plane++) {
1423  for (y = s->h - 1; y >= 1; y--) {
1424  memmove(outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x,
1425  outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x,
1426  s->w);
1427  }
1428  }
1429  s->xpos = 0;
1430  }
1431  for (plane = 0; plane < 3; plane++) {
1432  uint8_t *p = outpicref->data[plane] + s->start_x +
1433  (s->xpos + s->start_y) * outpicref->linesize[plane];
1434  for (x = 0; x < s->w; x++) {
1435  *p = lrintf(av_clipf(s->combine_buffer[3 * x + plane], 0, 255));
1436  p++;
1437  }
1438  }
1439  }
1440 
1441  if (s->sliding != FULLFRAME || s->xpos == 0)
1442  outpicref->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base);
1443 
1444  if (s->sliding == LREPLACE) {
1445  s->xpos--;
1446  if (s->orientation == VERTICAL && s->xpos < 0)
1447  s->xpos = s->w - 1;
1448  if (s->orientation == HORIZONTAL && s->xpos < 0)
1449  s->xpos = s->h - 1;
1450  } else {
1451  s->xpos++;
1452  if (s->orientation == VERTICAL && s->xpos >= s->w)
1453  s->xpos = 0;
1454  if (s->orientation == HORIZONTAL && s->xpos >= s->h)
1455  s->xpos = 0;
1456  }
1457 
1458  if (!s->single_pic && (s->sliding != FULLFRAME || s->xpos == 0)) {
1459  if (s->old_pts < outpicref->pts) {
1460  AVFrame *clone;
1461 
1462  if (s->legend) {
1463  char *units = get_time(ctx, insamples->pts /(float)inlink->sample_rate, x);
1464  if (!units)
1465  return AVERROR(ENOMEM);
1466 
1467  if (s->orientation == VERTICAL) {
1468  for (y = 0; y < 10; y++) {
1469  memset(s->outpicref->data[0] + outlink->w / 2 - 4 * s->old_len +
1470  (outlink->h - s->start_y / 2 - 20 + y) * s->outpicref->linesize[0], 0, 10 * s->old_len);
1471  }
1472  drawtext(s->outpicref,
1473  outlink->w / 2 - 4 * strlen(units),
1474  outlink->h - s->start_y / 2 - 20,
1475  units, 0);
1476  } else {
1477  for (y = 0; y < 10 * s->old_len; y++) {
1478  memset(s->outpicref->data[0] + s->start_x / 7 + 20 +
1479  (outlink->h / 2 - 4 * s->old_len + y) * s->outpicref->linesize[0], 0, 10);
1480  }
1481  drawtext(s->outpicref,
1482  s->start_x / 7 + 20,
1483  outlink->h / 2 - 4 * strlen(units),
1484  units, 1);
1485  }
1486  s->old_len = strlen(units);
1487  av_free(units);
1488  }
1489  s->old_pts = outpicref->pts;
1490  clone = av_frame_clone(s->outpicref);
1491  if (!clone)
1492  return AVERROR(ENOMEM);
1493  ret = ff_filter_frame(outlink, clone);
1494  if (ret < 0)
1495  return ret;
1496  return 0;
1497  }
1498  }
1499 
1500  return 1;
1501 }
1502 
1503 #if CONFIG_SHOWSPECTRUM_FILTER
1504 
1505 static int activate(AVFilterContext *ctx)
1506 {
1507  AVFilterLink *inlink = ctx->inputs[0];
1508  AVFilterLink *outlink = ctx->outputs[0];
1509  ShowSpectrumContext *s = ctx->priv;
1510  int ret;
1511 
1513 
1514  if (av_audio_fifo_size(s->fifo) < s->win_size) {
1515  AVFrame *frame = NULL;
1516 
1518  if (ret < 0)
1519  return ret;
1520  if (ret > 0) {
1521  s->pts = frame->pts;
1522  s->consumed = 0;
1523 
1524  av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples);
1525  av_frame_free(&frame);
1526  }
1527  }
1528 
1529  if (s->outpicref && (av_audio_fifo_size(s->fifo) >= s->win_size ||
1531  AVFrame *fin = ff_get_audio_buffer(inlink, s->win_size);
1532  if (!fin)
1533  return AVERROR(ENOMEM);
1534 
1535  fin->pts = s->pts + s->consumed;
1536  s->consumed += s->hop_size;
1537  ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data,
1538  FFMIN(s->win_size, av_audio_fifo_size(s->fifo)));
1539  if (ret < 0) {
1540  av_frame_free(&fin);
1541  return ret;
1542  }
1543 
1544  av_assert0(fin->nb_samples == s->win_size);
1545 
1546  ff_filter_execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
1547 
1548  if (s->data == D_MAGNITUDE)
1549  ff_filter_execute(ctx, calc_channel_magnitudes, NULL, NULL, s->nb_display_channels);
1550 
1551  if (s->data == D_PHASE)
1552  ff_filter_execute(ctx, calc_channel_phases, NULL, NULL, s->nb_display_channels);
1553 
1554  if (s->data == D_UPHASE)
1555  ff_filter_execute(ctx, calc_channel_uphases, NULL, NULL, s->nb_display_channels);
1556 
1558 
1559  av_frame_free(&fin);
1560  av_audio_fifo_drain(s->fifo, s->hop_size);
1561  if (ret <= 0 && !ff_outlink_get_status(inlink))
1562  return ret;
1563  }
1564 
1566  s->sliding == FULLFRAME &&
1567  s->xpos > 0 && s->outpicref) {
1568  int64_t pts;
1569 
1570  if (s->orientation == VERTICAL) {
1571  for (int i = 0; i < outlink->h; i++) {
1572  memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos);
1573  memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos);
1574  memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos);
1575  }
1576  } else {
1577  for (int i = s->xpos; i < outlink->h; i++) {
1578  memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w);
1579  memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w);
1580  memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w);
1581  }
1582  }
1583  s->outpicref->pts += av_rescale_q(s->consumed, inlink->time_base, outlink->time_base);
1584  pts = s->outpicref->pts;
1585  ret = ff_filter_frame(outlink, s->outpicref);
1586  s->outpicref = NULL;
1588  return 0;
1589  }
1590 
1591  FF_FILTER_FORWARD_STATUS(inlink, outlink);
1592  if (av_audio_fifo_size(s->fifo) >= s->win_size ||
1595  ff_filter_set_ready(ctx, 10);
1596  return 0;
1597  }
1598 
1599  if (ff_outlink_frame_wanted(outlink) && av_audio_fifo_size(s->fifo) < s->win_size &&
1603  return 0;
1604  }
1605 
1606  return FFERROR_NOT_READY;
1607 }
1608 
1609 static const AVFilterPad showspectrum_inputs[] = {
1610  {
1611  .name = "default",
1612  .type = AVMEDIA_TYPE_AUDIO,
1613  },
1614 };
1615 
1616 static const AVFilterPad showspectrum_outputs[] = {
1617  {
1618  .name = "default",
1619  .type = AVMEDIA_TYPE_VIDEO,
1620  .config_props = config_output,
1621  },
1622 };
1623 
1624 const AVFilter ff_avf_showspectrum = {
1625  .name = "showspectrum",
1626  .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."),
1627  .uninit = uninit,
1628  .priv_size = sizeof(ShowSpectrumContext),
1629  FILTER_INPUTS(showspectrum_inputs),
1630  FILTER_OUTPUTS(showspectrum_outputs),
1632  .activate = activate,
1633  .priv_class = &showspectrum_class,
1634  .flags = AVFILTER_FLAG_SLICE_THREADS,
1635 };
1636 #endif // CONFIG_SHOWSPECTRUM_FILTER
1637 
1638 #if CONFIG_SHOWSPECTRUMPIC_FILTER
1639 
1640 static const AVOption showspectrumpic_options[] = {
1641  { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "4096x2048"}, 0, 0, FLAGS },
1642  { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "4096x2048"}, 0, 0, FLAGS },
1643  { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, 0, NB_MODES-1, FLAGS, "mode" },
1644  { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
1645  { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
1646  { "color", "set channel coloring", OFFSET(color_mode), AV_OPT_TYPE_INT, {.i64=INTENSITY}, 0, NB_CLMODES-1, FLAGS, "color" },
1647  { "channel", "separate color for each channel", 0, AV_OPT_TYPE_CONST, {.i64=CHANNEL}, 0, 0, FLAGS, "color" },
1648  { "intensity", "intensity based coloring", 0, AV_OPT_TYPE_CONST, {.i64=INTENSITY}, 0, 0, FLAGS, "color" },
1649  { "rainbow", "rainbow based coloring", 0, AV_OPT_TYPE_CONST, {.i64=RAINBOW}, 0, 0, FLAGS, "color" },
1650  { "moreland", "moreland based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MORELAND}, 0, 0, FLAGS, "color" },
1651  { "nebulae", "nebulae based coloring", 0, AV_OPT_TYPE_CONST, {.i64=NEBULAE}, 0, 0, FLAGS, "color" },
1652  { "fire", "fire based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIRE}, 0, 0, FLAGS, "color" },
1653  { "fiery", "fiery based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIERY}, 0, 0, FLAGS, "color" },
1654  { "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" },
1655  { "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" },
1656  { "magma", "magma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MAGMA}, 0, 0, FLAGS, "color" },
1657  { "green", "green based coloring", 0, AV_OPT_TYPE_CONST, {.i64=GREEN}, 0, 0, FLAGS, "color" },
1658  { "viridis", "viridis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=VIRIDIS}, 0, 0, FLAGS, "color" },
1659  { "plasma", "plasma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=PLASMA}, 0, 0, FLAGS, "color" },
1660  { "cividis", "cividis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=CIVIDIS}, 0, 0, FLAGS, "color" },
1661  { "terrain", "terrain based coloring", 0, AV_OPT_TYPE_CONST, {.i64=TERRAIN}, 0, 0, FLAGS, "color" },
1662  { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=LOG}, 0, NB_SCALES-1, FLAGS, "scale" },
1663  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
1664  { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
1665  { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
1666  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
1667  { "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" },
1668  { "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" },
1669  { "fscale", "set frequency scale", OFFSET(fscale), AV_OPT_TYPE_INT, {.i64=F_LINEAR}, 0, NB_FSCALES-1, FLAGS, "fscale" },
1670  { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=F_LINEAR}, 0, 0, FLAGS, "fscale" },
1671  { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=F_LOG}, 0, 0, FLAGS, "fscale" },
1672  { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
1673  WIN_FUNC_OPTION("win_func", OFFSET(win_func), FLAGS, WFUNC_HANNING),
1674  { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" },
1675  { "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" },
1676  { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" },
1677  { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS },
1678  { "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
1679  { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS },
1680  { "start", "start frequency", OFFSET(start), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
1681  { "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS },
1682  { "drange", "set dynamic range in dBFS", OFFSET(drange), AV_OPT_TYPE_FLOAT, {.dbl = 120}, 10, 200, FLAGS },
1683  { "limit", "set upper limit in dBFS", OFFSET(limit), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -100, 100, FLAGS },
1684  { NULL }
1685 };
1686 
1687 AVFILTER_DEFINE_CLASS(showspectrumpic);
1688 
1689 static int showspectrumpic_request_frame(AVFilterLink *outlink)
1690 {
1691  AVFilterContext *ctx = outlink->src;
1692  ShowSpectrumContext *s = ctx->priv;
1693  AVFilterLink *inlink = ctx->inputs[0];
1694  int ret, samples;
1695 
1697  samples = av_audio_fifo_size(s->fifo);
1698  if (ret == AVERROR_EOF && s->outpicref && samples > 0) {
1699  int consumed = 0;
1700  int x = 0, sz = s->orientation == VERTICAL ? s->w : s->h;
1701  int ch, spf, spb;
1702  AVFrame *fin;
1703 
1704  spf = s->win_size * (samples / ((s->win_size * sz) * ceil(samples / (float)(s->win_size * sz))));
1705  spf = FFMAX(1, spf);
1706 
1707  spb = (samples / (spf * sz)) * spf;
1708 
1709  fin = ff_get_audio_buffer(inlink, s->win_size);
1710  if (!fin)
1711  return AVERROR(ENOMEM);
1712 
1713  while (x < sz) {
1714  ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size);
1715  if (ret < 0) {
1716  av_frame_free(&fin);
1717  return ret;
1718  }
1719 
1720  av_audio_fifo_drain(s->fifo, spf);
1721 
1722  if (ret < s->win_size) {
1723  for (ch = 0; ch < s->nb_display_channels; ch++) {
1724  memset(fin->extended_data[ch] + ret * sizeof(float), 0,
1725  (s->win_size - ret) * sizeof(float));
1726  }
1727  }
1728 
1729  ff_filter_execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels);
1731 
1732  consumed += spf;
1733  if (consumed >= spb) {
1734  int h = s->orientation == VERTICAL ? s->h : s->w;
1735 
1736  scale_magnitudes(s, 1.f / (consumed / spf));
1738  consumed = 0;
1739  x++;
1740  for (ch = 0; ch < s->nb_display_channels; ch++)
1741  memset(s->magnitudes[ch], 0, h * sizeof(float));
1742  }
1743  }
1744 
1745  av_frame_free(&fin);
1746  s->outpicref->pts = 0;
1747 
1748  if (s->legend)
1750 
1751  ret = ff_filter_frame(outlink, s->outpicref);
1752  s->outpicref = NULL;
1753  }
1754 
1755  return ret;
1756 }
1757 
1758 static int showspectrumpic_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
1759 {
1760  AVFilterContext *ctx = inlink->dst;
1761  ShowSpectrumContext *s = ctx->priv;
1762  int ret;
1763 
1764  ret = av_audio_fifo_write(s->fifo, (void **)insamples->extended_data, insamples->nb_samples);
1765  av_frame_free(&insamples);
1766  return ret;
1767 }
1768 
1769 static const AVFilterPad showspectrumpic_inputs[] = {
1770  {
1771  .name = "default",
1772  .type = AVMEDIA_TYPE_AUDIO,
1773  .filter_frame = showspectrumpic_filter_frame,
1774  },
1775 };
1776 
1777 static const AVFilterPad showspectrumpic_outputs[] = {
1778  {
1779  .name = "default",
1780  .type = AVMEDIA_TYPE_VIDEO,
1781  .config_props = config_output,
1782  .request_frame = showspectrumpic_request_frame,
1783  },
1784 };
1785 
1787  .name = "showspectrumpic",
1788  .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output single picture."),
1789  .uninit = uninit,
1790  .priv_size = sizeof(ShowSpectrumContext),
1791  FILTER_INPUTS(showspectrumpic_inputs),
1792  FILTER_OUTPUTS(showspectrumpic_outputs),
1794  .priv_class = &showspectrumpic_class,
1795  .flags = AVFILTER_FLAG_SLICE_THREADS,
1796 };
1797 
1798 #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:98
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:88
AV_SAMPLE_FMT_FLTP
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
ShowSpectrumContext::win_size
int win_size
Definition: avf_showspectrum.c:89
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:566
plot_channel_lin
static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:953
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
SCROLL
@ SCROLL
Definition: avf_showspectrum.c:53
av_clip
#define av_clip
Definition: common.h:96
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: avf_showspectrum.c:290
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:75
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:381
ShowSpectrumContext::frame_rate
AVRational frame_rate
Definition: avf_showspectrum.c:61
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:1018
log2f
#define log2f(x)
Definition: libm.h:409
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:568
ff_channel_layouts_ref
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:550
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:76
ShowSpectrumContext::mode
int mode
channel display mode
Definition: avf_showspectrum.c:68
ShowSpectrumContext::overlap
float overlap
Definition: avf_showspectrum.c:92
AVTXContext
Definition: tx_priv.h:110
ShowSpectrumContext::gain
float gain
Definition: avf_showspectrum.c:93
floorf
static __device__ float floorf(float a)
Definition: cuda_runtime.h:172
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:109
SQRT
@ SQRT
Definition: avf_showspectrum.c:51
PHASE
#define PHASE(y, ch)
Definition: avf_showspectrum.c:1252
ShowSpectrumContext::old_len
int old_len
Definition: avf_showspectrum.c:101
ColorTable::y
float y
Definition: avf_showspectrum.c:175
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:317
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:58
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:424
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:597
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:1254
AVOption
AVOption.
Definition: opt.h:247
clear_combine_buffer
static void clear_combine_buffer(ShowSpectrumContext *s, int size)
Definition: avf_showspectrum.c:1349
b
#define b
Definition: input.c:40
GREEN
@ GREEN
Definition: avf_showspectrum.c:52
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:168
config_output
static int config_output(AVFilterLink *outlink)
Definition: avf_showspectrum.c:1007
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:420
D_UPHASE
@ D_UPHASE
Definition: avf_showspectrum.c:49
calc_channel_uphases
static int calc_channel_uphases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:1304
ShowSpectrumContext::ifft
AVTXContext ** ifft
Inverse Fast Fourier Transform context.
Definition: avf_showspectrum.c:78
ShowSpectrumContext::hop_size
int hop_size
Definition: avf_showspectrum.c:95
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
float.h
AVComplexFloat
Definition: tx.h:27
WIN_FUNC_OPTION
#define WIN_FUNC_OPTION(win_func_opt_name, win_func_offset, flag, default_window_func)
Definition: window_func.h:36
ShowSpectrumContext::saturation
float saturation
color saturation multiplier
Definition: avf_showspectrum.c:72
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:169
COOL
@ COOL
Definition: avf_showspectrum.c:52
ShowSpectrumContext::channel_width
int channel_width
Definition: avf_showspectrum.c:65
OFFSET
#define OFFSET(x)
Definition: avf_showspectrum.c:110
video.h
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:1323
ceilf
static __device__ float ceilf(float a)
Definition: cuda_runtime.h:175
FIFTHRT
@ FIFTHRT
Definition: avf_showspectrum.c:51
scale_magnitudes
static void scale_magnitudes(ShowSpectrumContext *s, float scale)
Definition: avf_showspectrum.c:1337
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:228
get_value
static float get_value(AVFilterContext *ctx, int ch, int y)
Definition: avf_showspectrum.c:929
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:338
ShowSpectrumContext::magnitudes
float ** magnitudes
Definition: avf_showspectrum.c:86
MORELAND
@ MORELAND
Definition: avf_showspectrum.c:52
ShowSpectrumContext::fifo
AVAudioFifo * fifo
Definition: avf_showspectrum.c:98
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:88
ShowSpectrumContext::outpicref
AVFrame * outpicref
Definition: avf_showspectrum.c:62
ShowSpectrumContext::rotation
float rotation
color rotation
Definition: avf_showspectrum.c:73
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:1417
ShowSpectrumContext::fft_scratch
AVComplexFloat ** fft_scratch
scratch buffers
Definition: avf_showspectrum.c:84
calc_channel_phases
static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:1269
ShowSpectrumContext::fft_in
AVComplexFloat ** fft_in
input FFT coeffs
Definition: avf_showspectrum.c:82
AVAudioFifo
Context for an Audio FIFO Buffer.
Definition: audio_fifo.c:34
ColorMode
ColorMode
Definition: avf_showspectrum.c:52
cosf
#define cosf(x)
Definition: libm.h:78
ShowSpectrumContext::color_mode
int color_mode
display color scheme
Definition: avf_showspectrum.c:69
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:97
ShowSpectrumContext::window_func_lut
float * window_func_lut
Window function LUT.
Definition: avf_showspectrum.c:85
FULLFRAME
@ FULLFRAME
Definition: avf_showspectrum.c:53
unwrap
static void unwrap(float *x, int N, float tol, float *mi, float *ma)
Definition: avf_showspectrum.c:1283
NB_FSCALES
@ NB_FSCALES
Definition: avf_showspectrum.c:50
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1388
pts
static int64_t pts
Definition: transcode_aac.c:653
RAINBOW
@ RAINBOW
Definition: avf_showspectrum.c:52
ShowSpectrumContext::buf_size
int buf_size
Definition: avf_showspectrum.c:90
fabsf
static __device__ float fabsf(float a)
Definition: cuda_runtime.h:181
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
a1
#define a1
Definition: regdef.h:47
D_PHASE
@ D_PHASE
Definition: avf_showspectrum.c:49
FIERY
@ FIERY
Definition: avf_showspectrum.c:52
INTENSITY
@ INTENSITY
Definition: avf_showspectrum.c:52
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
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
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
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:49
ff_inlink_request_frame
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1534
s
#define s(width, name)
Definition: cbs_vp9.c:257
get_scale
static float get_scale(AVFilterContext *ctx, int scale, float a)
Definition: avf_showspectrum.c:660
Orientation
Orientation
Definition: avf_showspectrum.c:54
FRUIT
@ FRUIT
Definition: avf_showspectrum.c:52
mi
#define mi
Definition: vf_colormatrix.c:108
CHANNEL
@ CHANNEL
Definition: avf_showspectrum.c:52
g
const char * g
Definition: vf_curves.c:117
VIRIDIS
@ VIRIDIS
Definition: avf_showspectrum.c:52
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:555
draw_legend
static int draw_legend(AVFilterContext *ctx, int samples)
Definition: avf_showspectrum.c:729
fminf
float fminf(float, float)
ShowSpectrumContext::h
int h
Definition: avf_showspectrum.c:58
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
filters.h
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:296
plot_channel_log
static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:976
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:77
ctx
AVFormatContext * ctx
Definition: movenc.c:48
exp2f
#define exp2f(x)
Definition: libm.h:293
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:422
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
inv_log_scale
static float inv_log_scale(float bin, float bmin, float bmax, float min, float max)
Definition: avf_showspectrum.c:648
color_range
color_range
Definition: vf_selectivecolor.c:44
VERTICAL
@ VERTICAL
Definition: avf_showspectrum.c:54
f
#define f(width, name)
Definition: cbs_vp9.c:255
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
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:52
arg
const char * arg
Definition: jacosubdec.c:67
COMBINED
@ COMBINED
Definition: avf_showspectrum.c:48
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:91
ShowSpectrumContext::combine_buffer
float * combine_buffer
color combining buffer (3 * h items)
Definition: avf_showspectrum.c:96
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
ShowSpectrumContext::dmax
float dmax
Definition: avf_showspectrum.c:106
NULL
#define NULL
Definition: coverity.c:32
NB_SLIDES
@ NB_SLIDES
Definition: avf_showspectrum.c:53
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
ShowSpectrumContext::fft_data
AVComplexFloat ** fft_data
bins holder for each (displayed) channels
Definition: avf_showspectrum.c:83
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:52
parseutils.h
ShowSpectrumContext::start
int start
Definition: avf_showspectrum.c:74
get_time
static char * get_time(AVFilterContext *ctx, float seconds, int x)
Definition: avf_showspectrum.c:612
MAGNITUDE
#define MAGNITUDE(y, ch)
Definition: avf_showspectrum.c:1251
av_cpu_max_align
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
Definition: cpu.c:250
generate_window_func
static void generate_window_func(float *lut, int N, int win_func, float *overlap)
Definition: window_func.h:60
SEPARATE
@ SEPARATE
Definition: avf_showspectrum.c:48
WFUNC_HANNING
@ WFUNC_HANNING
Definition: window_func.h:28
sinf
#define sinf(x)
Definition: libm.h:419
log_scale
static float log_scale(const float bin, const float bmin, const float bmax, const float min, const float max)
Definition: avf_showspectrum.c:627
ShowSpectrumContext::limit
float limit
Definition: avf_showspectrum.c:105
get_iscale
static float get_iscale(AVFilterContext *ctx, int scale, float a)
Definition: avf_showspectrum.c:695
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:60
ff_inlink_queued_frames
size_t ff_inlink_queued_frames(AVFilterLink *link)
Get the number of frames available on the link.
Definition: avfilter.c:1386
for
for(j=16;j >0;--j)
Definition: h264pred_template.c:469
ShowSpectrumContext::pts
int64_t pts
Definition: avf_showspectrum.c:99
ShowSpectrumContext::consumed
int consumed
Definition: avf_showspectrum.c:94
ShowSpectrumContext::dmin
float dmin
Definition: avf_showspectrum.c:106
ShowSpectrumContext::single_pic
int single_pic
Definition: avf_showspectrum.c:102
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:117
powf
#define powf(x, y)
Definition: libm.h:50
RSCROLL
@ RSCROLL
Definition: avf_showspectrum.c:53
D_MAGNITUDE
@ D_MAGNITUDE
Definition: avf_showspectrum.c:49
cpu.h
fmaxf
float fmaxf(float, float)
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:52
LREPLACE
@ LREPLACE
Definition: avf_showspectrum.c:53
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:175
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:516
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:63
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:213
ff_avf_showspectrumpic
const AVFilter ff_avf_showspectrumpic
internal.h
ShowSpectrumContext::scale
int scale
Definition: avf_showspectrum.c:70
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:1360
ShowSpectrumContext::rate_str
char * rate_str
Definition: avf_showspectrum.c:59
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:181
ShowSpectrumContext::old_pts
int64_t old_pts
Definition: avf_showspectrum.c:100
AVFrame::nb_samples
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:397
ShowSpectrumContext::phases
float ** phases
Definition: avf_showspectrum.c:87
lrintf
#define lrintf(x)
Definition: libm_mips.h:72
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
FLAGS
#define FLAGS
Definition: avf_showspectrum.c:111
ShowSpectrumContext::channel_height
int channel_height
Definition: avf_showspectrum.c:66
ShowSpectrumContext
Definition: avf_showspectrum.c:56
AVFrame::extended_data
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:378
bin_pos
static float bin_pos(const int bin, const int num_bins, const float min, const float max)
Definition: avf_showspectrum.c:655
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:52
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:271
limit
static double limit(double x)
Definition: vf_pseudocolor.c:128
HORIZONTAL
@ HORIZONTAL
Definition: avf_showspectrum.c:54
F_LINEAR
@ F_LINEAR
Definition: avf_showspectrum.c:50
AVFilter
Filter definition.
Definition: avfilter.h:165
ret
ret
Definition: filter_design.txt:187
NB_ORIENTATIONS
@ NB_ORIENTATIONS
Definition: avf_showspectrum.c:54
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:506
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(showspectrum)
pos
unsigned int pos
Definition: spdifenc.c:412
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:419
ShowSpectrumContext::legend
int legend
Definition: avf_showspectrum.c:103
run_channel_fft
static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: avf_showspectrum.c:372
ShowSpectrumContext::fscale
int fscale
Definition: avf_showspectrum.c:71
L
#define L(x)
Definition: vp56_arith.h:36
window_func.h
NEBULAE
@ NEBULAE
Definition: avf_showspectrum.c:52
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: avf_showspectrum.c:341
ShowSpectrumContext::start_x
int start_x
Definition: avf_showspectrum.c:104
ShowSpectrumContext::stop
int stop
zoom mode
Definition: avf_showspectrum.c:74
ff_all_samplerates
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:510
ShowSpectrumContext::orientation
int orientation
Definition: avf_showspectrum.c:64
channel_layout.h
mode
mode
Definition: ebur128.h:83
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
LOG
@ LOG
Definition: avf_showspectrum.c:51
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:81
avfilter.h
FOURTHRT
@ FOURTHRT
Definition: avf_showspectrum.c:51
NB_MODES
@ NB_MODES
Definition: avf_showspectrum.c:48
cm
#define cm
Definition: dvbsubdec.c:38
F_LOG
@ F_LOG
Definition: avf_showspectrum.c:50
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
av_mul_q
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
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:1557
AVFilterContext
An instance of a filter.
Definition: avfilter.h:402
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:121
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ColorTable::v
float v
Definition: avf_showspectrum.c:175
LINEAR
@ LINEAR
Definition: avf_showspectrum.c:51
audio.h
ShowSpectrumContext::start_y
int start_y
Definition: avf_showspectrum.c:104
M_LN10
#define M_LN10
Definition: mathematics.h:43
AVFilterFormatsConfig::formats
AVFilterFormats * formats
List of supported formats (pixel or sample).
Definition: avfilter.h:506
DisplayScale
DisplayScale
Definition: avf_ahistogram.c:31
ShowSpectrumContext::itx_fn
av_tx_fn itx_fn
Definition: avf_showspectrum.c:80
ShowSpectrumContext::tx_fn
av_tx_fn tx_fn
Definition: avf_showspectrum.c:79
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:51
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
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:67
d
d
Definition: ffmpeg_filter.c:153
ColorTable::u
float u
Definition: avf_showspectrum.c:175
ShowSpectrumContext::drange
float drange
Definition: avf_showspectrum.c:105
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, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:362
CBRT
@ CBRT
Definition: avf_showspectrum.c:51
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
ma
#define ma
Definition: vf_colormatrix.c:100
h
h
Definition: vp9dsp_template.c:2038
MAGMA
@ MAGMA
Definition: avf_showspectrum.c:52
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:113
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:143
ColorTable
Definition: avf_showspectrum.c:174
get_hz
static float get_hz(const float bin, const float bmax, const float min, const float max, int fscale)
Definition: avf_showspectrum.c:634
int
int
Definition: ffmpeg_filter.c:153
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:53
FIRE
@ FIRE
Definition: avf_showspectrum.c:52
drawtext
static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o)
Definition: avf_showspectrum.c:472
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:211
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:107