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