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)) {
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)) {
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 
411  if ((err = av_expr_parse(&s->fontsize_pexpr, s->fontsize_expr, var_names,
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) {
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 
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 
571 static inline int is_newline(uint32_t c)
572 {
573  return c == '\n' || c == '\r' || c == '\f' || c == '\v';
574 }
575 
577 {
578  DrawTextContext *s = ctx->priv;
579  int err;
580  uint8_t *textbuf;
581  uint8_t *tmp;
582  size_t textbuf_size;
583 
584  if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
586  "The text file '%s' could not be read or is empty\n",
587  s->textfile);
588  return err;
589  }
590 
591  if (textbuf_size > 0 && is_newline(textbuf[textbuf_size - 1]))
592  textbuf_size--;
593  if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
594  av_file_unmap(textbuf, textbuf_size);
595  return AVERROR(ENOMEM);
596  }
597  s->text = tmp;
598  memcpy(s->text, textbuf, textbuf_size);
599  s->text[textbuf_size] = 0;
600  av_file_unmap(textbuf, textbuf_size);
601 
602  return 0;
603 }
604 
605 #if CONFIG_LIBFRIBIDI
606 static int shape_text(AVFilterContext *ctx)
607 {
608  DrawTextContext *s = ctx->priv;
609  uint8_t *tmp;
610  int ret = AVERROR(ENOMEM);
611  static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
612  FRIBIDI_FLAGS_ARABIC;
613  FriBidiChar *unicodestr = NULL;
614  FriBidiStrIndex len;
615  FriBidiParType direction = FRIBIDI_PAR_LTR;
616  FriBidiStrIndex line_start = 0;
617  FriBidiStrIndex line_end = 0;
618  FriBidiLevel *embedding_levels = NULL;
619  FriBidiArabicProp *ar_props = NULL;
620  FriBidiCharType *bidi_types = NULL;
621  FriBidiStrIndex i,j;
622 
623  len = strlen(s->text);
624  if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
625  goto out;
626  }
627  len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
628  s->text, len, unicodestr);
629 
630  bidi_types = av_malloc_array(len, sizeof(*bidi_types));
631  if (!bidi_types) {
632  goto out;
633  }
634 
635  fribidi_get_bidi_types(unicodestr, len, bidi_types);
636 
637  embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
638  if (!embedding_levels) {
639  goto out;
640  }
641 
642  if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
643  embedding_levels)) {
644  goto out;
645  }
646 
647  ar_props = av_malloc_array(len, sizeof(*ar_props));
648  if (!ar_props) {
649  goto out;
650  }
651 
652  fribidi_get_joining_types(unicodestr, len, ar_props);
653  fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
654  fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);
655 
656  for (line_end = 0, line_start = 0; line_end < len; line_end++) {
657  if (is_newline(unicodestr[line_end]) || line_end == len - 1) {
658  if (!fribidi_reorder_line(flags, bidi_types,
659  line_end - line_start + 1, line_start,
660  direction, embedding_levels, unicodestr,
661  NULL)) {
662  goto out;
663  }
664  line_start = line_end + 1;
665  }
666  }
667 
668  /* Remove zero-width fill chars put in by libfribidi */
669  for (i = 0, j = 0; i < len; i++)
670  if (unicodestr[i] != FRIBIDI_CHAR_FILL)
671  unicodestr[j++] = unicodestr[i];
672  len = j;
673 
674  if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
675  /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
676  goto out;
677  }
678 
679  s->text = tmp;
680  len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
681  unicodestr, len, s->text);
682  ret = 0;
683 
684 out:
685  av_free(unicodestr);
686  av_free(embedding_levels);
687  av_free(ar_props);
688  av_free(bidi_types);
689  return ret;
690 }
691 #endif
692 
694 {
695  int err;
696  DrawTextContext *s = ctx->priv;
697  Glyph *glyph;
698 
699  av_expr_free(s->fontsize_pexpr);
700  s->fontsize_pexpr = NULL;
701 
702  s->fontsize = 0;
703  s->default_fontsize = 16;
704 
705  if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
706  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
707  return AVERROR(EINVAL);
708  }
709 
710  if (s->textfile) {
711  if (s->text) {
713  "Both text and text file provided. Please provide only one\n");
714  return AVERROR(EINVAL);
715  }
716  if ((err = load_textfile(ctx)) < 0)
717  return err;
718  }
719 
720  if (s->reload && !s->textfile)
721  av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
722 
723  if (s->tc_opt_string) {
724  int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
725  s->tc_opt_string, ctx);
726  if (ret < 0)
727  return ret;
728  if (s->tc24hmax)
729  s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
730  if (!s->text)
731  s->text = av_strdup("");
732  }
733 
734  if (!s->text) {
736  "Either text, a valid file or a timecode must be provided\n");
737  return AVERROR(EINVAL);
738  }
739 
740 #if CONFIG_LIBFRIBIDI
741  if (s->text_shaping)
742  if ((err = shape_text(ctx)) < 0)
743  return err;
744 #endif
745 
746  if ((err = FT_Init_FreeType(&(s->library)))) {
748  "Could not load FreeType: %s\n", FT_ERRMSG(err));
749  return AVERROR(EINVAL);
750  }
751 
752  if ((err = load_font(ctx)) < 0)
753  return err;
754 
755  if ((err = update_fontsize(ctx)) < 0)
756  return err;
757 
758  if (s->borderw) {
759  if (FT_Stroker_New(s->library, &s->stroker)) {
760  av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
761  return AVERROR_EXTERNAL;
762  }
763  FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
764  FT_STROKER_LINEJOIN_ROUND, 0);
765  }
766 
767  s->use_kerning = FT_HAS_KERNING(s->face);
768 
769  /* load the fallback glyph with code 0 */
770  load_glyph(ctx, NULL, 0);
771 
772  /* set the tabsize in pixels */
773  if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
774  av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
775  return err;
776  }
777  s->tabsize *= glyph->advance;
778 
779  if (s->exp_mode == EXP_STRFTIME &&
780  (strchr(s->text, '%') || strchr(s->text, '\\')))
781  av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
782 
783  av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
784  av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);
785 
786  return 0;
787 }
788 
790 {
792 }
793 
794 static int glyph_enu_free(void *opaque, void *elem)
795 {
796  Glyph *glyph = elem;
797 
798  FT_Done_Glyph(glyph->glyph);
799  FT_Done_Glyph(glyph->border_glyph);
800  av_free(elem);
801  return 0;
802 }
803 
805 {
806  DrawTextContext *s = ctx->priv;
807 
808  av_expr_free(s->x_pexpr);
809  av_expr_free(s->y_pexpr);
810  av_expr_free(s->a_pexpr);
811  av_expr_free(s->fontsize_pexpr);
812 
813  s->x_pexpr = s->y_pexpr = s->a_pexpr = s->fontsize_pexpr = NULL;
814 
815  av_freep(&s->positions);
816  s->nb_positions = 0;
817 
819  av_tree_destroy(s->glyphs);
820  s->glyphs = NULL;
821 
822  FT_Done_Face(s->face);
823  FT_Stroker_Done(s->stroker);
824  FT_Done_FreeType(s->library);
825 
826  av_bprint_finalize(&s->expanded_text, NULL);
827  av_bprint_finalize(&s->expanded_fontcolor, NULL);
828 }
829 
831 {
832  AVFilterContext *ctx = inlink->dst;
833  DrawTextContext *s = ctx->priv;
834  char *expr;
835  int ret;
836 
837  ff_draw_init(&s->dc, inlink->format, FF_DRAW_PROCESS_ALPHA);
838  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
839  ff_draw_color(&s->dc, &s->shadowcolor, s->shadowcolor.rgba);
840  ff_draw_color(&s->dc, &s->bordercolor, s->bordercolor.rgba);
841  ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
842 
843  s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
844  s->var_values[VAR_h] = s->var_values[VAR_H] = s->var_values[VAR_MAIN_H] = inlink->h;
845  s->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
846  s->var_values[VAR_DAR] = (double)inlink->w / inlink->h * s->var_values[VAR_SAR];
847  s->var_values[VAR_HSUB] = 1 << s->dc.hsub_max;
848  s->var_values[VAR_VSUB] = 1 << s->dc.vsub_max;
849  s->var_values[VAR_X] = NAN;
850  s->var_values[VAR_Y] = NAN;
851  s->var_values[VAR_T] = NAN;
852 
853  av_lfg_init(&s->prng, av_get_random_seed());
854 
855  av_expr_free(s->x_pexpr);
856  av_expr_free(s->y_pexpr);
857  av_expr_free(s->a_pexpr);
858  s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
859 
860  if ((ret = av_expr_parse(&s->x_pexpr, expr = s->x_expr, var_names,
861  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
862  (ret = av_expr_parse(&s->y_pexpr, expr = s->y_expr, var_names,
863  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
864  (ret = av_expr_parse(&s->a_pexpr, expr = s->a_expr, var_names,
865  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
866  av_log(ctx, AV_LOG_ERROR, "Failed to parse expression: %s \n", expr);
867  return AVERROR(EINVAL);
868  }
869 
870  return 0;
871 }
872 
873 static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
874 {
875  DrawTextContext *old = ctx->priv;
876  DrawTextContext *new = NULL;
877  int ret;
878 
879  if (!strcmp(cmd, "reinit")) {
880  new = av_mallocz(sizeof(DrawTextContext));
881  if (!new)
882  return AVERROR(ENOMEM);
883 
884  new->class = &drawtext_class;
885  ret = av_opt_copy(new, old);
886  if (ret < 0)
887  goto fail;
888 
889  ctx->priv = new;
890  ret = av_set_options_string(ctx, arg, "=", ":");
891  if (ret < 0) {
892  ctx->priv = old;
893  goto fail;
894  }
895 
896  ret = init(ctx);
897  if (ret < 0) {
898  uninit(ctx);
899  ctx->priv = old;
900  goto fail;
901  }
902 
903  new->reinit = 1;
904 
905  ctx->priv = old;
906  uninit(ctx);
907  av_freep(&old);
908 
909  ctx->priv = new;
910  return config_input(ctx->inputs[0]);
911  } else
912  return AVERROR(ENOSYS);
913 
914 fail:
915  av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
916  av_freep(&new);
917  return ret;
918 }
919 
920 static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
921  char *fct, unsigned argc, char **argv, int tag)
922 {
923  DrawTextContext *s = ctx->priv;
924 
925  av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
926  return 0;
927 }
928 
929 static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
930  char *fct, unsigned argc, char **argv, int tag)
931 {
932  DrawTextContext *s = ctx->priv;
933  const char *fmt;
934  double pts = s->var_values[VAR_T];
935  int ret;
936 
937  fmt = argc >= 1 ? argv[0] : "flt";
938  if (argc >= 2) {
939  int64_t delta;
940  if ((ret = av_parse_time(&delta, argv[1], 1)) < 0) {
941  av_log(ctx, AV_LOG_ERROR, "Invalid delta '%s'\n", argv[1]);
942  return ret;
943  }
944  pts += (double)delta / AV_TIME_BASE;
945  }
946  if (!strcmp(fmt, "flt")) {
947  av_bprintf(bp, "%.6f", pts);
948  } else if (!strcmp(fmt, "hms")) {
949  if (isnan(pts)) {
950  av_bprintf(bp, " ??:??:??.???");
951  } else {
952  int64_t ms = llrint(pts * 1000);
953  char sign = ' ';
954  if (ms < 0) {
955  sign = '-';
956  ms = -ms;
957  }
958  if (argc >= 3) {
959  if (!strcmp(argv[2], "24HH")) {
960  ms %= 24 * 60 * 60 * 1000;
961  } else {
962  av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", argv[2]);
963  return AVERROR(EINVAL);
964  }
965  }
966  av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
967  (int)(ms / (60 * 60 * 1000)),
968  (int)(ms / (60 * 1000)) % 60,
969  (int)(ms / 1000) % 60,
970  (int)(ms % 1000));
971  }
972  } else if (!strcmp(fmt, "localtime") ||
973  !strcmp(fmt, "gmtime")) {
974  struct tm tm;
975  time_t ms = (time_t)pts;
976  const char *timefmt = argc >= 3 ? argv[2] : "%Y-%m-%d %H:%M:%S";
977  if (!strcmp(fmt, "localtime"))
978  localtime_r(&ms, &tm);
979  else
980  gmtime_r(&ms, &tm);
981  av_bprint_strftime(bp, timefmt, &tm);
982  } else {
983  av_log(ctx, AV_LOG_ERROR, "Invalid format '%s'\n", fmt);
984  return AVERROR(EINVAL);
985  }
986  return 0;
987 }
988 
989 static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
990  char *fct, unsigned argc, char **argv, int tag)
991 {
992  DrawTextContext *s = ctx->priv;
993 
994  av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
995  return 0;
996 }
997 
998 static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
999  char *fct, unsigned argc, char **argv, int tag)
1000 {
1001  DrawTextContext *s = ctx->priv;
1002  AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
1003 
1004  if (e && e->value)
1005  av_bprintf(bp, "%s", e->value);
1006  else if (argc >= 2)
1007  av_bprintf(bp, "%s", argv[1]);
1008  return 0;
1009 }
1010 
1011 static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
1012  char *fct, unsigned argc, char **argv, int tag)
1013 {
1014  const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
1015  time_t now;
1016  struct tm tm;
1017 
1018  time(&now);
1019  if (tag == 'L')
1020  localtime_r(&now, &tm);
1021  else
1022  tm = *gmtime_r(&now, &tm);
1023  av_bprint_strftime(bp, fmt, &tm);
1024  return 0;
1025 }
1026 
1027 static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
1028  char *fct, unsigned argc, char **argv, int tag)
1029 {
1030  DrawTextContext *s = ctx->priv;
1031  double res;
1032  int ret;
1033 
1034  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1035  NULL, NULL, fun2_names, fun2,
1036  &s->prng, 0, ctx);
1037  if (ret < 0)
1039  "Expression '%s' for the expr text expansion function is not valid\n",
1040  argv[0]);
1041  else
1042  av_bprintf(bp, "%f", res);
1043 
1044  return ret;
1045 }
1046 
1048  char *fct, unsigned argc, char **argv, int tag)
1049 {
1050  DrawTextContext *s = ctx->priv;
1051  double res;
1052  int intval;
1053  int ret;
1054  unsigned int positions = 0;
1055  char fmt_str[30] = "%";
1056 
1057  /*
1058  * argv[0] expression to be converted to `int`
1059  * argv[1] format: 'x', 'X', 'd' or 'u'
1060  * argv[2] positions printed (optional)
1061  */
1062 
1063  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1064  NULL, NULL, fun2_names, fun2,
1065  &s->prng, 0, ctx);
1066  if (ret < 0) {
1068  "Expression '%s' for the expr text expansion function is not valid\n",
1069  argv[0]);
1070  return ret;
1071  }
1072 
1073  if (!strchr("xXdu", argv[1][0])) {
1074  av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified,"
1075  " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
1076  return AVERROR(EINVAL);
1077  }
1078 
1079  if (argc == 3) {
1080  ret = sscanf(argv[2], "%u", &positions);
1081  if (ret != 1) {
1082  av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
1083  " to print: '%s'\n", argv[2]);
1084  return AVERROR(EINVAL);
1085  }
1086  }
1087 
1088  feclearexcept(FE_ALL_EXCEPT);
1089  intval = res;
1090 #if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
1091  if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
1092  av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
1093  return AVERROR(EINVAL);
1094  }
1095 #endif
1096 
1097  if (argc == 3)
1098  av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
1099  av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]);
1100 
1101  av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
1102  res, argv[0], fmt_str);
1103 
1104  av_bprintf(bp, fmt_str, intval);
1105 
1106  return 0;
1107 }
1108 
1109 static const struct drawtext_function {
1110  const char *name;
1111  unsigned argc_min, argc_max;
1112  int tag; /**< opaque argument to func */
1113  int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
1114 } functions[] = {
1115  { "expr", 1, 1, 0, func_eval_expr },
1116  { "e", 1, 1, 0, func_eval_expr },
1117  { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
1118  { "eif", 2, 3, 0, func_eval_expr_int_format },
1119  { "pict_type", 0, 0, 0, func_pict_type },
1120  { "pts", 0, 3, 0, func_pts },
1121  { "gmtime", 0, 1, 'G', func_strftime },
1122  { "localtime", 0, 1, 'L', func_strftime },
1123  { "frame_num", 0, 0, 0, func_frame_num },
1124  { "n", 0, 0, 0, func_frame_num },
1125  { "metadata", 1, 2, 0, func_metadata },
1126 };
1127 
1128 static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
1129  unsigned argc, char **argv)
1130 {
1131  unsigned i;
1132 
1133  for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
1134  if (strcmp(fct, functions[i].name))
1135  continue;
1136  if (argc < functions[i].argc_min) {
1137  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
1138  fct, functions[i].argc_min);
1139  return AVERROR(EINVAL);
1140  }
1141  if (argc > functions[i].argc_max) {
1142  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
1143  fct, functions[i].argc_max);
1144  return AVERROR(EINVAL);
1145  }
1146  break;
1147  }
1148  if (i >= FF_ARRAY_ELEMS(functions)) {
1149  av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
1150  return AVERROR(EINVAL);
1151  }
1152  return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
1153 }
1154 
1155 static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
1156 {
1157  const char *text = *rtext;
1158  char *argv[16] = { NULL };
1159  unsigned argc = 0, i;
1160  int ret;
1161 
1162  if (*text != '{') {
1163  av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
1164  return AVERROR(EINVAL);
1165  }
1166  text++;
1167  while (1) {
1168  if (!(argv[argc++] = av_get_token(&text, ":}"))) {
1169  ret = AVERROR(ENOMEM);
1170  goto end;
1171  }
1172  if (!*text) {
1173  av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
1174  ret = AVERROR(EINVAL);
1175  goto end;
1176  }
1177  if (argc == FF_ARRAY_ELEMS(argv))
1178  av_freep(&argv[--argc]); /* error will be caught later */
1179  if (*text == '}')
1180  break;
1181  text++;
1182  }
1183 
1184  if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
1185  goto end;
1186  ret = 0;
1187  *rtext = (char *)text + 1;
1188 
1189 end:
1190  for (i = 0; i < argc; i++)
1191  av_freep(&argv[i]);
1192  return ret;
1193 }
1194 
1195 static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
1196 {
1197  int ret;
1198 
1199  av_bprint_clear(bp);
1200  while (*text) {
1201  if (*text == '\\' && text[1]) {
1202  av_bprint_chars(bp, text[1], 1);
1203  text += 2;
1204  } else if (*text == '%') {
1205  text++;
1206  if ((ret = expand_function(ctx, bp, &text)) < 0)
1207  return ret;
1208  } else {
1209  av_bprint_chars(bp, *text, 1);
1210  text++;
1211  }
1212  }
1213  if (!av_bprint_is_complete(bp))
1214  return AVERROR(ENOMEM);
1215  return 0;
1216 }
1217 
1219  int width, int height,
1220  FFDrawColor *color,
1221  int x, int y, int borderw)
1222 {
1223  char *text = s->expanded_text.str;
1224  uint32_t code = 0;
1225  int i, x1, y1;
1226  uint8_t *p;
1227  Glyph *glyph = NULL;
1228 
1229  for (i = 0, p = text; *p; i++) {
1230  FT_Bitmap bitmap;
1231  Glyph dummy = { 0 };
1232  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1233 continue_on_invalid:
1234 
1235  /* skip new line chars, just go to new line */
1236  if (code == '\n' || code == '\r' || code == '\t')
1237  continue;
1238 
1239  dummy.code = code;
1240  dummy.fontsize = s->fontsize;
1241  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1242 
1243  bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
1244 
1245  if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
1246  glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1247  return AVERROR(EINVAL);
1248 
1249  x1 = s->positions[i].x+s->x+x - borderw;
1250  y1 = s->positions[i].y+s->y+y - borderw;
1251 
1252  ff_blend_mask(&s->dc, color,
1253  frame->data, frame->linesize, width, height,
1254  bitmap.buffer, bitmap.pitch,
1255  bitmap.width, bitmap.rows,
1256  bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
1257  0, x1, y1);
1258  }
1259 
1260  return 0;
1261 }
1262 
1263 
1265 {
1266  *color = incolor;
1267  color->rgba[3] = (color->rgba[3] * s->alpha) / 255;
1268  ff_draw_color(&s->dc, color, color->rgba);
1269 }
1270 
1272 {
1273  double alpha = av_expr_eval(s->a_pexpr, s->var_values, &s->prng);
1274 
1275  if (isnan(alpha))
1276  return;
1277 
1278  if (alpha >= 1.0)
1279  s->alpha = 255;
1280  else if (alpha <= 0)
1281  s->alpha = 0;
1282  else
1283  s->alpha = 256 * alpha;
1284 }
1285 
1287  int width, int height)
1288 {
1289  DrawTextContext *s = ctx->priv;
1290  AVFilterLink *inlink = ctx->inputs[0];
1291 
1292  uint32_t code = 0, prev_code = 0;
1293  int x = 0, y = 0, i = 0, ret;
1294  int max_text_line_w = 0, len;
1295  int box_w, box_h;
1296  char *text;
1297  uint8_t *p;
1298  int y_min = 32000, y_max = -32000;
1299  int x_min = 32000, x_max = -32000;
1300  FT_Vector delta;
1301  Glyph *glyph = NULL, *prev_glyph = NULL;
1302  Glyph dummy = { 0 };
1303 
1304  time_t now = time(0);
1305  struct tm ltime;
1306  AVBPrint *bp = &s->expanded_text;
1307 
1308  FFDrawColor fontcolor;
1309  FFDrawColor shadowcolor;
1310  FFDrawColor bordercolor;
1311  FFDrawColor boxcolor;
1312 
1313  av_bprint_clear(bp);
1314 
1315  if(s->basetime != AV_NOPTS_VALUE)
1316  now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + s->basetime/1000000;
1317 
1318  switch (s->exp_mode) {
1319  case EXP_NONE:
1320  av_bprintf(bp, "%s", s->text);
1321  break;
1322  case EXP_NORMAL:
1323  if ((ret = expand_text(ctx, s->text, &s->expanded_text)) < 0)
1324  return ret;
1325  break;
1326  case EXP_STRFTIME:
1327  localtime_r(&now, &ltime);
1328  av_bprint_strftime(bp, s->text, &ltime);
1329  break;
1330  }
1331 
1332  if (s->tc_opt_string) {
1333  char tcbuf[AV_TIMECODE_STR_SIZE];
1334  av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count_out);
1335  av_bprint_clear(bp);
1336  av_bprintf(bp, "%s%s", s->text, tcbuf);
1337  }
1338 
1339  if (!av_bprint_is_complete(bp))
1340  return AVERROR(ENOMEM);
1341  text = s->expanded_text.str;
1342  if ((len = s->expanded_text.len) > s->nb_positions) {
1343  if (!(s->positions =
1344  av_realloc(s->positions, len*sizeof(*s->positions))))
1345  return AVERROR(ENOMEM);
1346  s->nb_positions = len;
1347  }
1348 
1349  if (s->fontcolor_expr[0]) {
1350  /* If expression is set, evaluate and replace the static value */
1351  av_bprint_clear(&s->expanded_fontcolor);
1352  if ((ret = expand_text(ctx, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
1353  return ret;
1354  if (!av_bprint_is_complete(&s->expanded_fontcolor))
1355  return AVERROR(ENOMEM);
1356  av_log(s, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
1357  ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
1358  if (ret)
1359  return ret;
1360  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
1361  }
1362 
1363  x = 0;
1364  y = 0;
1365 
1366  if ((ret = update_fontsize(ctx)) < 0)
1367  return ret;
1368 
1369  /* load and cache glyphs */
1370  for (i = 0, p = text; *p; i++) {
1371  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1372 continue_on_invalid:
1373 
1374  /* get glyph */
1375  dummy.code = code;
1376  dummy.fontsize = s->fontsize;
1377  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1378  if (!glyph) {
1379  ret = load_glyph(ctx, &glyph, code);
1380  if (ret < 0)
1381  return ret;
1382  }
1383 
1384  y_min = FFMIN(glyph->bbox.yMin, y_min);
1385  y_max = FFMAX(glyph->bbox.yMax, y_max);
1386  x_min = FFMIN(glyph->bbox.xMin, x_min);
1387  x_max = FFMAX(glyph->bbox.xMax, x_max);
1388  }
1389  s->max_glyph_h = y_max - y_min;
1390  s->max_glyph_w = x_max - x_min;
1391 
1392  /* compute and save position for each glyph */
1393  glyph = NULL;
1394  for (i = 0, p = text; *p; i++) {
1395  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid2;);
1396 continue_on_invalid2:
1397 
1398  /* skip the \n in the sequence \r\n */
1399  if (prev_code == '\r' && code == '\n')
1400  continue;
1401 
1402  prev_code = code;
1403  if (is_newline(code)) {
1404 
1405  max_text_line_w = FFMAX(max_text_line_w, x);
1406  y += s->max_glyph_h + s->line_spacing;
1407  x = 0;
1408  continue;
1409  }
1410 
1411  /* get glyph */
1412  prev_glyph = glyph;
1413  dummy.code = code;
1414  dummy.fontsize = s->fontsize;
1415  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1416 
1417  /* kerning */
1418  if (s->use_kerning && prev_glyph && glyph->code) {
1419  FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
1420  ft_kerning_default, &delta);
1421  x += delta.x >> 6;
1422  }
1423 
1424  /* save position */
1425  s->positions[i].x = x + glyph->bitmap_left;
1426  s->positions[i].y = y - glyph->bitmap_top + y_max;
1427  if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
1428  else x += glyph->advance;
1429  }
1430 
1431  max_text_line_w = FFMAX(x, max_text_line_w);
1432 
1433  s->var_values[VAR_TW] = s->var_values[VAR_TEXT_W] = max_text_line_w;
1434  s->var_values[VAR_TH] = s->var_values[VAR_TEXT_H] = y + s->max_glyph_h;
1435 
1436  s->var_values[VAR_MAX_GLYPH_W] = s->max_glyph_w;
1437  s->var_values[VAR_MAX_GLYPH_H] = s->max_glyph_h;
1438  s->var_values[VAR_MAX_GLYPH_A] = s->var_values[VAR_ASCENT ] = y_max;
1439  s->var_values[VAR_MAX_GLYPH_D] = s->var_values[VAR_DESCENT] = y_min;
1440 
1441  s->var_values[VAR_LINE_H] = s->var_values[VAR_LH] = s->max_glyph_h;
1442 
1443  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1444  s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
1445  /* It is necessary if x is expressed from y */
1446  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1447 
1448  update_alpha(s);
1449  update_color_with_alpha(s, &fontcolor , s->fontcolor );
1450  update_color_with_alpha(s, &shadowcolor, s->shadowcolor);
1451  update_color_with_alpha(s, &bordercolor, s->bordercolor);
1452  update_color_with_alpha(s, &boxcolor , s->boxcolor );
1453 
1454  box_w = max_text_line_w;
1455  box_h = y + s->max_glyph_h;
1456 
1457  if (s->fix_bounds) {
1458 
1459  /* calculate footprint of text effects */
1460  int boxoffset = s->draw_box ? FFMAX(s->boxborderw, 0) : 0;
1461  int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0;
1462 
1463  int offsetleft = FFMAX3(boxoffset, borderoffset,
1464  (s->shadowx < 0 ? FFABS(s->shadowx) : 0));
1465  int offsettop = FFMAX3(boxoffset, borderoffset,
1466  (s->shadowy < 0 ? FFABS(s->shadowy) : 0));
1467 
1468  int offsetright = FFMAX3(boxoffset, borderoffset,
1469  (s->shadowx > 0 ? s->shadowx : 0));
1470  int offsetbottom = FFMAX3(boxoffset, borderoffset,
1471  (s->shadowy > 0 ? s->shadowy : 0));
1472 
1473 
1474  if (s->x - offsetleft < 0) s->x = offsetleft;
1475  if (s->y - offsettop < 0) s->y = offsettop;
1476 
1477  if (s->x + box_w + offsetright > width)
1478  s->x = FFMAX(width - box_w - offsetright, 0);
1479  if (s->y + box_h + offsetbottom > height)
1480  s->y = FFMAX(height - box_h - offsetbottom, 0);
1481  }
1482 
1483  /* draw box */
1484  if (s->draw_box)
1485  ff_blend_rectangle(&s->dc, &boxcolor,
1486  frame->data, frame->linesize, width, height,
1487  s->x - s->boxborderw, s->y - s->boxborderw,
1488  box_w + s->boxborderw * 2, box_h + s->boxborderw * 2);
1489 
1490  if (s->shadowx || s->shadowy) {
1491  if ((ret = draw_glyphs(s, frame, width, height,
1492  &shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
1493  return ret;
1494  }
1495 
1496  if (s->borderw) {
1497  if ((ret = draw_glyphs(s, frame, width, height,
1498  &bordercolor, 0, 0, s->borderw)) < 0)
1499  return ret;
1500  }
1501  if ((ret = draw_glyphs(s, frame, width, height,
1502  &fontcolor, 0, 0, 0)) < 0)
1503  return ret;
1504 
1505  return 0;
1506 }
1507 
1509 {
1510  AVFilterContext *ctx = inlink->dst;
1511  AVFilterLink *outlink = ctx->outputs[0];
1512  DrawTextContext *s = ctx->priv;
1513  int ret;
1514 
1515  if (s->reload) {
1516  if ((ret = load_textfile(ctx)) < 0) {
1517  av_frame_free(&frame);
1518  return ret;
1519  }
1520 #if CONFIG_LIBFRIBIDI
1521  if (s->text_shaping)
1522  if ((ret = shape_text(ctx)) < 0) {
1523  av_frame_free(&frame);
1524  return ret;
1525  }
1526 #endif
1527  }
1528 
1529  s->var_values[VAR_N] = inlink->frame_count_out + s->start_number;
1530  s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
1531  NAN : frame->pts * av_q2d(inlink->time_base);
1532 
1533  s->var_values[VAR_PICT_TYPE] = frame->pict_type;
1534  s->var_values[VAR_PKT_POS] = frame->pkt_pos;
1535  s->var_values[VAR_PKT_DURATION] = frame->pkt_duration * av_q2d(inlink->time_base);
1536  s->var_values[VAR_PKT_SIZE] = frame->pkt_size;
1537  s->metadata = frame->metadata;
1538 
1539  draw_text(ctx, frame, frame->width, frame->height);
1540 
1541  av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
1542  (int)s->var_values[VAR_N], s->var_values[VAR_T],
1543  (int)s->var_values[VAR_TEXT_W], (int)s->var_values[VAR_TEXT_H],
1544  s->x, s->y);
1545 
1546  return ff_filter_frame(outlink, frame);
1547 }
1548 
1550  {
1551  .name = "default",
1552  .type = AVMEDIA_TYPE_VIDEO,
1553  .filter_frame = filter_frame,
1554  .config_props = config_input,
1555  .needs_writable = 1,
1556  },
1557  { NULL }
1558 };
1559 
1561  {
1562  .name = "default",
1563  .type = AVMEDIA_TYPE_VIDEO,
1564  },
1565  { NULL }
1566 };
1567 
1569  .name = "drawtext",
1570  .description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
1571  .priv_size = sizeof(DrawTextContext),
1572  .priv_class = &drawtext_class,
1573  .init = init,
1574  .uninit = uninit,
1580 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:30
DrawTextContext::library
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:183
OFFSET
#define OFFSET(x)
Definition: vf_drawtext.c:208
fun2_names
static const char *const fun2_names[]
Definition: vf_drawtext.c:97
VAR_N
@ VAR_N
Definition: vf_drawtext.c:123
VAR_TEXT_H
@ VAR_TEXT_H
Definition: vf_drawtext.c:126
VAR_MAIN_H
@ VAR_MAIN_H
Definition: vf_drawtext.c:117
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
drawtext_function::func
int(* func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int)
Definition: vf_drawtext.c:1113
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
AV_TIMECODE_STR_SIZE
#define AV_TIMECODE_STR_SIZE
Definition: timecode.h:33
FFDrawColor
Definition: drawutils.h:49
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
VAR_LINE_H
@ VAR_LINE_H
Definition: vf_drawtext.c:116
VAR_Y
@ VAR_Y
Definition: vf_drawtext.c:129
VAR_MAX_GLYPH_H
@ VAR_MAX_GLYPH_H
Definition: vf_drawtext.c:121
DrawTextContext::a_expr
char * a_expr
Definition: vf_drawtext.c:192
ff_vf_drawtext
AVFilter ff_vf_drawtext
Definition: vf_drawtext.c:1568
AVERROR
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
opt.h
VAR_PKT_DURATION
@ VAR_PKT_DURATION
Definition: vf_drawtext.c:132
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
out
FILE * out
Definition: movenc.c:54
color
Definition: vf_paletteuse.c:583
av_lfg_init
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:32
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
av_get_token
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:151
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:1508
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1096
func_pts
static int func_pts(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:929
av_parse_color
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
av_tree_insert
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
DrawTextContext::default_fontsize
unsigned int default_fontsize
default font size to use
Definition: vf_drawtext.c:168
VAR_TW
@ VAR_TW
Definition: vf_drawtext.c:127
VAR_ASCENT
@ VAR_ASCENT
Definition: vf_drawtext.c:119
func_frame_num
static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:989
inlink
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
Definition: filter_design.txt:212
DrawTextContext::tc24hmax
int tc24hmax
1 if timecode is wrapped to 24 hours, 0 otherwise
Definition: vf_drawtext.c:199
drawtext_function
Definition: vf_drawtext.c:1109
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:27
DrawTextContext::x
int x
x position to start drawing text
Definition: vf_drawtext.c:159
DrawTextContext::bordercolor
FFDrawColor bordercolor
border color
Definition: vf_drawtext.c:180
AVTreeNode::elem
void * elem
Definition: tree.c:28
av_bprint_strftime
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
DrawTextContext::exp_mode
int exp_mode
expansion mode to use for the text
Definition: vf_drawtext.c:145
VAR_DESCENT
@ VAR_DESCENT
Definition: vf_drawtext.c:120
AVOption
AVOption.
Definition: opt.h:248
b
#define b
Definition: input.c:41
DrawTextContext::nb_positions
size_t nb_positions
number of elements of positions array
Definition: vf_drawtext.c:157
max
#define max(a, b)
Definition: cuda_runtime.h:33
func_pict_type
static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:920
AVDictionary
Definition: dict.c:30
DrawTextContext::stroker
FT_Stroker stroker
freetype stroker handle
Definition: vf_drawtext.c:185
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:149
expand_function
static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
Definition: vf_drawtext.c:1155
av_tree_node_alloc
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
drawtext_function::name
const char * name
Definition: vf_drawtext.c:1110
VAR_MAX_GLYPH_W
@ VAR_MAX_GLYPH_W
Definition: vf_drawtext.c:122
func_metadata
static int func_metadata(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:998
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
AV_OPT_TYPE_RATIONAL
@ AV_OPT_TYPE_RATIONAL
Definition: opt.h:230
DrawTextContext::prng
AVLFG prng
random
Definition: vf_drawtext.c:195
video.h
VAR_MAIN_W
@ VAR_MAIN_W
Definition: vf_drawtext.c:118
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
av_tree_enumerate
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
av_get_random_seed
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:120
formats.h
DrawTextContext::start_number
int start_number
starting frame number for n/frame_num var
Definition: vf_drawtext.c:201
av_expr_parse
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
DrawTextContext::text
uint8_t * text
text to be drawn
Definition: vf_drawtext.c:151
DrawTextContext::expanded_text
AVBPrint expanded_text
used to contain the expanded text
Definition: vf_drawtext.c:152
av_set_options_string
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:1479
VAR_H
@ VAR_H
Definition: vf_drawtext.c:117
DrawTextContext::fontsize
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:167
func_eval_expr
static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1027
DrawTextContext::x_expr
char * x_expr
expression for x position
Definition: vf_drawtext.c:187
positions
const static uint16_t positions[][14][3]
Definition: vf_vectorscope.c:817
DrawTextContext::fontfile
uint8_t * fontfile
font to be used
Definition: vf_drawtext.c:150
av_file_map
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
expansion_mode
expansion_mode
Definition: vf_drawtext.c:137
DrawTextContext::y_pexpr
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:189
fail
#define fail()
Definition: checkasm.h:133
VAR_VARS_NB
@ VAR_VARS_NB
Definition: vf_drawtext.c:134
timecode.h
EXP_NONE
@ EXP_NONE
Definition: vf_drawtext.c:138
av_timecode_make_string
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
Definition: timecode.c:102
is_newline
static int is_newline(uint32_t c)
Definition: vf_drawtext.c:571
gmtime_r
#define gmtime_r
Definition: time_internal.h:34
pts
static int64_t pts
Definition: transcode_aac.c:652
ff_blend_mask
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:528
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:336
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
DrawTextContext::var_values
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:191
GET_UTF8
#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:499
FLAGS
#define FLAGS
Definition: vf_drawtext.c:209
avfilter_vf_drawtext_inputs
static const AVFilterPad avfilter_vf_drawtext_inputs[]
Definition: vf_drawtext.c:1549
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
DrawTextContext::dc
FFDrawContext dc
Definition: vf_drawtext.c:177
var_name
var_name
Definition: setts_bsf.c:50
ff_set_common_formats
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:587
update_alpha
static void update_alpha(DrawTextContext *s)
Definition: vf_drawtext.c:1271
DrawTextContext::face
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:184
av_dict_get
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
width
#define width
FFMAX3
#define FFMAX3(a, b, c)
Definition: common.h:104
s
#define s(width, name)
Definition: cbs_vp9.c:257
update_fontsize
static av_cold int update_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:418
DrawTextContext::y
int y
y position to start drawing text
Definition: vf_drawtext.c:160
VAR_X
@ VAR_X
Definition: vf_drawtext.c:128
av_lfg_get
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:53
VAR_TH
@ VAR_TH
Definition: vf_drawtext.c:126
DrawTextContext::fontcolor
FFDrawColor fontcolor
foreground color
Definition: vf_drawtext.c:178
DrawTextContext::a_pexpr
AVExpr * a_pexpr
Definition: vf_drawtext.c:193
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
lfg.h
FF_DRAW_PROCESS_ALPHA
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
Definition: drawutils.h:61
DrawTextContext::boxborderw
int boxborderw
box border width
Definition: vf_drawtext.c:172
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Definition: opt.h:226
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_expr_eval
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:766
VAR_SAR
@ VAR_SAR
Definition: vf_drawtext.c:124
AVExpr
Definition: eval.c:157
ff_draw_init
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:84
DrawTextContext::fontsize_pexpr
AVExpr * fontsize_pexpr
parsed expressions for fontsize
Definition: vf_drawtext.c:166
eval_func2
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:106
ft_error::err
int err
Definition: vf_drawtext.c:282
key
const char * key
Definition: hwcontext_opencl.c:168
VAR_T
@ VAR_T
Definition: vf_drawtext.c:125
NAN
#define NAN
Definition: mathematics.h:64
command
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:873
av_file_unmap
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
arg
const char * arg
Definition: jacosubdec.c:66
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
time_internal.h
VAR_VSUB
@ VAR_VSUB
Definition: vf_drawtext.c:115
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
NULL
#define NULL
Definition: coverity.c:32
VAR_PICT_TYPE
@ VAR_PICT_TYPE
Definition: vf_drawtext.c:130
DrawTextContext::basetime
int64_t basetime
base pts time in the real world for display
Definition: vf_drawtext.c:190
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
DrawTextContext::fontsize_expr
char * fontsize_expr
expression for fontsize
Definition: vf_drawtext.c:165
isnan
#define isnan(x)
Definition: libm.h:340
AV_OPT_TYPE_COLOR
@ AV_OPT_TYPE_COLOR
Definition: opt.h:240
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_drawtext.c:789
draw_text
static int draw_text(AVFilterContext *ctx, AVFrame *frame, int width, int height)
Definition: vf_drawtext.c:1286
VAR_PKT_SIZE
@ VAR_PKT_SIZE
Definition: vf_drawtext.c:133
parseutils.h
AVTreeNode
Definition: tree.c:26
DrawTextContext::tc_rate
AVRational tc_rate
frame rate for timecode
Definition: vf_drawtext.c:197
DrawTextContext::x_pexpr
AVExpr * x_pexpr
Definition: vf_drawtext.c:189
av_parse_time
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
time.h
DrawTextContext::positions
FT_Vector * positions
positions for each element in the text
Definition: vf_drawtext.c:156
VAR_MAX_GLYPH_A
@ VAR_MAX_GLYPH_A
Definition: vf_drawtext.c:119
inputs
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
Definition: filter_design.txt:243
load_font_file
static int load_font_file(AVFilterContext *ctx, const char *path, int index)
Definition: vf_drawtext.c:454
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
DrawTextContext
Definition: vf_drawtext.c:143
DrawTextContext::tabsize
int tabsize
tab size
Definition: vf_drawtext.c:174
index
int index
Definition: gxfenc.c:89
c
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
var_names
static const char *const var_names[]
Definition: vf_drawtext.c:73
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
DrawTextContext::reload
int reload
reload text file for each frame
Definition: vf_drawtext.c:200
draw_glyphs
static int draw_glyphs(DrawTextContext *s, AVFrame *frame, int width, int height, FFDrawColor *color, int x, int y, int borderw)
Definition: vf_drawtext.c:1218
VAR_h
@ VAR_h
Definition: vf_drawtext.c:117
set_fontsize
static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
Definition: vf_drawtext.c:384
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:804
load_font
static int load_font(AVFilterContext *ctx)
Definition: vf_drawtext.c:554
eval.h
AVLFG
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
av_expr_parse_and_eval
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
ff_blend_rectangle
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:351
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_acrusher.c:336
localtime_r
#define localtime_r
Definition: time_internal.h:46
FFMAX
#define FFMAX(a, b)
Definition: common.h:103
size
int size
Definition: twinvq_data.h:10344
DrawTextContext::draw_box
short int draw_box
draw box around text - true or false
Definition: vf_drawtext.c:171
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
DrawTextContext::shadowy
int shadowy
Definition: vf_drawtext.c:163
FFDIFFSIGN
#define FFDIFFSIGN(x, y)
Comparator.
Definition: common.h:101
VAR_PKT_POS
@ VAR_PKT_POS
Definition: vf_drawtext.c:131
drand
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:101
tree.h
EXP_NORMAL
@ EXP_NORMAL
Definition: vf_drawtext.c:139
VAR_TEXT_W
@ VAR_TEXT_W
Definition: vf_drawtext.c:127
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(drawtext)
expand_text
static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
Definition: vf_drawtext.c:1195
height
#define height
FFMIN
#define FFMIN(a, b)
Definition: common.h:105
a
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:41
AV_TIMECODE_FLAG_24HOURSMAX
@ AV_TIMECODE_FLAG_24HOURSMAX
timecode wraps after 24 hours
Definition: timecode.h:37
DrawTextContext::expanded_fontcolor
AVBPrint expanded_fontcolor
used to contain the expanded fontcolor spec
Definition: vf_drawtext.c:154
update_color_with_alpha
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
Definition: vf_drawtext.c:1264
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
VAR_LH
@ VAR_LH
Definition: vf_drawtext.c:116
fun2
static const eval_func2 fun2[]
Definition: vf_drawtext.c:108
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
internal.h
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
#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:126
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
av_get_picture_type_char
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:83
glyph_enu_free
static int glyph_enu_free(void *opaque, void *elem)
Definition: vf_drawtext.c:794
bprint.h
i
int i
Definition: input.c:407
code
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
Definition: filter_design.txt:178
round
static av_always_inline av_const double round(double x)
Definition: libm.h:444
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
ff_draw_supported_pixel_formats
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:637
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
common.h
delta
float delta
Definition: vorbis_enc_data.h:457
DrawTextContext::shadowx
int shadowx
Definition: vf_drawtext.c:163
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:693
drawtext_function::tag
int tag
opaque argument to func
Definition: vf_drawtext.c:1112
uint8_t
uint8_t
Definition: audio_convert.c:194
DrawTextContext::max_glyph_h
int max_glyph_h
max glyph height
Definition: vf_drawtext.c:162
av_mallocz
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
FFDrawContext
Definition: drawutils.h:35
DrawTextContext::borderw
int borderw
border width
Definition: vf_drawtext.c:164
VAR_MAX_GLYPH_D
@ VAR_MAX_GLYPH_D
Definition: vf_drawtext.c:120
len
int len
Definition: vorbis_enc_data.h:452
VAR_W
@ VAR_W
Definition: vf_drawtext.c:118
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:830
DrawTextContext::use_kerning
int use_kerning
font kerning is used - true/false
Definition: vf_drawtext.c:173
ff_draw_color
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:137
AVFilter
Filter definition.
Definition: avfilter.h:145
DrawTextContext::tc
AVTimecode tc
timecode context
Definition: vf_drawtext.c:198
tag
uint32_t tag
Definition: movenc.c:1611
ret
ret
Definition: filter_design.txt:187
EXP_STRFTIME
@ EXP_STRFTIME
Definition: vf_drawtext.c:140
frame
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
Definition: filter_design.txt:264
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
VAR_HSUB
@ VAR_HSUB
Definition: vf_drawtext.c:115
DrawTextContext::ft_load_flags
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:155
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
drawtext_function::argc_max
unsigned argc_max
Definition: vf_drawtext.c:1111
random_seed.h
DrawTextContext::alpha
int alpha
Definition: vf_drawtext.c:194
ft_errors
static const struct ft_error ft_errors[]
VAR_w
@ VAR_w
Definition: vf_drawtext.c:118
drawtext_options
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:211
DrawTextContext::shadowcolor
FFDrawColor shadowcolor
shadow color
Definition: vf_drawtext.c:179
eval_function
static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv)
Definition: vf_drawtext.c:1128
DrawTextContext::reinit
int reinit
tells if the filter is being reinited
Definition: vf_drawtext.c:146
func_strftime
static int func_strftime(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1011
func_eval_expr_int_format
static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1047
dummy
int dummy
Definition: motion.c:64
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
avfilter.h
file.h
av_tree_find
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
Definition: tree.c:39
AVFilterContext
An instance of a filter.
Definition: avfilter.h:341
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
DrawTextContext::glyphs
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
Definition: vf_drawtext.c:186
DrawTextContext::textfile
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:158
load_textfile
static int load_textfile(AVFilterContext *ctx)
Definition: vf_drawtext.c:576
llrint
#define llrint(x)
Definition: libm.h:394
functions
static const struct drawtext_function functions[]
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:1789
diff
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Definition: vf_palettegen.c:136
avfilter_vf_drawtext_outputs
static const AVFilterPad avfilter_vf_drawtext_outputs[]
Definition: vf_drawtext.c:1560
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:81
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:242
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
glyph_cmp
static int glyph_cmp(const void *key, const void *b)
Definition: vf_drawtext.c:302
VAR_DAR
@ VAR_DAR
Definition: vf_drawtext.c:114
DrawTextContext::boxcolor
FFDrawColor boxcolor
background color
Definition: vf_drawtext.c:181
AV_OPT_TYPE_FLAGS
@ AV_OPT_TYPE_FLAGS
Definition: opt.h:224
load_glyph
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
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
parse_fontsize
static av_cold int parse_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:400
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
av_timecode_init_from_string
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:250
DrawTextContext::metadata
AVDictionary * metadata
Definition: vf_drawtext.c:205
AVDictionaryEntry::value
char * value
Definition: dict.h:83
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
drawutils.h
ft_error::err_msg
const char * err_msg
Definition: vf_drawtext.c:283
ft_error
Definition: vf_drawtext.c:281
AVTimecode
Definition: timecode.h:41
FT_ERRMSG
#define FT_ERRMSG(e)
DrawTextContext::y_expr
char * y_expr
expression for y position
Definition: vf_drawtext.c:188
int
int
Definition: ffmpeg_filter.c:170
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
DrawTextContext::line_spacing
int line_spacing
lines spacing in pixels
Definition: vf_drawtext.c:170
drawtext_function::argc_min
unsigned argc_min
Definition: vf_drawtext.c:1111
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:140
DrawTextContext::fontcolor_expr
uint8_t * fontcolor_expr
fontcolor expression to evaluate
Definition: vf_drawtext.c:153
DrawTextContext::max_glyph_w
int max_glyph_w
max glyph width
Definition: vf_drawtext.c:161
DrawTextContext::tc_opt_string
char * tc_opt_string
specified timecode option string
Definition: vf_drawtext.c:196
drawtext
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
Definition: af_afir.c:240
DrawTextContext::fix_bounds
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:175
min
float min
Definition: vorbis_enc_data.h:456