[FFmpeg-devel] [PATCH 2/2] drawtext: introduce fontcolor argument expansion

Stefano Sabatini stefasab at gmail.com
Mon Jun 23 16:27:46 CEST 2014


On date Sunday 2014-06-22 17:31:10 +0300, Andrey Utkin encoded:
> ---
>  libavfilter/vf_drawtext.c | 68 +++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 63 insertions(+), 5 deletions(-)

Missing doc updates.

> 
> diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
> index adc587e..4ac7ab9 100644
> --- a/libavfilter/vf_drawtext.c
> +++ b/libavfilter/vf_drawtext.c
> @@ -35,6 +35,7 @@
>  #include <sys/stat.h>
>  #include <time.h>
>  #include <unistd.h>
> +#include <fenv.h>
>  
>  #if CONFIG_LIBFONTCONFIG
>  #include <fontconfig/fontconfig.h>
> @@ -136,6 +137,8 @@ typedef struct DrawTextContext {
>      uint8_t *fontfile;              ///< font to be used
>      uint8_t *text;                  ///< text to be drawn
>      AVBPrint expanded_text;         ///< used to contain the expanded text
> +    uint8_t *fontcolor_expr;        ///< fontcolor expression to evaluate
> +    AVBPrint expanded_fontcolor;    ///< used to contain the expanded fontcolor spec
>      int ft_load_flags;              ///< flags used for loading fonts, see FT_LOAD_*
>      FT_Vector *positions;           ///< positions for each element in the text
>      size_t nb_positions;            ///< number of elements of positions array
> @@ -191,6 +194,7 @@ static const AVOption drawtext_options[]= {
>      {"text",        "set text",             OFFSET(text),               AV_OPT_TYPE_STRING, {.str=NULL},  CHAR_MIN, CHAR_MAX, FLAGS},
>      {"textfile",    "set text file",        OFFSET(textfile),           AV_OPT_TYPE_STRING, {.str=NULL},  CHAR_MIN, CHAR_MAX, FLAGS},
>      {"fontcolor",   "set foreground color", OFFSET(fontcolor.rgba),     AV_OPT_TYPE_COLOR,  {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
> +    {"fontcolor_expr", "set foreground color expression to evaluate", OFFSET(fontcolor_expr),     AV_OPT_TYPE_STRING,  {.str=""}, CHAR_MIN, CHAR_MAX, FLAGS},
>      {"boxcolor",    "set box color",        OFFSET(boxcolor.rgba),      AV_OPT_TYPE_COLOR,  {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
>      {"bordercolor", "set border color",     OFFSET(bordercolor.rgba),   AV_OPT_TYPE_COLOR,  {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
>      {"shadowcolor", "set shadow color",     OFFSET(shadowcolor.rgba),   AV_OPT_TYPE_COLOR,  {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
> @@ -198,6 +202,7 @@ static const AVOption drawtext_options[]= {
>      {"fontsize",    "set font size",        OFFSET(fontsize),           AV_OPT_TYPE_INT,    {.i64=0},     0,        INT_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},
> +    {"fontcolor_expr", "set fontcolor expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""},   CHAR_MIN, CHAR_MAX, FLAGS},

Duplicate?

>      {"shadowx",     "set x",                OFFSET(shadowx),            AV_OPT_TYPE_INT,    {.i64=0},     INT_MIN,  INT_MAX , FLAGS},
>      {"shadowy",     "set y",                OFFSET(shadowy),            AV_OPT_TYPE_INT,    {.i64=0},     INT_MIN,  INT_MAX , FLAGS},
>      {"borderw",     "set border width",     OFFSET(borderw),            AV_OPT_TYPE_INT,    {.i64=0},     INT_MIN,  INT_MAX , FLAGS},
> @@ -569,6 +574,7 @@ static av_cold int init(AVFilterContext *ctx)
>          av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
>  
>      av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
> +    av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);
>  
>      return 0;
>  }
> @@ -612,6 +618,7 @@ static av_cold void uninit(AVFilterContext *ctx)
>      FT_Done_FreeType(s->library);
>  
>      av_bprint_finalize(&s->expanded_text, NULL);
> +    av_bprint_finalize(&s->expanded_fontcolor, NULL);
>  }
>  
yy>  static inline int is_newline(uint32_t c)
> @@ -800,6 +807,44 @@ 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;
> +
> +    /* Check that argv[0] (format) contains exactly one output specifier */
> +    const char *percent_sign = strchr(argv[0], '%');
> +    if (!percent_sign || strchr(percent_sign + 1, '%')) {
> +        av_log(ctx, AV_LOG_ERROR, "Format must contain exactly one output "
> +                "specifier, but '%s' is supplied\n", argv[0]);
> +        return AVERROR(EINVAL);
> +    }
> +    ret = av_expr_parse_and_eval(&res, argv[1], 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[1]);
> +    else
> +    {
> +        av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
> +                res, argv[1], argv[0]);
> +        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);
> +        }
> +        av_bprintf(bp, argv[0], intval);
> +    }
> +
> +    return ret;
> +}

If I understand it correctly this evaluates some expression of the
kind "%d" 42.00 -> "42", right? I'd prefer this in a separate patch,
also I believe this has some security implications (for example an
invalid format sequence may lead to a crash). Also how is this related
to $subject.

> +
>  static const struct drawtext_function {
>      const char *name;
>      unsigned argc_min, argc_max;
> @@ -808,6 +853,7 @@ static const struct drawtext_function {
>  } functions[] = {
>      { "expr",      1, 1, 0,   func_eval_expr },
>      { "e",         1, 1, 0,   func_eval_expr },
> +    { "eif",       2, 2, 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 },
> @@ -884,11 +930,8 @@ end:
>      return ret;
>  }
>  
> -static int expand_text(AVFilterContext *ctx)
> +static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
>  {
> -    DrawTextContext *s = ctx->priv;
> -    char *text = s->text;
> -    AVBPrint *bp = &s->expanded_text;
>      int ret;
>  
>      av_bprint_clear(bp);
> @@ -984,7 +1027,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
>          av_bprintf(bp, "%s", s->text);
>          break;
>      case EXP_NORMAL:
> -        if ((ret = expand_text(ctx)) < 0)
> +        if ((ret = expand_text(ctx, s->text, &s->expanded_text)) < 0)
>              return ret;
>          break;
>      case EXP_STRFTIME:
> @@ -1010,6 +1053,21 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
>          s->nb_positions = len;
>      }
>  
> +    if (s->fontcolor_expr[0]) {
> +        /* If expression is set, evaluate and repace statically set */

repace -> replace?

> +        av_bprint_clear(&s->expanded_fontcolor);
> +        if ((ret = expand_text(ctx, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
> +            return ret;
> +        if (!av_bprint_is_complete(&s->expanded_fontcolor))
> +            return AVERROR(ENOMEM);
> +        av_log(s, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
> +        ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
> +        if (ret)
> +            return ret;
> +        ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
> +    }
-- 
FFmpeg = Fierce and Fascinating Mere Ponderous Extended Guide


More information about the ffmpeg-devel mailing list