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