[FFmpeg-devel] [PATCH] drawtext: Allow textfile path to be expanded per frame
David Andreoletti
david at andreoletti.net
Mon May 11 17:31:59 EEST 2020
drawtext allows a file to be reloaded per frame. However,
the file to be reloaded is constant across frame. With
textfile now supporting text expansion, a different file can
be reloaded per frame. Eg: textfile=/path/fo/file{frame_num}.txt
Signed-off-by: David Andreoletti <david at andreoletti.net>
---
doc/filters.texi | 16 +++++++++++++---
libavfilter/vf_drawtext.c | 19 ++++++++++++++++---
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index d19fd346ae..460d65dd88 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -9659,13 +9659,13 @@ The default value of @var{borderw} is 0.
Set the color to be used for drawing border around text. For the syntax of this
option, check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}.
The default value of @var{bordercolor} is "black".
@item expansion
-Select how the @var{text} is expanded. Can be either @code{none},
+Select how the @var{text} and @var{textfile} are expanded. Can be either @code{none},
@code{strftime} (deprecated) or
@code{normal} (default). See the @ref{drawtext_expansion, Text expansion} section
below for details.
@item basetime
Set a start time for the count. Value is in microseconds. Only applied
@@ -9786,15 +9786,19 @@ of UTF-8 encoded characters.
This parameter is mandatory if no text string is specified with the
parameter @var{text}.
If both @var{text} and @var{textfile} are specified, an error is thrown.
+This parameter supports (per frame) variable expansion. Per frame variable
+expansion requires @code{reload=1}. See @var{expansion} for details.
+
+
@item reload
-If set to 1, the @var{textfile} will be reloaded before each frame.
-Be sure to update it atomically, or it may be read partially, or even fail.
+If set to 1, then before each frame, @var{textfile} file path will be expanded and then the file at said path will be reloaded.
+Be sure to update the file atomically, or it may be read partially, or even fail.
@item x
@item y
The expressions which specify the offsets where text will be drawn
within the video frame. They are relative to the top/left border of the
output image.
@@ -10060,12 +10064,18 @@ drawtext="fontsize=15:fontfile=FreeSerif.ttf:text=LONG_LINE:y=h-line_h:x=-50*t"
@item
Show the content of file @file{CREDITS} off the bottom of the frame and scroll up.
@example
drawtext="fontsize=20:fontfile=FreeSerif.ttf:textfile=CREDITS:y=h-20*t"
@end example
+ at item
+Each frame, reload a different text file at /path/to/frameX.txt, where X is replaced with the frame number being processed by the filter
+ at example
+drawtext="expansion:normal:textfile=/path/to/frame%@{frame_num@}.txt:reload=1"
+ at end example
+
@item
Draw a single green letter "g", at the center of the input video.
The glyph baseline is placed at half screen height.
@example
drawtext="fontsize=60:fontfile=FreeSerif.ttf:fontcolor=green:text=g:x=(w-max_glyph_w)/2:y=h/2-ascent"
@end example
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index abe1ca6c35..ffb1ff2330 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -152,13 +152,14 @@ typedef struct DrawTextContext {
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
- char *textfile; ///< file with text to be drawn
+ char *textfile; ///< filename with text to be drawn
+ AVBPrint expanded_textfile; ///< Same as textfile, except the filename can be expanded
int x; ///< x position to start drawing text
int y; ///< y position to start drawing text
int max_glyph_w; ///< max glyph width
int max_glyph_h; ///< max glyph height
int shadowx, shadowy;
int borderw; ///< border width
@@ -565,24 +566,33 @@ static int load_font(AVFilterContext *ctx)
if (!err)
return 0;
#endif
return err;
}
+static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp);
static int load_textfile(AVFilterContext *ctx)
{
DrawTextContext *s = ctx->priv;
int err;
uint8_t *textbuf;
uint8_t *tmp;
size_t textbuf_size;
- if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
+ if ((err = expand_text(ctx, s->textfile, &s->expanded_textfile)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "The text file path '%s' is not expandable\n",
+ s->textfile);
+ return err;
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "expanded_textfile:%s\n", s->expanded_textfile.str);
+
+ if ((err = av_file_map(s->expanded_textfile.str, &textbuf, &textbuf_size, 0, ctx)) < 0) {
av_log(ctx, AV_LOG_ERROR,
"The text file '%s' could not be read or is empty\n",
- s->textfile);
+ s->expanded_textfile.str);
return err;
}
if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
av_file_unmap(textbuf, textbuf_size);
return AVERROR(ENOMEM);
@@ -702,12 +712,14 @@ static av_cold int init(AVFilterContext *ctx)
if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
return AVERROR(EINVAL);
}
+ av_bprint_init(&s->expanded_textfile, 0, AV_BPRINT_SIZE_UNLIMITED);
+
if (s->textfile) {
if (s->text) {
av_log(ctx, AV_LOG_ERROR,
"Both text and text file provided. Please provide only one\n");
return AVERROR(EINVAL);
}
@@ -820,12 +832,13 @@ static av_cold void uninit(AVFilterContext *ctx)
FT_Done_Face(s->face);
FT_Stroker_Done(s->stroker);
FT_Done_FreeType(s->library);
av_bprint_finalize(&s->expanded_text, NULL);
av_bprint_finalize(&s->expanded_fontcolor, NULL);
+ av_bprint_finalize(&s->expanded_textfile, NULL);
}
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
--
2.26.2
More information about the ffmpeg-devel
mailing list