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++) {
582 result[x][0] = l.
re * l.
re + l.
im * l.
im;
583 result[x][2] = r.
re * r.
re + r.
im * r.
im;
584 result[x][1] = 0.5f * (result[x][0] + result[x][2]);
587 result[x][3] = result[x][1];
588 else if (s->
gamma2 == 2.0f)
589 result[x][3] = sqrtf(result[x][1]);
590 else if (s->
gamma2 == 3.0f)
591 result[x][3] =
cbrtf(result[x][1]);
592 else if (s->
gamma2 == 4.0f)
593 result[x][3] = sqrtf(sqrtf(result[x][1]));
595 result[x][3] =
expf(logf(result[x][1]) * (1.0f / s->
gamma2));
597 result[x][0] =
FFMIN(1.0f, result[x][0]);
598 result[x][1] =
FFMIN(1.0f, result[x][1]);
599 result[x][2] =
FFMIN(1.0f, result[x][2]);
600 if (s->
gamma == 1.0f) {
601 result[x][0] = 255.0f * result[x][0];
602 result[x][1] = 255.0f * result[x][1];
603 result[x][2] = 255.0f * result[x][2];
604 }
else if (s->
gamma == 2.0f) {
605 result[x][0] = 255.0f * sqrtf(result[x][0]);
606 result[x][1] = 255.0f * sqrtf(result[x][1]);
607 result[x][2] = 255.0f * sqrtf(result[x][2]);
608 }
else if (s->
gamma == 3.0f) {
609 result[x][0] = 255.0f *
cbrtf(result[x][0]);
610 result[x][1] = 255.0f *
cbrtf(result[x][1]);
611 result[x][2] = 255.0f *
cbrtf(result[x][2]);
612 }
else if (s->
gamma == 4.0f) {
613 result[x][0] = 255.0f * sqrtf(sqrtf(result[x][0]));
614 result[x][1] = 255.0f * sqrtf(sqrtf(result[x][1]));
615 result[x][2] = 255.0f * sqrtf(sqrtf(result[x][2]));
617 result[x][0] = 255.0f *
expf(logf(result[x][0]) * (1.0f / s->
gamma));
618 result[x][1] = 255.0f *
expf(logf(result[x][1]) * (1.0f / s->
gamma));
619 result[x][2] = 255.0f *
expf(logf(result[x][2]) * (1.0f / s->
gamma));
624 for (x = 0; x < video_width; x++) {
625 result[x][0] = 0.5f * (result[2*x][0] + result[2*x+1][0]);
626 result[x][1] = 0.5f * (result[2*x][1] + result[2*x+1][1]);
627 result[x][2] = 0.5f * (result[2*x][2] + result[2*x+1][2]);
628 result[x][3] = 0.5f * (result[2*x][3] + result[2*x+1][3]);
632 for (x = 0; x < video_width; x++) {
641 float rcp_result[VIDEO_WIDTH];
642 int total_length = linesize * spectogram_height;
645 for (x = 0; x < video_width; x++)
646 rcp_result[x] = 1.0f / (result[x][3]+0.0001f);
649 for (y = 0; y < spectogram_height; y++) {
650 float height = (spectogram_height -
y) * (1.0f/spectogram_height);
651 uint8_t *lineptr = data + y * linesize;
652 for (x = 0; x < video_width; x++) {
654 if (result[x][3] <= height) {
659 mul = (result[x][3] -
height) * rcp_result[x];
660 *lineptr++ = mul * result[x][0] + 0.5f;
661 *lineptr++ = mul * result[x][1] + 0.5f;
662 *lineptr++ = mul * result[x][2] + 0.5f;
669 for (y = 0; y < font_height; y++) {
670 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
673 for (x = 0; x < video_width; x++) {
675 lineptr[3*x] = (spectogram_src[3*x] * (255-
alpha) + fontcolor_value[0] * alpha + 255) >> 8;
676 lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-
alpha) + fontcolor_value[1] * alpha + 255) >> 8;
677 lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-
alpha) + fontcolor_value[2] * alpha + 255) >> 8;
678 fontcolor_value += 3;
682 for (y = 0; y < font_height; y++) {
683 uint8_t *lineptr = data + (spectogram_height +
y) * linesize;
686 for (x = 0; x < video_width; x += video_width/10) {
688 static const char str[] =
"EF G A BC D ";
689 uint8_t *startptr = data + spectogram_height * linesize + x * 3;
690 for (u = 0; str[
u]; u++) {
692 for (v = 0; v < 16; v++) {
693 uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
694 int ux = x + 8 * u * video_scale;
696 for (mask = 0x80;
mask; mask >>= 1) {
701 if (video_scale == 2) {
703 p[linesize+1] = p[1];
704 p[linesize+2] = p[2];
710 p += 3 * video_scale;
719 data += spectogram_start * linesize;
722 data += total_length - back_length;
752 for (x = 0; x < (fft_len-step); x++)
760 audio_data = (
float*) insamples->
data[0];
777 for (m = 0; m < fft_len-step; m++)
784 for (m = 0; m < remaining; m++) {
833 .description =
NULL_IF_CONFIG_SMALL(
"Convert input audio to a CQT (Constant Q Transform) spectrum video output."),
839 .priv_class = &showcqt_class,
This structure describes decoded (raw) audio or video data.
ptrdiff_t const GLvoid * data
SparseCoeff * coeffs[VIDEO_WIDTH]
av_cold void av_fft_end(FFTContext *s)
static const AVOption showcqt_options[]
#define AV_LOG_WARNING
Something somehow does not look correct.
static const AVFilterPad outputs[]
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
int h
agreed upon image height
static av_cold void uninit(AVFilterContext *ctx)
const uint8_t avpriv_vga16_font[4096]
void av_fft_permute(FFTContext *s, FFTComplex *z)
Do the permutation needed BEFORE calling ff_fft_calc().
static enum AVSampleFormat formats[]
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
#define AV_CH_LAYOUT_STEREO
static int qsort_sparsecoeff(const SparseCoeff *a, const SparseCoeff *b)
static AVRational av_make_q(int num, int den)
Create a rational.
const char * name
Pad name.
AVFilterLink ** inputs
array of pointers to input links
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
static int64_t start_time
static av_always_inline av_const int isnan(float x)
FFTComplex * fft_result_right
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
static double a_weighting(void *p, double f)
FFTComplex * fft_result_left
#define AVERROR_EOF
End of file.
static double b_func(void *p, double x)
A filter pad used for either input or output.
A link between two filters.
static double alpha(void *priv, double x, double y)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
AVRational frame_rate
Frame rate of the stream on the link, or 1/0 if unknown; if left to 0/0, will be automatically be cop...
int sample_rate
samples per second
static const uint16_t mask[17]
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
static double b_weighting(void *p, double f)
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link...
simple assert() macros that are a bit more flexible than ISO C assert().
struct AVFilterChannelLayouts * out_channel_layouts
FFTContext * av_fft_init(int nbits, int inverse)
Set up a complex FFT.
AVFilterFormats * in_formats
Lists of formats and channel layouts supported by the input and output filters respectively.
static const AVFilterPad showcqt_outputs[]
#define SPECTOGRAM_HEIGHT
static const AVFilterPad showcqt_inputs[]
int w
agreed upon image width
#define FONTCOLOR_DEFAULT
audio channel layout utility functions
#define AV_CH_LAYOUT_STEREO_DOWNMIX
GLsizei GLboolean const GLfloat * value
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
AVFilterContext * src
source filter
static double r_func(void *p, double x)
AVFilterFormats * out_samplerates
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
static double g_func(void *p, double x)
A list of supported channel layouts.
#define AV_LOG_INFO
Standard information.
AVSampleFormat
Audio sample formats.
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
AVFILTER_DEFINE_CLASS(showcqt)
static av_always_inline float cbrtf(float x)
BYTE int const BYTE int int int height
Describe the class of an AVClass context structure.
int coeffs_len[VIDEO_WIDTH]
static const AVFilterPad inputs[]
static double midi(void *p, double f)
const char * name
Filter name.
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
AVFilterLink ** outputs
array of pointers to output links
enum MovChannelLayoutTag * layouts
static enum AVPixelFormat pix_fmts[]
static int config_output(AVFilterLink *outlink)
void * av_calloc(size_t nmemb, size_t size)
Allocate a block of nmemb * size bytes with alignment suitable for all memory accesses (including vec...
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
static int request_frame(AVFilterLink *outlink)
static int query_formats(AVFilterContext *ctx)
uint8_t fontcolor_value[VIDEO_WIDTH *3]
static const int16_t coeffs[]
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
AVFilterContext * dst
dest filter
static double c_weighting(void *p, double f)
static enum AVSampleFormat sample_fmts[]
#define av_malloc_array(a, b)
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
static int plot_cqt(AVFilterLink *inlink)
void av_fft_calc(FFTContext *s, FFTComplex *z)
Do a complex FFT with the parameters defined in av_fft_init().
AVPixelFormat
Pixel format.
int nb_samples
number of audio samples (per channel) described by this frame
#define AV_QSORT(p, num, type, cmp)
Quicksort This sort is fast, and fully inplace but not stable and it is possible to construct input t...
CGA/EGA/VGA ROM font data.
AVFilterFormats * out_formats
simple arithmetic expression evaluator