... | ... |
@@ -1935,6 +1935,10 @@ parameter @var{text}. |
1935 | 1935 |
|
1936 | 1936 |
If both @var{text} and @var{textfile} are specified, an error is thrown. |
1937 | 1937 |
|
1938 |
+@item reload |
|
1939 |
+If set to 1, the @var{textfile} will be reloaded before each frame. |
|
1940 |
+Be sure to update it atomically, or it may be read partially, or even fail. |
|
1941 |
+ |
|
1938 | 1942 |
@item x, y |
1939 | 1943 |
The expressions which specify the offsets where text will be drawn |
1940 | 1944 |
within the video frame. They are relative to the top/left border of the |
... | ... |
@@ -167,6 +167,7 @@ typedef struct { |
167 | 167 |
AVTimecode tc; ///< timecode context |
168 | 168 |
int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise |
169 | 169 |
int frame_id; |
170 |
+ int reload; ///< reload text file for each frame |
|
170 | 171 |
} DrawTextContext; |
171 | 172 |
|
172 | 173 |
#define OFFSET(x) offsetof(DrawTextContext, x) |
... | ... |
@@ -199,6 +200,7 @@ static const AVOption drawtext_options[]= { |
199 | 199 |
{"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS}, |
200 | 200 |
{"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS}, |
201 | 201 |
{"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS}, |
202 |
+{"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS}, |
|
202 | 203 |
{"fix_bounds", "if true, check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS}, |
203 | 204 |
|
204 | 205 |
/* FT_LOAD_* flags */ |
... | ... |
@@ -393,6 +395,29 @@ static int load_font(AVFilterContext *ctx) |
393 | 393 |
return err; |
394 | 394 |
} |
395 | 395 |
|
396 |
+static int load_textfile(AVFilterContext *ctx) |
|
397 |
+{ |
|
398 |
+ DrawTextContext *dtext = ctx->priv; |
|
399 |
+ int err; |
|
400 |
+ uint8_t *textbuf; |
|
401 |
+ size_t textbuf_size; |
|
402 |
+ |
|
403 |
+ if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) { |
|
404 |
+ av_log(ctx, AV_LOG_ERROR, |
|
405 |
+ "The text file '%s' could not be read or is empty\n", |
|
406 |
+ dtext->textfile); |
|
407 |
+ return err; |
|
408 |
+ } |
|
409 |
+ |
|
410 |
+ if (!(dtext->text = av_realloc(dtext->text, textbuf_size + 1))) |
|
411 |
+ return AVERROR(ENOMEM); |
|
412 |
+ memcpy(dtext->text, textbuf, textbuf_size); |
|
413 |
+ dtext->text[textbuf_size] = 0; |
|
414 |
+ av_file_unmap(textbuf, textbuf_size); |
|
415 |
+ |
|
416 |
+ return 0; |
|
417 |
+} |
|
418 |
+ |
|
396 | 419 |
static av_cold int init(AVFilterContext *ctx, const char *args) |
397 | 420 |
{ |
398 | 421 |
int err; |
... | ... |
@@ -411,28 +436,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args) |
411 | 411 |
} |
412 | 412 |
|
413 | 413 |
if (dtext->textfile) { |
414 |
- uint8_t *textbuf; |
|
415 |
- size_t textbuf_size; |
|
416 |
- |
|
417 | 414 |
if (dtext->text) { |
418 | 415 |
av_log(ctx, AV_LOG_ERROR, |
419 | 416 |
"Both text and text file provided. Please provide only one\n"); |
420 | 417 |
return AVERROR(EINVAL); |
421 | 418 |
} |
422 |
- if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) { |
|
423 |
- av_log(ctx, AV_LOG_ERROR, |
|
424 |
- "The text file '%s' could not be read or is empty\n", |
|
425 |
- dtext->textfile); |
|
419 |
+ if ((err = load_textfile(ctx)) < 0) |
|
426 | 420 |
return err; |
427 |
- } |
|
428 |
- |
|
429 |
- if (!(dtext->text = av_malloc(textbuf_size+1))) |
|
430 |
- return AVERROR(ENOMEM); |
|
431 |
- memcpy(dtext->text, textbuf, textbuf_size); |
|
432 |
- dtext->text[textbuf_size] = 0; |
|
433 |
- av_file_unmap(textbuf, textbuf_size); |
|
434 | 421 |
} |
435 | 422 |
|
423 |
+ if (dtext->reload && !dtext->textfile) |
|
424 |
+ av_log(ctx, AV_LOG_WARNING, "No file to reload\n"); |
|
425 |
+ |
|
436 | 426 |
if (dtext->tc_opt_string) { |
437 | 427 |
int ret = av_timecode_init_from_string(&dtext->tc, dtext->tc_rate, |
438 | 428 |
dtext->tc_opt_string, ctx); |
... | ... |
@@ -972,6 +987,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) |
972 | 972 |
DrawTextContext *dtext = ctx->priv; |
973 | 973 |
int ret; |
974 | 974 |
|
975 |
+ if (dtext->reload) |
|
976 |
+ if ((ret = load_textfile(ctx)) < 0) |
|
977 |
+ return ret; |
|
978 |
+ |
|
975 | 979 |
dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? |
976 | 980 |
NAN : frame->pts * av_q2d(inlink->time_base); |
977 | 981 |
|