"x",
"y",
"pict_type",
+ "pkt_pos",
+ "pkt_duration",
+ "pkt_size",
NULL
};
VAR_X,
VAR_Y,
VAR_PICT_TYPE,
+ VAR_PKT_POS,
+ VAR_PKT_DURATION,
+ VAR_PKT_SIZE,
VAR_VARS_NB
};
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption drawtext_options[]= {
- {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
+ {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
+ {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
+ {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
+ {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, 0, 0, FLAGS},
+ {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, 0, 0, FLAGS},
+ {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
+ {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
{"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 , FLAGS},
{"boxborderw", "set box border width", OFFSET(boxborderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX,FLAGS},
- {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX , FLAGS},
- {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
- {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0 , FLAGS},
+ {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
+ {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
{"shadowx", "set shadow x offset", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"shadowy", "set shadow y offset", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
{"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
- {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
{"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, 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},
return err;
}
+static inline int is_newline(uint32_t c)
+{
+ return c == '\n' || c == '\r' || c == '\f' || c == '\v';
+}
+
static int load_textfile(AVFilterContext *ctx)
{
DrawTextContext *s = ctx->priv;
return err;
}
+ if (textbuf_size > 0 && is_newline(textbuf[textbuf_size - 1]))
+ textbuf_size--;
if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
av_file_unmap(textbuf, textbuf_size);
return AVERROR(ENOMEM);
return 0;
}
-static inline int is_newline(uint32_t c)
-{
- return c == '\n' || c == '\r' || c == '\f' || c == '\v';
-}
-
#if CONFIG_LIBFRIBIDI
static int shape_text(AVFilterContext *ctx)
{
{
AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
+ char *expr;
int ret;
ff_draw_init(&s->dc, inlink->format, FF_DRAW_PROCESS_ALPHA);
av_expr_free(s->a_pexpr);
s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
- if ((ret = av_expr_parse(&s->x_pexpr, s->x_expr, var_names,
+ if ((ret = av_expr_parse(&s->x_pexpr, expr = s->x_expr, var_names,
NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
- (ret = av_expr_parse(&s->y_pexpr, s->y_expr, var_names,
+ (ret = av_expr_parse(&s->y_pexpr, expr = s->y_expr, var_names,
NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
- (ret = av_expr_parse(&s->a_pexpr, s->a_expr, var_names,
- NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
-
+ (ret = av_expr_parse(&s->a_pexpr, expr = s->a_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to parse expression: %s \n", expr);
return AVERROR(EINVAL);
+ }
return 0;
}
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
{
- DrawTextContext *s = ctx->priv;
+ DrawTextContext *old = ctx->priv;
+ DrawTextContext *new = NULL;
+ int ret;
if (!strcmp(cmd, "reinit")) {
- int ret;
+ new = av_mallocz(sizeof(DrawTextContext));
+ if (!new)
+ return AVERROR(ENOMEM);
+
+ new->class = &drawtext_class;
+ ret = av_opt_copy(new, old);
+ if (ret < 0)
+ goto fail;
+
+ ctx->priv = new;
+ ret = av_set_options_string(ctx, arg, "=", ":");
+ if (ret < 0) {
+ ctx->priv = old;
+ goto fail;
+ }
+
+ ret = init(ctx);
+ if (ret < 0) {
+ uninit(ctx);
+ ctx->priv = old;
+ goto fail;
+ }
+
+ new->reinit = 1;
+
+ ctx->priv = old;
uninit(ctx);
- s->reinit = 1;
- if ((ret = av_set_options_string(ctx, arg, "=", ":")) < 0)
- return ret;
- if ((ret = init(ctx)) < 0)
- return ret;
+ av_freep(&old);
+
+ ctx->priv = new;
return config_input(ctx->inputs[0]);
- }
+ } else
+ return AVERROR(ENOSYS);
- return AVERROR(ENOSYS);
+fail:
+ av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
+ av_freep(&new);
+ return ret;
}
static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
feclearexcept(FE_ALL_EXCEPT);
intval = res;
+#if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
return AVERROR(EINVAL);
}
+#endif
if (argc == 3)
av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
for (i = 0, p = text; *p; i++) {
FT_Bitmap bitmap;
Glyph dummy = { 0 };
- GET_UTF8(code, *p++, continue;);
+ GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
+continue_on_invalid:
/* skip new line chars, just go to new line */
if (code == '\n' || code == '\r' || code == '\t')
/* load and cache glyphs */
for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
+ GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
+continue_on_invalid:
/* get glyph */
dummy.code = code;
/* compute and save position for each glyph */
glyph = NULL;
for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
+ GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid2;);
+continue_on_invalid2:
/* skip the \n in the sequence \r\n */
if (prev_code == '\r' && code == '\n')
NAN : frame->pts * av_q2d(inlink->time_base);
s->var_values[VAR_PICT_TYPE] = frame->pict_type;
+ s->var_values[VAR_PKT_POS] = frame->pkt_pos;
+ s->var_values[VAR_PKT_DURATION] = frame->pkt_duration * av_q2d(inlink->time_base);
+ s->var_values[VAR_PKT_SIZE] = frame->pkt_size;
s->metadata = frame->metadata;
draw_text(ctx, frame, frame->width, frame->height);
{ NULL }
};
-AVFilter ff_vf_drawtext = {
+const AVFilter ff_vf_drawtext = {
.name = "drawtext",
.description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
.priv_size = sizeof(DrawTextContext),