#include "libavutil/eval.h"
#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
+#include "libavutil/random_seed.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/tree.h"
+#include "libavutil/lfg.h"
#include "avfilter.h"
#include "drawutils.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
-static const char *var_names[] = {
+static const char *const var_names[] = {
"E",
"PHI",
"PI",
NULL
};
+static const char *const fun2_names[] = {
+ "rand"
+};
+
+static double drand(void *opaque, double min, double max)
+{
+ return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
+}
+
+typedef double (*eval_func2)(void *, double a, double b);
+
+static const eval_func2 fun2[] = {
+ drand,
+ NULL
+};
+
enum var_name {
VAR_E,
VAR_PHI,
short int draw_box; ///< draw box around text - true or false
int use_kerning; ///< font kerning is used - true/false
int tabsize; ///< tab size
+ int fix_bounds; ///< do we let it go out of frame bounds - t/f
FT_Library library; ///< freetype font library handle
FT_Face face; ///< freetype font face handle
char *x_expr, *y_expr;
AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
double var_values[VAR_VARS_NB];
+ char *d_expr;
+ AVExpr *d_pexpr;
int draw; ///< set to zero to prevent drawing
+ AVLFG prng; ///< random
} DrawTextContext;
#define OFFSET(x) offsetof(DrawTextContext, x)
{"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX },
{"shadowy", "set y", OFFSET(shadowy), AV_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX },
{"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.dbl=4}, 0, INT_MAX },
+{"draw", "if false do not draw", OFFSET(d_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX },
+{"fix_bounds", "if true, check and fix text coords to avoid clipping",
+ OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
/* FT_LOAD_* flags */
{"ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, {.dbl=FT_LOAD_DEFAULT|FT_LOAD_RENDER}, 0, INT_MAX, 0, "ft_load_flags" },
static inline int is_newline(uint32_t c)
{
- return (c == '\n' || c == '\r' || c == '\f' || c == '\v');
+ return c == '\n' || c == '\r' || c == '\f' || c == '\v';
}
static int dtext_prepare_text(AVFilterContext *ctx)
/* get glyph */
dummy.code = code;
glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
- if (!glyph)
+ if (!glyph) {
ret = load_glyph(ctx, &glyph, code);
- if (ret) return ret;
+ if (ret)
+ return ret;
+ }
y_min = FFMIN(glyph->bbox.yMin, y_min);
y_max = FFMAX(glyph->bbox.yMax, y_max);
y = FFMIN(y + text_height, height - 1);
dtext->w = str_w;
+ dtext->var_values[VAR_TEXT_W] = dtext->var_values[VAR_TW] = dtext->w;
dtext->h = y;
+ dtext->var_values[VAR_TEXT_H] = dtext->var_values[VAR_TH] = dtext->h;
return 0;
}
dtext->var_values[VAR_N] = 0;
dtext->var_values[VAR_T] = NAN;
+ av_lfg_init(&dtext->prng, av_get_random_seed());
if ((ret = av_expr_parse(&dtext->x_pexpr, dtext->x_expr, var_names,
- NULL, NULL, NULL, NULL, 0, ctx)) < 0 ||
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
(ret = av_expr_parse(&dtext->y_pexpr, dtext->y_expr, var_names,
- NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
+ (ret = av_expr_parse(&dtext->d_pexpr, dtext->d_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
return AVERROR(EINVAL);
if ((ret =
{
AVFilterContext *ctx = inlink->dst;
DrawTextContext *dtext = ctx->priv;
+ int fail = 0;
if (dtext_prepare_text(ctx) < 0) {
av_log(ctx, AV_LOG_ERROR, "Can't draw text\n");
- dtext->draw = 0;
+ fail = 1;
}
dtext->var_values[VAR_T] = inpicref->pts == AV_NOPTS_VALUE ?
NAN : inpicref->pts * av_q2d(inlink->time_base);
dtext->var_values[VAR_X] =
- av_expr_eval(dtext->x_pexpr, dtext->var_values, NULL);
+ av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng);
dtext->var_values[VAR_Y] =
- av_expr_eval(dtext->y_pexpr, dtext->var_values, NULL);
+ av_expr_eval(dtext->y_pexpr, dtext->var_values, &dtext->prng);
dtext->var_values[VAR_X] =
- av_expr_eval(dtext->x_pexpr, dtext->var_values, NULL);
+ av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng);
+
+ dtext->draw = fail ? 0 :
+ av_expr_eval(dtext->d_pexpr, dtext->var_values, &dtext->prng);
normalize_double(&dtext->x, dtext->var_values[VAR_X]);
normalize_double(&dtext->y, dtext->var_values[VAR_Y]);
- if (dtext->x < 0) dtext->x = 0;
- if (dtext->y < 0) dtext->y = 0;
- if ((unsigned)dtext->x + (unsigned)dtext->w > inlink->w)
- dtext->x = inlink->w - dtext->w;
- if ((unsigned)dtext->y + (unsigned)dtext->h > inlink->h)
- dtext->y = inlink->h - dtext->h;
+ if (dtext->fix_bounds) {
+ if (dtext->x < 0) dtext->x = 0;
+ if (dtext->y < 0) dtext->y = 0;
+ if ((unsigned)dtext->x + (unsigned)dtext->w > inlink->w)
+ dtext->x = inlink->w - dtext->w;
+ if ((unsigned)dtext->y + (unsigned)dtext->h > inlink->h)
+ dtext->y = inlink->h - dtext->h;
+ }
dtext->x &= ~((1 << dtext->hsub) - 1);
dtext->y &= ~((1 << dtext->vsub) - 1);