[FFmpeg-devel] [PATCH] lavfi/drawtext: add the reload option.
Stefano Sabatini
stefasab at gmail.com
Sun Dec 2 23:54:41 CET 2012
On date Sunday 2012-12-02 19:59:27 +0100, Nicolas George encoded:
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> doc/filters.texi | 4 ++++
> libavfilter/vf_drawtext.c | 47 +++++++++++++++++++++++++++++++--------------
> 2 files changed, 37 insertions(+), 14 deletions(-)
>
>
> Requested by someone on the users mailing-list.
>
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index e25f548..3a6fa04 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -1964,6 +1964,10 @@ parameter @var{text}.
>
> If both @var{text} and @var{textfile} are specified, an error is thrown.
>
> + at 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.
> +
> @item x, 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
> diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
> index 5fff9bf..43f9844 100644
> --- a/libavfilter/vf_drawtext.c
> +++ b/libavfilter/vf_drawtext.c
> @@ -167,6 +167,7 @@ typedef struct {
> AVTimecode tc; ///< timecode context
> int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
> int frame_id;
> + int reload; ///< reload text file for each frame
> } DrawTextContext;
>
> #define OFFSET(x) offsetof(DrawTextContext, x)
> @@ -199,6 +200,7 @@ static const AVOption drawtext_options[]= {
> {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
> {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
> {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
> +{"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
> {"fix_bounds", "if true, check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
>
> /* FT_LOAD_* flags */
> @@ -393,6 +395,29 @@ static int load_font(AVFilterContext *ctx)
> return err;
> }
>
> +static int load_textfile(AVFilterContext *ctx)
> +{
> + DrawTextContext *dtext = ctx->priv;
> + int err;
> + uint8_t *textbuf;
> + size_t textbuf_size;
> +
> + if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
> + av_log(ctx, AV_LOG_ERROR,
> + "The text file '%s' could not be read or is empty\n",
> + dtext->textfile);
> + return err;
> + }
> +
> + if (!(dtext->text = av_realloc(dtext->text, textbuf_size + 1)))
> + return AVERROR(ENOMEM);
> + memcpy(dtext->text, textbuf, textbuf_size);
> + dtext->text[textbuf_size] = 0;
> + av_file_unmap(textbuf, textbuf_size);
> +
> + return 0;
> +}
> +
> static av_cold int init(AVFilterContext *ctx, const char *args)
> {
> int err;
> @@ -411,28 +436,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
> }
>
> if (dtext->textfile) {
> - uint8_t *textbuf;
> - size_t textbuf_size;
> -
> if (dtext->text) {
> av_log(ctx, AV_LOG_ERROR,
> "Both text and text file provided. Please provide only one\n");
> return AVERROR(EINVAL);
> }
> - if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
> - av_log(ctx, AV_LOG_ERROR,
> - "The text file '%s' could not be read or is empty\n",
> - dtext->textfile);
> + if ((err = load_textfile(ctx)) < 0)
> return err;
> - }
> -
> - if (!(dtext->text = av_malloc(textbuf_size+1)))
> - return AVERROR(ENOMEM);
> - memcpy(dtext->text, textbuf, textbuf_size);
> - dtext->text[textbuf_size] = 0;
> - av_file_unmap(textbuf, textbuf_size);
> }
>
> + if (dtext->reload && !dtext->textfile)
> + av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
> +
> if (dtext->tc_opt_string) {
> int ret = av_timecode_init_from_string(&dtext->tc, dtext->tc_rate,
> dtext->tc_opt_string, ctx);
> @@ -972,6 +987,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
> DrawTextContext *dtext = ctx->priv;
> int ret;
>
> + if (dtext->reload)
> + if ((ret = load_textfile(ctx)) < 0)
> + return ret;
My only concern is that reloading a file for each frame (thus possibly
several times in a second) doesn't sound very good.
Alternative solutions: the user injects an event (through a dedicated
event handler filter?) to reload the textfile, or it sends metadata
which is then read by drawtext (via the expansion mechanism, something
like %{metadata:text}.
But again, I'm not conceptually opposed to this patch, but we should
start to think about a more flexible (and efficient) solution.
--
FFmpeg = Fierce and Free Magic Political Extreme Glue
More information about the ffmpeg-devel
mailing list