]> git.sesse.net Git - ffmpeg/blob - libavfilter/avf_showcqt.c
Merge commit '6c445990e64124ad64c79423dfd3764520648c89'
[ffmpeg] / libavfilter / avf_showcqt.c
1 /*
2  * Copyright (c) 2014-2015 Muhammad Faiz <mfcc64@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "config.h"
22 #include "libavcodec/avfft.h"
23 #include "libavutil/avassert.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/xga_font_data.h"
26 #include "libavutil/eval.h"
27 #include "libavutil/pixdesc.h"
28 #include "libavutil/time.h"
29 #include "avfilter.h"
30 #include "internal.h"
31 #include "lavfutils.h"
32 #include "lswsutils.h"
33
34 #if CONFIG_LIBFREETYPE
35 #include <ft2build.h>
36 #include FT_FREETYPE_H
37 #endif
38
39 #if CONFIG_LIBFONTCONFIG
40 #include <fontconfig/fontconfig.h>
41 #endif
42
43 #include "avf_showcqt.h"
44
45 #define BASEFREQ        20.01523126408007475
46 #define ENDFREQ         20495.59681441799654
47 #define TLENGTH         "384*tc/(384+tc*f)"
48 #define TLENGTH_MIN     0.001
49 #define VOLUME_MAX      100.0
50 #define FONTCOLOR       "st(0, (midi(f)-59.5)/12);" \
51     "st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));" \
52     "r(1-ld(1)) + b(ld(1))"
53 #define CSCHEME         "1|0.5|0|0|0.5|1"
54 #define PTS_STEP 10
55 #define PTS_TOLERANCE 1
56
57 #define OFFSET(x) offsetof(ShowCQTContext, x)
58 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
59
60 static const AVOption showcqt_options[] = {
61     { "size",         "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, { .str = "1920x1080" },      0, 0,        FLAGS },
62     { "s",            "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, { .str = "1920x1080" },      0, 0,        FLAGS },
63     { "fps",          "set video rate", OFFSET(rate),  AV_OPT_TYPE_VIDEO_RATE, { .str = "25" },             1, 1000,     FLAGS },
64     { "rate",         "set video rate", OFFSET(rate),  AV_OPT_TYPE_VIDEO_RATE, { .str = "25" },             1, 1000,     FLAGS },
65     { "r",            "set video rate", OFFSET(rate),  AV_OPT_TYPE_VIDEO_RATE, { .str = "25" },             1, 1000,     FLAGS },
66     { "bar_h",   "set bargraph height", OFFSET(bar_h),        AV_OPT_TYPE_INT, { .i64 = -1 },              -1, INT_MAX,  FLAGS },
67     { "axis_h",      "set axis height", OFFSET(axis_h),       AV_OPT_TYPE_INT, { .i64 = -1 },              -1, INT_MAX,  FLAGS },
68     { "sono_h",  "set sonogram height", OFFSET(sono_h),       AV_OPT_TYPE_INT, { .i64 = -1 },              -1, INT_MAX,  FLAGS },
69     { "fullhd",      "set fullhd size", OFFSET(fullhd),      AV_OPT_TYPE_BOOL, { .i64 = 1 },                0, 1,        FLAGS },
70     { "sono_v",  "set sonogram volume", OFFSET(sono_v),    AV_OPT_TYPE_STRING, { .str = "16" },      CHAR_MIN, CHAR_MAX, FLAGS },
71     { "volume",  "set sonogram volume", OFFSET(sono_v),    AV_OPT_TYPE_STRING, { .str = "16" },      CHAR_MIN, CHAR_MAX, FLAGS },
72     { "bar_v",   "set bargraph volume", OFFSET(bar_v),     AV_OPT_TYPE_STRING, { .str = "sono_v" },  CHAR_MIN, CHAR_MAX, FLAGS },
73     { "volume2", "set bargraph volume", OFFSET(bar_v),     AV_OPT_TYPE_STRING, { .str = "sono_v" },  CHAR_MIN, CHAR_MAX, FLAGS },
74     { "sono_g",   "set sonogram gamma", OFFSET(sono_g),     AV_OPT_TYPE_FLOAT, { .dbl = 3.0 },            1.0, 7.0,      FLAGS },
75     { "gamma",    "set sonogram gamma", OFFSET(sono_g),     AV_OPT_TYPE_FLOAT, { .dbl = 3.0 },            1.0, 7.0,      FLAGS },
76     { "bar_g",    "set bargraph gamma", OFFSET(bar_g),      AV_OPT_TYPE_FLOAT, { .dbl = 1.0 },            1.0, 7.0,      FLAGS },
77     { "gamma2",   "set bargraph gamma", OFFSET(bar_g),      AV_OPT_TYPE_FLOAT, { .dbl = 1.0 },            1.0, 7.0,      FLAGS },
78     { "bar_t",  "set bar transparency", OFFSET(bar_t),      AV_OPT_TYPE_FLOAT, { .dbl = 1.0 },            0.0, 1.0,      FLAGS },
79     { "timeclamp",     "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 },           0.1, 1.0,      FLAGS },
80     { "tc",            "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 },           0.1, 1.0,      FLAGS },
81     { "basefreq", "set base frequency", OFFSET(basefreq),  AV_OPT_TYPE_DOUBLE, { .dbl = BASEFREQ },      10.0, 100000.0, FLAGS },
82     { "endfreq",   "set end frequency", OFFSET(endfreq),   AV_OPT_TYPE_DOUBLE, { .dbl = ENDFREQ },       10.0, 100000.0, FLAGS },
83     { "coeffclamp",   "set coeffclamp", OFFSET(coeffclamp), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 },            0.1, 10.0,     FLAGS },
84     { "tlength",         "set tlength", OFFSET(tlength),   AV_OPT_TYPE_STRING, { .str = TLENGTH },   CHAR_MIN, CHAR_MAX, FLAGS },
85     { "count",   "set transform count", OFFSET(count),        AV_OPT_TYPE_INT, { .i64 = 6 },                1, 30,       FLAGS },
86     { "fcount",  "set frequency count", OFFSET(fcount),       AV_OPT_TYPE_INT, { .i64 = 0 },                0, 10,       FLAGS },
87     { "fontfile", "set axis font file", OFFSET(fontfile),  AV_OPT_TYPE_STRING, { .str = NULL },      CHAR_MIN, CHAR_MAX, FLAGS },
88     { "font",          "set axis font", OFFSET(font),      AV_OPT_TYPE_STRING, { .str = NULL },      CHAR_MIN, CHAR_MAX, FLAGS },
89     { "fontcolor",    "set font color", OFFSET(fontcolor), AV_OPT_TYPE_STRING, { .str = FONTCOLOR }, CHAR_MIN, CHAR_MAX, FLAGS },
90     { "axisfile",     "set axis image", OFFSET(axisfile),  AV_OPT_TYPE_STRING, { .str = NULL },      CHAR_MIN, CHAR_MAX, FLAGS },
91     { "axis",              "draw axis", OFFSET(axis),        AV_OPT_TYPE_BOOL, { .i64 = 1 },                0, 1,        FLAGS },
92     { "text",              "draw axis", OFFSET(axis),        AV_OPT_TYPE_BOOL, { .i64 = 1 },                0, 1,        FLAGS },
93     { "csp",         "set color space", OFFSET(csp),          AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, INT_MAX, FLAGS, "csp" },
94         { "unspecified", "unspecified", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, 0, FLAGS, "csp" },
95         { "bt709",             "bt709", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT709 },       0, 0, FLAGS, "csp" },
96         { "fcc",                 "fcc", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_FCC },         0, 0, FLAGS, "csp" },
97         { "bt470bg",         "bt470bg", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG },     0, 0, FLAGS, "csp" },
98         { "smpte170m",     "smpte170m", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_SMPTE170M },   0, 0, FLAGS, "csp" },
99         { "smpte240m",     "smpte240m", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_SMPTE240M },   0, 0, FLAGS, "csp" },
100         { "bt2020ncl",     "bt2020ncl", 0,                  AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT2020_NCL },  0, 0, FLAGS, "csp" },
101     { "cscheme",    "set color scheme", OFFSET(cscheme),   AV_OPT_TYPE_STRING, { .str = CSCHEME },   CHAR_MIN, CHAR_MAX, FLAGS },
102     { NULL }
103 };
104
105 AVFILTER_DEFINE_CLASS(showcqt);
106
107 static void common_uninit(ShowCQTContext *s)
108 {
109     int k;
110     int level = AV_LOG_DEBUG;
111     int64_t plot_time;
112
113     if (s->fft_time)
114         av_log(s->ctx, level, "fft_time         = %16.3f s.\n", s->fft_time * 1e-6);
115     if (s->cqt_time)
116         av_log(s->ctx, level, "cqt_time         = %16.3f s.\n", s->cqt_time * 1e-6);
117     if (s->process_cqt_time)
118         av_log(s->ctx, level, "process_cqt_time = %16.3f s.\n", s->process_cqt_time * 1e-6);
119     if (s->update_sono_time)
120         av_log(s->ctx, level, "update_sono_time = %16.3f s.\n", s->update_sono_time * 1e-6);
121     if (s->alloc_time)
122         av_log(s->ctx, level, "alloc_time       = %16.3f s.\n", s->alloc_time * 1e-6);
123     if (s->bar_time)
124         av_log(s->ctx, level, "bar_time         = %16.3f s.\n", s->bar_time * 1e-6);
125     if (s->axis_time)
126         av_log(s->ctx, level, "axis_time        = %16.3f s.\n", s->axis_time * 1e-6);
127     if (s->sono_time)
128         av_log(s->ctx, level, "sono_time        = %16.3f s.\n", s->sono_time * 1e-6);
129
130     plot_time = s->fft_time + s->cqt_time + s->process_cqt_time + s->update_sono_time
131               + s->alloc_time + s->bar_time + s->axis_time + s->sono_time;
132     if (plot_time)
133         av_log(s->ctx, level, "plot_time        = %16.3f s.\n", plot_time * 1e-6);
134
135     s->fft_time = s->cqt_time = s->process_cqt_time = s->update_sono_time
136                 = s->alloc_time = s->bar_time = s->axis_time = s->sono_time = 0;
137     /* axis_frame may be non reference counted frame */
138     if (s->axis_frame && !s->axis_frame->buf[0]) {
139         av_freep(s->axis_frame->data);
140         for (k = 0; k < 4; k++)
141             s->axis_frame->data[k] = NULL;
142     }
143
144     av_frame_free(&s->axis_frame);
145     av_frame_free(&s->sono_frame);
146     av_fft_end(s->fft_ctx);
147     s->fft_ctx = NULL;
148     if (s->coeffs)
149         for (k = 0; k < s->cqt_len; k++)
150             av_freep(&s->coeffs[k].val);
151     av_freep(&s->coeffs);
152     av_freep(&s->fft_data);
153     av_freep(&s->fft_result);
154     av_freep(&s->cqt_result);
155     av_freep(&s->c_buf);
156     av_freep(&s->h_buf);
157     av_freep(&s->rcp_h_buf);
158     av_freep(&s->freq);
159     av_freep(&s->sono_v_buf);
160     av_freep(&s->bar_v_buf);
161 }
162
163 static double *create_freq_table(double base, double end, int n)
164 {
165     double log_base, log_end;
166     double rcp_n = 1.0 / n;
167     double *freq;
168     int x;
169
170     freq = av_malloc_array(n, sizeof(*freq));
171     if (!freq)
172         return NULL;
173
174     log_base = log(base);
175     log_end  = log(end);
176     for (x = 0; x < n; x++) {
177         double log_freq = log_base + (x + 0.5) * (log_end - log_base) * rcp_n;
178         freq[x] = exp(log_freq);
179     }
180     return freq;
181 }
182
183 static double clip_with_log(void *log_ctx, const char *name,
184                             double val, double min, double max,
185                             double nan_replace, int idx)
186 {
187     int level = AV_LOG_WARNING;
188     if (isnan(val)) {
189         av_log(log_ctx, level, "[%d] %s is nan, setting it to %g.\n",
190                idx, name, nan_replace);
191         val = nan_replace;
192     } else if (val < min) {
193         av_log(log_ctx, level, "[%d] %s is too low (%g), setting it to %g.\n",
194                idx, name, val, min);
195         val = min;
196     } else if (val > max) {
197         av_log(log_ctx, level, "[%d] %s it too high (%g), setting it to %g.\n",
198                idx, name, val, max);
199         val = max;
200     }
201     return val;
202 }
203
204 static double a_weighting(void *p, double f)
205 {
206     double ret = 12200.0*12200.0 * (f*f*f*f);
207     ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) *
208            sqrt((f*f + 107.7*107.7) * (f*f + 737.9*737.9));
209     return ret;
210 }
211
212 static double b_weighting(void *p, double f)
213 {
214     double ret = 12200.0*12200.0 * (f*f*f);
215     ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) * sqrt(f*f + 158.5*158.5);
216     return ret;
217 }
218
219 static double c_weighting(void *p, double f)
220 {
221     double ret = 12200.0*12200.0 * (f*f);
222     ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0);
223     return ret;
224 }
225
226 static int init_volume(ShowCQTContext *s)
227 {
228     const char *func_names[] = { "a_weighting", "b_weighting", "c_weighting", NULL };
229     const char *sono_names[] = { "timeclamp", "tc", "frequency", "freq", "f", "bar_v", NULL };
230     const char *bar_names[] = { "timeclamp", "tc", "frequency", "freq", "f", "sono_v", NULL };
231     double (*funcs[])(void *, double) = { a_weighting, b_weighting, c_weighting };
232     AVExpr *sono = NULL, *bar = NULL;
233     int x, ret = AVERROR(ENOMEM);
234
235     s->sono_v_buf = av_malloc_array(s->cqt_len, sizeof(*s->sono_v_buf));
236     s->bar_v_buf = av_malloc_array(s->cqt_len, sizeof(*s->bar_v_buf));
237     if (!s->sono_v_buf || !s->bar_v_buf)
238         goto error;
239
240     if ((ret = av_expr_parse(&sono, s->sono_v, sono_names, func_names, funcs, NULL, NULL, 0, s->ctx)) < 0)
241         goto error;
242
243     if ((ret = av_expr_parse(&bar, s->bar_v, bar_names, func_names, funcs, NULL, NULL, 0, s->ctx)) < 0)
244         goto error;
245
246     for (x = 0; x < s->cqt_len; x++) {
247         double vars[] = { s->timeclamp, s->timeclamp, s->freq[x], s->freq[x], s->freq[x], 0.0 };
248         double vol = clip_with_log(s->ctx, "sono_v", av_expr_eval(sono, vars, NULL), 0.0, VOLUME_MAX, 0.0, x);
249         vars[5] = vol;
250         vol = clip_with_log(s->ctx, "bar_v", av_expr_eval(bar, vars, NULL), 0.0, VOLUME_MAX, 0.0, x);
251         s->bar_v_buf[x] = vol * vol;
252         vars[5] = vol;
253         vol = clip_with_log(s->ctx, "sono_v", av_expr_eval(sono, vars, NULL), 0.0, VOLUME_MAX, 0.0, x);
254         s->sono_v_buf[x] = vol * vol;
255     }
256     av_expr_free(sono);
257     av_expr_free(bar);
258     return 0;
259
260 error:
261     av_freep(&s->sono_v_buf);
262     av_freep(&s->bar_v_buf);
263     av_expr_free(sono);
264     av_expr_free(bar);
265     return ret;
266 }
267
268 static void cqt_calc(FFTComplex *dst, const FFTComplex *src, const Coeffs *coeffs,
269                      int len, int fft_len)
270 {
271     int k, x, i, j;
272     for (k = 0; k < len; k++) {
273         FFTComplex l, r, a = {0,0}, b = {0,0};
274
275         for (x = 0; x < coeffs[k].len; x++) {
276             FFTSample u = coeffs[k].val[x];
277             i = coeffs[k].start + x;
278             j = fft_len - i;
279             a.re += u * src[i].re;
280             a.im += u * src[i].im;
281             b.re += u * src[j].re;
282             b.im += u * src[j].im;
283         }
284
285         /* separate left and right, (and multiply by 2.0) */
286         l.re = a.re + b.re;
287         l.im = a.im - b.im;
288         r.re = b.im + a.im;
289         r.im = b.re - a.re;
290         dst[k].re = l.re * l.re + l.im * l.im;
291         dst[k].im = r.re * r.re + r.im * r.im;
292     }
293 }
294
295 static int init_cqt(ShowCQTContext *s)
296 {
297     const char *var_names[] = { "timeclamp", "tc", "frequency", "freq", "f", NULL };
298     AVExpr *expr = NULL;
299     int rate = s->ctx->inputs[0]->sample_rate;
300     int nb_cqt_coeffs = 0;
301     int k, x, ret;
302
303     if ((ret = av_expr_parse(&expr, s->tlength, var_names, NULL, NULL, NULL, NULL, 0, s->ctx)) < 0)
304         goto error;
305
306     ret = AVERROR(ENOMEM);
307     if (!(s->coeffs = av_calloc(s->cqt_len, sizeof(*s->coeffs))))
308         goto error;
309
310     for (k = 0; k < s->cqt_len; k++) {
311         double vars[] = { s->timeclamp, s->timeclamp, s->freq[k], s->freq[k], s->freq[k] };
312         double flen, center, tlength;
313         int start, end, m = k;
314
315         if (s->freq[k] > 0.5 * rate)
316             continue;
317         tlength = clip_with_log(s->ctx, "tlength", av_expr_eval(expr, vars, NULL),
318                                 TLENGTH_MIN, s->timeclamp, s->timeclamp, k);
319
320         flen = 8.0 * s->fft_len / (tlength * rate);
321         center = s->freq[k] * s->fft_len / rate;
322         start = FFMAX(0, ceil(center - 0.5 * flen));
323         end = FFMIN(s->fft_len, floor(center + 0.5 * flen));
324
325         s->coeffs[m].start = start & ~(s->cqt_align - 1);
326         s->coeffs[m].len = (end | (s->cqt_align - 1)) + 1 - s->coeffs[m].start;
327         nb_cqt_coeffs += s->coeffs[m].len;
328         if (!(s->coeffs[m].val = av_calloc(s->coeffs[m].len, sizeof(*s->coeffs[m].val))))
329             goto error;
330
331         for (x = start; x <= end; x++) {
332             int sign = (x & 1) ? (-1) : 1;
333             double y = 2.0 * M_PI * (x - center) * (1.0 / flen);
334             /* nuttall window */
335             double w = 0.355768 + 0.487396 * cos(y) + 0.144232 * cos(2*y) + 0.012604 * cos(3*y);
336             w *= sign * (1.0 / s->fft_len);
337             s->coeffs[m].val[x - s->coeffs[m].start] = w;
338         }
339
340         if (s->permute_coeffs)
341             s->permute_coeffs(s->coeffs[m].val, s->coeffs[m].len);
342     }
343
344     av_expr_free(expr);
345     av_log(s->ctx, AV_LOG_INFO, "nb_cqt_coeffs = %d.\n", nb_cqt_coeffs);
346     return 0;
347
348 error:
349     av_expr_free(expr);
350     if (s->coeffs)
351         for (k = 0; k < s->cqt_len; k++)
352             av_freep(&s->coeffs[k].val);
353     av_freep(&s->coeffs);
354     return ret;
355 }
356
357 static AVFrame *alloc_frame_empty(enum AVPixelFormat format, int w, int h)
358 {
359     AVFrame *out;
360     out = av_frame_alloc();
361     if (!out)
362         return NULL;
363     out->format = format;
364     out->width = w;
365     out->height = h;
366     if (av_frame_get_buffer(out, 32) < 0) {
367         av_frame_free(&out);
368         return NULL;
369     }
370     if (format == AV_PIX_FMT_RGB24 || format == AV_PIX_FMT_RGBA) {
371         memset(out->data[0], 0, out->linesize[0] * h);
372     } else {
373         int hh = (format == AV_PIX_FMT_YUV420P || format == AV_PIX_FMT_YUVA420P) ? h / 2 : h;
374         memset(out->data[0], 16, out->linesize[0] * h);
375         memset(out->data[1], 128, out->linesize[1] * hh);
376         memset(out->data[2], 128, out->linesize[2] * hh);
377         if (out->data[3])
378             memset(out->data[3], 0, out->linesize[3] * h);
379     }
380     return out;
381 }
382
383 static enum AVPixelFormat convert_axis_pixel_format(enum AVPixelFormat format)
384 {
385     switch (format) {
386         case AV_PIX_FMT_RGB24:   format = AV_PIX_FMT_RGBA; break;
387         case AV_PIX_FMT_YUV444P:
388         case AV_PIX_FMT_YUV422P:
389         case AV_PIX_FMT_YUV420P: format = AV_PIX_FMT_YUVA444P; break;
390     }
391     return format;
392 }
393
394 static int init_axis_empty(ShowCQTContext *s)
395 {
396     if (!(s->axis_frame = alloc_frame_empty(convert_axis_pixel_format(s->format), s->width, s->axis_h)))
397         return AVERROR(ENOMEM);
398     return 0;
399 }
400
401 static int init_axis_from_file(ShowCQTContext *s)
402 {
403     uint8_t *tmp_data[4] = { NULL };
404     int tmp_linesize[4];
405     enum AVPixelFormat tmp_format;
406     int tmp_w, tmp_h, ret;
407
408     if ((ret = ff_load_image(tmp_data, tmp_linesize, &tmp_w, &tmp_h, &tmp_format,
409                              s->axisfile, s->ctx)) < 0)
410         goto error;
411
412     ret = AVERROR(ENOMEM);
413     if (!(s->axis_frame = av_frame_alloc()))
414         goto error;
415
416     if ((ret = ff_scale_image(s->axis_frame->data, s->axis_frame->linesize, s->width, s->axis_h,
417                               convert_axis_pixel_format(s->format), tmp_data, tmp_linesize, tmp_w, tmp_h,
418                               tmp_format, s->ctx)) < 0)
419         goto error;
420
421     s->axis_frame->width = s->width;
422     s->axis_frame->height = s->axis_h;
423     s->axis_frame->format = convert_axis_pixel_format(s->format);
424     av_freep(tmp_data);
425     return 0;
426
427 error:
428     av_frame_free(&s->axis_frame);
429     av_freep(tmp_data);
430     return ret;
431 }
432
433 static double midi(void *p, double f)
434 {
435     return log2(f/440.0) * 12.0 + 69.0;
436 }
437
438 static double r_func(void *p, double x)
439 {
440     x = av_clipd(x, 0.0, 1.0);
441     return lrint(x*255.0) << 16;
442 }
443
444 static double g_func(void *p, double x)
445 {
446     x = av_clipd(x, 0.0, 1.0);
447     return lrint(x*255.0) << 8;
448 }
449
450 static double b_func(void *p, double x)
451 {
452     x = av_clipd(x, 0.0, 1.0);
453     return lrint(x*255.0);
454 }
455
456 static int init_axis_color(ShowCQTContext *s, AVFrame *tmp, int half)
457 {
458     const char *var_names[] = { "timeclamp", "tc", "frequency", "freq", "f", NULL };
459     const char *func_names[] = { "midi", "r", "g", "b", NULL };
460     double (*funcs[])(void *, double) = { midi, r_func, g_func, b_func };
461     AVExpr *expr = NULL;
462     double *freq = NULL;
463     int x, xs, y, ret;
464     int width = half ? 1920/2 : 1920, height = half ? 16 : 32;
465     int step = half ? 2 : 1;
466
467     if (s->basefreq != (double) BASEFREQ || s->endfreq != (double) ENDFREQ) {
468         av_log(s->ctx, AV_LOG_WARNING, "font axis rendering is not implemented in non-default frequency range,"
469                " please use axisfile option instead.\n");
470         return AVERROR(EINVAL);
471     }
472
473     if (s->cqt_len == 1920)
474         freq = s->freq;
475     else if (!(freq = create_freq_table(s->basefreq, s->endfreq, 1920)))
476         return AVERROR(ENOMEM);
477
478     if ((ret = av_expr_parse(&expr, s->fontcolor, var_names, func_names, funcs, NULL, NULL, 0, s->ctx)) < 0) {
479         if (freq != s->freq)
480             av_freep(&freq);
481         return ret;
482     }
483
484     for (x = 0, xs = 0; x < width; x++, xs += step) {
485         double vars[] = { s->timeclamp, s->timeclamp, freq[xs], freq[xs], freq[xs] };
486         int color = (int) av_expr_eval(expr, vars, NULL);
487         uint8_t r = (color >> 16) & 0xFF, g = (color >> 8) & 0xFF, b = color & 0xFF;
488         uint8_t *data = tmp->data[0];
489         int linesize = tmp->linesize[0];
490         for (y = 0; y < height; y++) {
491             data[linesize * y + 4 * x] = r;
492             data[linesize * y + 4 * x + 1] = g;
493             data[linesize * y + 4 * x + 2] = b;
494         }
495     }
496
497     av_expr_free(expr);
498     if (freq != s->freq)
499         av_freep(&freq);
500     return 0;
501 }
502
503 static int render_freetype(ShowCQTContext *s, AVFrame *tmp, char *fontfile)
504 {
505 #if CONFIG_LIBFREETYPE
506     const char *str = "EF G A BC D ";
507     uint8_t *data = tmp->data[0];
508     int linesize = tmp->linesize[0];
509     FT_Library lib = NULL;
510     FT_Face face = NULL;
511     int font_width = 16, font_height = 32;
512     int font_repeat = font_width * 12;
513     int linear_hori_advance = font_width * 65536;
514     int non_monospace_warning = 0;
515     int x;
516
517     if (!fontfile)
518         return AVERROR(EINVAL);
519
520     if (FT_Init_FreeType(&lib))
521         goto fail;
522
523     if (FT_New_Face(lib, fontfile, 0, &face))
524         goto fail;
525
526     if (FT_Set_Char_Size(face, 16*64, 0, 0, 0))
527         goto fail;
528
529     if (FT_Load_Char(face, 'A', FT_LOAD_RENDER))
530         goto fail;
531
532     if (FT_Set_Char_Size(face, 16*64 * linear_hori_advance / face->glyph->linearHoriAdvance, 0, 0, 0))
533         goto fail;
534
535     for (x = 0; x < 12; x++) {
536         int sx, sy, rx, bx, by, dx, dy;
537
538         if (str[x] == ' ')
539             continue;
540
541         if (FT_Load_Char(face, str[x], FT_LOAD_RENDER))
542             goto fail;
543
544         if (face->glyph->advance.x != font_width*64 && !non_monospace_warning) {
545             av_log(s->ctx, AV_LOG_WARNING, "font is not monospace.\n");
546             non_monospace_warning = 1;
547         }
548
549         sy = font_height - 8 - face->glyph->bitmap_top;
550         for (rx = 0; rx < 10; rx++) {
551             sx = rx * font_repeat + x * font_width + face->glyph->bitmap_left;
552             for (by = 0; by < face->glyph->bitmap.rows; by++) {
553                 dy = by + sy;
554                 if (dy < 0)
555                     continue;
556                 if (dy >= font_height)
557                     break;
558
559                 for (bx = 0; bx < face->glyph->bitmap.width; bx++) {
560                     dx = bx + sx;
561                     if (dx < 0)
562                         continue;
563                     if (dx >= 1920)
564                         break;
565                     data[dy*linesize+4*dx+3] = face->glyph->bitmap.buffer[by*face->glyph->bitmap.width+bx];
566                 }
567             }
568         }
569     }
570
571     FT_Done_Face(face);
572     FT_Done_FreeType(lib);
573     return 0;
574
575 fail:
576     av_log(s->ctx, AV_LOG_WARNING, "error while loading freetype font.\n");
577     FT_Done_Face(face);
578     FT_Done_FreeType(lib);
579     return AVERROR(EINVAL);
580 #else
581     if (fontfile)
582         av_log(s->ctx, AV_LOG_WARNING, "freetype is not available, ignoring fontfile option.\n");
583     return AVERROR(EINVAL);
584 #endif
585 }
586
587 static int render_fontconfig(ShowCQTContext *s, AVFrame *tmp, char* font)
588 {
589 #if CONFIG_LIBFONTCONFIG
590     FcConfig *fontconfig;
591     FcPattern *pat, *best;
592     FcResult result = FcResultMatch;
593     char *filename;
594     int i, ret;
595
596     if (!font)
597         return AVERROR(EINVAL);
598
599     for (i = 0; font[i]; i++) {
600         if (font[i] == '|')
601             font[i] = ':';
602     }
603
604     if (!(fontconfig = FcInitLoadConfigAndFonts())) {
605         av_log(s->ctx, AV_LOG_ERROR, "impossible to init fontconfig.\n");
606         return AVERROR_UNKNOWN;
607     }
608
609     if (!(pat = FcNameParse((uint8_t *)font))) {
610         av_log(s->ctx, AV_LOG_ERROR, "could not parse fontconfig pat.\n");
611         FcConfigDestroy(fontconfig);
612         return AVERROR(EINVAL);
613     }
614
615     FcDefaultSubstitute(pat);
616
617     if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
618         av_log(s->ctx, AV_LOG_ERROR, "could not substitue fontconfig options.\n");
619         FcPatternDestroy(pat);
620         FcConfigDestroy(fontconfig);
621         return AVERROR(ENOMEM);
622     }
623
624     best = FcFontMatch(fontconfig, pat, &result);
625     FcPatternDestroy(pat);
626
627     ret = AVERROR(EINVAL);
628     if (!best || result != FcResultMatch) {
629         av_log(s->ctx, AV_LOG_ERROR, "cannot find a valid font for %s.\n", font);
630         goto fail;
631     }
632
633     if (FcPatternGetString(best, FC_FILE, 0, (FcChar8 **)&filename) != FcResultMatch) {
634         av_log(s->ctx, AV_LOG_ERROR, "no file path for %s\n", font);
635         goto fail;
636     }
637
638     ret = render_freetype(s, tmp, filename);
639
640 fail:
641     FcPatternDestroy(best);
642     FcConfigDestroy(fontconfig);
643     return ret;
644 #else
645     if (font)
646         av_log(s->ctx, AV_LOG_WARNING, "fontconfig is not available, ignoring font option.\n");
647     return AVERROR(EINVAL);
648 #endif
649 }
650
651 static int render_default_font(AVFrame *tmp)
652 {
653     const char *str = "EF G A BC D ";
654     int x, u, v, mask;
655     uint8_t *data = tmp->data[0];
656     int linesize = tmp->linesize[0];
657     int width = 1920/2, height = 16;
658
659     for (x = 0; x < width; x += width/10) {
660         uint8_t *startptr = data + 4 * x;
661         for (u = 0; u < 12; u++) {
662             for (v = 0; v < height; v++) {
663                 uint8_t *p = startptr + v * linesize + height/2 * 4 * u;
664                 for (mask = 0x80; mask; mask >>= 1, p += 4) {
665                     if (mask & avpriv_vga16_font[str[u] * 16 + v])
666                         p[3] = 255;
667                     else
668                         p[3] = 0;
669                 }
670             }
671         }
672     }
673
674     return 0;
675 }
676
677 static int init_axis_from_font(ShowCQTContext *s)
678 {
679     AVFrame *tmp = NULL;
680     int ret = AVERROR(ENOMEM);
681     int width = 1920, height = 32;
682     int default_font = 0;
683
684     if (!(tmp = alloc_frame_empty(AV_PIX_FMT_RGBA, width, height)))
685         goto fail;
686
687     if (!(s->axis_frame = av_frame_alloc()))
688         goto fail;
689
690     if (render_freetype(s, tmp, s->fontfile) < 0 &&
691         render_fontconfig(s, tmp, s->font) < 0 &&
692         (default_font = 1, ret = render_default_font(tmp)) < 0)
693         goto fail;
694
695     if (default_font)
696         width /= 2, height /= 2;
697
698     if ((ret = init_axis_color(s, tmp, default_font)) < 0)
699         goto fail;
700
701     if ((ret = ff_scale_image(s->axis_frame->data, s->axis_frame->linesize, s->width, s->axis_h,
702                               convert_axis_pixel_format(s->format), tmp->data, tmp->linesize,
703                               width, height, AV_PIX_FMT_RGBA, s->ctx)) < 0)
704         goto fail;
705
706     av_frame_free(&tmp);
707     s->axis_frame->width = s->width;
708     s->axis_frame->height = s->axis_h;
709     s->axis_frame->format = convert_axis_pixel_format(s->format);
710     return 0;
711
712 fail:
713     av_frame_free(&tmp);
714     av_frame_free(&s->axis_frame);
715     return ret;
716 }
717
718 static float calculate_gamma(float v, float g)
719 {
720     if (g == 1.0f)
721         return v;
722     if (g == 2.0f)
723         return sqrtf(v);
724     if (g == 3.0f)
725         return cbrtf(v);
726     if (g == 4.0f)
727         return sqrtf(sqrtf(v));
728     return expf(logf(v) / g);
729 }
730
731 static void rgb_from_cqt(ColorFloat *c, const FFTComplex *v, float g, int len, float cscheme[6])
732 {
733     int x;
734     for (x = 0; x < len; x++) {
735         c[x].rgb.r = 255.0f * calculate_gamma(FFMIN(1.0f, cscheme[0] * v[x].re + cscheme[3] * v[x].im), g);
736         c[x].rgb.g = 255.0f * calculate_gamma(FFMIN(1.0f, cscheme[1] * v[x].re + cscheme[4] * v[x].im), g);
737         c[x].rgb.b = 255.0f * calculate_gamma(FFMIN(1.0f, cscheme[2] * v[x].re + cscheme[5] * v[x].im), g);
738     }
739 }
740
741 static void yuv_from_cqt(ColorFloat *c, const FFTComplex *v, float gamma, int len, float cm[3][3], float cscheme[6])
742 {
743     int x;
744     for (x = 0; x < len; x++) {
745         float r, g, b;
746         r = calculate_gamma(FFMIN(1.0f, cscheme[0] * v[x].re + cscheme[3] * v[x].im), gamma);
747         g = calculate_gamma(FFMIN(1.0f, cscheme[1] * v[x].re + cscheme[4] * v[x].im), gamma);
748         b = calculate_gamma(FFMIN(1.0f, cscheme[2] * v[x].re + cscheme[5] * v[x].im), gamma);
749         c[x].yuv.y = cm[0][0] * r + cm[0][1] * g + cm[0][2] * b;
750         c[x].yuv.u = cm[1][0] * r + cm[1][1] * g + cm[1][2] * b;
751         c[x].yuv.v = cm[2][0] * r + cm[2][1] * g + cm[2][2] * b;
752     }
753 }
754
755 static void draw_bar_rgb(AVFrame *out, const float *h, const float *rcp_h,
756                          const ColorFloat *c, int bar_h, float bar_t)
757 {
758     int x, y, w = out->width;
759     float mul, ht, rcp_bar_h = 1.0f / bar_h, rcp_bar_t = 1.0f / bar_t;
760     uint8_t *v = out->data[0], *lp;
761     int ls = out->linesize[0];
762
763     for (y = 0; y < bar_h; y++) {
764         ht = (bar_h - y) * rcp_bar_h;
765         lp = v + y * ls;
766         for (x = 0; x < w; x++) {
767             if (h[x] <= ht) {
768                 *lp++ = 0;
769                 *lp++ = 0;
770                 *lp++ = 0;
771             } else {
772                 mul = (h[x] - ht) * rcp_h[x];
773                 mul = (mul < bar_t) ? (mul * rcp_bar_t) : 1.0f;
774                 *lp++ = lrintf(mul * c[x].rgb.r);
775                 *lp++ = lrintf(mul * c[x].rgb.g);
776                 *lp++ = lrintf(mul * c[x].rgb.b);
777             }
778         }
779     }
780 }
781
782 #define DRAW_BAR_WITH_CHROMA(x) \
783 do { \
784     if (h[x] <= ht) { \
785         *lpy++ = 16; \
786         *lpu++ = 128; \
787         *lpv++ = 128; \
788     } else { \
789         mul = (h[x] - ht) * rcp_h[x]; \
790         mul = (mul < bar_t) ? (mul * rcp_bar_t) : 1.0f; \
791         *lpy++ = lrintf(mul * c[x].yuv.y + 16.0f); \
792         *lpu++ = lrintf(mul * c[x].yuv.u + 128.0f); \
793         *lpv++ = lrintf(mul * c[x].yuv.v + 128.0f); \
794     } \
795 } while (0)
796
797 #define DRAW_BAR_WITHOUT_CHROMA(x) \
798 do { \
799     if (h[x] <= ht) { \
800         *lpy++ = 16; \
801     } else { \
802         mul = (h[x] - ht) * rcp_h[x]; \
803         mul = (mul < bar_t) ? (mul * rcp_bar_t) : 1.0f; \
804         *lpy++ = lrintf(mul * c[x].yuv.y + 16.0f); \
805     } \
806 } while (0)
807
808 static void draw_bar_yuv(AVFrame *out, const float *h, const float *rcp_h,
809                          const ColorFloat *c, int bar_h, float bar_t)
810 {
811     int x, y, yh, w = out->width;
812     float mul, ht, rcp_bar_h = 1.0f / bar_h, rcp_bar_t = 1.0f / bar_t;
813     uint8_t *vy = out->data[0], *vu = out->data[1], *vv = out->data[2];
814     uint8_t *lpy, *lpu, *lpv;
815     int lsy = out->linesize[0], lsu = out->linesize[1], lsv = out->linesize[2];
816     int fmt = out->format;
817
818     for (y = 0; y < bar_h; y += 2) {
819         yh = (fmt == AV_PIX_FMT_YUV420P) ? y / 2 : y;
820         ht = (bar_h - y) * rcp_bar_h;
821         lpy = vy + y * lsy;
822         lpu = vu + yh * lsu;
823         lpv = vv + yh * lsv;
824         if (fmt == AV_PIX_FMT_YUV444P) {
825             for (x = 0; x < w; x += 2) {
826                 DRAW_BAR_WITH_CHROMA(x);
827                 DRAW_BAR_WITH_CHROMA(x+1);
828             }
829         } else {
830             for (x = 0; x < w; x += 2) {
831                 DRAW_BAR_WITH_CHROMA(x);
832                 DRAW_BAR_WITHOUT_CHROMA(x+1);
833             }
834         }
835
836         ht = (bar_h - (y+1)) * rcp_bar_h;
837         lpy = vy + (y+1) * lsy;
838         lpu = vu + (y+1) * lsu;
839         lpv = vv + (y+1) * lsv;
840         if (fmt == AV_PIX_FMT_YUV444P) {
841             for (x = 0; x < w; x += 2) {
842                 DRAW_BAR_WITH_CHROMA(x);
843                 DRAW_BAR_WITH_CHROMA(x+1);
844             }
845         } else if (fmt == AV_PIX_FMT_YUV422P) {
846             for (x = 0; x < w; x += 2) {
847                 DRAW_BAR_WITH_CHROMA(x);
848                 DRAW_BAR_WITHOUT_CHROMA(x+1);
849             }
850         } else {
851             for (x = 0; x < w; x += 2) {
852                 DRAW_BAR_WITHOUT_CHROMA(x);
853                 DRAW_BAR_WITHOUT_CHROMA(x+1);
854             }
855         }
856     }
857 }
858
859 static void draw_axis_rgb(AVFrame *out, AVFrame *axis, const ColorFloat *c, int off)
860 {
861     int x, y, w = axis->width, h = axis->height;
862     float a, rcp_255 = 1.0f / 255.0f;
863     uint8_t *lp, *lpa;
864
865     for (y = 0; y < h; y++) {
866         lp = out->data[0] + (off + y) * out->linesize[0];
867         lpa = axis->data[0] + y * axis->linesize[0];
868         for (x = 0; x < w; x++) {
869             if (!lpa[3]) {
870                 *lp++ = lrintf(c[x].rgb.r);
871                 *lp++ = lrintf(c[x].rgb.g);
872                 *lp++ = lrintf(c[x].rgb.b);
873             } else if (lpa[3] == 255) {
874                 *lp++ = lpa[0];
875                 *lp++ = lpa[1];
876                 *lp++ = lpa[2];
877             } else {
878                 a = rcp_255 * lpa[3];
879                 *lp++ = lrintf(a * lpa[0] + (1.0f - a) * c[x].rgb.r);
880                 *lp++ = lrintf(a * lpa[1] + (1.0f - a) * c[x].rgb.g);
881                 *lp++ = lrintf(a * lpa[2] + (1.0f - a) * c[x].rgb.b);
882             }
883             lpa += 4;
884         }
885     }
886 }
887
888 #define BLEND_WITH_CHROMA(c) \
889 do { \
890     if (!*lpaa) { \
891         *lpy = lrintf(c.yuv.y + 16.0f); \
892         *lpu = lrintf(c.yuv.u + 128.0f); \
893         *lpv = lrintf(c.yuv.v + 128.0f); \
894     } else if (255 == *lpaa) { \
895         *lpy = *lpay; \
896         *lpu = *lpau; \
897         *lpv = *lpav; \
898     } else { \
899         float a = (1.0f/255.0f) * (*lpaa); \
900         *lpy = lrintf(a * (*lpay) + (1.0f - a) * (c.yuv.y + 16.0f)); \
901         *lpu = lrintf(a * (*lpau) + (1.0f - a) * (c.yuv.u + 128.0f)); \
902         *lpv = lrintf(a * (*lpav) + (1.0f - a) * (c.yuv.v + 128.0f)); \
903     } \
904     lpy++; lpu++; lpv++; \
905     lpay++; lpau++; lpav++; lpaa++; \
906 } while (0)
907
908 #define BLEND_WITHOUT_CHROMA(c, alpha_inc) \
909 do { \
910     if (!*lpaa) { \
911         *lpy = lrintf(c.yuv.y + 16.0f); \
912     } else if (255 == *lpaa) { \
913         *lpy = *lpay; \
914     } else { \
915         float a = (1.0f/255.0f) * (*lpaa); \
916         *lpy = lrintf(a * (*lpay) + (1.0f - a) * (c.yuv.y + 16.0f)); \
917     } \
918     lpy++; \
919     lpay++; lpaa += alpha_inc; \
920 } while (0)
921
922 #define BLEND_CHROMA2(c) \
923 do { \
924     if (!lpaa[0] && !lpaa[1]) { \
925         *lpu = lrintf(c.yuv.u + 128.0f); \
926         *lpv = lrintf(c.yuv.v + 128.0f); \
927     } else if (255 == lpaa[0] && 255 == lpaa[1]) { \
928         *lpu = *lpau; *lpv = *lpav; \
929     } else { \
930         float a0 = (0.5f/255.0f) * lpaa[0]; \
931         float a1 = (0.5f/255.0f) * lpaa[1]; \
932         float b = 1.0f - a0 - a1; \
933         *lpu = lrintf(a0 * lpau[0] + a1 * lpau[1] + b * (c.yuv.u + 128.0f)); \
934         *lpv = lrintf(a0 * lpav[0] + a1 * lpav[1] + b * (c.yuv.v + 128.0f)); \
935     } \
936     lpau += 2; lpav += 2; lpaa++; lpu++; lpv++; \
937 } while (0)
938
939 #define BLEND_CHROMA2x2(c) \
940 do { \
941     if (!lpaa[0] && !lpaa[1] && !lpaa[lsaa] && !lpaa[lsaa+1]) { \
942         *lpu = lrintf(c.yuv.u + 128.0f); \
943         *lpv = lrintf(c.yuv.v + 128.0f); \
944     } else if (255 == lpaa[0] && 255 == lpaa[1] && \
945                255 == lpaa[lsaa] && 255 == lpaa[lsaa+1]) { \
946         *lpu = *lpau; *lpv = *lpav; \
947     } else { \
948         float a0 = (0.25f/255.0f) * lpaa[0]; \
949         float a1 = (0.25f/255.0f) * lpaa[1]; \
950         float a2 = (0.25f/255.0f) * lpaa[lsaa]; \
951         float a3 = (0.25f/255.0f) * lpaa[lsaa+1]; \
952         float b = 1.0f - a0 - a1 - a2 - a3; \
953         *lpu = lrintf(a0 * lpau[0] + a1 * lpau[1] + a2 * lpau[lsau] + a3 * lpau[lsau+1] \
954                     + b * (c.yuv.u + 128.0f)); \
955         *lpv = lrintf(a0 * lpav[0] + a1 * lpav[1] + a2 * lpav[lsav] + a3 * lpav[lsav+1] \
956                     + b * (c.yuv.v + 128.0f)); \
957     } \
958     lpau += 2; lpav += 2; lpaa++; lpu++; lpv++; \
959 } while (0)
960
961 static void draw_axis_yuv(AVFrame *out, AVFrame *axis, const ColorFloat *c, int off)
962 {
963     int fmt = out->format, x, y, yh, w = axis->width, h = axis->height;
964     int offh = (fmt == AV_PIX_FMT_YUV420P) ? off / 2 : off;
965     uint8_t *vy = out->data[0], *vu = out->data[1], *vv = out->data[2];
966     uint8_t *vay = axis->data[0], *vau = axis->data[1], *vav = axis->data[2], *vaa = axis->data[3];
967     int lsy = out->linesize[0], lsu = out->linesize[1], lsv = out->linesize[2];
968     int lsay = axis->linesize[0], lsau = axis->linesize[1], lsav = axis->linesize[2], lsaa = axis->linesize[3];
969     uint8_t *lpy, *lpu, *lpv, *lpay, *lpau, *lpav, *lpaa;
970
971     for (y = 0; y < h; y += 2) {
972         yh = (fmt == AV_PIX_FMT_YUV420P) ? y / 2 : y;
973         lpy = vy + (off + y) * lsy;
974         lpu = vu + (offh + yh) * lsu;
975         lpv = vv + (offh + yh) * lsv;
976         lpay = vay + y * lsay;
977         lpau = vau + y * lsau;
978         lpav = vav + y * lsav;
979         lpaa = vaa + y * lsaa;
980         if (fmt == AV_PIX_FMT_YUV444P) {
981             for (x = 0; x < w; x += 2) {
982                 BLEND_WITH_CHROMA(c[x]);
983                 BLEND_WITH_CHROMA(c[x+1]);
984             }
985         } else if (fmt == AV_PIX_FMT_YUV422P) {
986             for (x = 0; x < w; x += 2) {
987                 BLEND_WITHOUT_CHROMA(c[x], 0);
988                 BLEND_CHROMA2(c[x]);
989                 BLEND_WITHOUT_CHROMA(c[x+1], 1);
990             }
991         } else {
992             for (x = 0; x < w; x += 2) {
993                 BLEND_WITHOUT_CHROMA(c[x], 0);
994                 BLEND_CHROMA2x2(c[x]);
995                 BLEND_WITHOUT_CHROMA(c[x+1], 1);
996             }
997         }
998
999         lpy = vy + (off + y + 1) * lsy;
1000         lpu = vu + (off + y + 1) * lsu;
1001         lpv = vv + (off + y + 1) * lsv;
1002         lpay = vay + (y + 1) * lsay;
1003         lpau = vau + (y + 1) * lsau;
1004         lpav = vav + (y + 1) * lsav;
1005         lpaa = vaa + (y + 1) * lsaa;
1006         if (fmt == AV_PIX_FMT_YUV444P) {
1007             for (x = 0; x < w; x += 2) {
1008                 BLEND_WITH_CHROMA(c[x]);
1009                 BLEND_WITH_CHROMA(c[x+1]);
1010             }
1011         } else if (fmt == AV_PIX_FMT_YUV422P) {
1012             for (x = 0; x < w; x += 2) {
1013                 BLEND_WITHOUT_CHROMA(c[x], 0);
1014                 BLEND_CHROMA2(c[x]);
1015                 BLEND_WITHOUT_CHROMA(c[x+1], 1);
1016             }
1017         } else {
1018             for (x = 0; x < w; x += 2) {
1019                 BLEND_WITHOUT_CHROMA(c[x], 1);
1020                 BLEND_WITHOUT_CHROMA(c[x+1], 1);
1021             }
1022         }
1023     }
1024 }
1025
1026 static void draw_sono(AVFrame *out, AVFrame *sono, int off, int idx)
1027 {
1028     int fmt = out->format, h = sono->height;
1029     int nb_planes = (fmt == AV_PIX_FMT_RGB24) ? 1 : 3;
1030     int offh = (fmt == AV_PIX_FMT_YUV420P) ? off / 2 : off;
1031     int inc = (fmt == AV_PIX_FMT_YUV420P) ? 2 : 1;
1032     int ls, i, y, yh;
1033
1034     ls = FFMIN(out->linesize[0], sono->linesize[0]);
1035     for (y = 0; y < h; y++) {
1036         memcpy(out->data[0] + (off + y) * out->linesize[0],
1037                sono->data[0] + (idx + y) % h * sono->linesize[0], ls);
1038     }
1039
1040     for (i = 1; i < nb_planes; i++) {
1041         ls = FFMIN(out->linesize[i], sono->linesize[i]);
1042         for (y = 0; y < h; y += inc) {
1043             yh = (fmt == AV_PIX_FMT_YUV420P) ? y / 2 : y;
1044             memcpy(out->data[i] + (offh + yh) * out->linesize[i],
1045                    sono->data[i] + (idx + y) % h * sono->linesize[i], ls);
1046         }
1047     }
1048 }
1049
1050 static void update_sono_rgb(AVFrame *sono, const ColorFloat *c, int idx)
1051 {
1052     int x, w = sono->width;
1053     uint8_t *lp = sono->data[0] + idx * sono->linesize[0];
1054
1055     for (x = 0; x < w; x++) {
1056         *lp++ = lrintf(c[x].rgb.r);
1057         *lp++ = lrintf(c[x].rgb.g);
1058         *lp++ = lrintf(c[x].rgb.b);
1059     }
1060 }
1061
1062 static void update_sono_yuv(AVFrame *sono, const ColorFloat *c, int idx)
1063 {
1064     int x, fmt = sono->format, w = sono->width;
1065     uint8_t *lpy = sono->data[0] + idx * sono->linesize[0];
1066     uint8_t *lpu = sono->data[1] + idx * sono->linesize[1];
1067     uint8_t *lpv = sono->data[2] + idx * sono->linesize[2];
1068
1069     for (x = 0; x < w; x += 2) {
1070         *lpy++ = lrintf(c[x].yuv.y + 16.0f);
1071         *lpu++ = lrintf(c[x].yuv.u + 128.0f);
1072         *lpv++ = lrintf(c[x].yuv.v + 128.0f);
1073         *lpy++ = lrintf(c[x+1].yuv.y + 16.0f);
1074         if (fmt == AV_PIX_FMT_YUV444P) {
1075             *lpu++ = lrintf(c[x+1].yuv.u + 128.0f);
1076             *lpv++ = lrintf(c[x+1].yuv.v + 128.0f);
1077         }
1078     }
1079 }
1080
1081 static void process_cqt(ShowCQTContext *s)
1082 {
1083     int x, i;
1084     if (!s->sono_count) {
1085         for (x = 0; x < s->cqt_len; x++) {
1086             s->h_buf[x] = s->bar_v_buf[x] * 0.5f * (s->cqt_result[x].re + s->cqt_result[x].im);
1087         }
1088         if (s->fcount > 1) {
1089             float rcp_fcount = 1.0f / s->fcount;
1090             for (x = 0; x < s->width; x++) {
1091                 float h = 0.0f;
1092                 for (i = 0; i < s->fcount; i++)
1093                     h += s->h_buf[s->fcount * x + i];
1094                 s->h_buf[x] = rcp_fcount * h;
1095             }
1096         }
1097         for (x = 0; x < s->width; x++) {
1098             s->h_buf[x] = calculate_gamma(s->h_buf[x], s->bar_g);
1099             s->rcp_h_buf[x] = 1.0f / (s->h_buf[x] + 0.0001f);
1100         }
1101     }
1102
1103     for (x = 0; x < s->cqt_len; x++) {
1104         s->cqt_result[x].re *= s->sono_v_buf[x];
1105         s->cqt_result[x].im *= s->sono_v_buf[x];
1106     }
1107
1108     if (s->fcount > 1) {
1109         float rcp_fcount = 1.0f / s->fcount;
1110         for (x = 0; x < s->width; x++) {
1111             FFTComplex result = {0.0f, 0.0f};
1112             for (i = 0; i < s->fcount; i++) {
1113                 result.re += s->cqt_result[s->fcount * x + i].re;
1114                 result.im += s->cqt_result[s->fcount * x + i].im;
1115             }
1116             s->cqt_result[x].re = rcp_fcount * result.re;
1117             s->cqt_result[x].im = rcp_fcount * result.im;
1118         }
1119     }
1120
1121     if (s->format == AV_PIX_FMT_RGB24)
1122         rgb_from_cqt(s->c_buf, s->cqt_result, s->sono_g, s->width, s->cscheme_v);
1123     else
1124         yuv_from_cqt(s->c_buf, s->cqt_result, s->sono_g, s->width, s->cmatrix, s->cscheme_v);
1125 }
1126
1127 static int plot_cqt(AVFilterContext *ctx, AVFrame **frameout)
1128 {
1129     AVFilterLink *outlink = ctx->outputs[0];
1130     ShowCQTContext *s = ctx->priv;
1131     int64_t last_time, cur_time;
1132
1133 #define UPDATE_TIME(t) \
1134     cur_time = av_gettime(); \
1135     t += cur_time - last_time; \
1136     last_time = cur_time
1137
1138     last_time = av_gettime();
1139
1140     memcpy(s->fft_result, s->fft_data, s->fft_len * sizeof(*s->fft_data));
1141     av_fft_permute(s->fft_ctx, s->fft_result);
1142     av_fft_calc(s->fft_ctx, s->fft_result);
1143     s->fft_result[s->fft_len] = s->fft_result[0];
1144     UPDATE_TIME(s->fft_time);
1145
1146     s->cqt_calc(s->cqt_result, s->fft_result, s->coeffs, s->cqt_len, s->fft_len);
1147     UPDATE_TIME(s->cqt_time);
1148
1149     process_cqt(s);
1150     UPDATE_TIME(s->process_cqt_time);
1151
1152     if (s->sono_h) {
1153         s->update_sono(s->sono_frame, s->c_buf, s->sono_idx);
1154         UPDATE_TIME(s->update_sono_time);
1155     }
1156
1157     if (!s->sono_count) {
1158         AVFrame *out = *frameout = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1159         if (!out)
1160             return AVERROR(ENOMEM);
1161         out->sample_aspect_ratio = av_make_q(1, 1);
1162         av_frame_set_color_range(out, AVCOL_RANGE_MPEG);
1163         av_frame_set_colorspace(out, s->csp);
1164         UPDATE_TIME(s->alloc_time);
1165
1166         if (s->bar_h) {
1167             s->draw_bar(out, s->h_buf, s->rcp_h_buf, s->c_buf, s->bar_h, s->bar_t);
1168             UPDATE_TIME(s->bar_time);
1169         }
1170
1171         if (s->axis_h) {
1172             s->draw_axis(out, s->axis_frame, s->c_buf, s->bar_h);
1173             UPDATE_TIME(s->axis_time);
1174         }
1175
1176         if (s->sono_h) {
1177             s->draw_sono(out, s->sono_frame, s->bar_h + s->axis_h, s->sono_idx);
1178             UPDATE_TIME(s->sono_time);
1179         }
1180         out->pts = s->next_pts;
1181         s->next_pts += PTS_STEP;
1182     }
1183     s->sono_count = (s->sono_count + 1) % s->count;
1184     if (s->sono_h)
1185         s->sono_idx = (s->sono_idx + s->sono_h - 1) % s->sono_h;
1186     return 0;
1187 }
1188
1189 static void init_colormatrix(ShowCQTContext *s)
1190 {
1191     double kr, kg, kb;
1192
1193     /* from vf_colorspace.c */
1194     switch (s->csp) {
1195     default:
1196         av_log(s->ctx, AV_LOG_WARNING, "unsupported colorspace, setting it to unspecified.\n");
1197         s->csp = AVCOL_SPC_UNSPECIFIED;
1198     case AVCOL_SPC_UNSPECIFIED:
1199     case AVCOL_SPC_BT470BG:
1200     case AVCOL_SPC_SMPTE170M:
1201         kr = 0.299; kb = 0.114; break;
1202     case AVCOL_SPC_BT709:
1203         kr = 0.2126; kb = 0.0722; break;
1204     case AVCOL_SPC_FCC:
1205         kr = 0.30; kb = 0.11; break;
1206     case AVCOL_SPC_SMPTE240M:
1207         kr = 0.212; kb = 0.087; break;
1208     case AVCOL_SPC_BT2020_NCL:
1209         kr = 0.2627; kb = 0.0593; break;
1210     }
1211
1212     kg = 1.0 - kr - kb;
1213     s->cmatrix[0][0] = 219.0 * kr;
1214     s->cmatrix[0][1] = 219.0 * kg;
1215     s->cmatrix[0][2] = 219.0 * kb;
1216     s->cmatrix[1][0] = -112.0 * kr / (1.0 - kb);
1217     s->cmatrix[1][1] = -112.0 * kg / (1.0 - kb);
1218     s->cmatrix[1][2] = 112.0;
1219     s->cmatrix[2][0] = 112.0;
1220     s->cmatrix[2][1] = -112.0 * kg / (1.0 - kr);
1221     s->cmatrix[2][2] = -112.0 * kb / (1.0 - kr);
1222 }
1223
1224 static int init_cscheme(ShowCQTContext *s)
1225 {
1226     char tail[2];
1227     int k;
1228
1229     if (sscanf(s->cscheme, " %f | %f | %f | %f | %f | %f %1s", &s->cscheme_v[0],
1230         &s->cscheme_v[1], &s->cscheme_v[2], &s->cscheme_v[3], &s->cscheme_v[4],
1231         &s->cscheme_v[5], tail) != 6)
1232         goto fail;
1233
1234     for (k = 0; k < 6; k++)
1235         if (isnan(s->cscheme_v[k]) || s->cscheme_v[k] < 0.0f || s->cscheme_v[k] > 1.0f)
1236             goto fail;
1237
1238     return 0;
1239
1240 fail:
1241     av_log(s->ctx, AV_LOG_ERROR, "invalid cscheme.\n");
1242     return AVERROR(EINVAL);
1243 }
1244
1245 /* main filter control */
1246 static av_cold int init(AVFilterContext *ctx)
1247 {
1248     ShowCQTContext *s = ctx->priv;
1249     s->ctx = ctx;
1250
1251     if (!s->fullhd) {
1252         av_log(ctx, AV_LOG_WARNING, "fullhd option is deprecated, use size/s option instead.\n");
1253         if (s->width != 1920 || s->height != 1080) {
1254             av_log(ctx, AV_LOG_ERROR, "fullhd set to 0 but with custom dimension.\n");
1255             return AVERROR(EINVAL);
1256         }
1257         s->width /= 2;
1258         s->height /= 2;
1259         s->fullhd = 1;
1260     }
1261
1262     if (s->axis_h < 0) {
1263         s->axis_h = s->width / 60;
1264         if (s->axis_h & 1)
1265             s->axis_h++;
1266         if (s->bar_h >= 0 && s->sono_h >= 0)
1267             s->axis_h = s->height - s->bar_h - s->sono_h;
1268         if (s->bar_h >= 0 && s->sono_h < 0)
1269             s->axis_h = FFMIN(s->axis_h, s->height - s->bar_h);
1270         if (s->bar_h < 0 && s->sono_h >= 0)
1271             s->axis_h = FFMIN(s->axis_h, s->height - s->sono_h);
1272     }
1273
1274     if (s->bar_h < 0) {
1275         s->bar_h = (s->height - s->axis_h) / 2;
1276         if (s->bar_h & 1)
1277             s->bar_h--;
1278         if (s->sono_h >= 0)
1279             s->bar_h = s->height - s->sono_h - s->axis_h;
1280     }
1281
1282     if (s->sono_h < 0)
1283         s->sono_h = s->height - s->axis_h - s->bar_h;
1284
1285     if ((s->width & 1) || (s->height & 1) || (s->bar_h & 1) || (s->axis_h & 1) || (s->sono_h & 1) ||
1286         (s->bar_h < 0) || (s->axis_h < 0) || (s->sono_h < 0) || (s->bar_h > s->height) ||
1287         (s->axis_h > s->height) || (s->sono_h > s->height) || (s->bar_h + s->axis_h + s->sono_h != s->height)) {
1288         av_log(ctx, AV_LOG_ERROR, "invalid dimension.\n");
1289         return AVERROR(EINVAL);
1290     }
1291
1292     if (!s->fcount) {
1293         do {
1294             s->fcount++;
1295         } while(s->fcount * s->width < 1920 && s->fcount < 10);
1296     }
1297
1298     init_colormatrix(s);
1299
1300     return init_cscheme(s);
1301 }
1302
1303 static av_cold void uninit(AVFilterContext *ctx)
1304 {
1305     common_uninit(ctx->priv);
1306 }
1307
1308 static int query_formats(AVFilterContext *ctx)
1309 {
1310     AVFilterFormats *formats = NULL;
1311     AVFilterChannelLayouts *layouts = NULL;
1312     AVFilterLink *inlink = ctx->inputs[0];
1313     AVFilterLink *outlink = ctx->outputs[0];
1314     enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE };
1315     enum AVPixelFormat pix_fmts[] = {
1316         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
1317         AV_PIX_FMT_YUV444P, AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
1318     };
1319     int64_t channel_layouts[] = { AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO_DOWNMIX, -1 };
1320     int ret;
1321
1322     /* set input audio formats */
1323     formats = ff_make_format_list(sample_fmts);
1324     if ((ret = ff_formats_ref(formats, &inlink->out_formats)) < 0)
1325         return ret;
1326
1327     layouts = avfilter_make_format64_list(channel_layouts);
1328     if ((ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts)) < 0)
1329         return ret;
1330
1331     formats = ff_all_samplerates();
1332     if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0)
1333         return ret;
1334
1335     /* set output video format */
1336     formats = ff_make_format_list(pix_fmts);
1337     if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0)
1338         return ret;
1339
1340     return 0;
1341 }
1342
1343 static int config_output(AVFilterLink *outlink)
1344 {
1345     AVFilterContext *ctx = outlink->src;
1346     AVFilterLink *inlink = ctx->inputs[0];
1347     ShowCQTContext *s = ctx->priv;
1348     int ret;
1349
1350     common_uninit(s);
1351
1352     outlink->w = s->width;
1353     outlink->h = s->height;
1354     s->format = outlink->format;
1355     outlink->sample_aspect_ratio = av_make_q(1, 1);
1356     outlink->frame_rate = s->rate;
1357     outlink->time_base = av_mul_q(av_inv_q(s->rate), av_make_q(1, PTS_STEP));
1358     av_log(ctx, AV_LOG_INFO, "video: %dx%d %s %d/%d fps, bar_h = %d, axis_h = %d, sono_h = %d.\n",
1359            s->width, s->height, av_get_pix_fmt_name(s->format), s->rate.num, s->rate.den,
1360            s->bar_h, s->axis_h, s->sono_h);
1361
1362     s->cqt_len = s->width * s->fcount;
1363     if (!(s->freq = create_freq_table(s->basefreq, s->endfreq, s->cqt_len)))
1364         return AVERROR(ENOMEM);
1365
1366     if ((ret = init_volume(s)) < 0)
1367         return ret;
1368
1369     s->fft_bits = ceil(log2(inlink->sample_rate * s->timeclamp));
1370     s->fft_len = 1 << s->fft_bits;
1371     av_log(ctx, AV_LOG_INFO, "fft_len = %d, cqt_len = %d.\n", s->fft_len, s->cqt_len);
1372
1373     s->fft_ctx = av_fft_init(s->fft_bits, 0);
1374     s->fft_data = av_calloc(s->fft_len, sizeof(*s->fft_data));
1375     s->fft_result = av_calloc(s->fft_len + 64, sizeof(*s->fft_result));
1376     s->cqt_result = av_malloc_array(s->cqt_len, sizeof(*s->cqt_result));
1377     if (!s->fft_ctx || !s->fft_data || !s->fft_result || !s->cqt_result)
1378         return AVERROR(ENOMEM);
1379
1380     s->cqt_align = 1;
1381     s->cqt_calc = cqt_calc;
1382     s->permute_coeffs = NULL;
1383     s->draw_sono = draw_sono;
1384     if (s->format == AV_PIX_FMT_RGB24) {
1385         s->draw_bar = draw_bar_rgb;
1386         s->draw_axis = draw_axis_rgb;
1387         s->update_sono = update_sono_rgb;
1388     } else {
1389         s->draw_bar = draw_bar_yuv;
1390         s->draw_axis = draw_axis_yuv;
1391         s->update_sono = update_sono_yuv;
1392     }
1393
1394     if (ARCH_X86)
1395         ff_showcqt_init_x86(s);
1396
1397     if ((ret = init_cqt(s)) < 0)
1398         return ret;
1399
1400     if (s->axis_h) {
1401         if (!s->axis) {
1402             if ((ret = init_axis_empty(s)) < 0)
1403                 return ret;
1404         } else if (s->axisfile) {
1405             if (init_axis_from_file(s) < 0) {
1406                 av_log(ctx, AV_LOG_WARNING, "loading axis image failed, fallback to font rendering.\n");
1407                 if (init_axis_from_font(s) < 0) {
1408                     av_log(ctx, AV_LOG_WARNING, "loading axis font failed, disable text drawing.\n");
1409                     if ((ret = init_axis_empty(s)) < 0)
1410                         return ret;
1411                 }
1412             }
1413         } else {
1414             if (init_axis_from_font(s) < 0) {
1415                 av_log(ctx, AV_LOG_WARNING, "loading axis font failed, disable text drawing.\n");
1416                 if ((ret = init_axis_empty(s)) < 0)
1417                     return ret;
1418             }
1419         }
1420     }
1421
1422     if (s->sono_h) {
1423         s->sono_frame = alloc_frame_empty((outlink->format == AV_PIX_FMT_YUV420P) ?
1424                         AV_PIX_FMT_YUV422P : outlink->format, s->width, s->sono_h);
1425         if (!s->sono_frame)
1426             return AVERROR(ENOMEM);
1427     }
1428
1429     s->h_buf = av_malloc_array(s->cqt_len, sizeof (*s->h_buf));
1430     s->rcp_h_buf = av_malloc_array(s->width, sizeof(*s->rcp_h_buf));
1431     s->c_buf = av_malloc_array(s->width, sizeof(*s->c_buf));
1432     if (!s->h_buf || !s->rcp_h_buf || !s->c_buf)
1433         return AVERROR(ENOMEM);
1434
1435     s->sono_count = 0;
1436     s->next_pts = 0;
1437     s->sono_idx = 0;
1438     s->remaining_fill = s->fft_len / 2;
1439     s->remaining_frac = 0;
1440     s->step_frac = av_div_q(av_make_q(inlink->sample_rate, s->count) , s->rate);
1441     s->step = (int)(s->step_frac.num / s->step_frac.den);
1442     s->step_frac.num %= s->step_frac.den;
1443     if (s->step_frac.num) {
1444         av_log(ctx, AV_LOG_INFO, "audio: %d Hz, step = %d + %d/%d.\n",
1445                inlink->sample_rate, s->step, s->step_frac.num, s->step_frac.den);
1446         av_log(ctx, AV_LOG_WARNING, "fractional step.\n");
1447     } else {
1448         av_log(ctx, AV_LOG_INFO, "audio: %d Hz, step = %d.\n",
1449                inlink->sample_rate, s->step);
1450     }
1451
1452     return 0;
1453 }
1454
1455
1456 static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
1457 {
1458     AVFilterContext *ctx = inlink->dst;
1459     AVFilterLink *outlink = ctx->outputs[0];
1460     ShowCQTContext *s = ctx->priv;
1461     int remaining, step, ret, x, i, j, m;
1462     float *audio_data;
1463     AVFrame *out = NULL;
1464
1465     if (!insamples) {
1466         while (s->remaining_fill < s->fft_len / 2) {
1467             memset(&s->fft_data[s->fft_len - s->remaining_fill], 0, sizeof(*s->fft_data) * s->remaining_fill);
1468             ret = plot_cqt(ctx, &out);
1469             if (ret < 0)
1470                 return ret;
1471
1472             step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den;
1473             s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den;
1474             for (x = 0; x < (s->fft_len-step); x++)
1475                 s->fft_data[x] = s->fft_data[x+step];
1476             s->remaining_fill += step;
1477
1478             if (out)
1479                 return ff_filter_frame(outlink, out);
1480         }
1481         return AVERROR_EOF;
1482     }
1483
1484     remaining = insamples->nb_samples;
1485     audio_data = (float*) insamples->data[0];
1486
1487     while (remaining) {
1488         i = insamples->nb_samples - remaining;
1489         j = s->fft_len - s->remaining_fill;
1490         if (remaining >= s->remaining_fill) {
1491             for (m = 0; m < s->remaining_fill; m++) {
1492                 s->fft_data[j+m].re = audio_data[2*(i+m)];
1493                 s->fft_data[j+m].im = audio_data[2*(i+m)+1];
1494             }
1495             ret = plot_cqt(ctx, &out);
1496             if (ret < 0) {
1497                 av_frame_free(&insamples);
1498                 return ret;
1499             }
1500             remaining -= s->remaining_fill;
1501             if (out) {
1502                 int64_t pts = av_rescale_q(insamples->pts, inlink->time_base, av_make_q(1, inlink->sample_rate));
1503                 pts += insamples->nb_samples - remaining - s->fft_len/2;
1504                 pts = av_rescale_q(pts, av_make_q(1, inlink->sample_rate), outlink->time_base);
1505                 if (FFABS(pts - out->pts) > PTS_TOLERANCE) {
1506                     av_log(ctx, AV_LOG_DEBUG, "changing pts from %"PRId64" (%.3f) to %"PRId64" (%.3f).\n",
1507                            out->pts, out->pts * av_q2d(outlink->time_base),
1508                            pts, pts * av_q2d(outlink->time_base));
1509                     out->pts = pts;
1510                     s->next_pts = pts + PTS_STEP;
1511                 }
1512                 ret = ff_filter_frame(outlink, out);
1513                 if (ret < 0) {
1514                     av_frame_free(&insamples);
1515                     return ret;
1516                 }
1517                 out = NULL;
1518             }
1519             step = s->step + (s->step_frac.num + s->remaining_frac) / s->step_frac.den;
1520             s->remaining_frac = (s->step_frac.num + s->remaining_frac) % s->step_frac.den;
1521             for (m = 0; m < s->fft_len-step; m++)
1522                 s->fft_data[m] = s->fft_data[m+step];
1523             s->remaining_fill = step;
1524         } else {
1525             for (m = 0; m < remaining; m++) {
1526                 s->fft_data[j+m].re = audio_data[2*(i+m)];
1527                 s->fft_data[j+m].im = audio_data[2*(i+m)+1];
1528             }
1529             s->remaining_fill -= remaining;
1530             remaining = 0;
1531         }
1532     }
1533     av_frame_free(&insamples);
1534     return 0;
1535 }
1536
1537 static int request_frame(AVFilterLink *outlink)
1538 {
1539     AVFilterLink *inlink = outlink->src->inputs[0];
1540     int ret;
1541
1542     ret = ff_request_frame(inlink);
1543     if (ret == AVERROR_EOF)
1544         ret = filter_frame(inlink, NULL);
1545     return ret;
1546 }
1547
1548 static const AVFilterPad showcqt_inputs[] = {
1549     {
1550         .name         = "default",
1551         .type         = AVMEDIA_TYPE_AUDIO,
1552         .filter_frame = filter_frame,
1553     },
1554     { NULL }
1555 };
1556
1557 static const AVFilterPad showcqt_outputs[] = {
1558     {
1559         .name          = "default",
1560         .type          = AVMEDIA_TYPE_VIDEO,
1561         .config_props  = config_output,
1562         .request_frame = request_frame,
1563     },
1564     { NULL }
1565 };
1566
1567 AVFilter ff_avf_showcqt = {
1568     .name          = "showcqt",
1569     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant/Clamped Q Transform) spectrum video output."),
1570     .init          = init,
1571     .uninit        = uninit,
1572     .query_formats = query_formats,
1573     .priv_size     = sizeof(ShowCQTContext),
1574     .inputs        = showcqt_inputs,
1575     .outputs       = showcqt_outputs,
1576     .priv_class    = &showcqt_class,
1577 };