[FFmpeg-devel] [PATCH] allows vf_drawtext to draw some filter context and environment variables

Jean First jeanfirst at gmail.com
Fri Apr 8 11:49:51 CEST 2011


Signed-off-by: Jean First <jeanfirst at gmail.com>
---
 libavfilter/vf_drawtext.c |  132 ++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 131 insertions(+), 1 deletions(-)

diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 99045b7..240c6d0 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -54,6 +54,7 @@ typedef struct {
     int ft_load_flags;              ///< flags used for loading fonts, see FT_LOAD_*
     /** buffer containing the text expanded by strftime */
     char expanded_text[MAX_EXPANDED_TEXT_SIZE];
+    char expanded_text2[MAX_EXPANDED_TEXT_SIZE];
     /** positions for each element in the text */
     FT_Vector positions[MAX_EXPANDED_TEXT_SIZE];
     char *textfile;                 ///< file with text to be drawn
@@ -83,6 +84,9 @@ typedef struct {
     int pixel_step[4];              ///< distance in bytes between the component of each pixel
     uint8_t rgba_map[4];            ///< map RGBA offsets to the positions in the packed RGBA format
     uint8_t *box_line[4];           ///< line used for filling the box background
+    unsigned int frame_index;       ///< current frame index
+    char *username;                 ///< current username
+    char hostname[MAX_EXPANDED_TEXT_SIZE];///< current hostname
 } DrawTextContext;
 
 #define OFFSET(x) offsetof(DrawTextContext, x)
@@ -213,6 +217,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
     dtext->fontcolor_string = av_strdup("black");
     dtext->boxcolor_string = av_strdup("white");
     dtext->shadowcolor_string = av_strdup("black");
+    dtext->username = getenv("USER");
+    dtext->hostname[MAX_EXPANDED_TEXT_SIZE-1] = '\0';
+    gethostname(dtext->hostname, MAX_EXPANDED_TEXT_SIZE-1);
+    dtext->frame_index = 0;
 
     if ((err = (av_set_options_string(dtext, args, "=", ":"))) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
@@ -498,7 +506,7 @@ static inline void drawbox(AVFilterBufferRef *picref, unsigned int x, unsigned i
 static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
                        int width, int height, const uint8_t rgbcolor[4], const uint8_t yuvcolor[4], int x, int y)
 {
-    char *text = HAVE_LOCALTIME_R ? dtext->expanded_text : dtext->text;
+    char *text = dtext->expanded_text2;
     uint32_t code = 0;
     int i;
     uint8_t *p;
@@ -533,6 +541,116 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
     return 0;
 }
 
+static char *stradd(const char *str, char *pt, const char *ptlim)
+{
+    while (pt < ptlim && (*pt = *str++) != '\0')
+        ++pt;
+    return pt;
+}
+
+static char *strconv(const int n, const char *format, char *pt,
+                     const char *ptlim)
+{
+    char buf[MAX_EXPANDED_TEXT_SIZE];
+    (void) snprintf(buf, sizeof(buf), format, n);
+    return stradd(buf, pt, ptlim);
+}
+
+static char *strfmt(const char *format, char *pt, const char *ptlim, 
+                    AVFilterContext *ctx)
+{
+    DrawTextContext *dtext = ctx->priv;
+    char envkey[MAX_EXPANDED_TEXT_SIZE];
+    char *penvkey = envkey;
+    char *penvval;
+    int envfound = 0;
+    
+    for ( ; *format; ++format) {
+        if (*format != '#') {
+            *pt++ = *format;
+        }else{
+            switch (*++format) {
+            case '\0':
+                --format;
+                break;                
+            case 'c':
+                pt = stradd(dtext->fontcolor_string, pt, ptlim);
+                continue;
+            case 'E':
+                format++;
+                envfound = 1;
+                for ( ; *format; ++format) {
+                    switch (*format) {                    
+                    case '\0':
+                        envfound = 0;
+                        --format;
+                        break;
+                    case '#':
+                    case ' ':
+                        envfound = 0;
+                        break;
+                    default:
+                        *penvkey++ = *format;
+                        break;
+                    }
+                    if(!envfound)
+                        break;
+                }
+                *penvkey = '\0';
+                penvval = getenv(envkey);
+                if(penvval)
+                    pt = stradd(penvval, pt, ptlim);
+                envkey[0] = '\0';
+                penvkey = envkey;
+                continue;
+            case 'f':
+                pt = strconv(dtext->frame_index, "%d", pt, ptlim);
+                continue;
+            case 'F':
+                pt = strconv(dtext->frame_index, "%04d", pt, ptlim);
+                continue;
+            case 'U':
+                if(dtext->username)
+                    pt = stradd(dtext->username, pt, ptlim);
+                continue;
+            case 'H':
+                if(dtext->hostname)
+                    pt = stradd(dtext->hostname, pt, ptlim);
+                continue;
+            case 's':
+                pt = strconv(dtext->fontsize, "%d", pt, ptlim);
+                continue;
+            case 't':
+                pt = stradd(dtext->fontfile, pt, ptlim);
+                continue;
+            case 'x':
+                pt = strconv(dtext->x, "%d", pt, ptlim);
+                continue;
+            case 'y':
+                pt = strconv(dtext->y, "%d", pt, ptlim);
+                continue;
+            case '#':
+            default:
+                *pt++ = *format;
+            }
+        }
+        if (pt == ptlim)
+            break;
+    }
+    return pt;
+}
+
+static size_t strfctx(char *s, size_t maxsize, const char *format,
+                       AVFilterContext *ctx)
+{
+    char *p;
+    p = strfmt(((format == NULL) ? "%c" : format), s, s + maxsize, ctx);
+    if (p == s + maxsize)
+        return 0;
+    *p = '\0';
+    return p - s;
+}
+
 static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
                      int width, int height)
 {
@@ -547,6 +665,9 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
     FT_Vector delta;
     Glyph *glyph = NULL, *prev_glyph = NULL;
     Glyph dummy = { 0 };
+    size_t expanded_text_len2;
+    
+    dtext->frame_index++;
 
 #if HAVE_LOCALTIME_R
     time_t now = time(0);
@@ -564,6 +685,15 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
     }
 #endif
 
+    dtext->expanded_text2[0] = '\1';
+    expanded_text_len2 = strfctx(dtext->expanded_text2, MAX_EXPANDED_TEXT_SIZE, text, ctx);
+    text = dtext->expanded_text2;
+    if (expanded_text_len2 == 0 && dtext->expanded_text2[0] != '\0') {
+        av_log(ctx, AV_LOG_ERROR,
+               "Impossible to print text, string is too big\n");
+        return AVERROR(EINVAL);
+    }
+    
     str_w = str_w_max = 0;
     x = dtext->x;
     y = dtext->y;
-- 
1.7.4.2



More information about the ffmpeg-devel mailing list