avfilter/showcqt: adding freetype support

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Muhammad Faiz 2014-06-30 10:30:23 +07:00 committed by Michael Niedermayer
parent 9efa7f82ce
commit 46563af79c
2 changed files with 154 additions and 29 deletions

View File

@ -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.

View File

@ -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 */