From dec87454deb2f2a314f309cd6c1fa636503a70ae Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Fri, 4 Jul 2014 12:16:16 +0300 Subject: [PATCH] lavfi/drawtext: add expansion function eif() It evaluates expression and outputs it as integer value, using specified format. Address trac ticket #3699. Signed-off-by: Stefano Sabatini --- doc/filters.texi | 9 ++++++ libavfilter/version.h | 2 +- libavfilter/vf_drawtext.c | 62 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/doc/filters.texi b/doc/filters.texi index 0f73314a12..6bea105d36 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -3911,6 +3911,15 @@ example the text size is not known when evaluating the expression, so the constants @var{text_w} and @var{text_h} will have an undefined value. +@item eif +Evaluate the expression's value and output as formatted integer. + +First argument is expression to be evaluated, same as for @var{expr} function. +Second argument specifies output format. Allowed values are 'x', 'X', 'd' and +'u', they are treated exactly as in printf function. +Third parameter is optional and sets the number of positions taken by output. +Effectively this allows to add padding with zeros from the left. + @item gmtime The time at which the filter is running, expressed in UTC. It can accept an argument: a strftime() format string. diff --git a/libavfilter/version.h b/libavfilter/version.h index 227d3203ff..8f47a9683e 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #define LIBAVFILTER_VERSION_MAJOR 4 #define LIBAVFILTER_VERSION_MINOR 11 -#define LIBAVFILTER_VERSION_MICRO 100 +#define LIBAVFILTER_VERSION_MICRO 101 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index 0b93d14533..3336eb2dc7 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -37,6 +37,7 @@ #if HAVE_UNISTD_H #include #endif +#include #if CONFIG_LIBFONTCONFIG #include @@ -908,6 +909,66 @@ static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp, return ret; } +static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp, + char *fct, unsigned argc, char **argv, int tag) +{ + DrawTextContext *s = ctx->priv; + double res; + int intval; + int ret; + unsigned int positions = 0; + char fmt_str[30] = "%"; + + /* + * argv[0] expression to be converted to `int` + * argv[1] format: 'x', 'X', 'd' or 'u' + * argv[2] positions printed (optional) + */ + + ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values, + NULL, NULL, fun2_names, fun2, + &s->prng, 0, ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, + "Expression '%s' for the expr text expansion function is not valid\n", + argv[0]); + return ret; + } + + if (!strchr("xXdu", argv[1][0])) { + av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified," + " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]); + return AVERROR(EINVAL); + } + + if (argc == 3) { + ret = sscanf(argv[2], "%u", &positions); + if (ret != 1) { + av_log(ctx, AV_LOG_ERROR, "eif(): Invalid number of positions" + " to print: '%s'\n", argv[2]); + return AVERROR(EINVAL); + } + } + + feclearexcept(FE_ALL_EXCEPT); + intval = res; + if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) { + av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval); + return AVERROR(EINVAL); + } + + if (argc == 3) + av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions); + av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]); + + av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n", + res, argv[0], fmt_str); + + av_bprintf(bp, fmt_str, intval); + + return 0; +} + static const struct drawtext_function { const char *name; unsigned argc_min, argc_max; @@ -916,6 +977,7 @@ static const struct drawtext_function { } functions[] = { { "expr", 1, 1, 0, func_eval_expr }, { "e", 1, 1, 0, func_eval_expr }, + { "eif", 2, 3, 0, func_eval_expr_int_format }, { "pict_type", 0, 0, 0, func_pict_type }, { "pts", 0, 2, 0, func_pts }, { "gmtime", 0, 1, 'G', func_strftime },