mirror of https://git.ffmpeg.org/ffmpeg.git
avfilter/showcqt: adding freetype support
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
9efa7f82ce
commit
46563af79c
|
@ -10430,6 +10430,9 @@ Specify gamma. Lower gamma makes the spectrum more contrast, higher gamma
|
||||||
makes the spectrum having more range. Acceptable value is [1.0, 7.0].
|
makes the spectrum having more range. Acceptable value is [1.0, 7.0].
|
||||||
Default value is @code{3.0}.
|
Default value is @code{3.0}.
|
||||||
|
|
||||||
|
@item fontfile
|
||||||
|
Specify font file for use with freetype. If not specified, use embedded font.
|
||||||
|
|
||||||
@item fullhd
|
@item fullhd
|
||||||
If set to 1 (the default), the video size is 1920x1080 (full HD),
|
If set to 1 (the default), the video size is 1920x1080 (full HD),
|
||||||
if set to 0, the video size is 960x540. Use this option to make CPU usage lower.
|
if set to 0, the video size is 960x540. Use this option to make CPU usage lower.
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "libavcodec/avfft.h"
|
#include "libavcodec/avfft.h"
|
||||||
#include "libavutil/avassert.h"
|
#include "libavutil/avassert.h"
|
||||||
#include "libavutil/channel_layout.h"
|
#include "libavutil/channel_layout.h"
|
||||||
|
@ -31,6 +32,11 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if CONFIG_LIBFREETYPE
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#endif
|
||||||
|
|
||||||
/* this filter is designed to do 16 bins/semitones constant Q transform with Brown-Puckette algorithm
|
/* this filter is designed to do 16 bins/semitones constant Q transform with Brown-Puckette algorithm
|
||||||
* start from E0 to D#10 (10 octaves)
|
* start from E0 to D#10 (10 octaves)
|
||||||
* so there are 16 bins/semitones * 12 semitones/octaves * 10 octaves = 1920 bins
|
* so there are 16 bins/semitones * 12 semitones/octaves * 10 octaves = 1920 bins
|
||||||
|
@ -59,6 +65,8 @@ typedef struct {
|
||||||
uint8_t *spectogram;
|
uint8_t *spectogram;
|
||||||
SparseCoeff *coeff_sort;
|
SparseCoeff *coeff_sort;
|
||||||
SparseCoeff *coeffs[VIDEO_WIDTH];
|
SparseCoeff *coeffs[VIDEO_WIDTH];
|
||||||
|
uint8_t *font_alpha;
|
||||||
|
char *fontfile; /* using freetype */
|
||||||
int coeffs_len[VIDEO_WIDTH];
|
int coeffs_len[VIDEO_WIDTH];
|
||||||
uint8_t font_color[VIDEO_WIDTH];
|
uint8_t font_color[VIDEO_WIDTH];
|
||||||
int64_t frame_count;
|
int64_t frame_count;
|
||||||
|
@ -87,6 +95,7 @@ static const AVOption showcqt_options[] = {
|
||||||
{ "fullhd", "set full HD resolution", OFFSET(fullhd), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
|
{ "fullhd", "set full HD resolution", OFFSET(fullhd), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
|
||||||
{ "fps", "set video fps", OFFSET(fps), AV_OPT_TYPE_INT, { .i64 = 25 }, 10, 100, FLAGS },
|
{ "fps", "set video fps", OFFSET(fps), AV_OPT_TYPE_INT, { .i64 = 25 }, 10, 100, FLAGS },
|
||||||
{ "count", "set number of transform per frame", OFFSET(count), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 30, FLAGS },
|
{ "count", "set number of transform per frame", OFFSET(count), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 30, FLAGS },
|
||||||
|
{ "fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,6 +115,7 @@ static av_cold void uninit(AVFilterContext *ctx)
|
||||||
av_freep(&s->fft_result_right);
|
av_freep(&s->fft_result_right);
|
||||||
av_freep(&s->coeff_sort);
|
av_freep(&s->coeff_sort);
|
||||||
av_freep(&s->spectogram);
|
av_freep(&s->spectogram);
|
||||||
|
av_freep(&s->font_alpha);
|
||||||
av_frame_free(&s->outpicref);
|
av_frame_free(&s->outpicref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +155,97 @@ static int query_formats(AVFilterContext *ctx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LIBFREETYPE
|
||||||
|
static void load_freetype_font(AVFilterContext *ctx)
|
||||||
|
{
|
||||||
|
static const char str[] = "EF G A BC D ";
|
||||||
|
ShowCQTContext *s = ctx->priv;
|
||||||
|
FT_Library lib = NULL;
|
||||||
|
FT_Face face = NULL;
|
||||||
|
int video_scale = s->fullhd ? 2 : 1;
|
||||||
|
int video_width = (VIDEO_WIDTH/2) * video_scale;
|
||||||
|
int font_height = (FONT_HEIGHT/2) * video_scale;
|
||||||
|
int font_width = 8 * video_scale;
|
||||||
|
int font_repeat = font_width * 12;
|
||||||
|
int linear_hori_advance = font_width * 65536;
|
||||||
|
int non_monospace_warning = 0;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
s->font_alpha = NULL;
|
||||||
|
|
||||||
|
if (!s->fontfile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (FT_Init_FreeType(&lib))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (FT_New_Face(lib, s->fontfile, 0, &face))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (FT_Set_Char_Size(face, 16*64, 0, 0, 0))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (FT_Load_Char(face, 'A', FT_LOAD_RENDER))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (FT_Set_Char_Size(face, 16*64 * linear_hori_advance / face->glyph->linearHoriAdvance, 0, 0, 0))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
s->font_alpha = av_malloc(font_height * video_width);
|
||||||
|
if (!s->font_alpha)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
memset(s->font_alpha, 0, font_height * video_width);
|
||||||
|
|
||||||
|
for (x = 0; x < 12; x++) {
|
||||||
|
int sx, sy, rx, bx, by, dx, dy;
|
||||||
|
|
||||||
|
if (str[x] == ' ')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (FT_Load_Char(face, str[x], FT_LOAD_RENDER))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (face->glyph->advance.x != font_width*64 && !non_monospace_warning) {
|
||||||
|
av_log(ctx, AV_LOG_WARNING, "Font is not monospace\n");
|
||||||
|
non_monospace_warning = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sy = font_height - 4*video_scale - face->glyph->bitmap_top;
|
||||||
|
for (rx = 0; rx < 10; rx++) {
|
||||||
|
sx = rx * font_repeat + x * font_width + face->glyph->bitmap_left;
|
||||||
|
for (by = 0; by < face->glyph->bitmap.rows; by++) {
|
||||||
|
dy = by + sy;
|
||||||
|
if (dy < 0)
|
||||||
|
continue;
|
||||||
|
if (dy >= font_height)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (bx = 0; bx < face->glyph->bitmap.width; bx++) {
|
||||||
|
dx = bx + sx;
|
||||||
|
if (dx < 0)
|
||||||
|
continue;
|
||||||
|
if (dx >= video_width)
|
||||||
|
break;
|
||||||
|
s->font_alpha[dy*video_width+dx] = face->glyph->bitmap.buffer[by*face->glyph->bitmap.width+bx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(lib);
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
av_log(ctx, AV_LOG_WARNING, "Error while loading freetype font, using default font instead\n");
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(lib);
|
||||||
|
av_freep(&s->font_alpha);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline int qsort_sparsecoeff(const SparseCoeff *a, const SparseCoeff *b)
|
static inline int qsort_sparsecoeff(const SparseCoeff *a, const SparseCoeff *b)
|
||||||
{
|
{
|
||||||
if (fabsf(a->value) >= fabsf(b->value))
|
if (fabsf(a->value) >= fabsf(b->value))
|
||||||
|
@ -196,6 +297,14 @@ static int config_output(AVFilterLink *outlink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_LIBFREETYPE
|
||||||
|
load_freetype_font(ctx);
|
||||||
|
#else
|
||||||
|
if (s->fontfile)
|
||||||
|
av_log(ctx, AV_LOG_WARNING, "Freetype is not available, ignoring fontfile option\n");
|
||||||
|
s->font_alpha = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
av_log(ctx, AV_LOG_INFO, "Calculating spectral kernel, please wait\n");
|
av_log(ctx, AV_LOG_INFO, "Calculating spectral kernel, please wait\n");
|
||||||
start_time = av_gettime_relative();
|
start_time = av_gettime_relative();
|
||||||
for (k = 0; k < VIDEO_WIDTH; k++) {
|
for (k = 0; k < VIDEO_WIDTH; k++) {
|
||||||
|
@ -413,40 +522,53 @@ static int plot_cqt(AVFilterLink *inlink)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* drawing font */
|
/* drawing font */
|
||||||
for (y = 0; y < font_height; y++) {
|
if (s->font_alpha) {
|
||||||
uint8_t *lineptr = data + (spectogram_height + y) * linesize;
|
for (y = 0; y < font_height; y++) {
|
||||||
memcpy(lineptr, s->spectogram + s->spectogram_index * linesize, video_width*3);
|
uint8_t *lineptr = data + (spectogram_height + y) * linesize;
|
||||||
}
|
uint8_t *spectogram_src = s->spectogram + s->spectogram_index * linesize;
|
||||||
for (x = 0; x < video_width; x += video_width/10) {
|
for (x = 0; x < video_width; x++) {
|
||||||
int u;
|
uint8_t alpha = s->font_alpha[y*video_width+x];
|
||||||
static const char str[] = "EF G A BC D ";
|
uint8_t color = s->font_color[x];
|
||||||
uint8_t *startptr = data + spectogram_height * linesize + x * 3;
|
lineptr[3*x] = (spectogram_src[3*x] * (255-alpha) + (255-color) * alpha + 255) >> 8;
|
||||||
for (u = 0; str[u]; u++) {
|
lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-alpha) + 255) >> 8;
|
||||||
int v;
|
lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-alpha) + color * alpha + 255) >> 8;
|
||||||
for (v = 0; v < 16; v++) {
|
}
|
||||||
uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
|
}
|
||||||
int ux = x + 8 * u * video_scale;
|
} else {
|
||||||
int mask;
|
for (y = 0; y < font_height; y++) {
|
||||||
for (mask = 0x80; mask; mask >>= 1) {
|
uint8_t *lineptr = data + (spectogram_height + y) * linesize;
|
||||||
if (mask & avpriv_vga16_font[str[u] * 16 + v]) {
|
memcpy(lineptr, s->spectogram + s->spectogram_index * linesize, video_width*3);
|
||||||
p[0] = 255 - s->font_color[ux];
|
}
|
||||||
p[1] = 0;
|
for (x = 0; x < video_width; x += video_width/10) {
|
||||||
p[2] = s->font_color[ux];
|
int u;
|
||||||
if (video_scale == 2) {
|
static const char str[] = "EF G A BC D ";
|
||||||
p[linesize] = p[0];
|
uint8_t *startptr = data + spectogram_height * linesize + x * 3;
|
||||||
p[linesize+1] = p[1];
|
for (u = 0; str[u]; u++) {
|
||||||
p[linesize+2] = p[2];
|
int v;
|
||||||
p[3] = p[linesize+3] = 255 - s->font_color[ux+1];
|
for (v = 0; v < 16; v++) {
|
||||||
p[4] = p[linesize+4] = 0;
|
uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
|
||||||
p[5] = p[linesize+5] = s->font_color[ux+1];
|
int ux = x + 8 * u * video_scale;
|
||||||
|
int mask;
|
||||||
|
for (mask = 0x80; mask; mask >>= 1) {
|
||||||
|
if (mask & avpriv_vga16_font[str[u] * 16 + v]) {
|
||||||
|
p[0] = 255 - s->font_color[ux];
|
||||||
|
p[1] = 0;
|
||||||
|
p[2] = s->font_color[ux];
|
||||||
|
if (video_scale == 2) {
|
||||||
|
p[linesize] = p[0];
|
||||||
|
p[linesize+1] = p[1];
|
||||||
|
p[linesize+2] = p[2];
|
||||||
|
p[3] = p[linesize+3] = 255 - s->font_color[ux+1];
|
||||||
|
p[4] = p[linesize+4] = 0;
|
||||||
|
p[5] = p[linesize+5] = s->font_color[ux+1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
p += 3 * video_scale;
|
||||||
|
ux += video_scale;
|
||||||
}
|
}
|
||||||
p += 3 * video_scale;
|
|
||||||
ux += video_scale;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* drawing spectogram/sonogram */
|
/* drawing spectogram/sonogram */
|
||||||
|
|
Loading…
Reference in New Issue