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

Andrey Utkin andrey.krieger.utkin at gmail.com
Sun Jun 22 16:31:10 CEST 2014


---
 libavfilter/vf_drawtext.c | 68 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 63 insertions(+), 5 deletions(-)

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},
     {"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);
 }
 
 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;
+}
+
 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 */
+        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);
+    }
+
+
     x = 0;
     y = 0;
 
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list