29#include "config_components.h"
55enum ColorMode {
CHANNEL,
INTENSITY,
RAINBOW,
MORELAND,
NEBULAE,
FIRE,
FIERY,
FRUIT,
COOL,
MAGMA,
GREEN,
VIRIDIS,
PLASMA,
CIVIDIS,
TERRAIN,
NB_CLMODES };
59#define DEFAULT_LENGTH 300
123#define OFFSET(x) offsetof(ShowSpectrumContext, x)
124#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
193 { 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 },
194 { 0.30, .18572281794568020, .1772436246393981, .17475554840414750 },
195 { 0.60, .28184980583656130, -.1593064119945782, .47132074554608920 },
196 { 0.73, .65830621175547810, -.3716070802232764, .24352759331252930 },
197 { 0.78, .76318535758242900, -.4307467689263783, .16866496622310430 },
198 { 0.91, .95336363636363640, -.2045454545454546, .03313636363636363 },
202 { 0.13, 44/256., (189-128)/256., (138-128)/256. },
203 { 0.25, 29/256., (186-128)/256., (119-128)/256. },
204 { 0.38, 119/256., (194-128)/256., (53-128)/256. },
205 { 0.60, 111/256., (73-128)/256., (59-128)/256. },
206 { 0.73, 205/256., (19-128)/256., (149-128)/256. },
207 { 0.86, 135/256., (83-128)/256., (200-128)/256. },
208 { 1, 73/256., (95-128)/256., (225-128)/256. }},
210 { 0, 44/256., (181-128)/256., (112-128)/256. },
211 { 0.13, 126/256., (177-128)/256., (106-128)/256. },
212 { 0.25, 164/256., (163-128)/256., (109-128)/256. },
213 { 0.38, 200/256., (140-128)/256., (120-128)/256. },
214 { 0.60, 201/256., (117-128)/256., (141-128)/256. },
215 { 0.73, 177/256., (103-128)/256., (165-128)/256. },
216 { 0.86, 136/256., (100-128)/256., (183-128)/256. },
217 { 1, 68/256., (117-128)/256., (203-128)/256. }},
219 { 0, 10/256., (134-128)/256., (132-128)/256. },
220 { 0.23, 21/256., (137-128)/256., (130-128)/256. },
221 { 0.45, 35/256., (134-128)/256., (134-128)/256. },
222 { 0.57, 51/256., (130-128)/256., (139-128)/256. },
223 { 0.67, 104/256., (116-128)/256., (162-128)/256. },
224 { 0.77, 120/256., (105-128)/256., (188-128)/256. },
225 { 0.87, 140/256., (105-128)/256., (188-128)/256. },
229 { 0.23, 44/256., (132-128)/256., (127-128)/256. },
230 { 0.45, 62/256., (116-128)/256., (140-128)/256. },
231 { 0.57, 75/256., (105-128)/256., (152-128)/256. },
232 { 0.67, 95/256., (91-128)/256., (166-128)/256. },
233 { 0.77, 126/256., (74-128)/256., (172-128)/256. },
234 { 0.87, 164/256., (73-128)/256., (162-128)/256. },
238 { 0.23, 36/256., (116-128)/256., (163-128)/256. },
239 { 0.45, 52/256., (102-128)/256., (200-128)/256. },
240 { 0.57, 116/256., (84-128)/256., (196-128)/256. },
241 { 0.67, 157/256., (67-128)/256., (181-128)/256. },
242 { 0.77, 193/256., (40-128)/256., (155-128)/256. },
243 { 0.87, 221/256., (101-128)/256., (134-128)/256. },
247 { 0.20, 29/256., (136-128)/256., (119-128)/256. },
248 { 0.30, 60/256., (119-128)/256., (90-128)/256. },
249 { 0.40, 85/256., (91-128)/256., (85-128)/256. },
250 { 0.50, 116/256., (70-128)/256., (105-128)/256. },
251 { 0.60, 151/256., (50-128)/256., (146-128)/256. },
252 { 0.70, 191/256., (63-128)/256., (178-128)/256. },
253 { 1, 98/256., (80-128)/256., (221-128)/256. }},
260 { 0.10, 23/256., (175-128)/256., (120-128)/256. },
261 { 0.23, 43/256., (158-128)/256., (144-128)/256. },
262 { 0.35, 85/256., (138-128)/256., (179-128)/256. },
263 { 0.48, 96/256., (128-128)/256., (189-128)/256. },
264 { 0.64, 128/256., (103-128)/256., (214-128)/256. },
265 { 0.92, 205/256., (80-128)/256., (152-128)/256. },
273 { 0.10, 0x39/255., (0x9D -128)/255., (0x8F -128)/255. },
274 { 0.23, 0x5C/255., (0x9A -128)/255., (0x68 -128)/255. },
275 { 0.35, 0x69/255., (0x93 -128)/255., (0x57 -128)/255. },
276 { 0.48, 0x76/255., (0x88 -128)/255., (0x4B -128)/255. },
277 { 0.64, 0x8A/255., (0x72 -128)/255., (0x4F -128)/255. },
278 { 0.80, 0xA3/255., (0x50 -128)/255., (0x66 -128)/255. },
279 { 1, 0xCC/255., (0x2F -128)/255., (0x87 -128)/255. }},
282 { 0.10, 0x27/255., (0xC2 -128)/255., (0x82 -128)/255. },
283 { 0.58, 0x5B/255., (0x9A -128)/255., (0xAE -128)/255. },
284 { 0.70, 0x89/255., (0x44 -128)/255., (0xAB -128)/255. },
285 { 0.80, 0xB4/255., (0x2B -128)/255., (0x9E -128)/255. },
286 { 0.91, 0xD2/255., (0x38 -128)/255., (0x92 -128)/255. },
290 { 0.20, 0x28/255., (0x98 -128)/255., (0x6F -128)/255. },
291 { 0.50, 0x48/255., (0x95 -128)/255., (0x74 -128)/255. },
292 { 0.63, 0x69/255., (0x84 -128)/255., (0x7F -128)/255. },
293 { 0.76, 0x89/255., (0x75 -128)/255., (0x84 -128)/255. },
294 { 0.90, 0xCE/255., (0x35 -128)/255., (0x95 -128)/255. },
299 { 0.60, 1, -.5, -.5 },
300 { 0.85, 1, -.5, .5 },
311 for (
i = 0;
i <
s->nb_display_channels;
i++)
316 for (
i = 0;
i <
s->nb_display_channels;
i++)
321 for (
i = 0;
i <
s->nb_display_channels;
i++)
326 for (
i = 0;
i <
s->nb_display_channels;
i++)
330 if (
s->fft_scratch) {
331 for (
i = 0;
i <
s->nb_display_channels;
i++)
335 if (
s->color_buffer) {
336 for (
i = 0;
i <
s->nb_display_channels;
i++)
342 for (
i = 0;
i <
s->nb_display_channels;
i++)
349 for (
i = 0;
i <
s->nb_display_channels;
i++)
354 while (
s->nb_frames > 0) {
388 const float *window_func_lut =
s->window_func_lut;
390 const int ch = jobnr;
395 float *in_frame = (
float *)
s->in_frame->extended_data[ch];
397 memmove(in_frame, in_frame +
s->hop_size, (
s->fft_size -
s->hop_size) *
sizeof(
float));
398 memcpy(in_frame +
s->fft_size -
s->hop_size, p, fin->
nb_samples *
sizeof(
float));
401 in_frame[
i +
s->fft_size -
s->hop_size] = 0.f;
404 float theta, phi, psi,
a,
b,
S,
c;
410 int M =
s->win_size / 2;
412 for (n = 0; n <
s->win_size; n++) {
413 s->fft_data[ch][n].re = in_frame[n] * window_func_lut[n];
414 s->fft_data[ch][n].im = 0;
420 for (
int n = 0; n <
M; n++) {
421 h[n].re =
cosf(n * n / 2.f * phi);
422 h[n].im =
sinf(n * n / 2.f * phi);
425 for (
int n =
M; n <
L; n++) {
430 for (
int n =
L -
N; n <
L; n++) {
431 h[n].re =
cosf((
L - n) * (
L - n) / 2.f * phi);
432 h[n].im =
sinf((
L - n) * (
L - n) / 2.f * phi);
435 for (
int n =
N; n <
L; n++) {
440 for (
int n = 0; n <
N; n++) {
441 psi = n * theta + n * n / 2.f * phi;
444 a =
c *
g[n].re -
S *
g[n].im;
445 b =
S *
g[n].re +
c *
g[n].im;
450 memcpy(
f,
h,
s->buf_size *
sizeof(*
f));
453 memcpy(
f,
g,
s->buf_size *
sizeof(*
f));
456 for (
int n = 0; n <
L; n++) {
459 a =
c *
h[n].re -
S *
h[n].im;
460 b =
S *
h[n].re +
c *
h[n].im;
466 memcpy(
f,
g,
s->buf_size *
sizeof(*
f));
469 for (
int k = 0; k <
M; k++) {
470 psi = k * k / 2.f * phi;
473 a =
c *
g[k].re -
S *
g[k].im;
474 b =
S *
g[k].re +
c *
g[k].im;
475 s->fft_data[ch][k].re =
a;
476 s->fft_data[ch][k].im =
b;
479 for (n = 0; n <
s->win_size; n++) {
480 s->fft_in[ch][n].re = in_frame[n] * window_func_lut[n];
481 s->fft_in[ch][n].im = 0;
498 for (
int i = 0; txt[
i];
i++) {
502 for (char_y = font_height - 1; char_y >= 0; char_y--) {
503 uint8_t *p = pic->
data[0] + (y +
i * 10) * pic->
linesize[0] + x;
505 if (font[txt[
i] * font_height + font_height - 1 - char_y] &
mask)
506 p[char_y] = ~p[char_y];
512 for (char_y = 0; char_y < font_height; char_y++) {
514 if (font[txt[
i] * font_height + char_y] &
mask)
523 for (
int i = 0; txt[
i] && pic->
data[3];
i++) {
527 for (char_y = font_height - 1; char_y >= 0; char_y--) {
528 uint8_t *p = pic->
data[3] + (y +
i * 10) * pic->
linesize[3] + x;
530 for (
int k = 0; k < 8; k++)
537 for (char_y = 0; char_y < font_height; char_y++) {
547 float *yf,
float *uf,
float *
vf)
552 *yf = 256.0f /
s->nb_display_channels;
553 switch (
s->color_mode) {
592 if (
s->nb_display_channels > 1) {
593 *uf *= 0.5f *
sinf((2 *
M_PI * ch) /
s->nb_display_channels +
M_PI *
s->rotation);
594 *
vf *= 0.5f *
cosf((2 *
M_PI * ch) /
s->nb_display_channels +
M_PI *
s->rotation);
604 *uf *=
s->saturation;
605 *
vf *=
s->saturation;
609 float yf,
float uf,
float vf,
612 const float af =
s->opacity_factor * 255.f;
615 const int cm =
s->color_mode;
635 float lerpfrac = (
a - start) / (end - start);
662 else if (log10(seconds) > 6)
664 else if (log10(seconds) > 3)
672 const float bmin,
const float bmax,
673 const float min,
const float max)
678static float get_hz(
const float bin,
const float bmax,
679 const float min,
const float max,
693 float bmin,
float bmax,
699static float bin_pos(
const int bin,
const int num_bins,
const float min,
const float max)
707 const float dmin =
s->dmin;
708 const float dmax =
s->dmax;
712 a = (
a - dmin) / (dmax - dmin);
730 a = (
s->drange -
s->limit +
log10f(
a) * 20.f) /
s->drange;
742 const float dmin =
s->dmin;
743 const float dmax =
s->dmax;
768 a =
a * (dmax - dmin) + dmin;
778 int ch, y, x = 0, sz =
s->orientation ==
VERTICAL ?
s->w :
s->h;
780 float spp = samples / (
float)sz;
783 char chlayout_str[128];
791 drawtext(
s->outpicref, 2, outlink->
h - 10,
"CREATED BY LIBAVFILTER", 0);
792 drawtext(
s->outpicref, outlink->
w - 2 - strlen(text) * 10, outlink->
h - 10, text, 0);
795 text =
av_asprintf(
"Zoom: %d Hz - %d Hz",
s->start,
s->stop);
798 drawtext(
s->outpicref, outlink->
w - 2 - strlen(text) * 10, 3, text, 0);
802 dst =
s->outpicref->data[0] + (
s->start_y - 1) *
s->outpicref->linesize[0] +
s->start_x - 1;
803 for (x = 0; x <
s->w + 1; x++)
805 dst =
s->outpicref->data[0] + (
s->start_y +
s->h) *
s->outpicref->linesize[0] +
s->start_x - 1;
806 for (x = 0; x <
s->w + 1; x++)
808 for (y = 0; y <
s->h + 2; y++) {
809 dst =
s->outpicref->data[0] + (y +
s->start_y - 1) *
s->outpicref->linesize[0];
810 dst[
s->start_x - 1] = 200;
811 dst[
s->start_x +
s->w] = 200;
814 int h =
s->mode ==
SEPARATE ?
s->h /
s->nb_display_channels :
s->h;
815 int hh =
s->mode ==
SEPARATE ? -(
s->h %
s->nb_display_channels) + 1 : 1;
816 for (ch = 0; ch < (
s->mode ==
SEPARATE ?
s->nb_display_channels : 1); ch++) {
817 for (y = 0; y <
h; y += 20) {
818 dst =
s->outpicref->data[0] + (
s->start_y +
h * (ch + 1) - y - hh) *
s->outpicref->linesize[0];
819 dst[
s->start_x - 2] = 200;
820 dst[
s->start_x +
s->w + 1] = 200;
822 for (y = 0; y <
h; y += 40) {
823 dst =
s->outpicref->data[0] + (
s->start_y +
h * (ch + 1) - y - hh) *
s->outpicref->linesize[0];
824 dst[
s->start_x - 3] = 200;
825 dst[
s->start_x +
s->w + 2] = 200;
827 dst =
s->outpicref->data[0] + (
s->start_y - 2) *
s->outpicref->linesize[0] +
s->start_x;
828 for (x = 0; x <
s->w; x+=40)
830 dst =
s->outpicref->data[0] + (
s->start_y - 3) *
s->outpicref->linesize[0] +
s->start_x;
831 for (x = 0; x <
s->w; x+=80)
833 dst =
s->outpicref->data[0] + (
s->h +
s->start_y + 1) *
s->outpicref->linesize[0] +
s->start_x;
834 for (x = 0; x <
s->w; x+=40) {
837 dst =
s->outpicref->data[0] + (
s->h +
s->start_y + 2) *
s->outpicref->linesize[0] +
s->start_x;
838 for (x = 0; x <
s->w; x+=80) {
841 for (y = 0; y <
h; y += 40) {
853 drawtext(
s->outpicref,
s->start_x - 8 * strlen(units) - 4,
h * (ch + 1) +
s->start_y - y - 4 - hh, units, 0);
858 for (x = 0; x <
s->w &&
s->single_pic; x+=80) {
864 drawtext(
s->outpicref,
s->start_x + x - 4 * strlen(units),
s->h +
s->start_y + 6, units, 0);
865 drawtext(
s->outpicref,
s->start_x + x - 4 * strlen(units),
s->start_y - 12, units, 0);
869 drawtext(
s->outpicref, outlink->
w / 2 - 4 * 4, outlink->
h -
s->start_y / 2,
"TIME", 0);
870 drawtext(
s->outpicref,
s->start_x / 7, outlink->
h / 2 - 14 * 4,
"FREQUENCY (Hz)", 1);
872 int w =
s->mode ==
SEPARATE ?
s->w /
s->nb_display_channels :
s->w;
873 for (y = 0; y <
s->h; y += 20) {
874 dst =
s->outpicref->data[0] + (
s->start_y + y) *
s->outpicref->linesize[0];
875 dst[
s->start_x - 2] = 200;
876 dst[
s->start_x +
s->w + 1] = 200;
878 for (y = 0; y <
s->h; y += 40) {
879 dst =
s->outpicref->data[0] + (
s->start_y + y) *
s->outpicref->linesize[0];
880 dst[
s->start_x - 3] = 200;
881 dst[
s->start_x +
s->w + 2] = 200;
883 for (ch = 0; ch < (
s->mode ==
SEPARATE ?
s->nb_display_channels : 1); ch++) {
884 dst =
s->outpicref->data[0] + (
s->start_y - 2) *
s->outpicref->linesize[0] +
s->start_x +
w * ch;
885 for (x = 0; x <
w; x+=40)
887 dst =
s->outpicref->data[0] + (
s->start_y - 3) *
s->outpicref->linesize[0] +
s->start_x +
w * ch;
888 for (x = 0; x <
w; x+=80)
890 dst =
s->outpicref->data[0] + (
s->h +
s->start_y + 1) *
s->outpicref->linesize[0] +
s->start_x +
w * ch;
891 for (x = 0; x <
w; x+=40) {
894 dst =
s->outpicref->data[0] + (
s->h +
s->start_y + 2) *
s->outpicref->linesize[0] +
s->start_x +
w * ch;
895 for (x = 0; x <
w; x+=80) {
898 for (x = 0; x <
w - 79; x += 80) {
910 drawtext(
s->outpicref,
s->start_x - 4 * strlen(units) + x +
w * ch,
s->start_y - 12, units, 0);
911 drawtext(
s->outpicref,
s->start_x - 4 * strlen(units) + x +
w * ch,
s->h +
s->start_y + 6, units, 0);
915 for (y = 0; y <
s->h &&
s->single_pic; y+=40) {
921 drawtext(
s->outpicref,
s->start_x - 8 * strlen(units) - 4,
s->start_y + y - 4, units, 0);
924 drawtext(
s->outpicref,
s->start_x / 7, outlink->
h / 2 - 4 * 4,
"TIME", 1);
925 drawtext(
s->outpicref, outlink->
w / 2 - 14 * 4, outlink->
h -
s->start_y / 2,
"FREQUENCY (Hz)", 0);
928 for (ch = 0; ch < (multi ?
s->nb_display_channels : 1); ch++) {
929 int h = multi ?
s->h /
s->nb_display_channels :
s->h;
931 for (y = 0; y <
h; y++) {
932 float out[4] = { 0., 127.5, 127.5, 0.f};
935 for (chn = 0; chn < (
s->mode ==
SEPARATE ? 1 :
s->nb_display_channels); chn++) {
937 int channel = (multi) ?
s->nb_display_channels - ch - 1 : chn;
947 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);
948 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);
949 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);
950 if (
s->outpicref->data[3])
951 memset(
s->outpicref->data[3]+(
s->start_y +
h * (ch + 1) - y - 1) *
s->outpicref->linesize[3] +
s->w +
s->start_x + 20,
av_clip_uint8(
out[3]), 10);
954 for (y = 0; ch == 0 && y <
h + 5; y += 25) {
955 const float a =
av_clipf(1.f - y / (
float)(
h - 1), 0.f, 1.f);
959 snprintf(scale_fmt,
sizeof(scale_fmt),
960 s->scale ==
LOG ?
"%.0f" :
"%.3f",
value);
961 drawtext(
s->outpicref,
s->w +
s->start_x + 35,
s->start_y + y - 3, scale_fmt, 0);
966 drawtext(
s->outpicref,
s->w +
s->start_x + 22,
s->start_y +
s->h + 20,
"dBFS", 0);
974 float *magnitudes =
s->magnitudes[ch];
975 float *phases =
s->phases[ch];
998 const int h =
s->orientation ==
VERTICAL ?
s->channel_height :
s->channel_width;
999 const int ch = jobnr;
1007 for (y = 0; y <
h; y++) {
1008 int row = (
s->mode ==
COMBINED) ? y : ch *
h + y;
1009 float *
out = &
s->color_buffer[ch][4 * row];
1022 const int h =
s->orientation ==
VERTICAL ?
s->channel_height :
s->channel_width;
1023 const int ch = jobnr;
1030 for (
int yy = 0; yy <
h; yy++) {
1039 int row = (
s->mode ==
COMBINED) ? yy : ch *
h + yy;
1040 float *
out = &
s->color_buffer[ch][4 * row];
1055 int i, fft_size,
h,
w, ret;
1062 switch (
s->fscale) {
1069 if ((
s->stop ||
s->start) &&
s->stop <=
s->start) {
1074 if (!strcmp(
ctx->filter->name,
"showspectrumpic"))
1084 outlink->
w +=
s->start_x * 2;
1085 outlink->
h +=
s->start_y * 2;
1090 s->channel_height =
h;
1091 s->channel_width =
w;
1101 s->win_size = fft_size;
1119 if (fft_size !=
s->fft_size) {
1122 s->fft_size = fft_size;
1127 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1139 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1145 "The window size might be too high.\n");
1152 "The window size might be too high.\n");
1158 s->magnitudes =
av_calloc(
s->nb_display_channels,
sizeof(*
s->magnitudes));
1161 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1163 if (!
s->magnitudes[
i])
1167 s->phases =
av_calloc(
s->nb_display_channels,
sizeof(*
s->phases));
1170 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1177 s->color_buffer =
av_calloc(
s->nb_display_channels,
sizeof(*
s->color_buffer));
1178 if (!
s->color_buffer)
1180 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1182 if (!
s->color_buffer[
i])
1186 s->fft_in =
av_calloc(
s->nb_display_channels,
sizeof(*
s->fft_in));
1189 s->fft_data =
av_calloc(
s->nb_display_channels,
sizeof(*
s->fft_data));
1192 s->fft_scratch =
av_calloc(
s->nb_display_channels,
sizeof(*
s->fft_scratch));
1193 if (!
s->fft_scratch)
1195 for (
i = 0;
i <
s->nb_display_channels;
i++) {
1200 s->fft_data[
i] =
av_calloc(
s->buf_size,
sizeof(**
s->fft_data));
1201 if (!
s->fft_data[
i])
1204 s->fft_scratch[
i] =
av_calloc(
s->buf_size,
sizeof(**
s->fft_scratch));
1205 if (!
s->fft_scratch[
i])
1210 s->window_func_lut =
1212 sizeof(*
s->window_func_lut));
1213 if (!
s->window_func_lut)
1216 if (
s->overlap == 1)
1217 s->overlap = overlap;
1218 s->hop_size = (1.f -
s->overlap) *
s->win_size;
1219 if (
s->hop_size < 1) {
1224 for (
s->win_scale = 0,
i = 0;
i < s->win_size;
i++) {
1225 s->win_scale +=
s->window_func_lut[
i] *
s->window_func_lut[
i];
1227 s->win_scale = 1.f /
sqrtf(
s->win_scale);
1231 s->outpicref = outpicref =
1236 for (
i = 0;
i < outlink->
h;
i++) {
1237 memset(outpicref->
data[0] +
i * outpicref->
linesize[0], 0, outlink->
w);
1238 memset(outpicref->
data[1] +
i * outpicref->
linesize[1], 128, outlink->
w);
1239 memset(outpicref->
data[2] +
i * outpicref->
linesize[2], 128, outlink->
w);
1240 if (outpicref->
data[3])
1241 memset(outpicref->
data[3] +
i * outpicref->
linesize[3], 0, outlink->
w);
1245 if (!
s->single_pic &&
s->legend)
1249 if ((
s->orientation ==
VERTICAL &&
s->xpos >=
s->w) ||
1265 if (!
s->single_pic && strcmp(
s->rate_str,
"auto")) {
1269 }
else if (
s->single_pic) {
1272 s->frame_rate =
s->auto_frame_rate;
1280 sizeof(*
s->combine_buffer));
1284 sizeof(*
s->combine_buffer));
1286 if (!
s->combine_buffer)
1290 s->w,
s->h,
s->win_size);
1304#define RE(y, ch) s->fft_data[ch][y].re
1305#define IM(y, ch) s->fft_data[ch][y].im
1306#define MAGNITUDE(y, ch) hypotf(RE(y, ch), IM(y, ch))
1307#define PHASE(y, ch) atan2f(IM(y, ch), RE(y, ch))
1312 const double w =
s->win_scale * (
s->scale ==
LOG ?
s->win_scale : 1);
1314 const float f =
s->gain *
w;
1315 const int ch = jobnr;
1316 float *magnitudes =
s->magnitudes[ch];
1318 for (y = 0; y <
h; y++)
1327 const int h =
s->orientation ==
VERTICAL ?
s->h :
s->w;
1328 const int ch = jobnr;
1329 float *phases =
s->phases[ch];
1332 for (y = 0; y <
h; y++)
1333 phases[y] = (
PHASE(y, ch) /
M_PI + 1) / 2;
1340 const float rng = 2.f *
M_PI;
1342 float max = -FLT_MAX;
1343 float min = FLT_MAX;
1345 for (
int i = 0;
i <
N;
i++) {
1346 const float d = x[
FFMIN(
i + 1,
N)] - x[
i];
1347 const float p =
ceilf(
fabsf(d) / rng) * rng * (((d < tol) > 0.f) - ((d > -tol) > 0.f));
1362 const int h =
s->orientation ==
VERTICAL ?
s->h :
s->w;
1363 const int ch = jobnr;
1364 float *phases =
s->phases[ch];
1368 for (y = 0; y <
h; y++)
1369 phases[y] =
PHASE(y, ch);
1372 for (y = 0; y <
h; y++)
1380 const double w =
s->win_scale * (
s->scale ==
LOG ?
s->win_scale : 1);
1381 int ch, y,
h =
s->orientation ==
VERTICAL ?
s->h :
s->w;
1382 const float f =
s->gain *
w;
1384 for (ch = 0; ch <
s->nb_display_channels; ch++) {
1385 float *magnitudes =
s->magnitudes[ch];
1387 for (y = 0; y <
h; y++)
1394 int ch, y,
h =
s->orientation ==
VERTICAL ?
s->h :
s->w;
1396 for (ch = 0; ch <
s->nb_display_channels; ch++) {
1397 float *magnitudes =
s->magnitudes[ch];
1399 for (y = 0; y <
h; y++)
1400 magnitudes[y] *=
scale;
1408 for (y = 0; y <
size; y++) {
1409 s->combine_buffer[4 * y ] = 0;
1410 s->combine_buffer[4 * y + 1] = 127.5;
1411 s->combine_buffer[4 * y + 2] = 127.5;
1412 s->combine_buffer[4 * y + 3] = 0;
1422 int ret, plane, x, y, z =
s->orientation ==
VERTICAL ?
s->h :
s->w;
1431 for (y = 0; y < z * 4; y++) {
1432 for (x = 0; x <
s->nb_display_channels; x++) {
1433 s->combine_buffer[y] +=
s->color_buffer[x][y];
1440 outpicref =
s->outpicref;
1444 for (plane = 0; plane < 3 +
alpha; plane++) {
1445 for (y = 0; y <
s->h; y++) {
1446 uint8_t *p = outpicref->
data[plane] +
s->start_x +
1447 (y +
s->start_y) * outpicref->
linesize[plane];
1448 memmove(p, p + 1,
s->w - 1);
1452 }
else if (
s->sliding ==
RSCROLL) {
1453 for (plane = 0; plane < 3 +
alpha; plane++) {
1454 for (y = 0; y <
s->h; y++) {
1455 uint8_t *p = outpicref->
data[plane] +
s->start_x +
1456 (y +
s->start_y) * outpicref->
linesize[plane];
1457 memmove(p + 1, p,
s->w - 1);
1462 for (plane = 0; plane < 3; plane++) {
1463 uint8_t *p = outpicref->
data[plane] +
s->start_x +
1464 (outlink->
h - 1 -
s->start_y) * outpicref->
linesize[plane] +
1466 for (y = 0; y <
s->h; y++) {
1472 uint8_t *p = outpicref->
data[3] +
s->start_x +
1473 (outlink->
h - 1 -
s->start_y) * outpicref->
linesize[3] +
1475 for (y = 0; y <
s->h; y++) {
1482 for (plane = 0; plane < 3 +
alpha; plane++) {
1483 for (y = 1; y <
s->h; y++) {
1484 memmove(outpicref->
data[plane] + (y-1 +
s->start_y) * outpicref->
linesize[plane] +
s->start_x,
1485 outpicref->
data[plane] + (y +
s->start_y) * outpicref->
linesize[plane] +
s->start_x,
1490 }
else if (
s->sliding ==
RSCROLL) {
1491 for (plane = 0; plane < 3 +
alpha; plane++) {
1492 for (y =
s->h - 1; y >= 1; y--) {
1493 memmove(outpicref->
data[plane] + (y +
s->start_y) * outpicref->
linesize[plane] +
s->start_x,
1494 outpicref->
data[plane] + (y-1 +
s->start_y) * outpicref->
linesize[plane] +
s->start_x,
1500 for (plane = 0; plane < 3; plane++) {
1501 uint8_t *p = outpicref->
data[plane] +
s->start_x +
1502 (
s->xpos +
s->start_y) * outpicref->
linesize[plane];
1503 for (x = 0; x <
s->w; x++) {
1509 uint8_t *p = outpicref->
data[3] +
s->start_x +
1510 (
s->xpos +
s->start_y) * outpicref->
linesize[3];
1511 for (x = 0; x <
s->w; x++) {
1523 if (
s->orientation ==
VERTICAL &&
s->xpos < 0)
1529 if (
s->orientation ==
VERTICAL &&
s->xpos >=
s->w)
1535 if (!
s->single_pic && (
s->sliding !=
FULLFRAME ||
s->xpos == 0)) {
1546 for (y = 0; y < 10; y++) {
1547 memset(
s->outpicref->data[0] + outlink->
w / 2 - 4 *
s->old_len +
1548 (outlink->
h -
s->start_y / 2 - 20 + y) *
s->outpicref->linesize[0], 0, 10 *
s->old_len);
1551 outlink->
w / 2 - 4 * strlen(units),
1552 outlink->
h -
s->start_y / 2 - 20,
1555 for (y = 0; y < 10 *
s->old_len; y++) {
1556 memset(
s->outpicref->data[0] +
s->start_x / 7 + 20 +
1557 (outlink->
h / 2 - 4 *
s->old_len + y) *
s->outpicref->linesize[0], 0, 10);
1560 s->start_x / 7 + 20,
1561 outlink->
h / 2 - 4 * strlen(units),
1564 s->old_len = strlen(units);
1567 s->old_pts = outpicref->
pts;
1581#if CONFIG_SHOWSPECTRUM_FILTER
1612 s->in_pts = fin->
pts;
1621 s->xpos > 0 &&
s->outpicref) {
1624 for (
int i = 0;
i < outlink->
h;
i++) {
1625 memset(
s->outpicref->data[0] +
i *
s->outpicref->linesize[0] +
s->xpos, 0, outlink->
w -
s->xpos);
1626 memset(
s->outpicref->data[1] +
i *
s->outpicref->linesize[1] +
s->xpos, 128, outlink->
w -
s->xpos);
1627 memset(
s->outpicref->data[2] +
i *
s->outpicref->linesize[2] +
s->xpos, 128, outlink->
w -
s->xpos);
1628 if (
s->outpicref->data[3])
1629 memset(
s->outpicref->data[3] +
i *
s->outpicref->linesize[3] +
s->xpos, 0, outlink->
w -
s->xpos);
1633 memset(
s->outpicref->data[0] +
i *
s->outpicref->linesize[0], 0, outlink->
w);
1634 memset(
s->outpicref->data[1] +
i *
s->outpicref->linesize[1], 128, outlink->
w);
1635 memset(
s->outpicref->data[2] +
i *
s->outpicref->linesize[2], 128, outlink->
w);
1636 if (
s->outpicref->data[3])
1637 memset(
s->outpicref->data[3] +
i *
s->outpicref->linesize[3], 0, outlink->
w);
1641 pts =
s->outpicref->pts;
1643 s->outpicref =
NULL;
1672static const AVFilterPad showspectrum_outputs[] = {
1681 .p.name =
"showspectrum",
1683 .p.priv_class = &showspectrum_class,
1694#if CONFIG_SHOWSPECTRUMPIC_FILTER
1696static const AVOption showspectrumpic_options[] = {
1746static int showspectrumpic_request_frame(
AVFilterLink *outlink)
1756 int x = 0, sz =
s->orientation ==
VERTICAL ?
s->w :
s->h;
1757 unsigned int nb_frame = 0;
1762 spf =
s->win_size * (
s->samples / ((
s->win_size * sz) *
ceil(
s->samples / (
float)(
s->win_size * sz))));
1763 spf =
FFMAX(1, spf);
1766 spb = (
s->samples / (spf * sz)) * spf;
1773 int acc_samples = 0;
1776 while (nb_frame < s->nb_frames) {
1777 AVFrame *cur_frame =
s->frames[nb_frame];
1778 int cur_frame_samples = cur_frame->
nb_samples;
1781 if (acc_samples < spf) {
1782 nb_samples =
FFMIN(spf - acc_samples, cur_frame_samples - src_offset);
1783 acc_samples += nb_samples;
1785 dst_offset, src_offset, nb_samples,
1789 src_offset += nb_samples;
1790 dst_offset += nb_samples;
1791 if (cur_frame_samples <= src_offset) {
1797 if (acc_samples == spf)
1805 if (consumed >= spb) {
1812 for (ch = 0; ch <
s->nb_display_channels; ch++)
1813 memset(
s->magnitudes[ch], 0,
h *
sizeof(
float));
1818 s->outpicref->pts = 0;
1824 s->outpicref =
NULL;
1836 if (
s->nb_frames + 1ULL >
s->frames_size /
sizeof(*(
s->frames))) {
1843 s->frames[
s->nb_frames] = insamples;
1850static const AVFilterPad showspectrumpic_inputs[] = {
1854 .filter_frame = showspectrumpic_filter_frame,
1858static const AVFilterPad showspectrumpic_outputs[] = {
1863 .request_frame = showspectrumpic_request_frame,
1868 .p.name =
"showspectrumpic",
1869 .p.description =
NULL_IF_CONFIG_SMALL(
"Convert input audio to a spectrum video output single picture."),
1870 .p.priv_class = &showspectrumpic_class,
uint8_t ptrdiff_t const uint8_t ptrdiff_t int const int8_t const int8_t * vf
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
static enum AVSampleFormat sample_fmts[]
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
const FFFilter ff_avf_showspectrumpic
const FFFilter ff_avf_showspectrum
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void unwrap(float *x, int N, float tol, float *mi, float *ma)
static float get_iscale(AVFilterContext *ctx, int scale, float a)
static float bin_pos(const int bin, const int num_bins, const float min, const float max)
static void clear_combine_buffer(ShowSpectrumContext *s, int size)
static int calc_channel_uphases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void pick_color(ShowSpectrumContext *s, float yf, float uf, float vf, float a, float *out)
static float get_value(AVFilterContext *ctx, int ch, int y)
static int calc_channel_phases(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void acalc_magnitudes(ShowSpectrumContext *s)
static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static float log_scale(const float bin, const float bmin, const float bmax, const float min, const float max)
static char * get_time(AVFilterContext *ctx, float seconds, int x)
static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o)
static float get_hz(const float bin, const float bmax, const float min, const float max, int fscale)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int draw_legend(AVFilterContext *ctx, uint64_t samples)
static av_cold void uninit(AVFilterContext *ctx)
static float inv_log_scale(float bin, float bmin, float bmax, float min, float max)
static int config_output(AVFilterLink *outlink)
static const AVOption showspectrum_options[]
static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void scale_magnitudes(ShowSpectrumContext *s, float scale)
static float get_scale(AVFilterContext *ctx, int scale, float a)
static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int ff_outlink_frame_wanted(AVFilterLink *link)
Test if a frame is wanted on an output link.
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe)
Make sure a frame is writable.
int ff_inlink_queued_samples(AVFilterLink *link)
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Main libavfilter public API header.
char * av_asprintf(const char *fmt,...)
#define i(width, name, range_min, range_max)
Public libavutil channel layout APIs header.
static IPT saturation(const CmsCtx *ctx, IPT ipt)
static __device__ float sqrtf(float a)
static __device__ float ceil(float a)
static __device__ float fabsf(float a)
static __device__ float floorf(float a)
static __device__ float ceilf(float a)
float fminf(float, float)
float fmaxf(float, float)
channel
Use these values when setting the channel map with ebur128_set_channel().
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size)
Get a human-readable string describing the channel layout properties.
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
#define AVERROR_EOF
End of file.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
static AVRational av_make_q(int num, int den)
Create an AVRational.
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
AVSampleFormat
Audio sample formats.
@ AV_SAMPLE_FMT_FLTP
float, planar
int av_samples_copy(uint8_t *const *dst, uint8_t *const *src, int dst_offset, int src_offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Copy samples from src to dst.
#define AV_NOPTS_VALUE
Undefined timestamp value.
static const int16_t alpha[]
static void scale(int *out, const int *in, const int w, const int h, const int shift)
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
#define u(width, name, range_min, range_max)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
static FilterLink * ff_filter_link(AVFilterLink *link)
#define AVFILTER_DEFINE_CLASS(fname)
#define FILTER_QUERY_FUNC2(func)
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static enum AVPixelFormat pix_fmts[]
static av_always_inline float cbrtf(float x)
static const uint16_t mask[17]
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
@ AVCOL_RANGE_JPEG
Full range content.
AVPixelFormat
Pixel format.
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
#define FF_ARRAY_ELEMS(a)
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVFilterContext * src
source filter
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
int sample_rate
samples per second
AVChannelLayout ch_layout
channel layout of current buffer (see libavutil/channel_layout.h)
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
This structure describes decoded (raw) audio or video data.
int nb_samples
number of audio samples (per channel) described by this frame
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
enum AVColorRange color_range
MPEG vs JPEG YUV range.
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
AVChannelLayout ch_layout
Channel layout of the audio data.
uint8_t ** extended_data
pointers to the data planes/channels.
Rational number (pair of numerator and denominator).
Link properties exposed to filter code, but not external callers.
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown or variable.
int color_mode
display color scheme
float saturation
color saturation multiplier
float rotation
color rotation
AVComplexFloat ** fft_scratch
scratch buffers
AVRational auto_frame_rate
int sliding
1 if sliding mode, 0 otherwise
int mode
channel display mode
int(* plot_channel)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
float * window_func_lut
Window function LUT.
AVComplexFloat ** fft_data
bins holder for each (displayed) channels
float * combine_buffer
color combining buffer (4 * h items)
int xpos
x position (current column)
float ** color_buffer
color buffer (4 * h * ch items)
AVTXContext ** ifft
Inverse Fast Fourier Transform context.
AVComplexFloat ** fft_in
input FFT coeffs
int fft_size
number of coeffs (FFT window size)
AVTXContext ** fft
Fast Fourier Transform context.
#define av_realloc_f(p, o, n)
static AVFormatContext * ctx
av_cold void av_tx_uninit(AVTXContext **ctx)
Frees a context and sets *ctx to NULL, does nothing when *ctx == NULL.
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...
@ AV_TX_FLOAT_FFT
Standard complex to complex FFT with sample data type of AVComplexFloat, AVComplexDouble or AVComplex...
void(* av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride)
Function pointer to a function to perform the transform.
static double limit(double x)
static double a0(void *priv, double x, double y)
static double a1(void *priv, double x, double y)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
#define WIN_FUNC_OPTION(win_func_opt_name, win_func_offset, flag, default_window_func)
static void generate_window_func(float *lut, int N, int win_func, float *overlap)
const uint8_t * avpriv_cga_font_get(void)
CGA/EGA/VGA ROM font data.
static const ColorEntry color_table[]