[FFmpeg-devel] [PATCH] allow vf_drawtext to draw framenumbers
Jean First
jeanfirst at gmail.com
Sat Apr 9 01:49:00 CEST 2011
simplified the patch and added some documentation.
---
doc/filters.texi | 14 ++++++++
libavfilter/vf_drawtext.c | 74 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 85 insertions(+), 3 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 5d63b5b..208170d 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -378,6 +378,12 @@ This parameter is mandatory.
@item text
The text string to be drawn. The text must be a sequence of UTF-8
encoded characters.
+
+Some special characters are defined:
+#f Unpadded frame number, starting with 1
+#F Four-digit padded frame number, starting with 0001
+The # (hash / number sign) character needs to be escaped with a double ##.
+
This parameter is mandatory if no file is specified with the parameter
@var{textfile}.
@@ -470,6 +476,14 @@ drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test
will draw "Test Text" with font FreeSerif, using the default values
for the optional parameters.
+For example the command:
+ at example
+drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Frame: #F'"
+ at end example
+
+will write four-digit padded continuos frame numbers prefixed with 'Frame: ' with font
+FreeSerif, using the default values for the optional parameters.
+
The command:
@example
drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test Text':\
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 99045b7..54da940 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -83,6 +83,7 @@ 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
} DrawTextContext;
#define OFFSET(x) offsetof(DrawTextContext, x)
@@ -213,6 +214,7 @@ 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->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 +500,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_text;
uint32_t code = 0;
int i;
uint8_t *p;
@@ -533,6 +535,61 @@ 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;
+
+ for ( ; *format; ++format) {
+ if (*format == '#') {
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+ case 'f':
+ pt = strconv(dtext->frame_index, "%d", pt, ptlim);
+ continue;
+ case 'F':
+ pt = strconv(dtext->frame_index, "%04d", pt, ptlim);
+ continue;
+ case '#':
+ default:
+ break;
+ }
+ }
+ if (pt == ptlim)
+ break;
+ *pt++ = *format;
+ }
+ 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,13 +604,24 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
FT_Vector delta;
Glyph *glyph = NULL, *prev_glyph = NULL;
Glyph dummy = { 0 };
+ size_t expanded_text_len;
+
+ dtext->frame_index++;
+
+ dtext->expanded_text[0] = '\1';
+ expanded_text_len = strfctx(dtext->expanded_text, MAX_EXPANDED_TEXT_SIZE, text, ctx);
+ text = dtext->expanded_text;
+ if (expanded_text_len == 0 && dtext->expanded_text[0] != '\0') {
+ av_log(ctx, AV_LOG_ERROR,
+ "Impossible to print text, string is too big\n");
+ return AVERROR(EINVAL);
+ }
#if HAVE_LOCALTIME_R
time_t now = time(0);
struct tm ltime;
- size_t expanded_text_len;
- dtext->expanded_text[0] = '\1';
+ expanded_text_len = 0;
expanded_text_len = strftime(dtext->expanded_text, MAX_EXPANDED_TEXT_SIZE,
text, localtime_r(&now, <ime));
text = dtext->expanded_text;
--
1.7.4.2
More information about the ffmpeg-devel
mailing list