Commit 0444733b authored by Nicolas George's avatar Nicolas George

lavfi/drawtext: add the reload option.

parent 83ddedbb
...@@ -1935,6 +1935,10 @@ parameter @var{text}. ...@@ -1935,6 +1935,10 @@ parameter @var{text}.
If both @var{text} and @var{textfile} are specified, an error is thrown. If both @var{text} and @var{textfile} are specified, an error is thrown.
@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 @item x, y
The expressions which specify the offsets where text will be drawn 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 within the video frame. They are relative to the top/left border of the
......
...@@ -167,6 +167,7 @@ typedef struct { ...@@ -167,6 +167,7 @@ typedef struct {
AVTimecode tc; ///< timecode context AVTimecode tc; ///< timecode context
int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
int frame_id; int frame_id;
int reload; ///< reload text file for each frame
} DrawTextContext; } DrawTextContext;
#define OFFSET(x) offsetof(DrawTextContext, x) #define OFFSET(x) offsetof(DrawTextContext, x)
...@@ -199,6 +200,7 @@ static const AVOption drawtext_options[]= { ...@@ -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}, {"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}, {"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}, {"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}, {"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 */ /* FT_LOAD_* flags */
...@@ -393,6 +395,29 @@ static int load_font(AVFilterContext *ctx) ...@@ -393,6 +395,29 @@ static int load_font(AVFilterContext *ctx)
return err; 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) static av_cold int init(AVFilterContext *ctx, const char *args)
{ {
int err; int err;
...@@ -411,28 +436,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args) ...@@ -411,28 +436,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
} }
if (dtext->textfile) { if (dtext->textfile) {
uint8_t *textbuf;
size_t textbuf_size;
if (dtext->text) { if (dtext->text) {
av_log(ctx, AV_LOG_ERROR, av_log(ctx, AV_LOG_ERROR,
"Both text and text file provided. Please provide only one\n"); "Both text and text file provided. Please provide only one\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) { if ((err = load_textfile(ctx)) < 0)
av_log(ctx, AV_LOG_ERROR,
"The text file '%s' could not be read or is empty\n",
dtext->textfile);
return err; 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) { if (dtext->tc_opt_string) {
int ret = av_timecode_init_from_string(&dtext->tc, dtext->tc_rate, int ret = av_timecode_init_from_string(&dtext->tc, dtext->tc_rate,
dtext->tc_opt_string, ctx); dtext->tc_opt_string, ctx);
...@@ -972,6 +987,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) ...@@ -972,6 +987,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
DrawTextContext *dtext = ctx->priv; DrawTextContext *dtext = ctx->priv;
int ret; int ret;
if (dtext->reload)
if ((ret = load_textfile(ctx)) < 0)
return ret;
dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
NAN : frame->pts * av_q2d(inlink->time_base); NAN : frame->pts * av_q2d(inlink->time_base);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment