FFmpeg
vf_drawtext.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Stefano Sabatini
3  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
4  * Copyright (c) 2003 Gustavo Sverzut Barbieri <gsbarbieri@yahoo.com.br>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * drawtext filter, based on the original vhook/drawtext.c
26  * filter by Gustavo Sverzut Barbieri
27  */
28 
29 #include "config.h"
30 
31 #if HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <time.h>
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <fenv.h>
41 
42 #if CONFIG_LIBFONTCONFIG
43 #include <fontconfig/fontconfig.h>
44 #endif
45 
46 #include "libavutil/avstring.h"
47 #include "libavutil/bprint.h"
48 #include "libavutil/common.h"
49 #include "libavutil/file.h"
50 #include "libavutil/eval.h"
51 #include "libavutil/opt.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/timecode.h"
56 #include "libavutil/tree.h"
57 #include "libavutil/lfg.h"
58 #include "avfilter.h"
59 #include "drawutils.h"
60 #include "formats.h"
61 #include "internal.h"
62 #include "video.h"
63 
64 #if CONFIG_LIBFRIBIDI
65 #include <fribidi.h>
66 #endif
67 
68 #include <ft2build.h>
69 #include FT_FREETYPE_H
70 #include FT_GLYPH_H
71 #include FT_STROKER_H
72 
73 static const char *const var_names[] = {
74  "dar",
75  "hsub", "vsub",
76  "line_h", "lh", ///< line height, same as max_glyph_h
77  "main_h", "h", "H", ///< height of the input video
78  "main_w", "w", "W", ///< width of the input video
79  "max_glyph_a", "ascent", ///< max glyph ascent
80  "max_glyph_d", "descent", ///< min glyph descent
81  "max_glyph_h", ///< max glyph height
82  "max_glyph_w", ///< max glyph width
83  "n", ///< number of frame
84  "sar",
85  "t", ///< timestamp expressed in seconds
86  "text_h", "th", ///< height of the rendered text
87  "text_w", "tw", ///< width of the rendered text
88  "x",
89  "y",
90  "pict_type",
91  "pkt_pos",
92  "pkt_duration",
93  "pkt_size",
94  NULL
95 };
96 
97 static const char *const fun2_names[] = {
98  "rand"
99 };
100 
101 static double drand(void *opaque, double min, double max)
102 {
103  return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
104 }
105 
106 typedef double (*eval_func2)(void *, double a, double b);
107 
108 static const eval_func2 fun2[] = {
109  drand,
110  NULL
111 };
112 
113 enum var_name {
135 };
136 
141 };
142 
143 typedef struct DrawTextContext {
144  const AVClass *class;
145  int exp_mode; ///< expansion mode to use for the text
146  int reinit; ///< tells if the filter is being reinited
147 #if CONFIG_LIBFONTCONFIG
148  uint8_t *font; ///< font to be used
149 #endif
150  uint8_t *fontfile; ///< font to be used
151  uint8_t *text; ///< text to be drawn
152  AVBPrint expanded_text; ///< used to contain the expanded text
153  uint8_t *fontcolor_expr; ///< fontcolor expression to evaluate
154  AVBPrint expanded_fontcolor; ///< used to contain the expanded fontcolor spec
155  int ft_load_flags; ///< flags used for loading fonts, see FT_LOAD_*
156  FT_Vector *positions; ///< positions for each element in the text
157  size_t nb_positions; ///< number of elements of positions array
158  char *textfile; ///< file with text to be drawn
159  int x; ///< x position to start drawing text
160  int y; ///< y position to start drawing text
161  int max_glyph_w; ///< max glyph width
162  int max_glyph_h; ///< max glyph height
164  int borderw; ///< border width
165  char *fontsize_expr; ///< expression for fontsize
166  AVExpr *fontsize_pexpr; ///< parsed expressions for fontsize
167  unsigned int fontsize; ///< font size to use
168  unsigned int default_fontsize; ///< default font size to use
169 
170  int line_spacing; ///< lines spacing in pixels
171  short int draw_box; ///< draw box around text - true or false
172  int boxborderw; ///< box border width
173  int use_kerning; ///< font kerning is used - true/false
174  int tabsize; ///< tab size
175  int fix_bounds; ///< do we let it go out of frame bounds - t/f
176 
178  FFDrawColor fontcolor; ///< foreground color
179  FFDrawColor shadowcolor; ///< shadow color
180  FFDrawColor bordercolor; ///< border color
181  FFDrawColor boxcolor; ///< background color
182 
183  FT_Library library; ///< freetype font library handle
184  FT_Face face; ///< freetype font face handle
185  FT_Stroker stroker; ///< freetype stroker handle
186  struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
187  char *x_expr; ///< expression for x position
188  char *y_expr; ///< expression for y position
189  AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
190  int64_t basetime; ///< base pts time in the real world for display
192  char *a_expr;
194  int alpha;
195  AVLFG prng; ///< random
196  char *tc_opt_string; ///< specified timecode option string
197  AVRational tc_rate; ///< frame rate for timecode
198  AVTimecode tc; ///< timecode context
199  int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
200  int reload; ///< reload text file for each frame
201  int start_number; ///< starting frame number for n/frame_num var
202 #if CONFIG_LIBFRIBIDI
203  int text_shaping; ///< 1 to shape the text before drawing it
204 #endif
207 
208 #define OFFSET(x) offsetof(DrawTextContext, x)
209 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
210 
211 static const AVOption drawtext_options[]= {
212  {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
213  {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
214  {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
215  {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
216  {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, 0, 0, FLAGS},
217  {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, 0, 0, FLAGS},
218  {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
219  {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
220  {"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 , FLAGS},
221  {"boxborderw", "set box border width", OFFSET(boxborderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
222  {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX,FLAGS},
223  {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0 , FLAGS},
224  {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
225  {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
226  {"shadowx", "set shadow x offset", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
227  {"shadowy", "set shadow y offset", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
228  {"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
229  {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
230  {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
231 #if CONFIG_LIBFONTCONFIG
232  { "font", "Font name", OFFSET(font), AV_OPT_TYPE_STRING, { .str = "Sans" }, .flags = FLAGS },
233 #endif
234 
235  {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, "expansion"},
236  {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
237  {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
238  {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
239 
240  {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
241  {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
242  {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
243  {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
244  {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
245  {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
246  { "alpha", "apply alpha while rendering", OFFSET(a_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
247  {"fix_bounds", "check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
248  {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
249 
250 #if CONFIG_LIBFRIBIDI
251  {"text_shaping", "attempt to shape text before drawing", OFFSET(text_shaping), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS},
252 #endif
253 
254  /* FT_LOAD_* flags */
255  { "ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT }, 0, INT_MAX, FLAGS, "ft_load_flags" },
256  { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
257  { "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
258  { "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
259  { "render", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_RENDER }, .flags = FLAGS, .unit = "ft_load_flags" },
260  { "no_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
261  { "vertical_layout", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags = FLAGS, .unit = "ft_load_flags" },
262  { "force_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_FORCE_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
263  { "crop_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_CROP_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
264  { "pedantic", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_PEDANTIC }, .flags = FLAGS, .unit = "ft_load_flags" },
265  { "ignore_global_advance_width", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags = FLAGS, .unit = "ft_load_flags" },
266  { "no_recurse", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_RECURSE }, .flags = FLAGS, .unit = "ft_load_flags" },
267  { "ignore_transform", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags = FLAGS, .unit = "ft_load_flags" },
268  { "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
269  { "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
270  { "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
271  { NULL }
272 };
273 
275 
276 #undef __FTERRORS_H__
277 #define FT_ERROR_START_LIST {
278 #define FT_ERRORDEF(e, v, s) { (e), (s) },
279 #define FT_ERROR_END_LIST { 0, NULL } };
280 
281 static const struct ft_error {
282  int err;
283  const char *err_msg;
284 } ft_errors[] =
285 #include FT_ERRORS_H
286 
287 #define FT_ERRMSG(e) ft_errors[e].err_msg
288 
289 typedef struct Glyph {
290  FT_Glyph glyph;
291  FT_Glyph border_glyph;
292  uint32_t code;
293  unsigned int fontsize;
294  FT_Bitmap bitmap; ///< array holding bitmaps of font
295  FT_Bitmap border_bitmap; ///< array holding bitmaps of font border
296  FT_BBox bbox;
297  int advance;
298  int bitmap_left;
299  int bitmap_top;
300 } Glyph;
301 
302 static int glyph_cmp(const void *key, const void *b)
303 {
304  const Glyph *a = key, *bb = b;
305  int64_t diff = (int64_t)a->code - (int64_t)bb->code;
306 
307  if (diff != 0)
308  return diff > 0 ? 1 : -1;
309  else
310  return FFDIFFSIGN((int64_t)a->fontsize, (int64_t)bb->fontsize);
311 }
312 
313 /**
314  * Load glyphs corresponding to the UTF-32 codepoint code.
315  */
316 static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
317 {
318  DrawTextContext *s = ctx->priv;
319  FT_BitmapGlyph bitmapglyph;
320  Glyph *glyph;
321  struct AVTreeNode *node = NULL;
322  int ret;
323 
324  /* load glyph into s->face->glyph */
325  if (FT_Load_Char(s->face, code, s->ft_load_flags))
326  return AVERROR(EINVAL);
327 
328  glyph = av_mallocz(sizeof(*glyph));
329  if (!glyph) {
330  ret = AVERROR(ENOMEM);
331  goto error;
332  }
333  glyph->code = code;
334  glyph->fontsize = s->fontsize;
335 
336  if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
337  ret = AVERROR(EINVAL);
338  goto error;
339  }
340  if (s->borderw) {
341  glyph->border_glyph = glyph->glyph;
342  if (FT_Glyph_StrokeBorder(&glyph->border_glyph, s->stroker, 0, 0) ||
343  FT_Glyph_To_Bitmap(&glyph->border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
344  ret = AVERROR_EXTERNAL;
345  goto error;
346  }
347  bitmapglyph = (FT_BitmapGlyph) glyph->border_glyph;
348  glyph->border_bitmap = bitmapglyph->bitmap;
349  }
350  if (FT_Glyph_To_Bitmap(&glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
351  ret = AVERROR_EXTERNAL;
352  goto error;
353  }
354  bitmapglyph = (FT_BitmapGlyph) glyph->glyph;
355 
356  glyph->bitmap = bitmapglyph->bitmap;
357  glyph->bitmap_left = bitmapglyph->left;
358  glyph->bitmap_top = bitmapglyph->top;
359  glyph->advance = s->face->glyph->advance.x >> 6;
360 
361  /* measure text height to calculate text_height (or the maximum text height) */
362  FT_Glyph_Get_CBox(glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
363 
364  /* cache the newly created glyph */
365  if (!(node = av_tree_node_alloc())) {
366  ret = AVERROR(ENOMEM);
367  goto error;
368  }
369  av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);
370 
371  if (glyph_ptr)
372  *glyph_ptr = glyph;
373  return 0;
374 
375 error:
376  if (glyph)
377  av_freep(&glyph->glyph);
378 
379  av_freep(&glyph);
380  av_freep(&node);
381  return ret;
382 }
383 
384 static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
385 {
386  int err;
387  DrawTextContext *s = ctx->priv;
388 
389  if ((err = FT_Set_Pixel_Sizes(s->face, 0, fontsize))) {
390  av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
391  fontsize, FT_ERRMSG(err));
392  return AVERROR(EINVAL);
393  }
394 
395  s->fontsize = fontsize;
396 
397  return 0;
398 }
399 
401 {
402  DrawTextContext *s = ctx->priv;
403  int err;
404 
405  if (s->fontsize_pexpr)
406  return 0;
407 
408  if (s->fontsize_expr == NULL)
409  return AVERROR(EINVAL);
410 
412  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
413  return err;
414 
415  return 0;
416 }
417 
419 {
420  DrawTextContext *s = ctx->priv;
421  unsigned int fontsize = s->default_fontsize;
422  int err;
423  double size, roundedsize;
424 
425  // if no fontsize specified use the default
426  if (s->fontsize_expr != NULL) {
427  if ((err = parse_fontsize(ctx)) < 0)
428  return err;
429 
430  size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
431 
432  if (!isnan(size)) {
433  roundedsize = round(size);
434  // test for overflow before cast
435  if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
436  av_log(ctx, AV_LOG_ERROR, "fontsize overflow\n");
437  return AVERROR(EINVAL);
438  }
439 
440  fontsize = roundedsize;
441  }
442  }
443 
444  if (fontsize == 0)
445  fontsize = 1;
446 
447  // no change
448  if (fontsize == s->fontsize)
449  return 0;
450 
451  return set_fontsize(ctx, fontsize);
452 }
453 
454 static int load_font_file(AVFilterContext *ctx, const char *path, int index)
455 {
456  DrawTextContext *s = ctx->priv;
457  int err;
458 
459  err = FT_New_Face(s->library, path, index, &s->face);
460  if (err) {
461 #if !CONFIG_LIBFONTCONFIG
462  av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
463  s->fontfile, FT_ERRMSG(err));
464 #endif
465  return AVERROR(EINVAL);
466  }
467  return 0;
468 }
469 
470 #if CONFIG_LIBFONTCONFIG
471 static int load_font_fontconfig(AVFilterContext *ctx)
472 {
473  DrawTextContext *s = ctx->priv;
474  FcConfig *fontconfig;
475  FcPattern *pat, *best;
476  FcResult result = FcResultMatch;
477  FcChar8 *filename;
478  int index;
479  double size;
480  int err = AVERROR(ENOENT);
481  int parse_err;
482 
483  fontconfig = FcInitLoadConfigAndFonts();
484  if (!fontconfig) {
485  av_log(ctx, AV_LOG_ERROR, "impossible to init fontconfig\n");
486  return AVERROR_UNKNOWN;
487  }
488  pat = FcNameParse(s->fontfile ? s->fontfile :
489  (uint8_t *)(intptr_t)"default");
490  if (!pat) {
491  av_log(ctx, AV_LOG_ERROR, "could not parse fontconfig pat");
492  return AVERROR(EINVAL);
493  }
494 
495  FcPatternAddString(pat, FC_FAMILY, s->font);
496 
497  parse_err = parse_fontsize(ctx);
498  if (!parse_err) {
499  double size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
500 
501  if (isnan(size)) {
502  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
503  return AVERROR(EINVAL);
504  }
505 
506  FcPatternAddDouble(pat, FC_SIZE, size);
507  }
508 
509  FcDefaultSubstitute(pat);
510 
511  if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
512  av_log(ctx, AV_LOG_ERROR, "could not substitue fontconfig options"); /* very unlikely */
513  FcPatternDestroy(pat);
514  return AVERROR(ENOMEM);
515  }
516 
517  best = FcFontMatch(fontconfig, pat, &result);
518  FcPatternDestroy(pat);
519 
520  if (!best || result != FcResultMatch) {
521  av_log(ctx, AV_LOG_ERROR,
522  "Cannot find a valid font for the family %s\n",
523  s->font);
524  goto fail;
525  }
526 
527  if (
528  FcPatternGetInteger(best, FC_INDEX, 0, &index ) != FcResultMatch ||
529  FcPatternGetDouble (best, FC_SIZE, 0, &size ) != FcResultMatch) {
530  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
531  return AVERROR(EINVAL);
532  }
533 
534  if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
535  av_log(ctx, AV_LOG_ERROR, "No file path for %s\n",
536  s->font);
537  goto fail;
538  }
539 
540  av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
541  if (parse_err)
542  s->default_fontsize = size + 0.5;
543 
544  err = load_font_file(ctx, filename, index);
545  if (err)
546  return err;
547  FcConfigDestroy(fontconfig);
548 fail:
549  FcPatternDestroy(best);
550  return err;
551 }
552 #endif
553 
554 static int load_font(AVFilterContext *ctx)
555 {
556  DrawTextContext *s = ctx->priv;
557  int err;
558 
559  /* load the face, and set up the encoding, which is by default UTF-8 */
560  err = load_font_file(ctx, s->fontfile, 0);
561  if (!err)
562  return 0;
563 #if CONFIG_LIBFONTCONFIG
564  err = load_font_fontconfig(ctx);
565  if (!err)
566  return 0;
567 #endif
568  return err;
569 }
570 
572 {
573  DrawTextContext *s = ctx->priv;
574  int err;
575  uint8_t *textbuf;
576  uint8_t *tmp;
577  size_t textbuf_size;
578 
579  if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
580  av_log(ctx, AV_LOG_ERROR,
581  "The text file '%s' could not be read or is empty\n",
582  s->textfile);
583  return err;
584  }
585 
586  if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
587  av_file_unmap(textbuf, textbuf_size);
588  return AVERROR(ENOMEM);
589  }
590  s->text = tmp;
591  memcpy(s->text, textbuf, textbuf_size);
592  s->text[textbuf_size] = 0;
593  av_file_unmap(textbuf, textbuf_size);
594 
595  return 0;
596 }
597 
598 static inline int is_newline(uint32_t c)
599 {
600  return c == '\n' || c == '\r' || c == '\f' || c == '\v';
601 }
602 
603 #if CONFIG_LIBFRIBIDI
604 static int shape_text(AVFilterContext *ctx)
605 {
606  DrawTextContext *s = ctx->priv;
607  uint8_t *tmp;
608  int ret = AVERROR(ENOMEM);
609  static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
610  FRIBIDI_FLAGS_ARABIC;
611  FriBidiChar *unicodestr = NULL;
612  FriBidiStrIndex len;
613  FriBidiParType direction = FRIBIDI_PAR_LTR;
614  FriBidiStrIndex line_start = 0;
615  FriBidiStrIndex line_end = 0;
616  FriBidiLevel *embedding_levels = NULL;
617  FriBidiArabicProp *ar_props = NULL;
618  FriBidiCharType *bidi_types = NULL;
619  FriBidiStrIndex i,j;
620 
621  len = strlen(s->text);
622  if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
623  goto out;
624  }
625  len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
626  s->text, len, unicodestr);
627 
628  bidi_types = av_malloc_array(len, sizeof(*bidi_types));
629  if (!bidi_types) {
630  goto out;
631  }
632 
633  fribidi_get_bidi_types(unicodestr, len, bidi_types);
634 
635  embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
636  if (!embedding_levels) {
637  goto out;
638  }
639 
640  if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
641  embedding_levels)) {
642  goto out;
643  }
644 
645  ar_props = av_malloc_array(len, sizeof(*ar_props));
646  if (!ar_props) {
647  goto out;
648  }
649 
650  fribidi_get_joining_types(unicodestr, len, ar_props);
651  fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
652  fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);
653 
654  for (line_end = 0, line_start = 0; line_end < len; line_end++) {
655  if (is_newline(unicodestr[line_end]) || line_end == len - 1) {
656  if (!fribidi_reorder_line(flags, bidi_types,
657  line_end - line_start + 1, line_start,
658  direction, embedding_levels, unicodestr,
659  NULL)) {
660  goto out;
661  }
662  line_start = line_end + 1;
663  }
664  }
665 
666  /* Remove zero-width fill chars put in by libfribidi */
667  for (i = 0, j = 0; i < len; i++)
668  if (unicodestr[i] != FRIBIDI_CHAR_FILL)
669  unicodestr[j++] = unicodestr[i];
670  len = j;
671 
672  if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
673  /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
674  goto out;
675  }
676 
677  s->text = tmp;
678  len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
679  unicodestr, len, s->text);
680  ret = 0;
681 
682 out:
683  av_free(unicodestr);
684  av_free(embedding_levels);
685  av_free(ar_props);
686  av_free(bidi_types);
687  return ret;
688 }
689 #endif
690 
691 static av_cold int init(AVFilterContext *ctx)
692 {
693  int err;
694  DrawTextContext *s = ctx->priv;
695  Glyph *glyph;
696 
698  s->fontsize_pexpr = NULL;
699 
700  s->fontsize = 0;
701  s->default_fontsize = 16;
702 
703  if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
704  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
705  return AVERROR(EINVAL);
706  }
707 
708  if (s->textfile) {
709  if (s->text) {
710  av_log(ctx, AV_LOG_ERROR,
711  "Both text and text file provided. Please provide only one\n");
712  return AVERROR(EINVAL);
713  }
714  if ((err = load_textfile(ctx)) < 0)
715  return err;
716  }
717 
718  if (s->reload && !s->textfile)
719  av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
720 
721  if (s->tc_opt_string) {
723  s->tc_opt_string, ctx);
724  if (ret < 0)
725  return ret;
726  if (s->tc24hmax)
728  if (!s->text)
729  s->text = av_strdup("");
730  }
731 
732  if (!s->text) {
733  av_log(ctx, AV_LOG_ERROR,
734  "Either text, a valid file or a timecode must be provided\n");
735  return AVERROR(EINVAL);
736  }
737 
738 #if CONFIG_LIBFRIBIDI
739  if (s->text_shaping)
740  if ((err = shape_text(ctx)) < 0)
741  return err;
742 #endif
743 
744  if ((err = FT_Init_FreeType(&(s->library)))) {
745  av_log(ctx, AV_LOG_ERROR,
746  "Could not load FreeType: %s\n", FT_ERRMSG(err));
747  return AVERROR(EINVAL);
748  }
749 
750  if ((err = load_font(ctx)) < 0)
751  return err;
752 
753  if ((err = update_fontsize(ctx)) < 0)
754  return err;
755 
756  if (s->borderw) {
757  if (FT_Stroker_New(s->library, &s->stroker)) {
758  av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
759  return AVERROR_EXTERNAL;
760  }
761  FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
762  FT_STROKER_LINEJOIN_ROUND, 0);
763  }
764 
765  s->use_kerning = FT_HAS_KERNING(s->face);
766 
767  /* load the fallback glyph with code 0 */
768  load_glyph(ctx, NULL, 0);
769 
770  /* set the tabsize in pixels */
771  if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
772  av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
773  return err;
774  }
775  s->tabsize *= glyph->advance;
776 
777  if (s->exp_mode == EXP_STRFTIME &&
778  (strchr(s->text, '%') || strchr(s->text, '\\')))
779  av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
780 
783 
784  return 0;
785 }
786 
788 {
790 }
791 
792 static int glyph_enu_free(void *opaque, void *elem)
793 {
794  Glyph *glyph = elem;
795 
796  FT_Done_Glyph(glyph->glyph);
797  FT_Done_Glyph(glyph->border_glyph);
798  av_free(elem);
799  return 0;
800 }
801 
802 static av_cold void uninit(AVFilterContext *ctx)
803 {
804  DrawTextContext *s = ctx->priv;
805 
806  av_expr_free(s->x_pexpr);
807  av_expr_free(s->y_pexpr);
808  av_expr_free(s->a_pexpr);
810 
811  s->x_pexpr = s->y_pexpr = s->a_pexpr = s->fontsize_pexpr = NULL;
812 
813  av_freep(&s->positions);
814  s->nb_positions = 0;
815 
818  s->glyphs = NULL;
819 
820  FT_Done_Face(s->face);
821  FT_Stroker_Done(s->stroker);
822  FT_Done_FreeType(s->library);
823 
826 }
827 
829 {
830  AVFilterContext *ctx = inlink->dst;
831  DrawTextContext *s = ctx->priv;
832  char *expr;
833  int ret;
834 
836  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
839  ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
840 
841  s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
842  s->var_values[VAR_h] = s->var_values[VAR_H] = s->var_values[VAR_MAIN_H] = inlink->h;
844  s->var_values[VAR_DAR] = (double)inlink->w / inlink->h * s->var_values[VAR_SAR];
845  s->var_values[VAR_HSUB] = 1 << s->dc.hsub_max;
846  s->var_values[VAR_VSUB] = 1 << s->dc.vsub_max;
847  s->var_values[VAR_X] = NAN;
848  s->var_values[VAR_Y] = NAN;
849  s->var_values[VAR_T] = NAN;
850 
852 
853  av_expr_free(s->x_pexpr);
854  av_expr_free(s->y_pexpr);
855  av_expr_free(s->a_pexpr);
856  s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
857 
858  if ((ret = av_expr_parse(&s->x_pexpr, expr = s->x_expr, var_names,
859  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
860  (ret = av_expr_parse(&s->y_pexpr, expr = s->y_expr, var_names,
861  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
862  (ret = av_expr_parse(&s->a_pexpr, expr = s->a_expr, var_names,
863  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
864  av_log(ctx, AV_LOG_ERROR, "Failed to parse expression: %s \n", expr);
865  return AVERROR(EINVAL);
866  }
867 
868  return 0;
869 }
870 
871 static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
872 {
873  DrawTextContext *old = ctx->priv;
874  DrawTextContext *new = NULL;
875  int ret;
876 
877  if (!strcmp(cmd, "reinit")) {
878  new = av_mallocz(sizeof(DrawTextContext));
879  if (!new)
880  return AVERROR(ENOMEM);
881 
882  new->class = &drawtext_class;
883  ret = av_opt_copy(new, old);
884  if (ret < 0)
885  goto fail;
886 
887  ctx->priv = new;
888  ret = av_set_options_string(ctx, arg, "=", ":");
889  if (ret < 0) {
890  ctx->priv = old;
891  goto fail;
892  }
893 
894  ret = init(ctx);
895  if (ret < 0) {
896  uninit(ctx);
897  ctx->priv = old;
898  goto fail;
899  }
900 
901  new->reinit = 1;
902 
903  ctx->priv = old;
904  uninit(ctx);
905  av_freep(&old);
906 
907  ctx->priv = new;
908  return config_input(ctx->inputs[0]);
909  } else
910  return AVERROR(ENOSYS);
911 
912 fail:
913  av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
914  av_freep(&new);
915  return ret;
916 }
917 
918 static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
919  char *fct, unsigned argc, char **argv, int tag)
920 {
921  DrawTextContext *s = ctx->priv;
922 
924  return 0;
925 }
926 
927 static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
928  char *fct, unsigned argc, char **argv, int tag)
929 {
930  DrawTextContext *s = ctx->priv;
931  const char *fmt;
932  double pts = s->var_values[VAR_T];
933  int ret;
934 
935  fmt = argc >= 1 ? argv[0] : "flt";
936  if (argc >= 2) {
937  int64_t delta;
938  if ((ret = av_parse_time(&delta, argv[1], 1)) < 0) {
939  av_log(ctx, AV_LOG_ERROR, "Invalid delta '%s'\n", argv[1]);
940  return ret;
941  }
942  pts += (double)delta / AV_TIME_BASE;
943  }
944  if (!strcmp(fmt, "flt")) {
945  av_bprintf(bp, "%.6f", pts);
946  } else if (!strcmp(fmt, "hms")) {
947  if (isnan(pts)) {
948  av_bprintf(bp, " ??:??:??.???");
949  } else {
950  int64_t ms = llrint(pts * 1000);
951  char sign = ' ';
952  if (ms < 0) {
953  sign = '-';
954  ms = -ms;
955  }
956  if (argc >= 3) {
957  if (!strcmp(argv[2], "24HH")) {
958  ms %= 24 * 60 * 60 * 1000;
959  } else {
960  av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", argv[2]);
961  return AVERROR(EINVAL);
962  }
963  }
964  av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
965  (int)(ms / (60 * 60 * 1000)),
966  (int)(ms / (60 * 1000)) % 60,
967  (int)(ms / 1000) % 60,
968  (int)(ms % 1000));
969  }
970  } else if (!strcmp(fmt, "localtime") ||
971  !strcmp(fmt, "gmtime")) {
972  struct tm tm;
973  time_t ms = (time_t)pts;
974  const char *timefmt = argc >= 3 ? argv[2] : "%Y-%m-%d %H:%M:%S";
975  if (!strcmp(fmt, "localtime"))
976  localtime_r(&ms, &tm);
977  else
978  gmtime_r(&ms, &tm);
979  av_bprint_strftime(bp, timefmt, &tm);
980  } else {
981  av_log(ctx, AV_LOG_ERROR, "Invalid format '%s'\n", fmt);
982  return AVERROR(EINVAL);
983  }
984  return 0;
985 }
986 
987 static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
988  char *fct, unsigned argc, char **argv, int tag)
989 {
990  DrawTextContext *s = ctx->priv;
991 
992  av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
993  return 0;
994 }
995 
996 static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
997  char *fct, unsigned argc, char **argv, int tag)
998 {
999  DrawTextContext *s = ctx->priv;
1000  AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
1001 
1002  if (e && e->value)
1003  av_bprintf(bp, "%s", e->value);
1004  else if (argc >= 2)
1005  av_bprintf(bp, "%s", argv[1]);
1006  return 0;
1007 }
1008 
1009 static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
1010  char *fct, unsigned argc, char **argv, int tag)
1011 {
1012  const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
1013  time_t now;
1014  struct tm tm;
1015 
1016  time(&now);
1017  if (tag == 'L')
1018  localtime_r(&now, &tm);
1019  else
1020  tm = *gmtime_r(&now, &tm);
1021  av_bprint_strftime(bp, fmt, &tm);
1022  return 0;
1023 }
1024 
1025 static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
1026  char *fct, unsigned argc, char **argv, int tag)
1027 {
1028  DrawTextContext *s = ctx->priv;
1029  double res;
1030  int ret;
1031 
1032  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1033  NULL, NULL, fun2_names, fun2,
1034  &s->prng, 0, ctx);
1035  if (ret < 0)
1036  av_log(ctx, AV_LOG_ERROR,
1037  "Expression '%s' for the expr text expansion function is not valid\n",
1038  argv[0]);
1039  else
1040  av_bprintf(bp, "%f", res);
1041 
1042  return ret;
1043 }
1044 
1045 static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp,
1046  char *fct, unsigned argc, char **argv, int tag)
1047 {
1048  DrawTextContext *s = ctx->priv;
1049  double res;
1050  int intval;
1051  int ret;
1052  unsigned int positions = 0;
1053  char fmt_str[30] = "%";
1054 
1055  /*
1056  * argv[0] expression to be converted to `int`
1057  * argv[1] format: 'x', 'X', 'd' or 'u'
1058  * argv[2] positions printed (optional)
1059  */
1060 
1061  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1062  NULL, NULL, fun2_names, fun2,
1063  &s->prng, 0, ctx);
1064  if (ret < 0) {
1065  av_log(ctx, AV_LOG_ERROR,
1066  "Expression '%s' for the expr text expansion function is not valid\n",
1067  argv[0]);
1068  return ret;
1069  }
1070 
1071  if (!strchr("xXdu", argv[1][0])) {
1072  av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified,"
1073  " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
1074  return AVERROR(EINVAL);
1075  }
1076 
1077  if (argc == 3) {
1078  ret = sscanf(argv[2], "%u", &positions);
1079  if (ret != 1) {
1080  av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
1081  " to print: '%s'\n", argv[2]);
1082  return AVERROR(EINVAL);
1083  }
1084  }
1085 
1086  feclearexcept(FE_ALL_EXCEPT);
1087  intval = res;
1088 #if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
1089  if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
1090  av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
1091  return AVERROR(EINVAL);
1092  }
1093 #endif
1094 
1095  if (argc == 3)
1096  av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
1097  av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]);
1098 
1099  av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
1100  res, argv[0], fmt_str);
1101 
1102  av_bprintf(bp, fmt_str, intval);
1103 
1104  return 0;
1105 }
1106 
1107 static const struct drawtext_function {
1108  const char *name;
1109  unsigned argc_min, argc_max;
1110  int tag; /**< opaque argument to func */
1111  int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
1112 } functions[] = {
1113  { "expr", 1, 1, 0, func_eval_expr },
1114  { "e", 1, 1, 0, func_eval_expr },
1115  { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
1116  { "eif", 2, 3, 0, func_eval_expr_int_format },
1117  { "pict_type", 0, 0, 0, func_pict_type },
1118  { "pts", 0, 3, 0, func_pts },
1119  { "gmtime", 0, 1, 'G', func_strftime },
1120  { "localtime", 0, 1, 'L', func_strftime },
1121  { "frame_num", 0, 0, 0, func_frame_num },
1122  { "n", 0, 0, 0, func_frame_num },
1123  { "metadata", 1, 2, 0, func_metadata },
1124 };
1125 
1126 static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
1127  unsigned argc, char **argv)
1128 {
1129  unsigned i;
1130 
1131  for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
1132  if (strcmp(fct, functions[i].name))
1133  continue;
1134  if (argc < functions[i].argc_min) {
1135  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
1136  fct, functions[i].argc_min);
1137  return AVERROR(EINVAL);
1138  }
1139  if (argc > functions[i].argc_max) {
1140  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
1141  fct, functions[i].argc_max);
1142  return AVERROR(EINVAL);
1143  }
1144  break;
1145  }
1146  if (i >= FF_ARRAY_ELEMS(functions)) {
1147  av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
1148  return AVERROR(EINVAL);
1149  }
1150  return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
1151 }
1152 
1153 static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
1154 {
1155  const char *text = *rtext;
1156  char *argv[16] = { NULL };
1157  unsigned argc = 0, i;
1158  int ret;
1159 
1160  if (*text != '{') {
1161  av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
1162  return AVERROR(EINVAL);
1163  }
1164  text++;
1165  while (1) {
1166  if (!(argv[argc++] = av_get_token(&text, ":}"))) {
1167  ret = AVERROR(ENOMEM);
1168  goto end;
1169  }
1170  if (!*text) {
1171  av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
1172  ret = AVERROR(EINVAL);
1173  goto end;
1174  }
1175  if (argc == FF_ARRAY_ELEMS(argv))
1176  av_freep(&argv[--argc]); /* error will be caught later */
1177  if (*text == '}')
1178  break;
1179  text++;
1180  }
1181 
1182  if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
1183  goto end;
1184  ret = 0;
1185  *rtext = (char *)text + 1;
1186 
1187 end:
1188  for (i = 0; i < argc; i++)
1189  av_freep(&argv[i]);
1190  return ret;
1191 }
1192 
1193 static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
1194 {
1195  int ret;
1196 
1197  av_bprint_clear(bp);
1198  while (*text) {
1199  if (*text == '\\' && text[1]) {
1200  av_bprint_chars(bp, text[1], 1);
1201  text += 2;
1202  } else if (*text == '%') {
1203  text++;
1204  if ((ret = expand_function(ctx, bp, &text)) < 0)
1205  return ret;
1206  } else {
1207  av_bprint_chars(bp, *text, 1);
1208  text++;
1209  }
1210  }
1211  if (!av_bprint_is_complete(bp))
1212  return AVERROR(ENOMEM);
1213  return 0;
1214 }
1215 
1217  int width, int height,
1218  FFDrawColor *color,
1219  int x, int y, int borderw)
1220 {
1221  char *text = s->expanded_text.str;
1222  uint32_t code = 0;
1223  int i, x1, y1;
1224  uint8_t *p;
1225  Glyph *glyph = NULL;
1226 
1227  for (i = 0, p = text; *p; i++) {
1228  FT_Bitmap bitmap;
1229  Glyph dummy = { 0 };
1230  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1231 continue_on_invalid:
1232 
1233  /* skip new line chars, just go to new line */
1234  if (code == '\n' || code == '\r' || code == '\t')
1235  continue;
1236 
1237  dummy.code = code;
1238  dummy.fontsize = s->fontsize;
1239  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1240 
1241  bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
1242 
1243  if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
1244  glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1245  return AVERROR(EINVAL);
1246 
1247  x1 = s->positions[i].x+s->x+x - borderw;
1248  y1 = s->positions[i].y+s->y+y - borderw;
1249 
1250  ff_blend_mask(&s->dc, color,
1251  frame->data, frame->linesize, width, height,
1252  bitmap.buffer, bitmap.pitch,
1253  bitmap.width, bitmap.rows,
1254  bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
1255  0, x1, y1);
1256  }
1257 
1258  return 0;
1259 }
1260 
1261 
1263 {
1264  *color = incolor;
1265  color->rgba[3] = (color->rgba[3] * s->alpha) / 255;
1266  ff_draw_color(&s->dc, color, color->rgba);
1267 }
1268 
1270 {
1271  double alpha = av_expr_eval(s->a_pexpr, s->var_values, &s->prng);
1272 
1273  if (isnan(alpha))
1274  return;
1275 
1276  if (alpha >= 1.0)
1277  s->alpha = 255;
1278  else if (alpha <= 0)
1279  s->alpha = 0;
1280  else
1281  s->alpha = 256 * alpha;
1282 }
1283 
1285  int width, int height)
1286 {
1287  DrawTextContext *s = ctx->priv;
1288  AVFilterLink *inlink = ctx->inputs[0];
1289 
1290  uint32_t code = 0, prev_code = 0;
1291  int x = 0, y = 0, i = 0, ret;
1292  int max_text_line_w = 0, len;
1293  int box_w, box_h;
1294  char *text;
1295  uint8_t *p;
1296  int y_min = 32000, y_max = -32000;
1297  int x_min = 32000, x_max = -32000;
1298  FT_Vector delta;
1299  Glyph *glyph = NULL, *prev_glyph = NULL;
1300  Glyph dummy = { 0 };
1301 
1302  time_t now = time(0);
1303  struct tm ltime;
1304  AVBPrint *bp = &s->expanded_text;
1305 
1310 
1311  av_bprint_clear(bp);
1312 
1313  if(s->basetime != AV_NOPTS_VALUE)
1314  now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + s->basetime/1000000;
1315 
1316  switch (s->exp_mode) {
1317  case EXP_NONE:
1318  av_bprintf(bp, "%s", s->text);
1319  break;
1320  case EXP_NORMAL:
1321  if ((ret = expand_text(ctx, s->text, &s->expanded_text)) < 0)
1322  return ret;
1323  break;
1324  case EXP_STRFTIME:
1325  localtime_r(&now, &ltime);
1326  av_bprint_strftime(bp, s->text, &ltime);
1327  break;
1328  }
1329 
1330  if (s->tc_opt_string) {
1331  char tcbuf[AV_TIMECODE_STR_SIZE];
1332  av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count_out);
1333  av_bprint_clear(bp);
1334  av_bprintf(bp, "%s%s", s->text, tcbuf);
1335  }
1336 
1337  if (!av_bprint_is_complete(bp))
1338  return AVERROR(ENOMEM);
1339  text = s->expanded_text.str;
1340  if ((len = s->expanded_text.len) > s->nb_positions) {
1341  if (!(s->positions =
1342  av_realloc(s->positions, len*sizeof(*s->positions))))
1343  return AVERROR(ENOMEM);
1344  s->nb_positions = len;
1345  }
1346 
1347  if (s->fontcolor_expr[0]) {
1348  /* If expression is set, evaluate and replace the static value */
1350  if ((ret = expand_text(ctx, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
1351  return ret;
1353  return AVERROR(ENOMEM);
1354  av_log(s, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
1355  ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
1356  if (ret)
1357  return ret;
1358  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
1359  }
1360 
1361  x = 0;
1362  y = 0;
1363 
1364  if ((ret = update_fontsize(ctx)) < 0)
1365  return ret;
1366 
1367  /* load and cache glyphs */
1368  for (i = 0, p = text; *p; i++) {
1369  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1370 continue_on_invalid:
1371 
1372  /* get glyph */
1373  dummy.code = code;
1374  dummy.fontsize = s->fontsize;
1375  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1376  if (!glyph) {
1377  ret = load_glyph(ctx, &glyph, code);
1378  if (ret < 0)
1379  return ret;
1380  }
1381 
1382  y_min = FFMIN(glyph->bbox.yMin, y_min);
1383  y_max = FFMAX(glyph->bbox.yMax, y_max);
1384  x_min = FFMIN(glyph->bbox.xMin, x_min);
1385  x_max = FFMAX(glyph->bbox.xMax, x_max);
1386  }
1387  s->max_glyph_h = y_max - y_min;
1388  s->max_glyph_w = x_max - x_min;
1389 
1390  /* compute and save position for each glyph */
1391  glyph = NULL;
1392  for (i = 0, p = text; *p; i++) {
1393  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid2;);
1394 continue_on_invalid2:
1395 
1396  /* skip the \n in the sequence \r\n */
1397  if (prev_code == '\r' && code == '\n')
1398  continue;
1399 
1400  prev_code = code;
1401  if (is_newline(code)) {
1402 
1403  max_text_line_w = FFMAX(max_text_line_w, x);
1404  y += s->max_glyph_h + s->line_spacing;
1405  x = 0;
1406  continue;
1407  }
1408 
1409  /* get glyph */
1410  prev_glyph = glyph;
1411  dummy.code = code;
1412  dummy.fontsize = s->fontsize;
1413  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1414 
1415  /* kerning */
1416  if (s->use_kerning && prev_glyph && glyph->code) {
1417  FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
1418  ft_kerning_default, &delta);
1419  x += delta.x >> 6;
1420  }
1421 
1422  /* save position */
1423  s->positions[i].x = x + glyph->bitmap_left;
1424  s->positions[i].y = y - glyph->bitmap_top + y_max;
1425  if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
1426  else x += glyph->advance;
1427  }
1428 
1429  max_text_line_w = FFMAX(x, max_text_line_w);
1430 
1431  s->var_values[VAR_TW] = s->var_values[VAR_TEXT_W] = max_text_line_w;
1433 
1436  s->var_values[VAR_MAX_GLYPH_A] = s->var_values[VAR_ASCENT ] = y_max;
1438 
1440 
1441  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1442  s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
1443  /* It is necessary if x is expressed from y */
1444  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1445 
1446  update_alpha(s);
1447  update_color_with_alpha(s, &fontcolor , s->fontcolor );
1448  update_color_with_alpha(s, &shadowcolor, s->shadowcolor);
1449  update_color_with_alpha(s, &bordercolor, s->bordercolor);
1450  update_color_with_alpha(s, &boxcolor , s->boxcolor );
1451 
1452  box_w = max_text_line_w;
1453  box_h = y + s->max_glyph_h;
1454 
1455  if (s->fix_bounds) {
1456 
1457  /* calculate footprint of text effects */
1458  int boxoffset = s->draw_box ? FFMAX(s->boxborderw, 0) : 0;
1459  int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0;
1460 
1461  int offsetleft = FFMAX3(boxoffset, borderoffset,
1462  (s->shadowx < 0 ? FFABS(s->shadowx) : 0));
1463  int offsettop = FFMAX3(boxoffset, borderoffset,
1464  (s->shadowy < 0 ? FFABS(s->shadowy) : 0));
1465 
1466  int offsetright = FFMAX3(boxoffset, borderoffset,
1467  (s->shadowx > 0 ? s->shadowx : 0));
1468  int offsetbottom = FFMAX3(boxoffset, borderoffset,
1469  (s->shadowy > 0 ? s->shadowy : 0));
1470 
1471 
1472  if (s->x - offsetleft < 0) s->x = offsetleft;
1473  if (s->y - offsettop < 0) s->y = offsettop;
1474 
1475  if (s->x + box_w + offsetright > width)
1476  s->x = FFMAX(width - box_w - offsetright, 0);
1477  if (s->y + box_h + offsetbottom > height)
1478  s->y = FFMAX(height - box_h - offsetbottom, 0);
1479  }
1480 
1481  /* draw box */
1482  if (s->draw_box)
1483  ff_blend_rectangle(&s->dc, &boxcolor,
1484  frame->data, frame->linesize, width, height,
1485  s->x - s->boxborderw, s->y - s->boxborderw,
1486  box_w + s->boxborderw * 2, box_h + s->boxborderw * 2);
1487 
1488  if (s->shadowx || s->shadowy) {
1489  if ((ret = draw_glyphs(s, frame, width, height,
1490  &shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
1491  return ret;
1492  }
1493 
1494  if (s->borderw) {
1495  if ((ret = draw_glyphs(s, frame, width, height,
1496  &bordercolor, 0, 0, s->borderw)) < 0)
1497  return ret;
1498  }
1499  if ((ret = draw_glyphs(s, frame, width, height,
1500  &fontcolor, 0, 0, 0)) < 0)
1501  return ret;
1502 
1503  return 0;
1504 }
1505 
1507 {
1508  AVFilterContext *ctx = inlink->dst;
1509  AVFilterLink *outlink = ctx->outputs[0];
1510  DrawTextContext *s = ctx->priv;
1511  int ret;
1512 
1513  if (s->reload) {
1514  if ((ret = load_textfile(ctx)) < 0) {
1515  av_frame_free(&frame);
1516  return ret;
1517  }
1518 #if CONFIG_LIBFRIBIDI
1519  if (s->text_shaping)
1520  if ((ret = shape_text(ctx)) < 0) {
1521  av_frame_free(&frame);
1522  return ret;
1523  }
1524 #endif
1525  }
1526 
1527  s->var_values[VAR_N] = inlink->frame_count_out + s->start_number;
1528  s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
1529  NAN : frame->pts * av_q2d(inlink->time_base);
1530 
1531  s->var_values[VAR_PICT_TYPE] = frame->pict_type;
1532  s->var_values[VAR_PKT_POS] = frame->pkt_pos;
1533  s->var_values[VAR_PKT_DURATION] = frame->pkt_duration * av_q2d(inlink->time_base);
1534  s->var_values[VAR_PKT_SIZE] = frame->pkt_size;
1535  s->metadata = frame->metadata;
1536 
1537  draw_text(ctx, frame, frame->width, frame->height);
1538 
1539  av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
1540  (int)s->var_values[VAR_N], s->var_values[VAR_T],
1541  (int)s->var_values[VAR_TEXT_W], (int)s->var_values[VAR_TEXT_H],
1542  s->x, s->y);
1543 
1544  return ff_filter_frame(outlink, frame);
1545 }
1546 
1548  {
1549  .name = "default",
1550  .type = AVMEDIA_TYPE_VIDEO,
1551  .filter_frame = filter_frame,
1552  .config_props = config_input,
1553  .needs_writable = 1,
1554  },
1555  { NULL }
1556 };
1557 
1559  {
1560  .name = "default",
1561  .type = AVMEDIA_TYPE_VIDEO,
1562  },
1563  { NULL }
1564 };
1565 
1567  .name = "drawtext",
1568  .description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
1569  .priv_size = sizeof(DrawTextContext),
1570  .priv_class = &drawtext_class,
1571  .init = init,
1572  .uninit = uninit,
1574  .inputs = avfilter_vf_drawtext_inputs,
1575  .outputs = avfilter_vf_drawtext_outputs,
1578 };
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:731
#define NULL
Definition: coverity.c:32
static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:987
char * y_expr
expression for y position
Definition: vf_drawtext.c:188
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
#define GET_UTF8(val, GET_BYTE, ERROR)
Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.
Definition: common.h:427
int tc24hmax
1 if timecode is wrapped to 24 hours, 0 otherwise
Definition: vf_drawtext.c:199
This structure describes decoded (raw) audio or video data.
Definition: frame.h:308
uint8_t * fontcolor_expr
fontcolor expression to evaluate
Definition: vf_drawtext.c:153
AVOption.
Definition: opt.h:248
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
int x
x position to start drawing text
Definition: vf_drawtext.c:159
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:101
static int func_metadata(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:996
int64_t pkt_pos
reordered pos from the last AVPacket that has been input into the decoder
Definition: frame.h:579
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:211
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:167
FFDrawColor boxcolor
background color
Definition: vf_drawtext.c:181
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
static av_cold int parse_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:400
char * x_expr
expression for x position
Definition: vf_drawtext.c:187
Main libavfilter public API header.
uint8_t * fontfile
font to be used
Definition: vf_drawtext.c:150
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
Parse timestr and return in *time a corresponding number of microseconds.
Definition: parseutils.c:587
#define FLAGS
Definition: vf_drawtext.c:209
int num
Numerator.
Definition: rational.h:59
static const struct drawtext_function functions[]
int av_set_options_string(void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep)
Parse the key/value pairs list in opts.
Definition: opt.c:1478
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:36
static int draw_text(AVFilterContext *ctx, AVFrame *frame, int width, int height)
Definition: vf_drawtext.c:1284
uint8_t * text
text to be drawn
Definition: vf_drawtext.c:151
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
Definition: tree.c:39
const char * key
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:685
char * tc_opt_string
specified timecode option string
Definition: vf_drawtext.c:196
static void error(const char *err)
static int draw_glyphs(DrawTextContext *s, AVFrame *frame, int width, int height, FFDrawColor *color, int x, int y, int borderw)
Definition: vf_drawtext.c:1216
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
int boxborderw
box border width
Definition: vf_drawtext.c:172
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:125
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
#define gmtime_r
Definition: time_internal.h:34
expansion_mode
Definition: vf_drawtext.c:137
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
Definition: timecode.c:226
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1091
FT_Stroker stroker
freetype stroker handle
Definition: vf_drawtext.c:185
static int glyph_enu_free(void *opaque, void *elem)
Definition: vf_drawtext.c:792
uint8_t
#define av_cold
Definition: attributes.h:88
static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:918
AVExpr * fontsize_pexpr
parsed expressions for fontsize
Definition: vf_drawtext.c:166
float delta
AVOptions.
A tree container.
AVLFG prng
random
Definition: vf_drawtext.c:195
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:184
static int glyph_cmp(const void *key, const void *b)
Definition: vf_drawtext.c:302
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:401
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:691
Definition: eval.c:157
int start_number
starting frame number for n/frame_num var
Definition: vf_drawtext.c:201
static int load_font_file(AVFilterContext *ctx, const char *path, int index)
Definition: vf_drawtext.c:454
Misc file utilities.
#define height
static const AVFilterPad avfilter_vf_drawtext_inputs[]
Definition: vf_drawtext.c:1547
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:40
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
uint32_t tag
Definition: movenc.c:1532
char av_get_picture_type_char(enum AVPictureType pict_type)
Return a single letter to describe the given picture type pict_type.
Definition: utils.c:88
const char * name
Definition: vf_drawtext.c:1108
AVDictionary * metadata
metadata.
Definition: frame.h:594
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:802
#define max(a, b)
Definition: cuda_runtime.h:33
ptrdiff_t size
Definition: opengl_enc.c:100
FT_Vector * positions
positions for each element in the text
Definition: vf_drawtext.c:156
AVExpr * x_pexpr
Definition: vf_drawtext.c:189
#define av_log(a,...)
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, void *log_ctx)
Put the RGBA values that correspond to color_string in rgba_color.
Definition: parseutils.c:354
A filter pad used for either input or output.
Definition: internal.h:54
int av_expr_parse_and_eval(double *d, const char *s, const char *const *const_names, const double *const_values, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), void *opaque, int log_offset, void *log_ctx)
Parse and evaluate an expression.
Definition: eval.c:776
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:191
int width
Definition: frame.h:366
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
Definition: file.c:144
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:600
AVBPrint expanded_text
used to contain the expanded text
Definition: vf_drawtext.c:152
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx)
Read the file with name filename, and put its content in a newly allocated buffer or map it with mmap...
Definition: file.c:53
#define AV_BPRINT_SIZE_UNLIMITED
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:189
const char * err_msg
Definition: vf_drawtext.c:283
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
int y
y position to start drawing text
Definition: vf_drawtext.c:160
const char * arg
Definition: jacosubdec.c:66
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:231
static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
Definition: vf_drawtext.c:1153
uint8_t vsub_max
Definition: drawutils.h:57
static av_always_inline av_const double round(double x)
Definition: libm.h:444
FFDrawColor fontcolor
foreground color
Definition: vf_drawtext.c:178
AVExpr * a_pexpr
Definition: vf_drawtext.c:193
#define FFMAX(a, b)
Definition: common.h:94
#define fail()
Definition: checkasm.h:123
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:149
static const char *const fun2_names[]
Definition: vf_drawtext.c:97
int reload
reload text file for each frame
Definition: vf_drawtext.c:200
AVBPrint expanded_fontcolor
used to contain the expanded fontcolor spec
Definition: vf_drawtext.c:154
var_name
Definition: aeval.c:46
FFDrawContext dc
Definition: vf_drawtext.c:177
#define FFDIFFSIGN(x, y)
Comparator.
Definition: common.h:92
static const struct ft_error ft_errors[]
#define b
Definition: input.c:41
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:391
#define NAN
Definition: mathematics.h:64
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
Definition: drawutils.h:74
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
#define FFMIN(a, b)
Definition: common.h:96
#define width
int64_t basetime
base pts time in the real world for display
Definition: vf_drawtext.c:190
char * fontsize_expr
expression for fontsize
Definition: vf_drawtext.c:165
AVFormatContext * ctx
Definition: movenc.c:48
int max_glyph_h
max glyph height
Definition: vf_drawtext.c:162
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
AVRational tc_rate
frame rate for timecode
Definition: vf_drawtext.c:197
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
#define s(width, name)
Definition: cbs_vp9.c:257
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
int dummy
Definition: motion.c:64
static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1025
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define FF_ARRAY_ELEMS(a)
AVTimecode tc
timecode context
Definition: vf_drawtext.c:198
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
Definition: vf_drawtext.c:1262
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0)
Blend an alpha mask with an uniform color.
Definition: drawutils.c:622
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
misc drawing utilities
int64_t pkt_duration
duration of the corresponding packet, expressed in AVStream->time_base units, 0 if unknown...
Definition: frame.h:587
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:336
Timecode helpers header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:339
static int load_font(AVFilterContext *ctx)
Definition: vf_drawtext.c:554
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:871
timecode wraps after 24 hours
Definition: timecode.h:37
int borderw
border width
Definition: vf_drawtext.c:164
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:53
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
#define llrint(x)
Definition: libm.h:394
uint8_t hsub_max
Definition: drawutils.h:56
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition: jacosubdec.c:67
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
int tabsize
tab size
Definition: vf_drawtext.c:174
int index
Definition: gxfenc.c:89
static int func_strftime(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1009
Rational number (pair of numerator and denominator).
Definition: rational.h:58
void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, int x0, int y0, int w, int h)
Blend a rectangle with an uniform color.
Definition: drawutils.c:445
#define isnan(x)
Definition: libm.h:340
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
Definition: vf_drawtext.c:186
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
static int is_newline(uint32_t c)
Definition: vf_drawtext.c:598
const char * name
Filter name.
Definition: avfilter.h:148
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:32
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:178
static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
Definition: vf_drawtext.c:1193
misc parsing utilities
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
int tag
opaque argument to func
Definition: vf_drawtext.c:1110
short int draw_box
draw box around text - true or false
Definition: vf_drawtext.c:171
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:828
static int64_t pts
#define flags(name, subs,...)
Definition: cbs_av1.c:560
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
Definition: af_afir.c:236
AVDictionary * metadata
Definition: vf_drawtext.c:205
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
Append a formatted date and time to a print buffer.
Definition: bprint.c:176
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
Definition: timecode.c:116
AVFILTER_DEFINE_CLASS(drawtext)
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
static void update_alpha(DrawTextContext *s)
Definition: vf_drawtext.c:1269
int(* func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int)
Definition: vf_drawtext.c:1111
static const char *const var_names[]
Definition: vf_drawtext.c:73
int use_kerning
font kerning is used - true/false
Definition: vf_drawtext.c:173
int
common internal and external API header
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:1788
static int query_formats(AVFilterContext *ctx)
Definition: vf_drawtext.c:787
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:183
#define localtime_r
Definition: time_internal.h:46
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:106
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:1506
static const AVFilterPad avfilter_vf_drawtext_outputs[]
Definition: vf_drawtext.c:1558
AVFilter ff_vf_drawtext
Definition: vf_drawtext.c:1566
static av_always_inline int diff(const uint32_t a, const uint32_t b)
#define av_free(p)
char * value
Definition: dict.h:87
int len
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:766
#define FT_ERRMSG(e)
int reinit
tells if the filter is being reinited
Definition: vf_drawtext.c:146
FFDrawColor shadowcolor
shadow color
Definition: vf_drawtext.c:179
static av_cold int update_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:418
#define OFFSET(x)
Definition: vf_drawtext.c:208
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:59
int line_spacing
lines spacing in pixels
Definition: vf_drawtext.c:170
An instance of a filter.
Definition: avfilter.h:338
int max_glyph_w
max glyph width
Definition: vf_drawtext.c:161
static const eval_func2 fun2[]
Definition: vf_drawtext.c:108
and forward the result(frame or status change) to the corresponding input.If nothing is possible
int height
Definition: frame.h:366
static int func_pts(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:927
FILE * out
Definition: movenc.c:54
unsigned int default_fontsize
default font size to use
Definition: vf_drawtext.c:168
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_afftdn.c:1374
#define av_freep(p)
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:175
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:120
#define av_malloc_array(a, b)
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:158
internal API functions
static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
Load glyphs corresponding to the UTF-32 codepoint code.
Definition: vf_drawtext.c:316
static int load_textfile(AVFilterContext *ctx)
Definition: vf_drawtext.c:571
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv)
Definition: vf_drawtext.c:1126
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:155
int pkt_size
size of the corresponding packet containing the compressed frame.
Definition: frame.h:623
int exp_mode
expansion mode to use for the text
Definition: vf_drawtext.c:145
uint32_t flags
flags such as drop frame, +24 hours support, ...
Definition: timecode.h:43
void av_tree_enumerate(AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem))
Apply enu(opaque, &elem) to all the elements in the tree in a given range.
Definition: tree.c:155
float min
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
size_t nb_positions
number of elements of positions array
Definition: vf_drawtext.c:157
FFDrawColor bordercolor
border color
Definition: vf_drawtext.c:180
int i
Definition: input.c:406
#define FFMAX3(a, b, c)
Definition: common.h:95
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
Definition: vf_drawtext.c:384
void * elem
Definition: tree.c:28
#define AV_TIMECODE_STR_SIZE
Definition: timecode.h:33
simple arithmetic expression evaluator
uint8_t rgba[4]
Definition: drawutils.h:63
const char * name
Definition: opengl_enc.c:102
static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1045
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:140
static uint8_t tmp[11]
Definition: aes_ctr.c:26