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"
59 #include "avfilter.h"
60 #include "drawutils.h"
61 #include "formats.h"
62 #include "internal.h"
63 #include "video.h"
64 
65 #if CONFIG_LIBFRIBIDI
66 #include <fribidi.h>
67 #endif
68 
69 #include <ft2build.h>
70 #include FT_FREETYPE_H
71 #include FT_GLYPH_H
72 #include FT_STROKER_H
73 
74 static const char *const var_names[] = {
75  "dar",
76  "hsub", "vsub",
77  "line_h", "lh", ///< line height, same as max_glyph_h
78  "main_h", "h", "H", ///< height of the input video
79  "main_w", "w", "W", ///< width of the input video
80  "max_glyph_a", "ascent", ///< max glyph ascent
81  "max_glyph_d", "descent", ///< min glyph descent
82  "max_glyph_h", ///< max glyph height
83  "max_glyph_w", ///< max glyph width
84  "n", ///< number of frame
85  "sar",
86  "t", ///< timestamp expressed in seconds
87  "text_h", "th", ///< height of the rendered text
88  "text_w", "tw", ///< width of the rendered text
89  "x",
90  "y",
91  "pict_type",
92  "pkt_pos",
93  "pkt_duration",
94  "pkt_size",
95  NULL
96 };
97 
98 static const char *const fun2_names[] = {
99  "rand"
100 };
101 
102 static double drand(void *opaque, double min, double max)
103 {
104  return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
105 }
106 
107 typedef double (*eval_func2)(void *, double a, double b);
108 
109 static const eval_func2 fun2[] = {
110  drand,
111  NULL
112 };
113 
114 enum var_name {
136 };
137 
142 };
143 
144 typedef struct DrawTextContext {
145  const AVClass *class;
146  int exp_mode; ///< expansion mode to use for the text
147  int reinit; ///< tells if the filter is being reinited
148 #if CONFIG_LIBFONTCONFIG
149  uint8_t *font; ///< font to be used
150 #endif
151  uint8_t *fontfile; ///< font to be used
152  uint8_t *text; ///< text to be drawn
153  AVBPrint expanded_text; ///< used to contain the expanded text
154  uint8_t *fontcolor_expr; ///< fontcolor expression to evaluate
155  AVBPrint expanded_fontcolor; ///< used to contain the expanded fontcolor spec
156  int ft_load_flags; ///< flags used for loading fonts, see FT_LOAD_*
157  FT_Vector *positions; ///< positions for each element in the text
158  size_t nb_positions; ///< number of elements of positions array
159  char *textfile; ///< file with text to be drawn
160  int x; ///< x position to start drawing text
161  int y; ///< y position to start drawing text
162  int max_glyph_w; ///< max glyph width
163  int max_glyph_h; ///< max glyph height
165  int borderw; ///< border width
166  char *fontsize_expr; ///< expression for fontsize
167  AVExpr *fontsize_pexpr; ///< parsed expressions for fontsize
168  unsigned int fontsize; ///< font size to use
169  unsigned int default_fontsize; ///< default font size to use
170 
171  int line_spacing; ///< lines spacing in pixels
172  short int draw_box; ///< draw box around text - true or false
173  int boxborderw; ///< box border width
174  int use_kerning; ///< font kerning is used - true/false
175  int tabsize; ///< tab size
176  int fix_bounds; ///< do we let it go out of frame bounds - t/f
177 
179  FFDrawColor fontcolor; ///< foreground color
180  FFDrawColor shadowcolor; ///< shadow color
181  FFDrawColor bordercolor; ///< border color
182  FFDrawColor boxcolor; ///< background color
183 
184  FT_Library library; ///< freetype font library handle
185  FT_Face face; ///< freetype font face handle
186  FT_Stroker stroker; ///< freetype stroker handle
187  struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
188  char *x_expr; ///< expression for x position
189  char *y_expr; ///< expression for y position
190  AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
191  int64_t basetime; ///< base pts time in the real world for display
193  char *a_expr;
195  int alpha;
196  AVLFG prng; ///< random
197  char *tc_opt_string; ///< specified timecode option string
198  AVRational tc_rate; ///< frame rate for timecode
199  AVTimecode tc; ///< timecode context
200  int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
201  int reload; ///< reload text file for each frame
202  int start_number; ///< starting frame number for n/frame_num var
203  char *text_source_string; ///< the string to specify text data source
205 #if CONFIG_LIBFRIBIDI
206  int text_shaping; ///< 1 to shape the text before drawing it
207 #endif
210 
211 #define OFFSET(x) offsetof(DrawTextContext, x)
212 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
213 
214 static const AVOption drawtext_options[]= {
215  {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
216  {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
217  {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
218  {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
219  {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, 0, 0, FLAGS},
220  {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, 0, 0, FLAGS},
221  {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
222  {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, FLAGS},
223  {"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 , FLAGS},
224  {"boxborderw", "set box border width", OFFSET(boxborderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
225  {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX,FLAGS},
226  {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0 , FLAGS},
227  {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
228  {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
229  {"shadowx", "set shadow x offset", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
230  {"shadowy", "set shadow y offset", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
231  {"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
232  {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
233  {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
234 #if CONFIG_LIBFONTCONFIG
235  { "font", "Font name", OFFSET(font), AV_OPT_TYPE_STRING, { .str = "Sans" }, .flags = FLAGS },
236 #endif
237 
238  {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, "expansion"},
239  {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
240  {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
241  {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
242 
243  {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
244  {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
245  {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
246  {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
247  {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
248  {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
249  { "alpha", "apply alpha while rendering", OFFSET(a_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
250  {"fix_bounds", "check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
251  {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
252  {"text_source", "the source of text", OFFSET(text_source_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS },
253 
254 #if CONFIG_LIBFRIBIDI
255  {"text_shaping", "attempt to shape text before drawing", OFFSET(text_shaping), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS},
256 #endif
257 
258  /* FT_LOAD_* flags */
259  { "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" },
260  { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
261  { "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
262  { "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
263  { "render", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_RENDER }, .flags = FLAGS, .unit = "ft_load_flags" },
264  { "no_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
265  { "vertical_layout", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags = FLAGS, .unit = "ft_load_flags" },
266  { "force_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_FORCE_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
267  { "crop_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_CROP_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
268  { "pedantic", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_PEDANTIC }, .flags = FLAGS, .unit = "ft_load_flags" },
269  { "ignore_global_advance_width", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags = FLAGS, .unit = "ft_load_flags" },
270  { "no_recurse", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_RECURSE }, .flags = FLAGS, .unit = "ft_load_flags" },
271  { "ignore_transform", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags = FLAGS, .unit = "ft_load_flags" },
272  { "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
273  { "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
274  { "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
275  { NULL }
276 };
277 
279 
280 #undef __FTERRORS_H__
281 #define FT_ERROR_START_LIST {
282 #define FT_ERRORDEF(e, v, s) { (e), (s) },
283 #define FT_ERROR_END_LIST { 0, NULL } };
284 
285 static const struct ft_error {
286  int err;
287  const char *err_msg;
288 } ft_errors[] =
289 #include FT_ERRORS_H
290 
291 #define FT_ERRMSG(e) ft_errors[e].err_msg
292 
293 typedef struct Glyph {
294  FT_Glyph glyph;
295  FT_Glyph border_glyph;
296  uint32_t code;
297  unsigned int fontsize;
298  FT_Bitmap bitmap; ///< array holding bitmaps of font
299  FT_Bitmap border_bitmap; ///< array holding bitmaps of font border
300  FT_BBox bbox;
301  int advance;
302  int bitmap_left;
303  int bitmap_top;
304 } Glyph;
305 
306 static int glyph_cmp(const void *key, const void *b)
307 {
308  const Glyph *a = key, *bb = b;
309  int64_t diff = (int64_t)a->code - (int64_t)bb->code;
310 
311  if (diff != 0)
312  return diff > 0 ? 1 : -1;
313  else
314  return FFDIFFSIGN((int64_t)a->fontsize, (int64_t)bb->fontsize);
315 }
316 
317 /**
318  * Load glyphs corresponding to the UTF-32 codepoint code.
319  */
320 static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
321 {
322  DrawTextContext *s = ctx->priv;
323  FT_BitmapGlyph bitmapglyph;
324  Glyph *glyph;
325  struct AVTreeNode *node = NULL;
326  int ret;
327 
328  /* load glyph into s->face->glyph */
329  if (FT_Load_Char(s->face, code, s->ft_load_flags))
330  return AVERROR(EINVAL);
331 
332  glyph = av_mallocz(sizeof(*glyph));
333  if (!glyph) {
334  ret = AVERROR(ENOMEM);
335  goto error;
336  }
337  glyph->code = code;
338  glyph->fontsize = s->fontsize;
339 
340  if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
341  ret = AVERROR(EINVAL);
342  goto error;
343  }
344  if (s->borderw) {
345  glyph->border_glyph = glyph->glyph;
346  if (FT_Glyph_StrokeBorder(&glyph->border_glyph, s->stroker, 0, 0) ||
347  FT_Glyph_To_Bitmap(&glyph->border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
349  goto error;
350  }
351  bitmapglyph = (FT_BitmapGlyph) glyph->border_glyph;
352  glyph->border_bitmap = bitmapglyph->bitmap;
353  }
354  if (FT_Glyph_To_Bitmap(&glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
356  goto error;
357  }
358  bitmapglyph = (FT_BitmapGlyph) glyph->glyph;
359 
360  glyph->bitmap = bitmapglyph->bitmap;
361  glyph->bitmap_left = bitmapglyph->left;
362  glyph->bitmap_top = bitmapglyph->top;
363  glyph->advance = s->face->glyph->advance.x >> 6;
364 
365  /* measure text height to calculate text_height (or the maximum text height) */
366  FT_Glyph_Get_CBox(glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
367 
368  /* cache the newly created glyph */
369  if (!(node = av_tree_node_alloc())) {
370  ret = AVERROR(ENOMEM);
371  goto error;
372  }
373  av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);
374 
375  if (glyph_ptr)
376  *glyph_ptr = glyph;
377  return 0;
378 
379 error:
380  if (glyph)
381  av_freep(&glyph->glyph);
382 
383  av_freep(&glyph);
384  av_freep(&node);
385  return ret;
386 }
387 
388 static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
389 {
390  int err;
391  DrawTextContext *s = ctx->priv;
392 
393  if ((err = FT_Set_Pixel_Sizes(s->face, 0, fontsize))) {
394  av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
395  fontsize, FT_ERRMSG(err));
396  return AVERROR(EINVAL);
397  }
398 
399  s->fontsize = fontsize;
400 
401  return 0;
402 }
403 
405 {
406  DrawTextContext *s = ctx->priv;
407  int err;
408 
409  if (s->fontsize_pexpr)
410  return 0;
411 
412  if (s->fontsize_expr == NULL)
413  return AVERROR(EINVAL);
414 
415  if ((err = av_expr_parse(&s->fontsize_pexpr, s->fontsize_expr, var_names,
416  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
417  return err;
418 
419  return 0;
420 }
421 
423 {
424  DrawTextContext *s = ctx->priv;
425  unsigned int fontsize = s->default_fontsize;
426  int err;
427  double size, roundedsize;
428 
429  // if no fontsize specified use the default
430  if (s->fontsize_expr != NULL) {
431  if ((err = parse_fontsize(ctx)) < 0)
432  return err;
433 
434  size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
435 
436  if (!isnan(size)) {
437  roundedsize = round(size);
438  // test for overflow before cast
439  if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
440  av_log(ctx, AV_LOG_ERROR, "fontsize overflow\n");
441  return AVERROR(EINVAL);
442  }
443 
444  fontsize = roundedsize;
445  }
446  }
447 
448  if (fontsize == 0)
449  fontsize = 1;
450 
451  // no change
452  if (fontsize == s->fontsize)
453  return 0;
454 
455  return set_fontsize(ctx, fontsize);
456 }
457 
458 static int load_font_file(AVFilterContext *ctx, const char *path, int index)
459 {
460  DrawTextContext *s = ctx->priv;
461  int err;
462 
463  err = FT_New_Face(s->library, path, index, &s->face);
464  if (err) {
465 #if !CONFIG_LIBFONTCONFIG
466  av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
467  s->fontfile, FT_ERRMSG(err));
468 #endif
469  return AVERROR(EINVAL);
470  }
471  return 0;
472 }
473 
474 #if CONFIG_LIBFONTCONFIG
475 static int load_font_fontconfig(AVFilterContext *ctx)
476 {
477  DrawTextContext *s = ctx->priv;
478  FcConfig *fontconfig;
479  FcPattern *pat, *best;
480  FcResult result = FcResultMatch;
481  FcChar8 *filename;
482  int index;
483  double size;
484  int err = AVERROR(ENOENT);
485  int parse_err;
486 
487  fontconfig = FcInitLoadConfigAndFonts();
488  if (!fontconfig) {
489  av_log(ctx, AV_LOG_ERROR, "impossible to init fontconfig\n");
490  return AVERROR_UNKNOWN;
491  }
492  pat = FcNameParse(s->fontfile ? s->fontfile :
493  (uint8_t *)(intptr_t)"default");
494  if (!pat) {
495  av_log(ctx, AV_LOG_ERROR, "could not parse fontconfig pat");
496  return AVERROR(EINVAL);
497  }
498 
499  FcPatternAddString(pat, FC_FAMILY, s->font);
500 
501  parse_err = parse_fontsize(ctx);
502  if (!parse_err) {
503  double size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
504 
505  if (isnan(size)) {
506  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
507  return AVERROR(EINVAL);
508  }
509 
510  FcPatternAddDouble(pat, FC_SIZE, size);
511  }
512 
513  FcDefaultSubstitute(pat);
514 
515  if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
516  av_log(ctx, AV_LOG_ERROR, "could not substitue fontconfig options"); /* very unlikely */
517  FcPatternDestroy(pat);
518  return AVERROR(ENOMEM);
519  }
520 
521  best = FcFontMatch(fontconfig, pat, &result);
522  FcPatternDestroy(pat);
523 
524  if (!best || result != FcResultMatch) {
526  "Cannot find a valid font for the family %s\n",
527  s->font);
528  goto fail;
529  }
530 
531  if (
532  FcPatternGetInteger(best, FC_INDEX, 0, &index ) != FcResultMatch ||
533  FcPatternGetDouble (best, FC_SIZE, 0, &size ) != FcResultMatch) {
534  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
535  return AVERROR(EINVAL);
536  }
537 
538  if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
539  av_log(ctx, AV_LOG_ERROR, "No file path for %s\n",
540  s->font);
541  goto fail;
542  }
543 
544  av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
545  if (parse_err)
546  s->default_fontsize = size + 0.5;
547 
548  err = load_font_file(ctx, filename, index);
549  if (err)
550  return err;
551  FcConfigDestroy(fontconfig);
552 fail:
553  FcPatternDestroy(best);
554  return err;
555 }
556 #endif
557 
559 {
560  DrawTextContext *s = ctx->priv;
561  int err;
562 
563  /* load the face, and set up the encoding, which is by default UTF-8 */
564  err = load_font_file(ctx, s->fontfile, 0);
565  if (!err)
566  return 0;
567 #if CONFIG_LIBFONTCONFIG
568  err = load_font_fontconfig(ctx);
569  if (!err)
570  return 0;
571 #endif
572  return err;
573 }
574 
575 static inline int is_newline(uint32_t c)
576 {
577  return c == '\n' || c == '\r' || c == '\f' || c == '\v';
578 }
579 
581 {
582  DrawTextContext *s = ctx->priv;
583  int err;
584  uint8_t *textbuf;
585  uint8_t *tmp;
586  size_t textbuf_size;
587 
588  if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
590  "The text file '%s' could not be read or is empty\n",
591  s->textfile);
592  return err;
593  }
594 
595  if (textbuf_size > 0 && is_newline(textbuf[textbuf_size - 1]))
596  textbuf_size--;
597  if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
598  av_file_unmap(textbuf, textbuf_size);
599  return AVERROR(ENOMEM);
600  }
601  s->text = tmp;
602  memcpy(s->text, textbuf, textbuf_size);
603  s->text[textbuf_size] = 0;
604  av_file_unmap(textbuf, textbuf_size);
605 
606  return 0;
607 }
608 
609 #if CONFIG_LIBFRIBIDI
610 static int shape_text(AVFilterContext *ctx)
611 {
612  DrawTextContext *s = ctx->priv;
613  uint8_t *tmp;
614  int ret = AVERROR(ENOMEM);
615  static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
616  FRIBIDI_FLAGS_ARABIC;
617  FriBidiChar *unicodestr = NULL;
618  FriBidiStrIndex len;
619  FriBidiParType direction = FRIBIDI_PAR_LTR;
620  FriBidiStrIndex line_start = 0;
621  FriBidiStrIndex line_end = 0;
622  FriBidiLevel *embedding_levels = NULL;
623  FriBidiArabicProp *ar_props = NULL;
624  FriBidiCharType *bidi_types = NULL;
625  FriBidiStrIndex i,j;
626 
627  len = strlen(s->text);
628  if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
629  goto out;
630  }
631  len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
632  s->text, len, unicodestr);
633 
634  bidi_types = av_malloc_array(len, sizeof(*bidi_types));
635  if (!bidi_types) {
636  goto out;
637  }
638 
639  fribidi_get_bidi_types(unicodestr, len, bidi_types);
640 
641  embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
642  if (!embedding_levels) {
643  goto out;
644  }
645 
646  if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
647  embedding_levels)) {
648  goto out;
649  }
650 
651  ar_props = av_malloc_array(len, sizeof(*ar_props));
652  if (!ar_props) {
653  goto out;
654  }
655 
656  fribidi_get_joining_types(unicodestr, len, ar_props);
657  fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
658  fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);
659 
660  for (line_end = 0, line_start = 0; line_end < len; line_end++) {
661  if (is_newline(unicodestr[line_end]) || line_end == len - 1) {
662  if (!fribidi_reorder_line(flags, bidi_types,
663  line_end - line_start + 1, line_start,
664  direction, embedding_levels, unicodestr,
665  NULL)) {
666  goto out;
667  }
668  line_start = line_end + 1;
669  }
670  }
671 
672  /* Remove zero-width fill chars put in by libfribidi */
673  for (i = 0, j = 0; i < len; i++)
674  if (unicodestr[i] != FRIBIDI_CHAR_FILL)
675  unicodestr[j++] = unicodestr[i];
676  len = j;
677 
678  if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
679  /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
680  goto out;
681  }
682 
683  s->text = tmp;
684  len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
685  unicodestr, len, s->text);
686  ret = 0;
687 
688 out:
689  av_free(unicodestr);
690  av_free(embedding_levels);
691  av_free(ar_props);
692  av_free(bidi_types);
693  return ret;
694 }
695 #endif
696 
697 static enum AVFrameSideDataType text_source_string_parse(const char *text_source_string)
698 {
699  av_assert0(text_source_string);
700  if (!strcmp(text_source_string, "side_data_detection_bboxes")) {
702  } else {
703  return AVERROR(EINVAL);
704  }
705 }
706 
708 {
709  int err;
710  DrawTextContext *s = ctx->priv;
711  Glyph *glyph;
712 
713  av_expr_free(s->fontsize_pexpr);
714  s->fontsize_pexpr = NULL;
715 
716  s->fontsize = 0;
717  s->default_fontsize = 16;
718 
719  if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
720  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
721  return AVERROR(EINVAL);
722  }
723 
724  if (s->textfile) {
725  if (s->text) {
727  "Both text and text file provided. Please provide only one\n");
728  return AVERROR(EINVAL);
729  }
730  if ((err = load_textfile(ctx)) < 0)
731  return err;
732  }
733 
734  if (s->reload && !s->textfile)
735  av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
736 
737  if (s->tc_opt_string) {
738  int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
739  s->tc_opt_string, ctx);
740  if (ret < 0)
741  return ret;
742  if (s->tc24hmax)
743  s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
744  if (!s->text)
745  s->text = av_strdup("");
746  }
747 
748  if (s->text_source_string) {
749  s->text_source = text_source_string_parse(s->text_source_string);
750  if ((int)s->text_source < 0) {
751  av_log(ctx, AV_LOG_ERROR, "Error text source: %s\n", s->text_source_string);
752  return AVERROR(EINVAL);
753  }
754  }
755 
756  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
757  if (s->text) {
758  av_log(ctx, AV_LOG_WARNING, "Multiple texts provided, will use text_source only\n");
759  av_free(s->text);
760  }
763  if (!s->text)
764  return AVERROR(ENOMEM);
765  }
766 
767  if (!s->text) {
769  "Either text, a valid file, a timecode or text source must be provided\n");
770  return AVERROR(EINVAL);
771  }
772 
773 #if CONFIG_LIBFRIBIDI
774  if (s->text_shaping)
775  if ((err = shape_text(ctx)) < 0)
776  return err;
777 #endif
778 
779  if ((err = FT_Init_FreeType(&(s->library)))) {
781  "Could not load FreeType: %s\n", FT_ERRMSG(err));
782  return AVERROR(EINVAL);
783  }
784 
785  if ((err = load_font(ctx)) < 0)
786  return err;
787 
788  if ((err = update_fontsize(ctx)) < 0)
789  return err;
790 
791  if (s->borderw) {
792  if (FT_Stroker_New(s->library, &s->stroker)) {
793  av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
794  return AVERROR_EXTERNAL;
795  }
796  FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
797  FT_STROKER_LINEJOIN_ROUND, 0);
798  }
799 
800  s->use_kerning = FT_HAS_KERNING(s->face);
801 
802  /* load the fallback glyph with code 0 */
803  load_glyph(ctx, NULL, 0);
804 
805  /* set the tabsize in pixels */
806  if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
807  av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
808  return err;
809  }
810  s->tabsize *= glyph->advance;
811 
812  if (s->exp_mode == EXP_STRFTIME &&
813  (strchr(s->text, '%') || strchr(s->text, '\\')))
814  av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
815 
816  av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
817  av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);
818 
819  return 0;
820 }
821 
823 {
825 }
826 
827 static int glyph_enu_free(void *opaque, void *elem)
828 {
829  Glyph *glyph = elem;
830 
831  FT_Done_Glyph(glyph->glyph);
832  FT_Done_Glyph(glyph->border_glyph);
833  av_free(elem);
834  return 0;
835 }
836 
838 {
839  DrawTextContext *s = ctx->priv;
840 
841  av_expr_free(s->x_pexpr);
842  av_expr_free(s->y_pexpr);
843  av_expr_free(s->a_pexpr);
844  av_expr_free(s->fontsize_pexpr);
845 
846  s->x_pexpr = s->y_pexpr = s->a_pexpr = s->fontsize_pexpr = NULL;
847 
848  av_freep(&s->positions);
849  s->nb_positions = 0;
850 
852  av_tree_destroy(s->glyphs);
853  s->glyphs = NULL;
854 
855  FT_Done_Face(s->face);
856  FT_Stroker_Done(s->stroker);
857  FT_Done_FreeType(s->library);
858 
859  av_bprint_finalize(&s->expanded_text, NULL);
860  av_bprint_finalize(&s->expanded_fontcolor, NULL);
861 }
862 
864 {
865  AVFilterContext *ctx = inlink->dst;
866  DrawTextContext *s = ctx->priv;
867  char *expr;
868  int ret;
869 
870  ff_draw_init(&s->dc, inlink->format, FF_DRAW_PROCESS_ALPHA);
871  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
872  ff_draw_color(&s->dc, &s->shadowcolor, s->shadowcolor.rgba);
873  ff_draw_color(&s->dc, &s->bordercolor, s->bordercolor.rgba);
874  ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
875 
876  s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
877  s->var_values[VAR_h] = s->var_values[VAR_H] = s->var_values[VAR_MAIN_H] = inlink->h;
878  s->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
879  s->var_values[VAR_DAR] = (double)inlink->w / inlink->h * s->var_values[VAR_SAR];
880  s->var_values[VAR_HSUB] = 1 << s->dc.hsub_max;
881  s->var_values[VAR_VSUB] = 1 << s->dc.vsub_max;
882  s->var_values[VAR_X] = NAN;
883  s->var_values[VAR_Y] = NAN;
884  s->var_values[VAR_T] = NAN;
885 
886  av_lfg_init(&s->prng, av_get_random_seed());
887 
888  av_expr_free(s->x_pexpr);
889  av_expr_free(s->y_pexpr);
890  av_expr_free(s->a_pexpr);
891  s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
892 
893  if ((ret = av_expr_parse(&s->x_pexpr, expr = s->x_expr, var_names,
894  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
895  (ret = av_expr_parse(&s->y_pexpr, expr = s->y_expr, var_names,
896  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
897  (ret = av_expr_parse(&s->a_pexpr, expr = s->a_expr, var_names,
898  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
899  av_log(ctx, AV_LOG_ERROR, "Failed to parse expression: %s \n", expr);
900  return AVERROR(EINVAL);
901  }
902 
903  return 0;
904 }
905 
906 static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
907 {
908  DrawTextContext *old = ctx->priv;
909  DrawTextContext *new = NULL;
910  int ret;
911 
912  if (!strcmp(cmd, "reinit")) {
913  new = av_mallocz(sizeof(DrawTextContext));
914  if (!new)
915  return AVERROR(ENOMEM);
916 
917  new->class = &drawtext_class;
918  ret = av_opt_copy(new, old);
919  if (ret < 0)
920  goto fail;
921 
922  ctx->priv = new;
923  ret = av_set_options_string(ctx, arg, "=", ":");
924  if (ret < 0) {
925  ctx->priv = old;
926  goto fail;
927  }
928 
929  ret = init(ctx);
930  if (ret < 0) {
931  uninit(ctx);
932  ctx->priv = old;
933  goto fail;
934  }
935 
936  new->reinit = 1;
937 
938  ctx->priv = old;
939  uninit(ctx);
940  av_freep(&old);
941 
942  ctx->priv = new;
943  return config_input(ctx->inputs[0]);
944  } else
945  return AVERROR(ENOSYS);
946 
947 fail:
948  av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
949  av_freep(&new);
950  return ret;
951 }
952 
953 static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
954  char *fct, unsigned argc, char **argv, int tag)
955 {
956  DrawTextContext *s = ctx->priv;
957 
958  av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
959  return 0;
960 }
961 
962 static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
963  char *fct, unsigned argc, char **argv, int tag)
964 {
965  DrawTextContext *s = ctx->priv;
966  const char *fmt;
967  double pts = s->var_values[VAR_T];
968  int ret;
969 
970  fmt = argc >= 1 ? argv[0] : "flt";
971  if (argc >= 2) {
972  int64_t delta;
973  if ((ret = av_parse_time(&delta, argv[1], 1)) < 0) {
974  av_log(ctx, AV_LOG_ERROR, "Invalid delta '%s'\n", argv[1]);
975  return ret;
976  }
977  pts += (double)delta / AV_TIME_BASE;
978  }
979  if (!strcmp(fmt, "flt")) {
980  av_bprintf(bp, "%.6f", pts);
981  } else if (!strcmp(fmt, "hms")) {
982  if (isnan(pts)) {
983  av_bprintf(bp, " ??:??:??.???");
984  } else {
985  int64_t ms = llrint(pts * 1000);
986  char sign = ' ';
987  if (ms < 0) {
988  sign = '-';
989  ms = -ms;
990  }
991  if (argc >= 3) {
992  if (!strcmp(argv[2], "24HH")) {
993  ms %= 24 * 60 * 60 * 1000;
994  } else {
995  av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", argv[2]);
996  return AVERROR(EINVAL);
997  }
998  }
999  av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
1000  (int)(ms / (60 * 60 * 1000)),
1001  (int)(ms / (60 * 1000)) % 60,
1002  (int)(ms / 1000) % 60,
1003  (int)(ms % 1000));
1004  }
1005  } else if (!strcmp(fmt, "localtime") ||
1006  !strcmp(fmt, "gmtime")) {
1007  struct tm tm;
1008  time_t ms = (time_t)pts;
1009  const char *timefmt = argc >= 3 ? argv[2] : "%Y-%m-%d %H:%M:%S";
1010  if (!strcmp(fmt, "localtime"))
1011  localtime_r(&ms, &tm);
1012  else
1013  gmtime_r(&ms, &tm);
1014  av_bprint_strftime(bp, timefmt, &tm);
1015  } else {
1016  av_log(ctx, AV_LOG_ERROR, "Invalid format '%s'\n", fmt);
1017  return AVERROR(EINVAL);
1018  }
1019  return 0;
1020 }
1021 
1022 static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
1023  char *fct, unsigned argc, char **argv, int tag)
1024 {
1025  DrawTextContext *s = ctx->priv;
1026 
1027  av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
1028  return 0;
1029 }
1030 
1031 static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
1032  char *fct, unsigned argc, char **argv, int tag)
1033 {
1034  DrawTextContext *s = ctx->priv;
1035  AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
1036 
1037  if (e && e->value)
1038  av_bprintf(bp, "%s", e->value);
1039  else if (argc >= 2)
1040  av_bprintf(bp, "%s", argv[1]);
1041  return 0;
1042 }
1043 
1044 static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
1045  char *fct, unsigned argc, char **argv, int tag)
1046 {
1047  const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
1048  time_t now;
1049  struct tm tm;
1050 
1051  time(&now);
1052  if (tag == 'L')
1053  localtime_r(&now, &tm);
1054  else
1055  tm = *gmtime_r(&now, &tm);
1056  av_bprint_strftime(bp, fmt, &tm);
1057  return 0;
1058 }
1059 
1060 static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
1061  char *fct, unsigned argc, char **argv, int tag)
1062 {
1063  DrawTextContext *s = ctx->priv;
1064  double res;
1065  int ret;
1066 
1067  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1068  NULL, NULL, fun2_names, fun2,
1069  &s->prng, 0, ctx);
1070  if (ret < 0)
1072  "Expression '%s' for the expr text expansion function is not valid\n",
1073  argv[0]);
1074  else
1075  av_bprintf(bp, "%f", res);
1076 
1077  return ret;
1078 }
1079 
1081  char *fct, unsigned argc, char **argv, int tag)
1082 {
1083  DrawTextContext *s = ctx->priv;
1084  double res;
1085  int intval;
1086  int ret;
1087  unsigned int positions = 0;
1088  char fmt_str[30] = "%";
1089 
1090  /*
1091  * argv[0] expression to be converted to `int`
1092  * argv[1] format: 'x', 'X', 'd' or 'u'
1093  * argv[2] positions printed (optional)
1094  */
1095 
1096  ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
1097  NULL, NULL, fun2_names, fun2,
1098  &s->prng, 0, ctx);
1099  if (ret < 0) {
1101  "Expression '%s' for the expr text expansion function is not valid\n",
1102  argv[0]);
1103  return ret;
1104  }
1105 
1106  if (!strchr("xXdu", argv[1][0])) {
1107  av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified,"
1108  " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
1109  return AVERROR(EINVAL);
1110  }
1111 
1112  if (argc == 3) {
1113  ret = sscanf(argv[2], "%u", &positions);
1114  if (ret != 1) {
1115  av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
1116  " to print: '%s'\n", argv[2]);
1117  return AVERROR(EINVAL);
1118  }
1119  }
1120 
1121  feclearexcept(FE_ALL_EXCEPT);
1122  intval = res;
1123 #if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
1124  if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
1125  av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
1126  return AVERROR(EINVAL);
1127  }
1128 #endif
1129 
1130  if (argc == 3)
1131  av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
1132  av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]);
1133 
1134  av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
1135  res, argv[0], fmt_str);
1136 
1137  av_bprintf(bp, fmt_str, intval);
1138 
1139  return 0;
1140 }
1141 
1142 static const struct drawtext_function {
1143  const char *name;
1144  unsigned argc_min, argc_max;
1145  int tag; /**< opaque argument to func */
1146  int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
1147 } functions[] = {
1148  { "expr", 1, 1, 0, func_eval_expr },
1149  { "e", 1, 1, 0, func_eval_expr },
1150  { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
1151  { "eif", 2, 3, 0, func_eval_expr_int_format },
1152  { "pict_type", 0, 0, 0, func_pict_type },
1153  { "pts", 0, 3, 0, func_pts },
1154  { "gmtime", 0, 1, 'G', func_strftime },
1155  { "localtime", 0, 1, 'L', func_strftime },
1156  { "frame_num", 0, 0, 0, func_frame_num },
1157  { "n", 0, 0, 0, func_frame_num },
1158  { "metadata", 1, 2, 0, func_metadata },
1159 };
1160 
1161 static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
1162  unsigned argc, char **argv)
1163 {
1164  unsigned i;
1165 
1166  for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
1167  if (strcmp(fct, functions[i].name))
1168  continue;
1169  if (argc < functions[i].argc_min) {
1170  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
1171  fct, functions[i].argc_min);
1172  return AVERROR(EINVAL);
1173  }
1174  if (argc > functions[i].argc_max) {
1175  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
1176  fct, functions[i].argc_max);
1177  return AVERROR(EINVAL);
1178  }
1179  break;
1180  }
1181  if (i >= FF_ARRAY_ELEMS(functions)) {
1182  av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
1183  return AVERROR(EINVAL);
1184  }
1185  return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
1186 }
1187 
1188 static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
1189 {
1190  const char *text = *rtext;
1191  char *argv[16] = { NULL };
1192  unsigned argc = 0, i;
1193  int ret;
1194 
1195  if (*text != '{') {
1196  av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
1197  return AVERROR(EINVAL);
1198  }
1199  text++;
1200  while (1) {
1201  if (!(argv[argc++] = av_get_token(&text, ":}"))) {
1202  ret = AVERROR(ENOMEM);
1203  goto end;
1204  }
1205  if (!*text) {
1206  av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
1207  ret = AVERROR(EINVAL);
1208  goto end;
1209  }
1210  if (argc == FF_ARRAY_ELEMS(argv))
1211  av_freep(&argv[--argc]); /* error will be caught later */
1212  if (*text == '}')
1213  break;
1214  text++;
1215  }
1216 
1217  if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
1218  goto end;
1219  ret = 0;
1220  *rtext = (char *)text + 1;
1221 
1222 end:
1223  for (i = 0; i < argc; i++)
1224  av_freep(&argv[i]);
1225  return ret;
1226 }
1227 
1228 static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
1229 {
1230  int ret;
1231 
1232  av_bprint_clear(bp);
1233  while (*text) {
1234  if (*text == '\\' && text[1]) {
1235  av_bprint_chars(bp, text[1], 1);
1236  text += 2;
1237  } else if (*text == '%') {
1238  text++;
1239  if ((ret = expand_function(ctx, bp, &text)) < 0)
1240  return ret;
1241  } else {
1242  av_bprint_chars(bp, *text, 1);
1243  text++;
1244  }
1245  }
1246  if (!av_bprint_is_complete(bp))
1247  return AVERROR(ENOMEM);
1248  return 0;
1249 }
1250 
1252  int width, int height,
1253  FFDrawColor *color,
1254  int x, int y, int borderw)
1255 {
1256  char *text = s->expanded_text.str;
1257  uint32_t code = 0;
1258  int i, x1, y1;
1259  uint8_t *p;
1260  Glyph *glyph = NULL;
1261 
1262  for (i = 0, p = text; *p; i++) {
1263  FT_Bitmap bitmap;
1264  Glyph dummy = { 0 };
1265  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1266 continue_on_invalid:
1267 
1268  /* skip new line chars, just go to new line */
1269  if (code == '\n' || code == '\r' || code == '\t')
1270  continue;
1271 
1272  dummy.code = code;
1273  dummy.fontsize = s->fontsize;
1274  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1275 
1276  bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
1277 
1278  if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
1279  glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1280  return AVERROR(EINVAL);
1281 
1282  x1 = s->positions[i].x+s->x+x - borderw;
1283  y1 = s->positions[i].y+s->y+y - borderw;
1284 
1285  ff_blend_mask(&s->dc, color,
1286  frame->data, frame->linesize, width, height,
1287  bitmap.buffer, bitmap.pitch,
1288  bitmap.width, bitmap.rows,
1289  bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
1290  0, x1, y1);
1291  }
1292 
1293  return 0;
1294 }
1295 
1296 
1298 {
1299  *color = incolor;
1300  color->rgba[3] = (color->rgba[3] * s->alpha) / 255;
1301  ff_draw_color(&s->dc, color, color->rgba);
1302 }
1303 
1305 {
1306  double alpha = av_expr_eval(s->a_pexpr, s->var_values, &s->prng);
1307 
1308  if (isnan(alpha))
1309  return;
1310 
1311  if (alpha >= 1.0)
1312  s->alpha = 255;
1313  else if (alpha <= 0)
1314  s->alpha = 0;
1315  else
1316  s->alpha = 256 * alpha;
1317 }
1318 
1320  int width, int height)
1321 {
1322  DrawTextContext *s = ctx->priv;
1323  AVFilterLink *inlink = ctx->inputs[0];
1324 
1325  uint32_t code = 0, prev_code = 0;
1326  int x = 0, y = 0, i = 0, ret;
1327  int max_text_line_w = 0, len;
1328  int box_w, box_h;
1329  char *text;
1330  uint8_t *p;
1331  int y_min = 32000, y_max = -32000;
1332  int x_min = 32000, x_max = -32000;
1333  FT_Vector delta;
1334  Glyph *glyph = NULL, *prev_glyph = NULL;
1335  Glyph dummy = { 0 };
1336 
1337  time_t now = time(0);
1338  struct tm ltime;
1339  AVBPrint *bp = &s->expanded_text;
1340 
1341  FFDrawColor fontcolor;
1342  FFDrawColor shadowcolor;
1343  FFDrawColor bordercolor;
1344  FFDrawColor boxcolor;
1345 
1346  av_bprint_clear(bp);
1347 
1348  if(s->basetime != AV_NOPTS_VALUE)
1349  now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + s->basetime/1000000;
1350 
1351  switch (s->exp_mode) {
1352  case EXP_NONE:
1353  av_bprintf(bp, "%s", s->text);
1354  break;
1355  case EXP_NORMAL:
1356  if ((ret = expand_text(ctx, s->text, &s->expanded_text)) < 0)
1357  return ret;
1358  break;
1359  case EXP_STRFTIME:
1360  localtime_r(&now, &ltime);
1361  av_bprint_strftime(bp, s->text, &ltime);
1362  break;
1363  }
1364 
1365  if (s->tc_opt_string) {
1366  char tcbuf[AV_TIMECODE_STR_SIZE];
1367  av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count_out);
1368  av_bprint_clear(bp);
1369  av_bprintf(bp, "%s%s", s->text, tcbuf);
1370  }
1371 
1372  if (!av_bprint_is_complete(bp))
1373  return AVERROR(ENOMEM);
1374  text = s->expanded_text.str;
1375  if ((len = s->expanded_text.len) > s->nb_positions) {
1376  if (!(s->positions =
1377  av_realloc(s->positions, len*sizeof(*s->positions))))
1378  return AVERROR(ENOMEM);
1379  s->nb_positions = len;
1380  }
1381 
1382  if (s->fontcolor_expr[0]) {
1383  /* If expression is set, evaluate and replace the static value */
1384  av_bprint_clear(&s->expanded_fontcolor);
1385  if ((ret = expand_text(ctx, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
1386  return ret;
1387  if (!av_bprint_is_complete(&s->expanded_fontcolor))
1388  return AVERROR(ENOMEM);
1389  av_log(s, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
1390  ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
1391  if (ret)
1392  return ret;
1393  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
1394  }
1395 
1396  x = 0;
1397  y = 0;
1398 
1399  if ((ret = update_fontsize(ctx)) < 0)
1400  return ret;
1401 
1402  /* load and cache glyphs */
1403  for (i = 0, p = text; *p; i++) {
1404  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid;);
1405 continue_on_invalid:
1406 
1407  /* get glyph */
1408  dummy.code = code;
1409  dummy.fontsize = s->fontsize;
1410  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1411  if (!glyph) {
1412  ret = load_glyph(ctx, &glyph, code);
1413  if (ret < 0)
1414  return ret;
1415  }
1416 
1417  y_min = FFMIN(glyph->bbox.yMin, y_min);
1418  y_max = FFMAX(glyph->bbox.yMax, y_max);
1419  x_min = FFMIN(glyph->bbox.xMin, x_min);
1420  x_max = FFMAX(glyph->bbox.xMax, x_max);
1421  }
1422  s->max_glyph_h = y_max - y_min;
1423  s->max_glyph_w = x_max - x_min;
1424 
1425  /* compute and save position for each glyph */
1426  glyph = NULL;
1427  for (i = 0, p = text; *p; i++) {
1428  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_invalid2;);
1429 continue_on_invalid2:
1430 
1431  /* skip the \n in the sequence \r\n */
1432  if (prev_code == '\r' && code == '\n')
1433  continue;
1434 
1435  prev_code = code;
1436  if (is_newline(code)) {
1437 
1438  max_text_line_w = FFMAX(max_text_line_w, x);
1439  y += s->max_glyph_h + s->line_spacing;
1440  x = 0;
1441  continue;
1442  }
1443 
1444  /* get glyph */
1445  prev_glyph = glyph;
1446  dummy.code = code;
1447  dummy.fontsize = s->fontsize;
1448  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1449 
1450  /* kerning */
1451  if (s->use_kerning && prev_glyph && glyph->code) {
1452  FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
1453  ft_kerning_default, &delta);
1454  x += delta.x >> 6;
1455  }
1456 
1457  /* save position */
1458  s->positions[i].x = x + glyph->bitmap_left;
1459  s->positions[i].y = y - glyph->bitmap_top + y_max;
1460  if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
1461  else x += glyph->advance;
1462  }
1463 
1464  max_text_line_w = FFMAX(x, max_text_line_w);
1465 
1466  s->var_values[VAR_TW] = s->var_values[VAR_TEXT_W] = max_text_line_w;
1467  s->var_values[VAR_TH] = s->var_values[VAR_TEXT_H] = y + s->max_glyph_h;
1468 
1469  s->var_values[VAR_MAX_GLYPH_W] = s->max_glyph_w;
1470  s->var_values[VAR_MAX_GLYPH_H] = s->max_glyph_h;
1471  s->var_values[VAR_MAX_GLYPH_A] = s->var_values[VAR_ASCENT ] = y_max;
1472  s->var_values[VAR_MAX_GLYPH_D] = s->var_values[VAR_DESCENT] = y_min;
1473 
1474  s->var_values[VAR_LINE_H] = s->var_values[VAR_LH] = s->max_glyph_h;
1475 
1476  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
1477  s->var_values[VAR_X] = s->x;
1478  s->var_values[VAR_Y] = s->y;
1479  } else {
1480  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1481  s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
1482  /* It is necessary if x is expressed from y */
1483  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1484  }
1485 
1486  update_alpha(s);
1487  update_color_with_alpha(s, &fontcolor , s->fontcolor );
1488  update_color_with_alpha(s, &shadowcolor, s->shadowcolor);
1489  update_color_with_alpha(s, &bordercolor, s->bordercolor);
1490  update_color_with_alpha(s, &boxcolor , s->boxcolor );
1491 
1492  box_w = max_text_line_w;
1493  box_h = y + s->max_glyph_h;
1494 
1495  if (s->fix_bounds) {
1496 
1497  /* calculate footprint of text effects */
1498  int boxoffset = s->draw_box ? FFMAX(s->boxborderw, 0) : 0;
1499  int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0;
1500 
1501  int offsetleft = FFMAX3(boxoffset, borderoffset,
1502  (s->shadowx < 0 ? FFABS(s->shadowx) : 0));
1503  int offsettop = FFMAX3(boxoffset, borderoffset,
1504  (s->shadowy < 0 ? FFABS(s->shadowy) : 0));
1505 
1506  int offsetright = FFMAX3(boxoffset, borderoffset,
1507  (s->shadowx > 0 ? s->shadowx : 0));
1508  int offsetbottom = FFMAX3(boxoffset, borderoffset,
1509  (s->shadowy > 0 ? s->shadowy : 0));
1510 
1511 
1512  if (s->x - offsetleft < 0) s->x = offsetleft;
1513  if (s->y - offsettop < 0) s->y = offsettop;
1514 
1515  if (s->x + box_w + offsetright > width)
1516  s->x = FFMAX(width - box_w - offsetright, 0);
1517  if (s->y + box_h + offsetbottom > height)
1518  s->y = FFMAX(height - box_h - offsetbottom, 0);
1519  }
1520 
1521  /* draw box */
1522  if (s->draw_box)
1523  ff_blend_rectangle(&s->dc, &boxcolor,
1524  frame->data, frame->linesize, width, height,
1525  s->x - s->boxborderw, s->y - s->boxborderw,
1526  box_w + s->boxborderw * 2, box_h + s->boxborderw * 2);
1527 
1528  if (s->shadowx || s->shadowy) {
1529  if ((ret = draw_glyphs(s, frame, width, height,
1530  &shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
1531  return ret;
1532  }
1533 
1534  if (s->borderw) {
1535  if ((ret = draw_glyphs(s, frame, width, height,
1536  &bordercolor, 0, 0, s->borderw)) < 0)
1537  return ret;
1538  }
1539  if ((ret = draw_glyphs(s, frame, width, height,
1540  &fontcolor, 0, 0, 0)) < 0)
1541  return ret;
1542 
1543  return 0;
1544 }
1545 
1547 {
1548  AVFilterContext *ctx = inlink->dst;
1549  AVFilterLink *outlink = ctx->outputs[0];
1550  DrawTextContext *s = ctx->priv;
1551  int ret;
1553  const AVDetectionBBox *bbox;
1554  AVFrameSideData *sd;
1555  int loop = 1;
1556 
1557  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
1559  if (sd) {
1561  loop = header->nb_bboxes;
1562  } else {
1563  av_log(s, AV_LOG_WARNING, "No detection bboxes.\n");
1564  return ff_filter_frame(outlink, frame);
1565  }
1566  }
1567 
1568  if (s->reload) {
1569  if ((ret = load_textfile(ctx)) < 0) {
1570  av_frame_free(&frame);
1571  return ret;
1572  }
1573 #if CONFIG_LIBFRIBIDI
1574  if (s->text_shaping)
1575  if ((ret = shape_text(ctx)) < 0) {
1576  av_frame_free(&frame);
1577  return ret;
1578  }
1579 #endif
1580  }
1581 
1582  s->var_values[VAR_N] = inlink->frame_count_out + s->start_number;
1583  s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
1584  NAN : frame->pts * av_q2d(inlink->time_base);
1585 
1586  s->var_values[VAR_PICT_TYPE] = frame->pict_type;
1587  s->var_values[VAR_PKT_POS] = frame->pkt_pos;
1588  s->var_values[VAR_PKT_DURATION] = frame->pkt_duration * av_q2d(inlink->time_base);
1589  s->var_values[VAR_PKT_SIZE] = frame->pkt_size;
1590  s->metadata = frame->metadata;
1591 
1592  for (int i = 0; i < loop; i++) {
1593  if (header) {
1594  bbox = av_get_detection_bbox(header, i);
1595  strcpy(s->text, bbox->detect_label);
1596  for (int j = 0; j < bbox->classify_count; j++) {
1597  strcat(s->text, ", ");
1598  strcat(s->text, bbox->classify_labels[j]);
1599  }
1600  s->x = bbox->x;
1601  s->y = bbox->y - s->fontsize;
1602  }
1603  draw_text(ctx, frame, frame->width, frame->height);
1604  }
1605 
1606  av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
1607  (int)s->var_values[VAR_N], s->var_values[VAR_T],
1608  (int)s->var_values[VAR_TEXT_W], (int)s->var_values[VAR_TEXT_H],
1609  s->x, s->y);
1610 
1611  return ff_filter_frame(outlink, frame);
1612 }
1613 
1615  {
1616  .name = "default",
1617  .type = AVMEDIA_TYPE_VIDEO,
1619  .filter_frame = filter_frame,
1620  .config_props = config_input,
1621  },
1622 };
1623 
1625  {
1626  .name = "default",
1627  .type = AVMEDIA_TYPE_VIDEO,
1628  },
1629 };
1630 
1632  .name = "drawtext",
1633  .description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
1634  .priv_size = sizeof(DrawTextContext),
1635  .priv_class = &drawtext_class,
1636  .init = init,
1637  .uninit = uninit,
1641  .process_command = command,
1643 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
DrawTextContext::library
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:184
OFFSET
#define OFFSET(x)
Definition: vf_drawtext.c:211
fun2_names
static const char *const fun2_names[]
Definition: vf_drawtext.c:98
VAR_N
@ VAR_N
Definition: vf_drawtext.c:124
VAR_TEXT_H
@ VAR_TEXT_H
Definition: vf_drawtext.c:127
VAR_MAIN_H
@ VAR_MAIN_H
Definition: vf_drawtext.c:118
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
drawtext_function::func
int(* func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int)
Definition: vf_drawtext.c:1146
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:48
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:117
VAR_Y
@ VAR_Y
Definition: vf_drawtext.c:130
VAR_MAX_GLYPH_H
@ VAR_MAX_GLYPH_H
Definition: vf_drawtext.c:122
DrawTextContext::a_expr
char * a_expr
Definition: vf_drawtext.c:193
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:133
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:234
out
FILE * out
Definition: movenc.c:54
color
Definition: vf_paletteuse.c:599
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:68
av_frame_get_side_data
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition: frame.c:617
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
ff_vf_drawtext
const AVFilter ff_vf_drawtext
Definition: vf_drawtext.c:1631
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:1546
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1018
func_pts
static int func_pts(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:962
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:356
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:169
VAR_TW
@ VAR_TW
Definition: vf_drawtext.c:128
VAR_ASCENT
@ VAR_ASCENT
Definition: vf_drawtext.c:120
func_frame_num
static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1022
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:200
drawtext_function
Definition: vf_drawtext.c:1142
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:109
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
index
fg index
Definition: ffmpeg_filter.c:167
DrawTextContext::x
int x
x position to start drawing text
Definition: vf_drawtext.c:160
DrawTextContext::bordercolor
FFDrawColor bordercolor
border color
Definition: vf_drawtext.c:181
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:175
DrawTextContext::exp_mode
int exp_mode
expansion mode to use for the text
Definition: vf_drawtext.c:146
VAR_DESCENT
@ VAR_DESCENT
Definition: vf_drawtext.c:121
AVOption
AVOption.
Definition: opt.h:247
b
#define b
Definition: input.c:40
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:168
DrawTextContext::nb_positions
size_t nb_positions
number of elements of positions array
Definition: vf_drawtext.c:158
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:953
AVDictionary
Definition: dict.c:30
DrawTextContext::stroker
FT_Stroker stroker
freetype stroker handle
Definition: vf_drawtext.c:186
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:169
expand_function
static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
Definition: vf_drawtext.c:1188
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:1143
VAR_MAX_GLYPH_W
@ VAR_MAX_GLYPH_W
Definition: vf_drawtext.c:123
func_metadata
static int func_metadata(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1031
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AV_OPT_TYPE_RATIONAL
@ AV_OPT_TYPE_RATIONAL
Definition: opt.h:229
DrawTextContext::prng
AVLFG prng
random
Definition: vf_drawtext.c:196
AVDetectionBBox::y
int y
Definition: detection_bbox.h:32
video.h
VAR_MAIN_W
@ VAR_MAIN_W
Definition: vf_drawtext.c:119
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:202
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:152
DrawTextContext::expanded_text
AVBPrint expanded_text
used to contain the expanded text
Definition: vf_drawtext.c:153
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:1485
VAR_H
@ VAR_H
Definition: vf_drawtext.c:118
DrawTextContext::fontsize
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:168
func_eval_expr
static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1060
DrawTextContext::x_expr
char * x_expr
expression for x position
Definition: vf_drawtext.c:188
positions
const static uint16_t positions[][14][3]
Definition: vf_vectorscope.c:817
AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE
#define AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE
Definition: detection_bbox.h:36
DrawTextContext::fontfile
uint8_t * fontfile
font to be used
Definition: vf_drawtext.c:151
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
AVDetectionBBox::detect_label
char detect_label[AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
Detect result with confidence.
Definition: detection_bbox.h:41
expansion_mode
expansion_mode
Definition: vf_drawtext.c:138
DrawTextContext::y_pexpr
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:190
fail
#define fail()
Definition: checkasm.h:127
VAR_VARS_NB
@ VAR_VARS_NB
Definition: vf_drawtext.c:135
timecode.h
EXP_NONE
@ EXP_NONE
Definition: vf_drawtext.c:139
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:575
gmtime_r
#define gmtime_r
Definition: time_internal.h:34
pts
static int64_t pts
Definition: transcode_aac.c:653
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:517
loop
static int loop
Definition: ffplay.c:339
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:336
AVFrameSideDataType
AVFrameSideDataType
Definition: frame.h:48
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
FFDIFFSIGN
#define FFDIFFSIGN(x, y)
Comparator.
Definition: macros.h:45
av_get_detection_bbox
static av_always_inline AVDetectionBBox * av_get_detection_bbox(const AVDetectionBBoxHeader *header, unsigned int idx)
Definition: detection_bbox.h:84
DrawTextContext::var_values
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:192
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:470
FLAGS
#define FLAGS
Definition: vf_drawtext.c:212
avfilter_vf_drawtext_inputs
static const AVFilterPad avfilter_vf_drawtext_inputs[]
Definition: vf_drawtext.c:1614
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
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:178
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:699
update_alpha
static void update_alpha(DrawTextContext *s)
Definition: vf_drawtext.c:1304
DrawTextContext::face
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:185
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
s
#define s(width, name)
Definition: cbs_vp9.c:257
update_fontsize
static av_cold int update_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:422
DrawTextContext::y
int y
y position to start drawing text
Definition: vf_drawtext.c:161
VAR_X
@ VAR_X
Definition: vf_drawtext.c:129
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:127
DrawTextContext::fontcolor
FFDrawColor fontcolor
foreground color
Definition: vf_drawtext.c:179
DrawTextContext::a_pexpr
AVExpr * a_pexpr
Definition: vf_drawtext.c:194
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:60
DrawTextContext::boxborderw
int boxborderw
box border width
Definition: vf_drawtext.c:173
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Definition: opt.h:225
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
var_name
var_name
Definition: noise_bsf.c:47
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
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:125
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:79
DrawTextContext::fontsize_pexpr
AVExpr * fontsize_pexpr
parsed expressions for fontsize
Definition: vf_drawtext.c:167
eval_func2
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:107
ft_error::err
int err
Definition: vf_drawtext.c:286
key
const char * key
Definition: hwcontext_opencl.c:168
VAR_T
@ VAR_T
Definition: vf_drawtext.c:126
NAN
#define NAN
Definition: mathematics.h:64
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:191
command
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:906
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
text_source_string_parse
static enum AVFrameSideDataType text_source_string_parse(const char *text_source_string)
Definition: vf_drawtext.c:697
arg
const char * arg
Definition: jacosubdec.c:67
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:65
time_internal.h
VAR_VSUB
@ VAR_VSUB
Definition: vf_drawtext.c:116
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
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:131
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:152
DrawTextContext::basetime
int64_t basetime
base pts time in the real world for display
Definition: vf_drawtext.c:191
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVDetectionBBox::classify_labels
char classify_labels[AV_NUM_DETECTION_BBOX_CLASSIFY][AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
Definition: detection_bbox.h:52
AVDetectionBBoxHeader
Definition: detection_bbox.h:56
DrawTextContext::fontsize_expr
char * fontsize_expr
expression for fontsize
Definition: vf_drawtext.c:166
isnan
#define isnan(x)
Definition: libm.h:340
AV_OPT_TYPE_COLOR
@ AV_OPT_TYPE_COLOR
Definition: opt.h:239
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_drawtext.c:822
draw_text
static int draw_text(AVFilterContext *ctx, AVFrame *frame, int width, int height)
Definition: vf_drawtext.c:1319
VAR_PKT_SIZE
@ VAR_PKT_SIZE
Definition: vf_drawtext.c:134
parseutils.h
AVTreeNode
Definition: tree.c:26
DrawTextContext::tc_rate
AVRational tc_rate
frame rate for timecode
Definition: vf_drawtext.c:198
DrawTextContext::x_pexpr
AVExpr * x_pexpr
Definition: vf_drawtext.c:190
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:589
time.h
DrawTextContext::positions
FT_Vector * positions
positions for each element in the text
Definition: vf_drawtext.c:157
VAR_MAX_GLYPH_A
@ VAR_MAX_GLYPH_A
Definition: vf_drawtext.c:120
load_font_file
static int load_font_file(AVFilterContext *ctx, const char *path, int index)
Definition: vf_drawtext.c:458
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
DrawTextContext
Definition: vf_drawtext.c:144
DrawTextContext::tabsize
int tabsize
tab size
Definition: vf_drawtext.c:175
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:74
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:201
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:1251
DrawTextContext::text_source_string
char * text_source_string
the string to specify text data source
Definition: vf_drawtext.c:203
VAR_h
@ VAR_h
Definition: vf_drawtext.c:118
set_fontsize
static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
Definition: vf_drawtext.c:388
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:837
load_font
static int load_font(AVFilterContext *ctx)
Definition: vf_drawtext.c:558
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:336
localtime_r
#define localtime_r
Definition: time_internal.h:46
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:172
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
AVFrameSideData::data
uint8_t * data
Definition: frame.h:225
DrawTextContext::shadowy
int shadowy
Definition: vf_drawtext.c:164
VAR_PKT_POS
@ VAR_PKT_POS
Definition: vf_drawtext.c:132
drand
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:102
tree.h
EXP_NORMAL
@ EXP_NORMAL
Definition: vf_drawtext.c:140
header
static const uint8_t header[24]
Definition: sdr2.c:67
VAR_TEXT_W
@ VAR_TEXT_W
Definition: vf_drawtext.c:128
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(drawtext)
expand_text
static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
Definition: vf_drawtext.c:1228
AVDetectionBBox::classify_count
uint32_t classify_count
Definition: detection_bbox.h:51
height
#define height
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:155
update_color_with_alpha
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
Definition: vf_drawtext.c:1297
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
VAR_LH
@ VAR_LH
Definition: vf_drawtext.c:117
fun2
static const eval_func2 fun2[]
Definition: vf_drawtext.c:109
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
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:146
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:827
bprint.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:271
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:630
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
common.h
delta
float delta
Definition: vorbis_enc_data.h:430
DrawTextContext::shadowx
int shadowx
Definition: vf_drawtext.c:164
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:707
drawtext_function::tag
int tag
opaque argument to func
Definition: vf_drawtext.c:1145
DrawTextContext::max_glyph_h
int max_glyph_h
max glyph height
Definition: vf_drawtext.c:163
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:263
FFDrawContext
Definition: drawutils.h:35
DrawTextContext::borderw
int borderw
border width
Definition: vf_drawtext.c:165
VAR_MAX_GLYPH_D
@ VAR_MAX_GLYPH_D
Definition: vf_drawtext.c:121
len
int len
Definition: vorbis_enc_data.h:426
VAR_W
@ VAR_W
Definition: vf_drawtext.c:119
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:863
DrawTextContext::use_kerning
int use_kerning
font kerning is used - true/false
Definition: vf_drawtext.c:174
ff_draw_color
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:141
AVFilter
Filter definition.
Definition: avfilter.h:165
DrawTextContext::tc
AVTimecode tc
timecode context
Definition: vf_drawtext.c:199
tag
uint32_t tag
Definition: movenc.c:1596
ret
ret
Definition: filter_design.txt:187
EXP_STRFTIME
@ EXP_STRFTIME
Definition: vf_drawtext.c:141
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:93
VAR_HSUB
@ VAR_HSUB
Definition: vf_drawtext.c:116
DrawTextContext::ft_load_flags
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:156
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:226
drawtext_function::argc_max
unsigned argc_max
Definition: vf_drawtext.c:1144
random_seed.h
DrawTextContext::alpha
int alpha
Definition: vf_drawtext.c:195
ft_errors
static const struct ft_error ft_errors[]
VAR_w
@ VAR_w
Definition: vf_drawtext.c:119
drawtext_options
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:214
DrawTextContext::shadowcolor
FFDrawColor shadowcolor
shadow color
Definition: vf_drawtext.c:180
eval_function
static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv)
Definition: vf_drawtext.c:1161
DrawTextContext::reinit
int reinit
tells if the filter is being reinited
Definition: vf_drawtext.c:147
func_strftime
static int func_strftime(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:1044
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:1080
dummy
int dummy
Definition: motion.c:65
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
AVDetectionBBox::x
int x
Distance in pixels from the left/top edge of the frame, together with width and height,...
Definition: detection_bbox.h:31
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:402
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:279
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:187
DrawTextContext::textfile
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:159
load_textfile
static int load_textfile(AVFilterContext *ctx)
Definition: vf_drawtext.c:580
llrint
#define llrint(x)
Definition: libm.h:394
AVFrameSideData
Structure to hold side data for an AVFrame.
Definition: frame.h:223
AV_NUM_DETECTION_BBOX_CLASSIFY
#define AV_NUM_DETECTION_BBOX_CLASSIFY
At most 4 classifications based on the detected bounding box.
Definition: detection_bbox.h:50
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:1775
DrawTextContext::text_source
enum AVFrameSideDataType text_source
Definition: vf_drawtext.c:204
diff
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Definition: vf_palettegen.c:139
avfilter_vf_drawtext_outputs
static const AVFilterPad avfilter_vf_drawtext_outputs[]
Definition: vf_drawtext.c:1624
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:79
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:241
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:192
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:306
VAR_DAR
@ VAR_DAR
Definition: vf_drawtext.c:115
FFMAX3
#define FFMAX3(a, b, c)
Definition: macros.h:48
DrawTextContext::boxcolor
FFDrawColor boxcolor
background color
Definition: vf_drawtext.c:182
AV_OPT_TYPE_FLAGS
@ AV_OPT_TYPE_FLAGS
Definition: opt.h:223
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:320
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
parse_fontsize
static av_cold int parse_fontsize(AVFilterContext *ctx)
Definition: vf_drawtext.c:404
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVDetectionBBox
Definition: detection_bbox.h:26
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:208
AVDictionaryEntry::value
char * value
Definition: dict.h:81
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:228
drawutils.h
ft_error::err_msg
const char * err_msg
Definition: vf_drawtext.c:287
ft_error
Definition: vf_drawtext.c:285
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:189
int
int
Definition: ffmpeg_filter.c:153
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
DrawTextContext::line_spacing
int line_spacing
lines spacing in pixels
Definition: vf_drawtext.c:171
drawtext_function::argc_min
unsigned argc_min
Definition: vf_drawtext.c:1144
detection_bbox.h
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:139
DrawTextContext::fontcolor_expr
uint8_t * fontcolor_expr
fontcolor expression to evaluate
Definition: vf_drawtext.c:154
AV_FRAME_DATA_DETECTION_BBOXES
@ AV_FRAME_DATA_DETECTION_BBOXES
Bounding boxes for object detection and classification, as described by AVDetectionBBoxHeader.
Definition: frame.h:189
DrawTextContext::max_glyph_w
int max_glyph_w
max glyph width
Definition: vf_drawtext.c:162
DrawTextContext::tc_opt_string
char * tc_opt_string
specified timecode option string
Definition: vf_drawtext.c:197
drawtext
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
Definition: af_afir.c:241
DrawTextContext::fix_bounds
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:176
min
float min
Definition: vorbis_enc_data.h:429
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: internal.h:69