[FFmpeg-devel] [PATCH 4/4] lavfi/drawtext: implement more generic expansion.
Stefano Sabatini
stefasab at gmail.com
Thu Nov 15 21:48:34 CET 2012
On date Thursday 2012-11-15 17:13:58 +0100, Nicolas George encoded:
> The new expansion mechanism uses the %{...} notation.
> For compatibility reasons, it must be enabled explicitly,
> but a warning is printed if a change is likely to happen.
>
> TODO micro bump
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> Changelog | 1 +
> doc/filters.texi | 55 ++++++++++++++-
> libavfilter/vf_drawtext.c | 167 +++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 214 insertions(+), 9 deletions(-)
>
>
> Implement Clément and Stefano's comments.
>
>
> diff --git a/Changelog b/Changelog
> index 9ef12b8..8fe99af 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -23,6 +23,7 @@ version <next>:
> - field filter ported from libmpcodecs
> - AVR demuxer
> - geq filter ported from libmpcodecs
> +- new expansion syntax for drawtext
>
>
> version 1.0:
> diff --git a/doc/filters.texi b/doc/filters.texi
> index b86b146..e75cd15 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -1844,8 +1844,7 @@ libfreetype library.
> To enable compilation of this filter you need to configure FFmpeg with
> @code{--enable-libfreetype}.
>
> -The filter also recognizes strftime() sequences in the provided text
> -and expands them accordingly. Check the documentation of strftime().
> + at subsection Syntax
>
> The filter accepts parameters as a list of @var{key}=@var{value} pairs,
> separated by ":".
> @@ -1875,6 +1874,12 @@ Default value is "1".
>
> See below for the list of accepted constants and functions.
>
> + at item expand
> +Select how the @var{text} is expanded. Can be either @code{none},
> + at code{strftime} (default for compatibity reasons but deprecated) or
> + at code{expand}. See the @ref{drawtext_expansion, Text expansion} section
> +below for details.
> +
> @item fix_bounds
> If true, check and fix text coords to avoid clipping.
>
> @@ -2039,6 +2044,46 @@ each other, so you can for example specify @code{y=x/dar}.
> If libavfilter was built with @code{--enable-fontconfig}, then
> @option{fontfile} can be a fontconfig pattern or omitted.
>
> + at anchor{drawtext_expansion}
> + at subsection Text expansion
> +
> +If @option{expand} is set to @code{strftime} (which is the default for now),
> +the filter recognizes strftime() sequences in the provided text and expands
> +them accordingly. Check the documentation of strftime(). This feature is
> +deprecated.
> +
> +If @option{expand} is set to @code{none}, the text is printed verbatim.
> +
> +If @option{expand} is set to @code{expand} (which will be the default), the
> +following expansion mechanism is used.
> +
> +The backslash character '\', followed by any character, always expand to the
expandS
> +second character.
> +
> +Sequence of the form @code{%@{...@}} are expanded. The text between the
> +braces is a function name, possibly followed by arguments separated by ':'.
> +If the arguments contain special characters or delimiters (':' or '@}'),
> +they should be escaped.
> Note that they probably must also be escaped as the
> +value for the @option{text} option in the filter argument string and as the
> +filter argument in the filter graph description, and possibly also for the
> +shell, that makes up to four levels of escaping; using a text file avoids
> +these problems.
This may go in a separate paragraph, to stand out better and keep the
previous normative paragraph short.
> +
> +The following functions are available:
> +
> + at table @command
> +
> + at item localtime
> +The time at which the filter is running, expressed in the local time zone.
> +It can accept an argument: a strftime() format string.
> +
> + at item pts
> +The timestamp of the current frame, in seconds, with microsecond accuracy.
> +
> + at end table
> +
> + at subsection Examples
> +
> Some examples follow.
>
> @itemize
> @@ -2104,6 +2149,12 @@ Use fontconfig to set the font. Note that the colons need to be escaped.
> drawtext='fontfile=Linux Libertine O-40\:style=Semibold:text=FFmpeg'
> @end example
>
> + at item
> +Print the date of a real-time encoding (see strftime(3)):
> + at example
> +drawtext='fontfile=FreeSans.ttf:expand=expand:text=%@{localtime:%a %b %d %Y@}'
> + at end example
> +
> @end itemize
>
> For more information about libfreetype, check:
> diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
> index f9c69ae..54c303c 100644
> --- a/libavfilter/vf_drawtext.c
> +++ b/libavfilter/vf_drawtext.c
> @@ -113,8 +113,15 @@ enum var_name {
> VAR_VARS_NB
> };
>
> +enum expansion_mode {
> + EXP_NONE,
> + EXP_EXPAND,
> + EXP_STRFTIME,
> +};
> +
> typedef struct {
> const AVClass *class;
> + enum expansion_mode exp_mode; ///< use old strftime-style expand
Needs to be updated.
> int reinit; ///< tells if the filter is being reinited
> uint8_t *fontfile; ///< font to be used
> uint8_t *text; ///< text to be drawn
> @@ -181,6 +188,10 @@ static const AVOption drawtext_options[]= {
> {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
> {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
> {"draw", "if false do not draw", OFFSET(draw_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS},
> +{"expand", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_STRFTIME}, 0, 2, FLAGS, "expand"},
maybe "expansion" (I tend to prefer a noun in this context)
> +{"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expand"},
> +{"expand", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_EXPAND}, 0, 0, FLAGS, "expand"},
foo=foo is a bit ugly, what about expand=normal?
> +{"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expand"},
Nit+: add empty lines around the group, easier to get they stand together.
> {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
> {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
> {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
> @@ -484,6 +495,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
> }
> dtext->tabsize *= glyph->advance;
>
> + if (dtext->exp_mode == EXP_STRFTIME &&
> + (strchr(dtext->text, '%') || strchr(dtext->text, '\\')))
> + av_log(ctx, AV_LOG_WARNING, "expand=strftime is deprecated.\n");
> +
> av_bprint_init(&dtext->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
>
> return 0;
> @@ -585,6 +600,138 @@ static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char
> return AVERROR(ENOSYS);
> }
>
> +static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
> + char *fct, unsigned argc, char **argv, int tag)
> +{
> + DrawTextContext *dtext = ctx->priv;
> +
> + av_bprintf(bp, "%.6f", dtext->var_values[VAR_T]);
> + return 0;
> +}
> +
> +#if !HAVE_LOCALTIME_R
> +static void localtime_r(const time_t *t, struct tm *tm)
> +{
> + *tm = localtime(t);
> +}
> +#endif
> +
> +static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
> + char *fct, unsigned argc, char **argv, int tag)
> +{
> + const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
> + time_t now;
> + struct tm tm;
> +
> + time(&now);
> + localtime_r(&now, &tm);
> + av_bprint_strftime(bp, fmt, &tm);
> + return 0;
> +}
> +
> +static const struct drawtext_function {
> + const char *name;
> + unsigned argc_min, argc_max;
> + int tag;
> + int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
> +} functions[] = {
> + { "pts", 0, 0, 0, func_pts },
> + { "localtime", 0, 1, 'L', func_strftime },
> +};
what's "tag" good for?
[...]
--
FFmpeg = Fascinating and Faithless Mythic Patchable Empowered Game
More information about the ffmpeg-devel
mailing list