36 #if CONFIG_LIBFREETYPE
38 #include FT_FREETYPE_H
46 #define VIDEO_WIDTH 1920
47 #define VIDEO_HEIGHT 1080
48 #define FONT_HEIGHT 32
49 #define SPECTOGRAM_HEIGHT ((VIDEO_HEIGHT-FONT_HEIGHT)/2)
50 #define SPECTOGRAM_START (VIDEO_HEIGHT-SPECTOGRAM_HEIGHT)
51 #define BASE_FREQ 20.051392800492
52 #define COEFF_CLAMP 1.0e-4
53 #define TLENGTH_MIN 0.001
54 #define TLENGTH_DEFAULT "384/f*tc/(384/f+tc)"
55 #define VOLUME_MIN 1e-10
56 #define VOLUME_MAX 100.0
57 #define FONTCOLOR_DEFAULT "st(0, (midi(f)-59.5)/12);" \
58 "st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));" \
59 "r(1-ld(1)) + b(ld(1))"
98 #define OFFSET(x) offsetof(ShowCQTContext, x)
99 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
145 static const int samplerates[] = { 44100, 48000, -1 };
172 #if CONFIG_LIBFREETYPE
175 static const char str[] =
"EF G A BC D ";
177 FT_Library lib =
NULL;
179 int video_scale = s->
fullhd ? 2 : 1;
182 int font_width = 8 * video_scale;
183 int font_repeat = font_width * 12;
184 int linear_hori_advance = font_width * 65536;
185 int non_monospace_warning = 0;
193 if (FT_Init_FreeType(&lib))
196 if (FT_New_Face(lib, s->
fontfile, 0, &face))
199 if (FT_Set_Char_Size(face, 16*64, 0, 0, 0))
202 if (FT_Load_Char(face,
'A', FT_LOAD_RENDER))
205 if (FT_Set_Char_Size(face, 16*64 * linear_hori_advance / face->glyph->linearHoriAdvance, 0, 0, 0))
212 memset(s->
font_alpha, 0, font_height * video_width);
214 for (x = 0; x < 12; x++) {
215 int sx, sy, rx, bx, by, dx, dy;
220 if (FT_Load_Char(face, str[x], FT_LOAD_RENDER))
223 if (face->glyph->advance.x != font_width*64 && !non_monospace_warning) {
225 non_monospace_warning = 1;
228 sy = font_height - 4*video_scale - face->glyph->bitmap_top;
229 for (rx = 0; rx < 10; rx++) {
230 sx = rx * font_repeat + x * font_width + face->glyph->bitmap_left;
231 for (by = 0; by < face->glyph->bitmap.rows; by++) {
235 if (dy >= font_height)
238 for (bx = 0; bx < face->glyph->bitmap.width; bx++) {
242 if (dx >= video_width)
244 s->
font_alpha[dy*video_width+dx] = face->glyph->bitmap.buffer[by*face->glyph->bitmap.width+bx];
251 FT_Done_FreeType(lib);
257 FT_Done_FreeType(lib);
265 double ret = 12200.0*12200.0 * (f*f*f*f);
266 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) *
267 sqrt((f*f + 107.7*107.7) * (f*f + 737.9*737.9));
273 double ret = 12200.0*12200.0 * (f*f*f);
274 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) * sqrt(f*f + 158.5*158.5);
280 double ret = 12200.0*12200.0 * (f*f);
281 ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0);
285 static double midi(
void *p,
double f)
287 return log2(f/440.0) * 12.0 + 69.0;
292 x = av_clipd(x, 0.0, 1.0);
293 return (
int)(x*255.0+0.5) << 16;
298 x = av_clipd(x, 0.0, 1.0);
299 return (
int)(x*255.0+0.5) << 8;
304 x = av_clipd(x, 0.0, 1.0);
305 return (
int)(x*255.0+0.5);
323 static const char *
const expr_vars[] = {
"timeclamp",
"tc",
"frequency",
"freq",
"f",
NULL };
324 static const char *
const expr_func_names[] = {
"a_weighting",
"b_weighting",
"c_weighting",
NULL };
325 static const char *
const expr_fontcolor_func_names[] = {
"midi",
"r",
"g",
"b",
NULL };
328 int fft_len, k, x,
y,
ret;
331 double max_len = rate * (double) s->
timeclamp;
333 int video_scale = s->
fullhd ? 2 : 1;
355 #if CONFIG_LIBFREETYPE
356 load_freetype_font(ctx);
375 expr_fontcolor_funcs,
NULL,
NULL, 0, ctx);
380 int hlen = fft_len >> 1;
384 double tlen, tlength, volume;
390 double a0 = 0.355768;
391 double a1 = 0.487396/
a0;
392 double a2 = 0.144232/
a0;
393 double a3 = 0.012604/
a0;
394 double sv_step, cv_step, sv, cv;
395 double sw_step, cw_step, sw, cw, w;
398 if (
isnan(tlength)) {
420 if (s->
fullhd || !(k & 1)) {
422 fontcolor_value[0] = (fontcolor >> 16) & 0xFF;
423 fontcolor_value[1] = (fontcolor >> 8) & 0xFF;
424 fontcolor_value[2] = fontcolor & 0xFF;
425 fontcolor_value += 3;
428 tlen = tlength * rate;
431 s->
fft_data[hlen].
re = (1.0 + a1 + a2 +
a3) * (1.0/tlen) * volume * (1.0/fft_len);
433 sv_step = sv = sin(2.0*
M_PI*freq*(1.0/rate));
434 cv_step = cv = cos(2.0*
M_PI*freq*(1.0/rate));
436 sw_step = sw = sin(2.0*
M_PI*(1.0/tlen));
437 cw_step = cw = cos(2.0*
M_PI*(1.0/tlen));
438 for (x = 1; x < 0.5 * tlen; x++) {
439 double cv_tmp, cw_tmp;
440 double cw2, cw3, sw2;
442 cw2 = cw * cw - sw * sw;
443 sw2 = cw * sw + sw * cw;
444 cw3 = cw * cw2 - sw * sw2;
445 w = (1.0 + a1 * cw + a2 * cw2 + a3 * cw3) * (1.0/tlen) * volume * (1.0/fft_len);
451 cv_tmp = cv * cv_step - sv * sv_step;
452 sv = sv * cv_step + cv * sv_step;
454 cw_tmp = cw * cw_step - sw * sw_step;
455 sw = sw * cw_step + cw * sw_step;
458 for (; x < hlen; x++) {
467 for (x = 0; x < fft_len; x++) {
473 for (x = 0; x < fft_len; x++)
476 for (x = 0; x < fft_len; x++) {
496 av_log(ctx,
AV_LOG_INFO,
"Elapsed time %.6f s (fft_len=%u, num_coeffs=%u)\n", 1e-6 * (end_time-start_time), fft_len, num_coeffs);
498 outlink->
w = video_width;
499 outlink->
h = video_height;
537 int video_scale = s->
fullhd ? 2 : 1;
553 for (x = 1; x <= fft_len >> 1; x++) {
570 float g = 1.0f / s->
gamma;
571 float g2 = 1.0f / s->
gamma2;
584 result[x][0] = l.
re * l.
re + l.
im * l.
im;
585 result[x][2] = r.
re * r.
re + r.
im * r.
im;
586 result[x][1] = 0.5f * (result[x][0] + result[x][2]);
587 result[x][3] = (g2 == 1.0f) ? result[x][1] :
powf(result[x][1], g2);
588 result[x][0] = 255.0f *
powf(
FFMIN(1.0f,result[x][0]), g);
589 result[x][1] = 255.0f *
powf(
FFMIN(1.0f,result[x][1]), g);
590 result[x][2] = 255.0f *
powf(
FFMIN(1.0f,result[x][2]), g);
594 for (x = 0; x < video_width; x++) {
595 result[x][0] = 0.5f * (result[2*x][0] + result[2*x+1][0]);
596 result[x][1] = 0.5f * (result[2*x][1] + result[2*x+1][1]);
597 result[x][2] = 0.5f * (result[2*x][2] + result[2*x+1][2]);
598 result[x][3] = 0.5f * (result[2*x][3] + result[2*x+1][3]);
602 for (x = 0; x < video_width; x++) {
611 float rcp_result[VIDEO_WIDTH];
612 int total_length = linesize * spectogram_height;
615 for (x = 0; x < video_width; x++)
616 rcp_result[x] = 1.0f / (result[x][3]+0.0001f);
619 for (y = 0; y < spectogram_height; y++) {
620 float height = (spectogram_height -
y) * (1.0f/spectogram_height);
621 uint8_t *lineptr = data + y * linesize;
622 for (x = 0; x < video_width; x++) {
624 if (result[x][3] <= height) {
629 mul = (result[x][3] -
height) * rcp_result[x];
630 *lineptr++ = mul * result[x][0] + 0.5f;
631 *lineptr++ = mul * result[x][1] + 0.5f;
632 *lineptr++ = mul * result[x][2] + 0.5f;
639 for (y = 0; y < font_height; y++) {
640 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
643 for (x = 0; x < video_width; x++) {
645 lineptr[3*x] = (spectogram_src[3*x] * (255-
alpha) + fontcolor_value[0] * alpha + 255) >> 8;
646 lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-
alpha) + fontcolor_value[1] * alpha + 255) >> 8;
647 lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-
alpha) + fontcolor_value[2] * alpha + 255) >> 8;
648 fontcolor_value += 3;
652 for (y = 0; y < font_height; y++) {
653 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
656 for (x = 0; x < video_width; x += video_width/10) {
658 static const char str[] =
"EF G A BC D ";
659 uint8_t *startptr = data + spectogram_height * linesize + x * 3;
660 for (u = 0; str[
u]; u++) {
662 for (v = 0; v < 16; v++) {
663 uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
664 int ux = x + 8 * u * video_scale;
666 for (mask = 0x80;
mask; mask >>= 1) {
671 if (video_scale == 2) {
673 p[linesize+1] = p[1];
674 p[linesize+2] = p[2];
680 p += 3 * video_scale;
689 data += spectogram_start * linesize;
692 data += total_length - back_length;
722 for (x = 0; x < (fft_len-step); x++)
730 audio_data = (
float*) insamples->
data[0];
747 for (m = 0; m < fft_len-step; m++)
754 for (m = 0; m < remaining; m++) {
803 .description =
NULL_IF_CONFIG_SMALL(
"Convert input audio to a CQT (Constant Q Transform) spectrum video output."),
809 .priv_class = &showcqt_class,