summaryrefslogtreecommitdiff
path: root/libavfilter/vf_drawtext.c
diff options
context:
space:
mode:
authorBrett Harrison <brett.harrison@musicmastermind.com>2017-04-18 18:15:39 -0700
committerMichael Niedermayer <michael@niedermayer.cc>2017-04-19 12:39:05 +0200
commit6442e4ab3cab573e6f86bfa6db096afd8edef453 (patch)
treebb02bbf627b6de99d80273242ed71f56f4424e4e /libavfilter/vf_drawtext.c
parent61088051bd70e94224e8fbc95044ca1c6ca7240a (diff)
downloadffmpeg-6442e4ab3cab573e6f86bfa6db096afd8edef453.tar.gz
avfilter/vf_drawtext: added expr evaluation to drawtext fontsize
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavfilter/vf_drawtext.c')
-rw-r--r--libavfilter/vf_drawtext.c133
1 files changed, 116 insertions, 17 deletions
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 8b24f508e1..cba6cc803f 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -156,7 +156,10 @@ typedef struct DrawTextContext {
int max_glyph_h; ///< max glyph height
int shadowx, shadowy;
int borderw; ///< border width
+ char *fontsize_expr; ///< expression for fontsize
+ AVExpr *fontsize_pexpr; ///< parsed expressions for fontsize
unsigned int fontsize; ///< font size to use
+ unsigned int default_fontsize; ///< default font size to use
int line_spacing; ///< lines spacing in pixels
short int draw_box; ///< draw box around text - true or false
@@ -211,7 +214,7 @@ static const AVOption drawtext_options[]= {
{"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 , FLAGS},
{"boxborderw", "set box border width", OFFSET(boxborderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX,FLAGS},
- {"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX , FLAGS},
+ {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX , FLAGS},
{"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"shadowx", "set shadow x offset", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
@@ -281,6 +284,7 @@ typedef struct Glyph {
FT_Glyph glyph;
FT_Glyph border_glyph;
uint32_t code;
+ unsigned int fontsize;
FT_Bitmap bitmap; ///< array holding bitmaps of font
FT_Bitmap border_bitmap; ///< array holding bitmaps of font border
FT_BBox bbox;
@@ -293,7 +297,11 @@ static int glyph_cmp(const void *key, const void *b)
{
const Glyph *a = key, *bb = b;
int64_t diff = (int64_t)a->code - (int64_t)bb->code;
- return diff > 0 ? 1 : diff < 0 ? -1 : 0;
+
+ if (diff != 0)
+ return diff > 0 ? 1 : -1;
+ else
+ return FFDIFFSIGN((int64_t)a->fontsize, (int64_t)bb->fontsize);
}
/**
@@ -317,6 +325,7 @@ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
goto error;
}
glyph->code = code;
+ glyph->fontsize = s->fontsize;
if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
ret = AVERROR(EINVAL);
@@ -366,6 +375,76 @@ error:
return ret;
}
+static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
+{
+ int err;
+ DrawTextContext *s = ctx->priv;
+
+ if ((err = FT_Set_Pixel_Sizes(s->face, 0, fontsize))) {
+ av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
+ fontsize, FT_ERRMSG(err));
+ return AVERROR(EINVAL);
+ }
+
+ s->fontsize = fontsize;
+
+ return 0;
+}
+
+static av_cold int parse_fontsize(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+
+ if (s->fontsize_pexpr)
+ return 0;
+
+ if (s->fontsize_expr == NULL)
+ return AVERROR(EINVAL);
+
+ if ((err = av_expr_parse(&s->fontsize_pexpr, s->fontsize_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
+ return err;
+
+ return 0;
+}
+
+static av_cold int update_fontsize(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ unsigned int fontsize = s->default_fontsize;
+ int err;
+ double size, roundedsize;
+
+ // if no fontsize specified use the default
+ if (s->fontsize_expr != NULL) {
+ if ((err = parse_fontsize(ctx)) < 0)
+ return err;
+
+ size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
+
+ if (!isnan(size)) {
+ roundedsize = round(size);
+ // test for overflow before cast
+ if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
+ av_log(ctx, AV_LOG_ERROR, "fontsize overflow\n");
+ return AVERROR(EINVAL);
+ }
+
+ fontsize = roundedsize;
+ }
+ }
+
+ if (fontsize == 0)
+ fontsize = 1;
+
+ // no change
+ if (fontsize == s->fontsize)
+ return 0;
+
+ return set_fontsize(ctx, fontsize);
+}
+
static int load_font_file(AVFilterContext *ctx, const char *path, int index)
{
DrawTextContext *s = ctx->priv;
@@ -393,6 +472,7 @@ static int load_font_fontconfig(AVFilterContext *ctx)
int index;
double size;
int err = AVERROR(ENOENT);
+ int parse_err;
fontconfig = FcInitLoadConfigAndFonts();
if (!fontconfig) {
@@ -407,8 +487,18 @@ static int load_font_fontconfig(AVFilterContext *ctx)
}
FcPatternAddString(pat, FC_FAMILY, s->font);
- if (s->fontsize)
- FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize);
+
+ parse_err = parse_fontsize(ctx);
+ if (!parse_err) {
+ double size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
+
+ if (isnan(size)) {
+ av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
+ return AVERROR(EINVAL);
+ }
+
+ FcPatternAddDouble(pat, FC_SIZE, size);
+ }
FcDefaultSubstitute(pat);
@@ -442,8 +532,8 @@ static int load_font_fontconfig(AVFilterContext *ctx)
}
av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
- if (!s->fontsize)
- s->fontsize = size + 0.5;
+ if (parse_err)
+ s->default_fontsize = size + 0.5;
err = load_font_file(ctx, filename, index);
if (err)
@@ -598,6 +688,12 @@ static av_cold int init(AVFilterContext *ctx)
DrawTextContext *s = ctx->priv;
Glyph *glyph;
+ av_expr_free(s->fontsize_pexpr);
+ s->fontsize_pexpr = NULL;
+
+ s->fontsize = 0;
+ s->default_fontsize = 16;
+
if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
return AVERROR(EINVAL);
@@ -645,16 +741,11 @@ static av_cold int init(AVFilterContext *ctx)
return AVERROR(EINVAL);
}
- err = load_font(ctx);
- if (err)
+ if ((err = load_font(ctx)) < 0)
+ return err;
+
+ if ((err = update_fontsize(ctx)) < 0)
return err;
- if (!s->fontsize)
- s->fontsize = 16;
- if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
- av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
- s->fontsize, FT_ERRMSG(err));
- return AVERROR(EINVAL);
- }
if (s->borderw) {
if (FT_Stroker_New(s->library, &s->stroker)) {
@@ -709,11 +800,13 @@ static av_cold void uninit(AVFilterContext *ctx)
av_expr_free(s->x_pexpr);
av_expr_free(s->y_pexpr);
av_expr_free(s->a_pexpr);
- s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
+ av_expr_free(s->fontsize_pexpr);
+
+ s->x_pexpr = s->y_pexpr = s->a_pexpr = s->fontsize_pexpr = NULL;
+
av_freep(&s->positions);
s->nb_positions = 0;
-
av_tree_enumerate(s->glyphs, NULL, NULL, glyph_enu_free);
av_tree_destroy(s->glyphs);
s->glyphs = NULL;
@@ -1094,6 +1187,7 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
continue;
dummy.code = code;
+ dummy.fontsize = s->fontsize;
glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
@@ -1219,12 +1313,16 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
x = 0;
y = 0;
+ if ((ret = update_fontsize(ctx)) < 0)
+ return ret;
+
/* load and cache glyphs */
for (i = 0, p = text; *p; i++) {
GET_UTF8(code, *p++, continue;);
/* get glyph */
dummy.code = code;
+ dummy.fontsize = s->fontsize;
glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
if (!glyph) {
ret = load_glyph(ctx, &glyph, code);
@@ -1261,6 +1359,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
/* get glyph */
prev_glyph = glyph;
dummy.code = code;
+ dummy.fontsize = s->fontsize;
glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
/* kerning */