FFmpeg
vf_drawtext.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2023 Francesco Carusi
3  * Copyright (c) 2011 Stefano Sabatini
4  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
5  * Copyright (c) 2003 Gustavo Sverzut Barbieri <gsbarbieri@yahoo.com.br>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 /**
25  * @file
26  * drawtext filter, based on the original vhook/drawtext.c
27  * filter by Gustavo Sverzut Barbieri
28  */
29 
30 #include "config.h"
31 
32 #if HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <time.h>
38 #if HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <fenv.h>
42 
43 #if CONFIG_LIBFONTCONFIG
44 #include <fontconfig/fontconfig.h>
45 #endif
46 
47 #include "libavutil/avstring.h"
48 #include "libavutil/bprint.h"
49 #include "libavutil/common.h"
50 #include "libavutil/eval.h"
51 #include "libavutil/mem.h"
52 #include "libavutil/opt.h"
53 #include "libavutil/random_seed.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/time.h"
56 #include "libavutil/timecode.h"
58 #include "libavutil/tree.h"
59 #include "libavutil/lfg.h"
61 #include "avfilter.h"
62 #include "drawutils.h"
63 #include "filters.h"
64 #include "formats.h"
65 #include "textutils.h"
66 #include "video.h"
67 
68 #if CONFIG_LIBFRIBIDI
69 #include <fribidi.h>
70 #endif
71 
72 #include <ft2build.h>
73 #include FT_FREETYPE_H
74 #include FT_GLYPH_H
75 #include FT_STROKER_H
76 
77 #include <hb.h>
78 #include <hb-ft.h>
79 
80 // Ceiling operation for positive integers division
81 #define POS_CEIL(x, y) ((x)/(y) + ((x)%(y) != 0))
82 
83 static const char *const var_names[] = {
84  "dar",
85  "hsub", "vsub",
86  "line_h", "lh", ///< line height
87  "main_h", "h", "H", ///< height of the input video
88  "main_w", "w", "W", ///< width of the input video
89  "max_glyph_a", "ascent", ///< max glyph ascender
90  "max_glyph_d", "descent", ///< min glyph descender
91  "max_glyph_h", ///< max glyph height
92  "max_glyph_w", ///< max glyph width
93  "font_a", ///< font-defined ascent
94  "font_d", ///< font-defined descent
95  "top_a", ///< max glyph ascender of the top line
96  "bottom_d", ///< max glyph descender of the bottom line
97  "n", ///< number of frame
98  "sar",
99  "t", ///< timestamp expressed in seconds
100  "text_h", "th", ///< height of the rendered text
101  "text_w", "tw", ///< width of the rendered text
102  "x",
103  "y",
104  "pict_type",
105  "duration",
106  NULL
107 };
108 
109 static const char *const fun2_names[] = {
110  "rand"
111 };
112 
113 static double drand(void *opaque, double min, double max)
114 {
115  return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
116 }
117 
118 typedef double (*eval_func2)(void *, double a, double b);
119 
120 static const eval_func2 fun2[] = {
121  drand,
122  NULL
123 };
124 
125 enum var_name {
149 };
150 
155 };
156 
161 };
162 
164  TA_LEFT = (1 << 0),
165  TA_RIGHT = (1 << 1),
166  TA_TOP = (1 << 2),
167  TA_BOTTOM = (1 << 3),
168 };
169 
170 typedef struct HarfbuzzData {
171  hb_buffer_t* buf;
172  hb_font_t* font;
173  unsigned int glyph_count;
174  hb_glyph_info_t* glyph_info;
175  hb_glyph_position_t* glyph_pos;
176 } HarfbuzzData;
177 
178 /** Information about a single glyph in a text line */
179 typedef struct GlyphInfo {
180  uint32_t code; ///< the glyph code point
181  int x; ///< the x position of the glyph
182  int y; ///< the y position of the glyph
183  int shift_x64; ///< the horizontal shift of the glyph in 26.6 units
184  int shift_y64; ///< the vertical shift of the glyph in 26.6 units
185 } GlyphInfo;
186 
187 /** Information about a single line of text */
188 typedef struct TextLine {
189  int offset_left64; ///< offset between the origin and
190  /// the leftmost pixel of the first glyph
191  int offset_right64; ///< maximum offset between the origin and
192  /// the rightmost pixel of the last glyph
193  int width64; ///< width of the line
194  HarfbuzzData hb_data; ///< libharfbuzz data of this text line
195  GlyphInfo* glyphs; ///< array of glyphs in this text line
196  int cluster_offset; ///< the offset at which this line begins
197 } TextLine;
198 
199 /** A glyph as loaded and rendered using libfreetype */
200 typedef struct Glyph {
201  FT_Glyph glyph;
202  FT_Glyph border_glyph;
203  uint32_t code;
204  unsigned int fontsize;
205  /** Glyph bitmaps with 1/4 pixel precision in both directions */
206  FT_BitmapGlyph bglyph[16];
207  /** Outlined glyph bitmaps with 1/4 pixel precision in both directions */
208  FT_BitmapGlyph border_bglyph[16];
209  FT_BBox bbox;
210 } Glyph;
211 
212 /** Global text metrics */
213 typedef struct TextMetrics {
214  int offset_top64; ///< ascender amount of the first line (in 26.6 units)
215  int offset_bottom64; ///< descender amount of the last line (in 26.6 units)
216  int offset_left64; ///< maximum offset between the origin and
217  /// the leftmost pixel of the first glyph
218  /// of each line (in 26.6 units)
219  int offset_right64; ///< maximum offset between the origin and
220  /// the rightmost pixel of the last glyph
221  /// of each line (in 26.6 units)
222  int line_height64; ///< the font-defined line height
223  int width; ///< width of the longest line - ceil(width64/64)
224  int height; ///< total height of the text - ceil(height64/64)
225 
226  int min_y64; ///< minimum value of bbox.yMin among glyphs (in 26.6 units)
227  int max_y64; ///< maximum value of bbox.yMax among glyphs (in 26.6 units)
228  int min_x64; ///< minimum value of bbox.xMin among glyphs (in 26.6 units)
229  int max_x64; ///< maximum value of bbox.xMax among glyphs (in 26.6 units)
230 
231  // Position of the background box (without borders)
232  int rect_x; ///< x position of the box
233  int rect_y; ///< y position of the box
234 } TextMetrics;
235 
236 typedef struct DrawTextContext {
237  const AVClass *class;
238  int exp_mode; ///< expansion mode to use for the text
239  FFExpandTextContext expand_text; ///< expand text in case exp_mode == NORMAL
240  int reinit; ///< tells if the filter is being reinited
241 #if CONFIG_LIBFONTCONFIG
242  uint8_t *font; ///< font to be used
243 #endif
244  uint8_t *fontfile; ///< font to be used
245  uint8_t *text; ///< text to be drawn
246  AVBPrint expanded_text; ///< used to contain the expanded text
247  uint8_t *fontcolor_expr; ///< fontcolor expression to evaluate
248  AVBPrint expanded_fontcolor; ///< used to contain the expanded fontcolor spec
249  int ft_load_flags; ///< flags used for loading fonts, see FT_LOAD_*
250  char *textfile; ///< file with text to be drawn
251  double x; ///< x position to start drawing text
252  double y; ///< y position to start drawing text
253  int max_glyph_w; ///< max glyph width
254  int max_glyph_h; ///< max glyph height
256  int borderw; ///< border width
257  char *fontsize_expr; ///< expression for fontsize
258  AVExpr *fontsize_pexpr; ///< parsed expressions for fontsize
259  unsigned int fontsize; ///< font size to use
260  unsigned int default_fontsize; ///< default font size to use
261 
262  int line_spacing; ///< lines spacing in pixels
263  short int draw_box; ///< draw box around text - true or false
264  char *boxborderw; ///< box border width (padding)
265  /// allowed formats: "all", "vert|oriz", "top|right|bottom|left"
266  int bb_top; ///< the size of the top box border
267  int bb_right; ///< the size of the right box border
268  int bb_bottom; ///< the size of the bottom box border
269  int bb_left; ///< the size of the left box border
270  int box_width; ///< the width of box
271  int box_height; ///< the height of box
272  int tabsize; ///< tab size
273  int fix_bounds; ///< do we let it go out of frame bounds - t/f
274 
276  FFDrawColor fontcolor; ///< foreground color
277  FFDrawColor shadowcolor; ///< shadow color
278  FFDrawColor bordercolor; ///< border color
279  FFDrawColor boxcolor; ///< background color
280 
281  FT_Library library; ///< freetype font library handle
282  FT_Face face; ///< freetype font face handle
283  FT_Stroker stroker; ///< freetype stroker handle
284  struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
285  char *x_expr; ///< expression for x position
286  char *y_expr; ///< expression for y position
287  AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
288  int64_t basetime; ///< base pts time in the real world for display
290  char *a_expr;
292  int alpha;
293  AVLFG prng; ///< random
294  char *tc_opt_string; ///< specified timecode option string
295  AVRational tc_rate; ///< frame rate for timecode
296  AVTimecode tc; ///< timecode context
297  int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
298  int reload; ///< reload text file at specified frame interval
299  int start_number; ///< starting frame number for n/frame_num var
300  char *text_source_string; ///< the string to specify text data source
302 #if CONFIG_LIBFRIBIDI
303  int text_shaping; ///< 1 to shape the text before drawing it
304 #endif
306 
307  int boxw; ///< the value of the boxw parameter
308  int boxh; ///< the value of the boxh parameter
309  int text_align; ///< the horizontal and vertical text alignment
310  int y_align; ///< the value of the y_align parameter
311 
312  TextLine *lines; ///< computed information about text lines
313  int line_count; ///< the number of text lines
314  uint32_t *tab_clusters; ///< the position of tab characters in the text
315  int tab_count; ///< the number of tab characters
316  int blank_advance64; ///< the size of the space character
317  int tab_warning_printed; ///< ensure the tab warning to be printed only once
319 
320 #define OFFSET(x) offsetof(DrawTextContext, x)
321 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
322 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
323 
324 static const AVOption drawtext_options[]= {
325  {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
326  {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, TFLAGS},
327  {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
328  {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, TFLAGS},
329  {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, 0, 0, FLAGS},
330  {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, 0, 0, TFLAGS},
331  {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, TFLAGS},
332  {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, TFLAGS},
333  {"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, TFLAGS},
334  {"boxborderw", "set box borders width", OFFSET(boxborderw), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
335  {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS},
336  {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, TFLAGS},
337  {"text_align", "set text alignment", OFFSET(text_align), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, (TA_LEFT|TA_RIGHT|TA_TOP|TA_BOTTOM), TFLAGS, .unit = "text_align"},
338  { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_LEFT }, .flags = TFLAGS, .unit = "text_align" },
339  { "L", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_LEFT }, .flags = TFLAGS, .unit = "text_align" },
340  { "right", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_RIGHT }, .flags = TFLAGS, .unit = "text_align" },
341  { "R", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_RIGHT }, .flags = TFLAGS, .unit = "text_align" },
342  { "center", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_LEFT|TA_RIGHT) }, .flags = TFLAGS, .unit = "text_align" },
343  { "C", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_LEFT|TA_RIGHT) }, .flags = TFLAGS, .unit = "text_align" },
344  { "top", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_TOP }, .flags = TFLAGS, .unit = "text_align" },
345  { "T", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_TOP }, .flags = TFLAGS, .unit = "text_align" },
346  { "bottom", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_BOTTOM }, .flags = TFLAGS, .unit = "text_align" },
347  { "B", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_BOTTOM }, .flags = TFLAGS, .unit = "text_align" },
348  { "middle", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_TOP|TA_BOTTOM) }, .flags = TFLAGS, .unit = "text_align" },
349  { "M", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_TOP|TA_BOTTOM) }, .flags = TFLAGS, .unit = "text_align" },
350  {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
351  {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
352  {"boxw", "set box width", OFFSET(boxw), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, TFLAGS},
353  {"boxh", "set box height", OFFSET(boxh), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, TFLAGS},
354  {"shadowx", "set shadow x offset", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS},
355  {"shadowy", "set shadow y offset", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS},
356  {"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS},
357  {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX, TFLAGS},
358  {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX, FLAGS},
359 #if CONFIG_LIBFONTCONFIG
360  { "font", "Font name", OFFSET(font), AV_OPT_TYPE_STRING, { .str = "Sans" }, .flags = FLAGS },
361 #endif
362 
363  {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, .unit = "expansion"},
364  {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, .unit = "expansion"},
365  {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, .unit = "expansion"},
366  {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, .unit = "expansion"},
367  {"y_align", "set the y alignment", OFFSET(y_align), AV_OPT_TYPE_INT, {.i64=YA_TEXT}, 0, 2, TFLAGS, .unit = "y_align"},
368  {"text", "y is referred to the top of the first text line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_TEXT}, 0, 0, FLAGS, .unit = "y_align"},
369  {"baseline", "y is referred to the baseline of the first line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_BASELINE}, 0, 0, FLAGS, .unit = "y_align"},
370  {"font", "y is referred to the font defined line metrics", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_FONT}, 0, 0, FLAGS, .unit = "y_align"},
371 
372  {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
373  {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
374  {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
375  {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
376  {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
377  {"reload", "reload text file at specified frame interval", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
378  {"alpha", "apply alpha while rendering", OFFSET(a_expr), AV_OPT_TYPE_STRING, {.str = "1"}, .flags = TFLAGS},
379  {"fix_bounds", "check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
380  {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
381  {"text_source", "the source of text", OFFSET(text_source_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS },
382 
383 #if CONFIG_LIBFRIBIDI
384  {"text_shaping", "attempt to shape text before drawing", OFFSET(text_shaping), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS},
385 #endif
386 
387  /* FT_LOAD_* flags */
388  { "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, .unit = "ft_load_flags" },
389  { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
390  { "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
391  { "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
392  { "render", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_RENDER }, .flags = FLAGS, .unit = "ft_load_flags" },
393  { "no_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
394  { "vertical_layout", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags = FLAGS, .unit = "ft_load_flags" },
395  { "force_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_FORCE_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
396  { "crop_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_CROP_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
397  { "pedantic", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_PEDANTIC }, .flags = FLAGS, .unit = "ft_load_flags" },
398  { "ignore_global_advance_width", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags = FLAGS, .unit = "ft_load_flags" },
399  { "no_recurse", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_RECURSE }, .flags = FLAGS, .unit = "ft_load_flags" },
400  { "ignore_transform", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags = FLAGS, .unit = "ft_load_flags" },
401  { "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
402  { "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
403  { "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
404  { NULL }
405 };
406 
408 
409 #undef __FTERRORS_H__
410 #define FT_ERROR_START_LIST {
411 #define FT_ERRORDEF(e, v, s) { (e), (s) },
412 #define FT_ERROR_END_LIST { 0, NULL } };
413 
414 static const struct ft_error {
415  int err;
416  const char *err_msg;
417 } ft_errors[] =
418 #include FT_ERRORS_H
419 
420 #define FT_ERRMSG(e) ft_errors[e].err_msg
421 
422 static int glyph_cmp(const void *key, const void *b)
423 {
424  const Glyph *a = key, *bb = b;
425  int64_t diff = (int64_t)a->code - (int64_t)bb->code;
426 
427  if (diff != 0)
428  return diff > 0 ? 1 : -1;
429  else
430  return FFDIFFSIGN((int64_t)a->fontsize, (int64_t)bb->fontsize);
431 }
432 
433 static av_cold int set_fontsize(AVFilterContext *ctx, unsigned int fontsize)
434 {
435  int err;
436  DrawTextContext *s = ctx->priv;
437 
438  if ((err = FT_Set_Pixel_Sizes(s->face, 0, fontsize))) {
439  av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
440  fontsize, FT_ERRMSG(err));
441  return AVERROR(EINVAL);
442  }
443 
444  // Whenever the underlying FT_Face changes, harfbuzz has to be notified of the change.
445  for (int line = 0; line < s->line_count; line++) {
446  TextLine *cur_line = &s->lines[line];
447  hb_ft_font_changed(cur_line->hb_data.font);
448  }
449 
450  s->fontsize = fontsize;
451 
452  return 0;
453 }
454 
455 static av_cold int parse_fontsize(AVFilterContext *ctx)
456 {
457  DrawTextContext *s = ctx->priv;
458  int err;
459 
460  if (s->fontsize_pexpr)
461  return 0;
462 
463  if (s->fontsize_expr == NULL)
464  return AVERROR(EINVAL);
465 
466  if ((err = av_expr_parse(&s->fontsize_pexpr, s->fontsize_expr, var_names,
467  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
468  return err;
469 
470  return 0;
471 }
472 
473 static av_cold int update_fontsize(AVFilterContext *ctx)
474 {
475  DrawTextContext *s = ctx->priv;
476  unsigned int fontsize = s->default_fontsize;
477  int err;
478  double size, roundedsize;
479 
480  // if no fontsize specified use the default
481  if (s->fontsize_expr != NULL) {
482  if ((err = parse_fontsize(ctx)) < 0)
483  return err;
484 
485  size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
486  if (!isnan(size)) {
487  roundedsize = round(size);
488  // test for overflow before cast
489  if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
490  av_log(ctx, AV_LOG_ERROR, "fontsize overflow\n");
491  return AVERROR(EINVAL);
492  }
493  fontsize = roundedsize;
494  }
495  }
496 
497  if (fontsize == 0)
498  fontsize = 1;
499 
500  // no change
501  if (fontsize == s->fontsize)
502  return 0;
503 
504  return set_fontsize(ctx, fontsize);
505 }
506 
507 static int load_font_file(AVFilterContext *ctx, const char *path, int index)
508 {
509  DrawTextContext *s = ctx->priv;
510  int err;
511 
512  err = FT_New_Face(s->library, path, index, &s->face);
513  if (err) {
514 #if !CONFIG_LIBFONTCONFIG
515  av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
516  s->fontfile, FT_ERRMSG(err));
517 #endif
518  return AVERROR(EINVAL);
519  }
520  return 0;
521 }
522 
523 #if CONFIG_LIBFONTCONFIG
524 static int load_font_fontconfig(AVFilterContext *ctx)
525 {
526  DrawTextContext *s = ctx->priv;
527  FcConfig *fontconfig;
528  FcPattern *pat, *best;
529  FcResult result = FcResultMatch;
530  FcChar8 *filename;
531  int index;
532  double size;
533  int err = AVERROR(ENOENT);
534  int parse_err;
535 
536  fontconfig = FcInitLoadConfigAndFonts();
537  if (!fontconfig) {
538  av_log(ctx, AV_LOG_ERROR, "impossible to init fontconfig\n");
539  return AVERROR_UNKNOWN;
540  }
541  pat = FcNameParse(s->fontfile ? s->fontfile :
542  (uint8_t *)(intptr_t)"default");
543  if (!pat) {
544  av_log(ctx, AV_LOG_ERROR, "could not parse fontconfig pat");
545  return AVERROR(EINVAL);
546  }
547 
548  FcPatternAddString(pat, FC_FAMILY, s->font);
549 
550  parse_err = parse_fontsize(ctx);
551  if (!parse_err) {
552  double size = av_expr_eval(s->fontsize_pexpr, s->var_values, &s->prng);
553 
554  if (isnan(size)) {
555  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
556  return AVERROR(EINVAL);
557  }
558 
559  FcPatternAddDouble(pat, FC_SIZE, size);
560  }
561 
562  FcDefaultSubstitute(pat);
563 
564  if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
565  av_log(ctx, AV_LOG_ERROR, "could not substitute fontconfig options"); /* very unlikely */
566  FcPatternDestroy(pat);
567  return AVERROR(ENOMEM);
568  }
569 
570  best = FcFontMatch(fontconfig, pat, &result);
571  FcPatternDestroy(pat);
572 
573  if (!best || result != FcResultMatch) {
575  "Cannot find a valid font for the family %s\n",
576  s->font);
577  goto fail;
578  }
579 
580  if (
581  FcPatternGetInteger(best, FC_INDEX, 0, &index ) != FcResultMatch ||
582  FcPatternGetDouble (best, FC_SIZE, 0, &size ) != FcResultMatch) {
583  av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
584  return AVERROR(EINVAL);
585  }
586 
587  if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
588  av_log(ctx, AV_LOG_ERROR, "No file path for %s\n",
589  s->font);
590  goto fail;
591  }
592 
593  av_log(ctx, AV_LOG_VERBOSE, "Using \"%s\"\n", filename);
594  if (parse_err)
595  s->default_fontsize = size + 0.5;
596 
597  err = load_font_file(ctx, filename, index);
598  if (err)
599  return err;
600  FcConfigDestroy(fontconfig);
601 fail:
602  FcPatternDestroy(best);
603  return err;
604 }
605 #endif
606 
607 static int load_font(AVFilterContext *ctx)
608 {
609  DrawTextContext *s = ctx->priv;
610  int err;
611 
612  /* load the face, and set up the encoding, which is by default UTF-8 */
613  err = load_font_file(ctx, s->fontfile, 0);
614  if (!err)
615  return 0;
616 #if CONFIG_LIBFONTCONFIG
617  err = load_font_fontconfig(ctx);
618  if (!err)
619  return 0;
620 #endif
621  return err;
622 }
623 
624 #if CONFIG_LIBFRIBIDI
625 static int shape_text(AVFilterContext *ctx)
626 {
627  DrawTextContext *s = ctx->priv;
628  uint8_t *tmp;
629  int ret = AVERROR(ENOMEM);
630  static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
631  FRIBIDI_FLAGS_ARABIC;
632  FriBidiChar *unicodestr = NULL;
633  FriBidiStrIndex len;
634  FriBidiParType direction = FRIBIDI_PAR_LTR;
635  FriBidiStrIndex line_start = 0;
636  FriBidiStrIndex line_end = 0;
637  FriBidiLevel *embedding_levels = NULL;
638  FriBidiArabicProp *ar_props = NULL;
639  FriBidiCharType *bidi_types = NULL;
640  FriBidiStrIndex i,j;
641 
642  len = strlen(s->text);
643  if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
644  goto out;
645  }
646  len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
647  s->text, len, unicodestr);
648 
649  bidi_types = av_malloc_array(len, sizeof(*bidi_types));
650  if (!bidi_types) {
651  goto out;
652  }
653 
654  fribidi_get_bidi_types(unicodestr, len, bidi_types);
655 
656  embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
657  if (!embedding_levels) {
658  goto out;
659  }
660 
661  if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
662  embedding_levels)) {
663  goto out;
664  }
665 
666  ar_props = av_malloc_array(len, sizeof(*ar_props));
667  if (!ar_props) {
668  goto out;
669  }
670 
671  fribidi_get_joining_types(unicodestr, len, ar_props);
672  fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
673  fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);
674 
675  for (line_end = 0, line_start = 0; line_end < len; line_end++) {
676  if (ff_is_newline(unicodestr[line_end]) || line_end == len - 1) {
677  if (!fribidi_reorder_line(flags, bidi_types,
678  line_end - line_start + 1, line_start,
679  direction, embedding_levels, unicodestr,
680  NULL)) {
681  goto out;
682  }
683  line_start = line_end + 1;
684  }
685  }
686 
687  /* Remove zero-width fill chars put in by libfribidi */
688  for (i = 0, j = 0; i < len; i++)
689  if (unicodestr[i] != FRIBIDI_CHAR_FILL)
690  unicodestr[j++] = unicodestr[i];
691  len = j;
692 
693  if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
694  /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
695  goto out;
696  }
697 
698  s->text = tmp;
699  len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
700  unicodestr, len, s->text);
701 
702  ret = 0;
703 
704 out:
705  av_free(unicodestr);
706  av_free(embedding_levels);
707  av_free(ar_props);
708  av_free(bidi_types);
709  return ret;
710 }
711 #endif
712 
713 static enum AVFrameSideDataType text_source_string_parse(const char *text_source_string)
714 {
715  av_assert0(text_source_string);
716  if (!strcmp(text_source_string, "side_data_detection_bboxes")) {
718  } else {
719  return AVERROR(EINVAL);
720  }
721 }
722 
723 static inline int get_subpixel_idx(int shift_x64, int shift_y64)
724 {
725  int idx = (shift_x64 >> 2) + (shift_y64 >> 4);
726  return idx;
727 }
728 
729 // Loads and (optionally) renders a glyph
730 static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code, int8_t shift_x64, int8_t shift_y64)
731 {
732  DrawTextContext *s = ctx->priv;
733  Glyph dummy = { 0 };
734  Glyph *glyph;
735  FT_Vector shift;
736  struct AVTreeNode *node = NULL;
737  int ret = 0;
738  int cached = 0;
739 
740  /* get glyph */
741  dummy.code = code;
742  dummy.fontsize = s->fontsize;
743  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
744  cached = !!glyph;
745  if (!glyph) {
746  if (FT_Load_Glyph(s->face, code, s->ft_load_flags)) {
747  return AVERROR(EINVAL);
748  }
749  glyph = av_mallocz(sizeof(*glyph));
750  if (!glyph) {
751  ret = AVERROR(ENOMEM);
752  goto error;
753  }
754  glyph->code = code;
755  glyph->fontsize = s->fontsize;
756  if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
757  ret = AVERROR(EINVAL);
758  goto error;
759  }
760  if (s->borderw) {
761  FT_Glyph tmp = glyph->glyph;
762  if (FT_Glyph_StrokeBorder(&tmp, s->stroker, 0, 0)) {
764  goto error;
765  }
766  glyph->border_glyph = tmp;
767  }
768  /* measure text height to calculate text_height (or the maximum text height) */
769  FT_Glyph_Get_CBox(glyph->glyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph->bbox);
770 
771  /* cache the newly created glyph */
772  if (!(node = av_tree_node_alloc())) {
773  ret = AVERROR(ENOMEM);
774  goto error;
775  }
776  av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);
777  cached = 1;
778  } else {
779  if (s->borderw && !glyph->border_glyph) {
780  FT_Glyph tmp = glyph->glyph;
781  if (FT_Glyph_StrokeBorder(&tmp, s->stroker, 0, 0)) {
783  goto error;
784  }
785  glyph->border_glyph = tmp;
786  }
787  }
788 
789  // Check if a bitmap is needed
790  if (shift_x64 >= 0 && shift_y64 >= 0) {
791  // Get the bitmap subpixel index (0 -> 15)
792  int idx = get_subpixel_idx(shift_x64, shift_y64);
793  shift.x = shift_x64;
794  shift.y = shift_y64;
795 
796  if (!glyph->bglyph[idx]) {
797  FT_Glyph tmp_glyph = glyph->glyph;
798  if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &shift, 0)) {
800  goto error;
801  }
802  glyph->bglyph[idx] = (FT_BitmapGlyph)tmp_glyph;
803  }
804  if (glyph->bglyph[idx]->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
805  av_log(ctx, AV_LOG_ERROR, "Monocromatic (1bpp) fonts are not supported.\n");
806  ret = AVERROR(EINVAL);
807  goto error;
808  }
809  if (s->borderw && !glyph->border_bglyph[idx]) {
810  FT_Glyph tmp_glyph = glyph->border_glyph;
811  if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &shift, 0)) {
813  goto error;
814  }
815  glyph->border_bglyph[idx] = (FT_BitmapGlyph)tmp_glyph;
816  }
817  }
818  if (glyph_ptr) {
819  *glyph_ptr = glyph;
820  }
821  return 0;
822 
823 error:
824  if (glyph && !cached) {
825  if (glyph->border_glyph && glyph->border_glyph != glyph->glyph)
826  FT_Done_Glyph(glyph->border_glyph);
827  if (glyph->glyph)
828  FT_Done_Glyph(glyph->glyph);
829  av_freep(&glyph);
830  }
831  av_freep(&node);
832  return ret;
833 }
834 
835 // Convert a string formatted as "n1|n2|...|nN" into an integer array
836 static int string_to_array(const char *source, int *result, int result_size)
837 {
838  int counter = 0, size = strlen(source) + 1;
839  char *saveptr, *curval, *dup = av_malloc(size);
840  if (!dup)
841  return 0;
842  av_strlcpy(dup, source, size);
843  if (result_size > 0 && (curval = av_strtok(dup, "|", &saveptr))) {
844  do {
845  result[counter++] = atoi(curval);
846  } while ((curval = av_strtok(NULL, "|", &saveptr)) && counter < result_size);
847  }
848  av_free(dup);
849  return counter;
850 }
851 
852 static int func_pict_type(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
853 {
854  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
855 
856  av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
857  return 0;
858 }
859 
860 static int func_pts(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
861 {
862  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
863  const char *fmt;
864  const char *strftime_fmt = NULL;
865  const char *delta = NULL;
866  double pts = s->var_values[VAR_T];
867 
868  // argv: pts, FMT, [DELTA, 24HH | strftime_fmt]
869 
870  fmt = argc >= 1 ? argv[0] : "flt";
871  if (argc >= 2) {
872  delta = argv[1];
873  }
874  if (argc >= 3) {
875  if (!strcmp(fmt, "hms")) {
876  if (!strcmp(argv[2], "24HH")) {
877  av_log(ctx, AV_LOG_WARNING, "pts third argument 24HH is deprecated, use pts:hms24hh instead\n");
878  fmt = "hms24";
879  } else {
880  av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s', '24HH' was expected\n", argv[2]);
881  return AVERROR(EINVAL);
882  }
883  } else {
884  strftime_fmt = argv[2];
885  }
886  }
887 
888  return ff_print_pts(ctx, bp, pts, delta, fmt, strftime_fmt);
889 }
890 
891 static int func_frame_num(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
892 {
893  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
894 
895  av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
896  return 0;
897 }
898 
899 static int func_metadata(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
900 {
901  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
902  AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
903 
904  if (e && e->value)
905  av_bprintf(bp, "%s", e->value);
906  else if (argc >= 2)
907  av_bprintf(bp, "%s", argv[1]);
908  return 0;
909 }
910 
911 static int func_strftime(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
912 {
913  const char *strftime_fmt = argc ? argv[0] : NULL;
914 
915  return ff_print_time(ctx, bp, strftime_fmt, !strcmp(function_name, "localtime"));
916 }
917 
918 static int func_eval_expr(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
919 {
920  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
921 
922  return ff_print_eval_expr(ctx, bp, argv[0],
923  fun2_names, fun2,
924  var_names, s->var_values, &s->prng);
925 }
926 
927 static int func_eval_expr_int_format(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
928 {
929  DrawTextContext *s = ((AVFilterContext *)ctx)->priv;
930  int ret;
931  int positions = -1;
932 
933  /*
934  * argv[0] expression to be converted to `int`
935  * argv[1] format: 'x', 'X', 'd' or 'u'
936  * argv[2] positions printed (optional)
937  */
938 
939  if (argc == 3) {
940  ret = sscanf(argv[2], "%u", &positions);
941  if (ret != 1) {
942  av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
943  " to print: '%s'\n", argv[2]);
944  return AVERROR(EINVAL);
945  }
946  }
947 
948  return ff_print_formatted_eval_expr(ctx, bp, argv[0],
949  fun2_names, fun2,
950  var_names, s->var_values,
951  &s->prng,
952  argv[1][0], positions);
953 }
954 
956  { "e", 1, 1, func_eval_expr },
957  { "eif", 2, 3, func_eval_expr_int_format },
958  { "expr", 1, 1, func_eval_expr },
959  { "expr_int_format", 2, 3, func_eval_expr_int_format },
960  { "frame_num", 0, 0, func_frame_num },
961  { "gmtime", 0, 1, func_strftime },
962  { "localtime", 0, 1, func_strftime },
963  { "metadata", 1, 2, func_metadata },
964  { "n", 0, 0, func_frame_num },
965  { "pict_type", 0, 0, func_pict_type },
966  { "pts", 0, 3, func_pts }
967 };
968 
970 {
971  int err;
972  DrawTextContext *s = ctx->priv;
973 
974  av_expr_free(s->fontsize_pexpr);
975  s->fontsize_pexpr = NULL;
976 
977  s->fontsize = 0;
978  s->default_fontsize = 16;
979 
980  if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
981  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
982  return AVERROR(EINVAL);
983  }
984 
985  if (s->textfile) {
986  if (s->text) {
988  "Both text and text file provided. Please provide only one\n");
989  return AVERROR(EINVAL);
990  }
991  if ((err = ff_load_textfile(ctx, (const char *)s->textfile, &s->text, NULL)) < 0)
992  return err;
993  }
994 
995  if (s->reload && !s->textfile)
996  av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
997 
998  if (s->tc_opt_string) {
999  int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
1000  s->tc_opt_string, ctx);
1001  if (ret < 0)
1002  return ret;
1003  if (s->tc24hmax)
1004  s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
1005  if (!s->text)
1006  s->text = av_strdup("");
1007  }
1008 
1009  if (s->text_source_string) {
1010  s->text_source = text_source_string_parse(s->text_source_string);
1011  if ((int)s->text_source < 0) {
1012  av_log(ctx, AV_LOG_ERROR, "Error text source: %s\n", s->text_source_string);
1013  return AVERROR(EINVAL);
1014  }
1015  }
1016 
1017  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
1018  if (s->text) {
1019  av_log(ctx, AV_LOG_WARNING, "Multiple texts provided, will use text_source only\n");
1020  av_free(s->text);
1021  }
1024  if (!s->text)
1025  return AVERROR(ENOMEM);
1026  }
1027 
1028  if (!s->text) {
1030  "Either text, a valid file, a timecode or text source must be provided\n");
1031  return AVERROR(EINVAL);
1032  }
1033 
1034  s->expand_text = (FFExpandTextContext) {
1035  .log_ctx = ctx,
1036  .functions = expand_text_functions,
1037  .functions_nb = FF_ARRAY_ELEMS(expand_text_functions)
1038  };
1039 
1040 #if CONFIG_LIBFRIBIDI
1041  if (s->text_shaping)
1042  if ((err = shape_text(ctx)) < 0)
1043  return err;
1044 #endif
1045 
1046  if ((err = FT_Init_FreeType(&(s->library)))) {
1048  "Could not load FreeType: %s\n", FT_ERRMSG(err));
1049  return AVERROR(EINVAL);
1050  }
1051 
1052  if ((err = load_font(ctx)) < 0)
1053  return err;
1054 
1055  if ((err = update_fontsize(ctx)) < 0)
1056  return err;
1057 
1058  // Always init the stroker, may be needed if borderw is set via command
1059  if (FT_Stroker_New(s->library, &s->stroker)) {
1060  av_log(ctx, AV_LOG_ERROR, "Could not init FT stroker\n");
1061  return AVERROR_EXTERNAL;
1062  }
1063 
1064  if (s->borderw) {
1065  FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
1066  FT_STROKER_LINEJOIN_ROUND, 0);
1067  }
1068 
1069  /* load the fallback glyph with code 0 */
1070  load_glyph(ctx, NULL, 0, 0, 0);
1071 
1072  if (s->exp_mode == EXP_STRFTIME &&
1073  (strchr(s->text, '%') || strchr(s->text, '\\')))
1074  av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
1075 
1076  av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
1077  av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);
1078 
1079  return 0;
1080 }
1081 
1083  AVFilterFormatsConfig **cfg_in,
1084  AVFilterFormatsConfig **cfg_out)
1085 {
1086  return ff_set_common_formats2(ctx, cfg_in, cfg_out,
1088 }
1089 
1090 static int glyph_enu_border_free(void *opaque, void *elem)
1091 {
1092  Glyph *glyph = elem;
1093 
1094  if (glyph->border_glyph != NULL) {
1095  for (int t = 0; t < 16; ++t) {
1096  FT_Glyph bbg = (FT_Glyph)glyph->border_bglyph[t];
1097  if (bbg && bbg != glyph->border_glyph)
1098  FT_Done_Glyph(bbg);
1099  glyph->border_bglyph[t] = NULL;
1100  }
1101  FT_Done_Glyph(glyph->border_glyph);
1102  glyph->border_glyph = NULL;
1103  }
1104  return 0;
1105 }
1106 
1107 static int glyph_enu_free(void *opaque, void *elem)
1108 {
1109  Glyph *glyph = elem;
1110 
1111  for (int t = 0; t < 16; ++t) {
1112  FT_Glyph bg = (FT_Glyph)glyph->bglyph[t];
1113  FT_Glyph bbg = (FT_Glyph)glyph->border_bglyph[t];
1114  if (bg && bg != glyph->glyph && bg != glyph->border_glyph)
1115  FT_Done_Glyph(bg);
1116  if (bbg && bbg != glyph->glyph && bbg != glyph->border_glyph)
1117  FT_Done_Glyph(bbg);
1118  }
1119  if (glyph->border_glyph && glyph->border_glyph != glyph->glyph)
1120  FT_Done_Glyph(glyph->border_glyph);
1121  FT_Done_Glyph(glyph->glyph);
1122  av_free(elem);
1123  return 0;
1124 }
1125 
1127 {
1128  DrawTextContext *s = ctx->priv;
1129 
1130  av_expr_free(s->x_pexpr);
1131  av_expr_free(s->y_pexpr);
1132  av_expr_free(s->a_pexpr);
1133  av_expr_free(s->fontsize_pexpr);
1134 
1135  s->x_pexpr = s->y_pexpr = s->a_pexpr = s->fontsize_pexpr = NULL;
1136 
1138  av_tree_destroy(s->glyphs);
1139  s->glyphs = NULL;
1140 
1141  FT_Done_Face(s->face);
1142  FT_Stroker_Done(s->stroker);
1143  FT_Done_FreeType(s->library);
1144 
1145  av_bprint_finalize(&s->expanded_text, NULL);
1146  av_bprint_finalize(&s->expanded_fontcolor, NULL);
1147 }
1148 
1150 {
1151  AVFilterContext *ctx = inlink->dst;
1152  DrawTextContext *s = ctx->priv;
1153  char *expr;
1154  int ret;
1155 
1157  if (ret < 0) {
1158  av_log(ctx, AV_LOG_ERROR, "Failed to initialize FFDrawContext\n");
1159  return ret;
1160  }
1161  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
1162  ff_draw_color(&s->dc, &s->shadowcolor, s->shadowcolor.rgba);
1163  ff_draw_color(&s->dc, &s->bordercolor, s->bordercolor.rgba);
1164  ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
1165 
1166  s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
1167  s->var_values[VAR_h] = s->var_values[VAR_H] = s->var_values[VAR_MAIN_H] = inlink->h;
1168  s->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
1169  s->var_values[VAR_DAR] = (double)inlink->w / inlink->h * s->var_values[VAR_SAR];
1170  s->var_values[VAR_HSUB] = 1 << s->dc.hsub_max;
1171  s->var_values[VAR_VSUB] = 1 << s->dc.vsub_max;
1172  s->var_values[VAR_X] = NAN;
1173  s->var_values[VAR_Y] = NAN;
1174  s->var_values[VAR_T] = NAN;
1175 
1176  av_lfg_init(&s->prng, av_get_random_seed());
1177 
1178  av_expr_free(s->x_pexpr);
1179  av_expr_free(s->y_pexpr);
1180  av_expr_free(s->a_pexpr);
1181  s->x_pexpr = s->y_pexpr = s->a_pexpr = NULL;
1182 
1183  if ((ret = av_expr_parse(&s->x_pexpr, expr = s->x_expr, var_names,
1184  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
1185  (ret = av_expr_parse(&s->y_pexpr, expr = s->y_expr, var_names,
1186  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
1187  (ret = av_expr_parse(&s->a_pexpr, expr = s->a_expr, var_names,
1188  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
1189  av_log(ctx, AV_LOG_ERROR, "Failed to parse expression: %s \n", expr);
1190  return AVERROR(EINVAL);
1191  }
1192 
1193  return 0;
1194 }
1195 
1196 static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
1197 {
1198  DrawTextContext *old = ctx->priv;
1199  DrawTextContext *new = NULL;
1200  int ret;
1201 
1202  if (!strcmp(cmd, "reinit")) {
1203  new = av_mallocz(sizeof(DrawTextContext));
1204  if (!new)
1205  return AVERROR(ENOMEM);
1206 
1207  new->class = &drawtext_class;
1208  ret = av_opt_copy(new, old);
1209  if (ret < 0)
1210  goto fail;
1211 
1212  ctx->priv = new;
1213  ret = av_set_options_string(ctx, arg, "=", ":");
1214  if (ret < 0) {
1215  ctx->priv = old;
1216  goto fail;
1217  }
1218 
1219  ret = init(ctx);
1220  if (ret < 0) {
1221  uninit(ctx);
1222  ctx->priv = old;
1223  goto fail;
1224  }
1225 
1226  new->reinit = 1;
1227 
1228  ctx->priv = old;
1229  uninit(ctx);
1230  av_opt_free(old);
1231  av_freep(&old);
1232 
1233  ctx->priv = new;
1234  return config_input(ctx->inputs[0]);
1235  } else {
1236  int old_borderw = old->borderw;
1237  if ((ret = ff_filter_process_command(ctx, cmd, arg, res, res_len, flags)) < 0) {
1238  return ret;
1239  }
1240  if (old->borderw != old_borderw) {
1241  FT_Stroker_Set(old->stroker, old->borderw << 6, FT_STROKER_LINECAP_ROUND,
1242  FT_STROKER_LINEJOIN_ROUND, 0);
1243  // Dispose the old border glyphs
1245  } else if (strcmp(cmd, "fontsize") == 0) {
1247  old->fontsize_pexpr = NULL;
1248  old->blank_advance64 = 0;
1249  }
1250  return config_input(ctx->inputs[0]);
1251  }
1252 
1253 fail:
1254  av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
1255  av_freep(&new);
1256  return ret;
1257 }
1258 
1260 {
1261  *color = incolor;
1262  color->rgba[3] = (color->rgba[3] * s->alpha) / 255;
1263  ff_draw_color(&s->dc, color, color->rgba);
1264 }
1265 
1267 {
1268  double alpha = av_expr_eval(s->a_pexpr, s->var_values, &s->prng);
1269 
1270  if (isnan(alpha))
1271  return;
1272 
1273  if (alpha >= 1.0)
1274  s->alpha = 255;
1275  else if (alpha <= 0)
1276  s->alpha = 0;
1277  else
1278  s->alpha = 256 * alpha;
1279 }
1280 
1282  FFDrawColor *color,
1283  TextMetrics *metrics,
1284  int x, int y, int borderw)
1285 {
1286  DrawTextContext *s = ctx->priv;
1287  int g, l, x1, y1, w1, h1, idx;
1288  int dx = 0, dy = 0, pdx = 0;
1289  GlyphInfo *info;
1290  Glyph dummy = { 0 }, *glyph;
1291  FT_Bitmap bitmap;
1292  FT_BitmapGlyph b_glyph;
1293  uint8_t j_left = 0, j_right = 0, j_top = 0, j_bottom = 0;
1294  int line_w, offset_y = 0;
1295  int clip_x = 0, clip_y = 0;
1296 
1297  j_left = !!(s->text_align & TA_LEFT);
1298  j_right = !!(s->text_align & TA_RIGHT);
1299  j_top = !!(s->text_align & TA_TOP);
1300  j_bottom = !!(s->text_align & TA_BOTTOM);
1301 
1302  if (j_top && j_bottom) {
1303  offset_y = (s->box_height - metrics->height) / 2;
1304  } else if (j_bottom) {
1305  offset_y = s->box_height - metrics->height;
1306  }
1307 
1308  if ((!j_left || j_right) && !s->tab_warning_printed && s->tab_count > 0) {
1309  s->tab_warning_printed = 1;
1310  av_log(ctx, AV_LOG_WARNING, "Tab characters are only supported with left horizontal alignment\n");
1311  }
1312 
1313  clip_x = FFMIN(metrics->rect_x + s->box_width + s->bb_right, frame->width);
1314  clip_y = FFMIN(metrics->rect_y + s->box_height + s->bb_bottom, frame->height);
1315 
1316  for (l = 0; l < s->line_count; ++l) {
1317  TextLine *line = &s->lines[l];
1318  line_w = POS_CEIL(line->width64, 64);
1319  for (g = 0; g < line->hb_data.glyph_count; ++g) {
1320  info = &line->glyphs[g];
1321  dummy.fontsize = s->fontsize;
1322  dummy.code = info->code;
1323  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
1324  if (!glyph) {
1325  return AVERROR(EINVAL);
1326  }
1327 
1328  idx = get_subpixel_idx(info->shift_x64, info->shift_y64);
1329  b_glyph = borderw ? glyph->border_bglyph[idx] : glyph->bglyph[idx];
1330  bitmap = b_glyph->bitmap;
1331  x1 = x + info->x + b_glyph->left;
1332  y1 = y + info->y - b_glyph->top + offset_y;
1333  w1 = bitmap.width;
1334  h1 = bitmap.rows;
1335 
1336  if (j_left && j_right) {
1337  x1 += (s->box_width - line_w) / 2;
1338  } else if (j_right) {
1339  x1 += s->box_width - line_w;
1340  }
1341 
1342  // Offset of the glyph's bitmap in the visible region
1343  dx = dy = 0;
1344  if (x1 < metrics->rect_x - s->bb_left) {
1345  dx = metrics->rect_x - s->bb_left - x1;
1346  x1 = metrics->rect_x - s->bb_left;
1347  }
1348  if (y1 < metrics->rect_y - s->bb_top) {
1349  dy = metrics->rect_y - s->bb_top - y1;
1350  y1 = metrics->rect_y - s->bb_top;
1351  }
1352 
1353  // check if the glyph is empty or out of the clipping region
1354  if (dx >= w1 || dy >= h1 || x1 >= clip_x || y1 >= clip_y) {
1355  continue;
1356  }
1357 
1358  pdx = dx + dy * bitmap.pitch;
1359  w1 = FFMIN(clip_x - x1, w1 - dx);
1360  h1 = FFMIN(clip_y - y1, h1 - dy);
1361 
1362  ff_blend_mask(&s->dc, color, frame->data, frame->linesize, clip_x, clip_y,
1363  bitmap.buffer + pdx, bitmap.pitch, w1, h1, 3, 0, x1, y1);
1364  }
1365  }
1366 
1367  return 0;
1368 }
1369 
1370 // Shapes a line of text using libharfbuzz
1372  HarfbuzzData *hb, const char *text, int textLen)
1373 {
1374  unsigned codepoints;
1375 
1376  hb->buf = hb_buffer_create();
1377  if (!hb_buffer_allocation_successful(hb->buf))
1378  goto fail;
1379  hb_buffer_add_utf8(hb->buf, text, textLen, 0, -1);
1380  /* Preserve the existing FriBidi visual-order pipeline and the explicit
1381  * language while letting HarfBuzz infer only the script, so complex
1382  * scripts (Bengali / Indic / USE) are dispatched to the correct shaper.
1383  * Setting the language explicitly keeps shaping deterministic and avoids
1384  * the locale-dependent, non-threadsafe first hb_language_get_default(). */
1385  hb_buffer_set_direction(hb->buf, HB_DIRECTION_LTR);
1386  hb_buffer_set_language(hb->buf, hb_language_from_string("en", -1));
1387  hb_buffer_guess_segment_properties(hb->buf);
1388  /* Sample the buffer length here, before hb_shape() flips the buffer's
1389  * content type from UNICODE to GLYPHS. */
1390  codepoints = hb_buffer_get_length(hb->buf);
1391  hb->font = hb_ft_font_create_referenced(s->face);
1392  if (hb->font == NULL)
1393  goto fail;
1394  hb_shape(hb->font, hb->buf, NULL, 0);
1395  hb->glyph_info = hb_buffer_get_glyph_infos(hb->buf, &hb->glyph_count);
1396  hb->glyph_pos = hb_buffer_get_glyph_positions(hb->buf, &hb->glyph_count);
1397 
1398  if (av_log_get_level() >= AV_LOG_VERBOSE) {
1399  char script_tag[5] = { 0 };
1400  hb_script_t script = hb_buffer_get_script(hb->buf);
1401  hb_direction_t dir = hb_buffer_get_direction(hb->buf);
1402  hb_tag_to_string(hb_script_to_iso15924_tag(script), script_tag);
1404  "shape: script=%s direction=%s codepoints=%u glyphs=%u\n",
1405  script_tag, hb_direction_to_string(dir),
1406  codepoints, hb->glyph_count);
1407  }
1408 
1409  return 0;
1410 fail:
1411  hb_buffer_destroy(hb->buf);
1412  hb->buf = NULL;
1413  return AVERROR(ENOMEM);
1414 }
1415 
1416 static void hb_destroy(HarfbuzzData *hb)
1417 {
1418  hb_font_destroy(hb->font);
1419  hb_buffer_destroy(hb->buf);
1420  hb->buf = NULL;
1421  hb->font = NULL;
1422  hb->glyph_info = NULL;
1423  hb->glyph_pos = NULL;
1424 }
1425 
1427 {
1428  DrawTextContext *s = ctx->priv;
1429  char *text = s->expanded_text.str;
1430  char *textdup = NULL;
1431  int width64 = 0, w64 = 0;
1432  int cur_min_y64 = 0, first_max_y64 = -32000;
1433  int first_min_x64 = 32000, last_max_x64 = -32000;
1434  int min_y64 = 32000, max_y64 = -32000, min_x64 = 32000, max_x64 = -32000;
1435  int line_count = 0;
1436  uint32_t code = 0;
1437  Glyph *glyph = NULL;
1438 
1439  int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
1440  uint8_t *start, *p;
1441  int ret = 0;
1442 
1443  // Count the lines and the tab characters
1444  s->tab_count = 0;
1445  for (i = 0, p = text; 1; i++) {
1446  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_failed;);
1447 continue_on_failed:
1448  if (ff_is_newline(code) || code == 0) {
1449  ++line_count;
1450  if (code == 0) {
1451  break;
1452  }
1453  } else if (code == '\t') {
1454  ++s->tab_count;
1455  }
1456  }
1457 
1458  // Evaluate the width of the space character if needed to replace tabs
1459  if (s->tab_count > 0 && !s->blank_advance64) {
1460  HarfbuzzData hb_data;
1461  ret = shape_text_hb(ctx, s, &hb_data, " ", 1);
1462  if(ret != 0) {
1463  goto done;
1464  }
1465  s->blank_advance64 = hb_data.glyph_pos[0].x_advance;
1466  hb_destroy(&hb_data);
1467  }
1468 
1469  s->line_count = line_count;
1470  s->lines = av_calloc(line_count, sizeof(TextLine));
1471  s->tab_clusters = av_calloc(s->tab_count, sizeof(uint32_t));
1472  if ((line_count > 0 && !s->lines) ||
1473  (s->tab_count > 0 && !s->tab_clusters)) {
1474  ret = AVERROR(ENOMEM);
1475  goto done;
1476  }
1477  for (i = 0; i < s->tab_count; ++i) {
1478  s->tab_clusters[i] = -1;
1479  }
1480 
1481  start = textdup = av_strdup(text);
1482  if (textdup == NULL) {
1483  ret = AVERROR(ENOMEM);
1484  goto done;
1485  }
1486  line_count = 0;
1487  for (i = 0, p = textdup; 1; i++) {
1488  if (*p == '\t') {
1489  s->tab_clusters[tab_idx++] = i;
1490  *p = ' ';
1491  }
1492  size_t len = p - start;
1493  GET_UTF8(code, *p ? *p++ : 0, code = 0xfffd; goto continue_on_failed2;);
1494 continue_on_failed2:
1495  if (ff_is_newline(code) || code == 0) {
1496  TextLine *cur_line = &s->lines[line_count];
1497  HarfbuzzData *hb = &cur_line->hb_data;
1498  cur_line->cluster_offset = line_offset;
1499  ret = shape_text_hb(ctx, s, hb, start, len);
1500  if (ret != 0) {
1501  goto done;
1502  }
1503  w64 = 0;
1504  cur_min_y64 = 32000;
1505  for (int t = 0; t < hb->glyph_count; ++t) {
1506  uint8_t is_tab = last_tab_idx < s->tab_count &&
1507  hb->glyph_info[t].cluster == s->tab_clusters[last_tab_idx] - line_offset;
1508  if (is_tab) {
1509  ++last_tab_idx;
1510  }
1511  ret = load_glyph(ctx, &glyph, hb->glyph_info[t].codepoint, -1, -1);
1512  if (ret != 0) {
1513  goto done;
1514  }
1515  if (line_count == 0) {
1516  first_max_y64 = FFMAX(glyph->bbox.yMax, first_max_y64);
1517  }
1518  if (t == 0) {
1519  cur_line->offset_left64 = glyph->bbox.xMin;
1520  first_min_x64 = FFMIN(glyph->bbox.xMin, first_min_x64);
1521  }
1522  if (t == hb->glyph_count - 1) {
1523  // The following code measures the width of the line up to the last
1524  // character's horizontal advance
1525  int last_char_width = hb->glyph_pos[t].x_advance;
1526 
1527  // The following code measures the width of the line up to the rightmost
1528  // visible pixel of the last character
1529  // int last_char_width = glyph->bbox.xMax;
1530 
1531  w64 += last_char_width;
1532  last_max_x64 = FFMAX(last_char_width, last_max_x64);
1533  cur_line->offset_right64 = last_char_width;
1534  } else {
1535  if (is_tab) {
1536  int size = s->blank_advance64 * s->tabsize;
1537  w64 = (w64 / size + 1) * size;
1538  } else {
1539  w64 += hb->glyph_pos[t].x_advance;
1540  }
1541  }
1542  cur_min_y64 = FFMIN(glyph->bbox.yMin, cur_min_y64);
1543  min_y64 = FFMIN(glyph->bbox.yMin, min_y64);
1544  max_y64 = FFMAX(glyph->bbox.yMax, max_y64);
1545  min_x64 = FFMIN(glyph->bbox.xMin, min_x64);
1546  max_x64 = FFMAX(glyph->bbox.xMax, max_x64);
1547  }
1548 
1549  cur_line->width64 = w64;
1550 
1551  av_log(ctx, AV_LOG_DEBUG, " Line: %d -- glyphs count: %d - width64: %d - offset_left64: %d - offset_right64: %d)\n",
1552  line_count, hb->glyph_count, cur_line->width64, cur_line->offset_left64, cur_line->offset_right64);
1553 
1554  if (w64 > width64) {
1555  width64 = w64;
1556  }
1557  start = p;
1558  ++line_count;
1559  line_offset = i + 1;
1560  }
1561 
1562  if (code == 0) break;
1563  }
1564 
1565  metrics->line_height64 = s->face->size->metrics.height;
1566 
1567  metrics->width = POS_CEIL(width64, 64);
1568  if (s->y_align == YA_FONT) {
1569  metrics->height = POS_CEIL(metrics->line_height64 * line_count, 64);
1570  } else {
1571  int height64 = (metrics->line_height64 + s->line_spacing * 64) *
1572  (FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
1573  metrics->height = POS_CEIL(height64, 64);
1574  }
1575  metrics->offset_top64 = first_max_y64;
1576  metrics->offset_right64 = last_max_x64;
1577  metrics->offset_bottom64 = cur_min_y64;
1578  metrics->offset_left64 = first_min_x64;
1579  metrics->min_x64 = min_x64;
1580  metrics->min_y64 = min_y64;
1581  metrics->max_x64 = max_x64;
1582  metrics->max_y64 = max_y64;
1583 
1584 done:
1585  av_free(textdup);
1586  if (ret < 0) {
1587  if (s->lines) {
1588  for (int l = 0; l < s->line_count; ++l)
1589  hb_destroy(&s->lines[l].hb_data);
1590  }
1591  av_freep(&s->lines);
1592  av_freep(&s->tab_clusters);
1593  s->line_count = 0;
1594  }
1595  return ret;
1596 }
1597 
1599 {
1600  DrawTextContext *s = ctx->priv;
1601  AVFilterLink *inlink = ctx->inputs[0];
1603  int x = 0, y = 0, ret;
1604  int shift_x64, shift_y64;
1605  int x64, y64;
1606  Glyph *glyph = NULL;
1607 
1608  time_t now = time(0);
1609  struct tm ltime;
1610  AVBPrint *bp = &s->expanded_text;
1611 
1612  FFDrawColor fontcolor;
1613  FFDrawColor shadowcolor;
1614  FFDrawColor bordercolor;
1615  FFDrawColor boxcolor;
1616 
1617  int width = frame->width;
1618  int height = frame->height;
1619  int rec_x = 0, rec_y = 0, rec_width = 0, rec_height = 0;
1620  int is_outside = 0;
1621  int last_tab_idx = 0;
1622 
1623  TextMetrics metrics;
1624 
1625  av_bprint_clear(bp);
1626 
1627  if (s->basetime != AV_NOPTS_VALUE)
1628  now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + s->basetime/1000000;
1629 
1630  switch (s->exp_mode) {
1631  case EXP_NONE:
1632  av_bprintf(bp, "%s", s->text);
1633  break;
1634  case EXP_NORMAL:
1635  if ((ret = ff_expand_text(&s->expand_text, s->text, &s->expanded_text)) < 0)
1636  return ret;
1637  break;
1638  case EXP_STRFTIME:
1639  localtime_r(&now, &ltime);
1640  av_bprint_strftime(bp, s->text, &ltime);
1641  break;
1642  }
1643 
1644  if (s->tc_opt_string) {
1645  char tcbuf[AV_TIMECODE_STR_SIZE];
1646  av_timecode_make_string(&s->tc, tcbuf, inl->frame_count_out);
1647  av_bprint_clear(bp);
1648  av_bprintf(bp, "%s%s", s->text, tcbuf);
1649  }
1650 
1651  if (!av_bprint_is_complete(bp))
1652  return AVERROR(ENOMEM);
1653 
1654  if (s->fontcolor_expr[0]) {
1655  /* If expression is set, evaluate and replace the static value */
1656  av_bprint_clear(&s->expanded_fontcolor);
1657  if ((ret = ff_expand_text(&s->expand_text, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
1658  return ret;
1659  if (!av_bprint_is_complete(&s->expanded_fontcolor))
1660  return AVERROR(ENOMEM);
1661  av_log(ctx, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
1662  ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
1663  if (ret)
1664  return ret;
1665  ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
1666  }
1667 
1668  if ((ret = update_fontsize(ctx)) < 0) {
1669  return ret;
1670  }
1671 
1672  if ((ret = measure_text(ctx, &metrics)) < 0) {
1673  return ret;
1674  }
1675 
1676  s->max_glyph_h = POS_CEIL(metrics.max_y64 - metrics.min_y64, 64);
1677  s->max_glyph_w = POS_CEIL(metrics.max_x64 - metrics.min_x64, 64);
1678 
1679  s->var_values[VAR_TW] = s->var_values[VAR_TEXT_W] = metrics.width;
1680  s->var_values[VAR_TH] = s->var_values[VAR_TEXT_H] = metrics.height;
1681 
1682  s->var_values[VAR_MAX_GLYPH_W] = s->max_glyph_w;
1683  s->var_values[VAR_MAX_GLYPH_H] = s->max_glyph_h;
1684  s->var_values[VAR_MAX_GLYPH_A] = s->var_values[VAR_ASCENT] = POS_CEIL(metrics.max_y64, 64);
1685  s->var_values[VAR_FONT_A] = s->face->size->metrics.ascender / 64;
1686  s->var_values[VAR_MAX_GLYPH_D] = s->var_values[VAR_DESCENT] = POS_CEIL(metrics.min_y64, 64);
1687  s->var_values[VAR_FONT_D] = -s->face->size->metrics.descender / 64;
1688 
1689  s->var_values[VAR_TOP_A] = POS_CEIL(metrics.offset_top64, 64);
1690  s->var_values[VAR_BOTTOM_D] = -POS_CEIL(metrics.offset_bottom64, 64);
1691  s->var_values[VAR_LINE_H] = s->var_values[VAR_LH] = metrics.line_height64 / 64.;
1692 
1693  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
1694  s->var_values[VAR_X] = s->x;
1695  s->var_values[VAR_Y] = s->y;
1696  } else {
1697  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1698  s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
1699  /* It is necessary if x is expressed from y */
1700  s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
1701  }
1702 
1703  update_alpha(s);
1704  update_color_with_alpha(s, &fontcolor , s->fontcolor );
1705  update_color_with_alpha(s, &shadowcolor, s->shadowcolor);
1706  update_color_with_alpha(s, &bordercolor, s->bordercolor);
1707  update_color_with_alpha(s, &boxcolor , s->boxcolor );
1708 
1709  if (s->draw_box && s->boxborderw) {
1710  int bbsize[4];
1711  int count;
1712  count = string_to_array(s->boxborderw, bbsize, 4);
1713  if (count == 1) {
1714  s->bb_top = s->bb_right = s->bb_bottom = s->bb_left = bbsize[0];
1715  } else if (count == 2) {
1716  s->bb_top = s->bb_bottom = bbsize[0];
1717  s->bb_right = s->bb_left = bbsize[1];
1718  } else if (count == 3) {
1719  s->bb_top = bbsize[0];
1720  s->bb_right = s->bb_left = bbsize[1];
1721  s->bb_bottom = bbsize[2];
1722  } else if (count == 4) {
1723  s->bb_top = bbsize[0];
1724  s->bb_right = bbsize[1];
1725  s->bb_bottom = bbsize[2];
1726  s->bb_left = bbsize[3];
1727  }
1728  } else {
1729  s->bb_top = s->bb_right = s->bb_bottom = s->bb_left = 0;
1730  }
1731 
1732  if (s->fix_bounds) {
1733  /* calculate footprint of text effects */
1734  int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0;
1735 
1736  int offsetleft = FFMAX3(FFMAX(s->bb_left, 0), borderoffset,
1737  (s->shadowx < 0 ? FFABS(s->shadowx) : 0));
1738  int offsettop = FFMAX3(FFMAX(s->bb_top, 0), borderoffset,
1739  (s->shadowy < 0 ? FFABS(s->shadowy) : 0));
1740  int offsetright = FFMAX3(FFMAX(s->bb_right, 0), borderoffset,
1741  (s->shadowx > 0 ? s->shadowx : 0));
1742  int offsetbottom = FFMAX3(FFMAX(s->bb_bottom, 0), borderoffset,
1743  (s->shadowy > 0 ? s->shadowy : 0));
1744 
1745  if (s->x - offsetleft < 0) s->x = offsetleft;
1746  if (s->y - offsettop < 0) s->y = offsettop;
1747 
1748  if (s->x + metrics.width + offsetright > width)
1749  s->x = FFMAX(width - metrics.width - offsetright, 0);
1750  if (s->y + metrics.height + offsetbottom > height)
1751  s->y = FFMAX(height - metrics.height - offsetbottom, 0);
1752  }
1753 
1754  x = 0;
1755  y = 0;
1756  x64 = (int)(s->x * 64.);
1757  if (s->y_align == YA_FONT) {
1758  y64 = (int)(s->y * 64. + s->face->size->metrics.ascender);
1759  } else if (s->y_align == YA_BASELINE) {
1760  y64 = (int)(s->y * 64.);
1761  } else {
1762  y64 = (int)(s->y * 64. + metrics.offset_top64);
1763  }
1764 
1765  for (int l = 0; l < s->line_count; ++l) {
1766  TextLine *line = &s->lines[l];
1767  HarfbuzzData *hb = &line->hb_data;
1768  line->glyphs = av_mallocz(hb->glyph_count * sizeof(GlyphInfo));
1769 
1770  for (int t = 0; t < hb->glyph_count; ++t) {
1771  GlyphInfo *g_info = &line->glyphs[t];
1772  uint8_t is_tab = last_tab_idx < s->tab_count &&
1773  hb->glyph_info[t].cluster == s->tab_clusters[last_tab_idx] - line->cluster_offset;
1774  int true_x, true_y;
1775  if (is_tab) {
1776  ++last_tab_idx;
1777  }
1778  true_x = x + hb->glyph_pos[t].x_offset;
1779  true_y = y + hb->glyph_pos[t].y_offset;
1780  shift_x64 = (((x64 + true_x) >> 4) & 0b0011) << 4;
1781  shift_y64 = ((4 - (((y64 + true_y) >> 4) & 0b0011)) & 0b0011) << 4;
1782 
1783  ret = load_glyph(ctx, &glyph, hb->glyph_info[t].codepoint, shift_x64, shift_y64);
1784  if (ret != 0) {
1785  goto fail;
1786  }
1787  g_info->code = hb->glyph_info[t].codepoint;
1788  g_info->x = (x64 + true_x) >> 6;
1789  g_info->y = ((y64 + true_y) >> 6) + (shift_y64 > 0 ? 1 : 0);
1790  g_info->shift_x64 = shift_x64;
1791  g_info->shift_y64 = shift_y64;
1792 
1793  if (!is_tab) {
1794  x += hb->glyph_pos[t].x_advance;
1795  } else {
1796  int size = s->blank_advance64 * s->tabsize;
1797  x = (x / size + 1) * size;
1798  }
1799  y += hb->glyph_pos[t].y_advance;
1800  }
1801 
1802  y += metrics.line_height64 + s->line_spacing * 64;
1803  x = 0;
1804  }
1805 
1806  metrics.rect_x = s->x;
1807  if (s->y_align == YA_BASELINE) {
1808  metrics.rect_y = s->y - metrics.offset_top64 / 64;
1809  } else {
1810  metrics.rect_y = s->y;
1811  }
1812 
1813  s->box_width = s->boxw == 0 ? metrics.width : s->boxw;
1814  s->box_height = s->boxh == 0 ? metrics.height : s->boxh;
1815 
1816  if (!s->draw_box) {
1817  // Create a border for the clipping region to take into account subpixel
1818  // errors in text measurement and effects.
1819  int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0;
1820  s->bb_left = borderoffset + (s->shadowx < 0 ? FFABS(s->shadowx) : 0) + 1;
1821  s->bb_top = borderoffset + (s->shadowy < 0 ? FFABS(s->shadowy) : 0) + 1;
1822  s->bb_right = borderoffset + (s->shadowx > 0 ? s->shadowx : 0) + 1;
1823  s->bb_bottom = borderoffset + (s->shadowy > 0 ? s->shadowy : 0) + 1;
1824  }
1825 
1826  /* Check if the whole box is out of the frame */
1827  is_outside = metrics.rect_x - s->bb_left >= width ||
1828  metrics.rect_y - s->bb_top >= height ||
1829  metrics.rect_x + s->box_width + s->bb_right <= 0 ||
1830  metrics.rect_y + s->box_height + s->bb_bottom <= 0;
1831 
1832  if (!is_outside) {
1833  /* draw box */
1834  if (s->draw_box) {
1835  rec_x = metrics.rect_x - s->bb_left;
1836  rec_y = metrics.rect_y - s->bb_top;
1837  rec_width = s->box_width + s->bb_right + s->bb_left;
1838  rec_height = s->box_height + s->bb_bottom + s->bb_top;
1839  ff_blend_rectangle(&s->dc, &boxcolor,
1840  frame->data, frame->linesize, width, height,
1841  rec_x, rec_y, rec_width, rec_height);
1842  }
1843 
1844  if (s->shadowx || s->shadowy) {
1845  if ((ret = draw_glyphs(ctx, frame, &shadowcolor, &metrics,
1846  s->shadowx, s->shadowy, s->borderw)) < 0) {
1847  goto fail;
1848  }
1849  }
1850 
1851  if (s->borderw) {
1852  if ((ret = draw_glyphs(ctx, frame, &bordercolor, &metrics,
1853  0, 0, s->borderw)) < 0) {
1854  goto fail;
1855  }
1856  }
1857 
1858  if ((ret = draw_glyphs(ctx, frame, &fontcolor, &metrics, 0,
1859  0, 0)) < 0) {
1860  goto fail;
1861  }
1862  }
1863 
1864  ret = 0;
1865 fail:
1866  // FREE data structures
1867  for (int l = 0; l < s->line_count; ++l) {
1868  TextLine *line = &s->lines[l];
1869  av_freep(&line->glyphs);
1870  hb_destroy(&line->hb_data);
1871  }
1872  av_freep(&s->lines);
1873  av_freep(&s->tab_clusters);
1874  s->line_count = 0;
1875 
1876  return ret;
1877 }
1878 
1880 {
1882  AVFilterContext *ctx = inlink->dst;
1883  AVFilterLink *outlink = ctx->outputs[0];
1884  DrawTextContext *s = ctx->priv;
1885  int ret;
1887  const AVDetectionBBox *bbox;
1888  AVFrameSideData *sd;
1889  int loop = 1;
1890 
1891  if (s->text_source == AV_FRAME_DATA_DETECTION_BBOXES) {
1893  if (sd) {
1895  loop = header->nb_bboxes;
1896  } else {
1897  av_log(ctx, AV_LOG_WARNING, "No detection bboxes.\n");
1898  return ff_filter_frame(outlink, frame);
1899  }
1900  }
1901 
1902  if (s->reload && !(inl->frame_count_out % s->reload)) {
1903  if ((ret = ff_load_textfile(ctx, (const char *)s->textfile, &s->text, NULL)) < 0) {
1904  av_frame_free(&frame);
1905  return ret;
1906  }
1907 #if CONFIG_LIBFRIBIDI
1908  if (s->text_shaping)
1909  if ((ret = shape_text(ctx)) < 0) {
1910  av_frame_free(&frame);
1911  return ret;
1912  }
1913 #endif
1914  }
1915 
1916  s->var_values[VAR_N] = inl->frame_count_out + s->start_number;
1917  s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
1918  NAN : frame->pts * av_q2d(inlink->time_base);
1919 
1920  s->var_values[VAR_PICT_TYPE] = frame->pict_type;
1921  s->var_values[VAR_DURATION] = frame->duration * av_q2d(inlink->time_base);
1922 
1923  s->metadata = frame->metadata;
1924 
1925  for (int i = 0; i < loop; i++) {
1926  if (header) {
1927  bbox = av_get_detection_bbox(header, i);
1928  strcpy(s->text, bbox->detect_label);
1929  for (int j = 0; j < bbox->classify_count; j++) {
1930  strcat(s->text, ", ");
1931  strcat(s->text, bbox->classify_labels[j]);
1932  }
1933  s->x = bbox->x;
1934  s->y = bbox->y - s->fontsize;
1935  }
1936  ret = draw_text(ctx, frame);
1937  if (ret < 0) {
1938  av_frame_free(&frame);
1939  return ret;
1940  }
1941  }
1942 
1943  return ff_filter_frame(outlink, frame);
1944 }
1945 
1947  {
1948  .name = "default",
1949  .type = AVMEDIA_TYPE_VIDEO,
1951  .filter_frame = filter_frame,
1952  .config_props = config_input,
1953  },
1954 };
1955 
1957  .p.name = "drawtext",
1958  .p.description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
1959  .p.priv_class = &drawtext_class,
1961  .priv_size = sizeof(DrawTextContext),
1962  .init = init,
1963  .uninit = uninit,
1967  .process_command = command,
1968 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:85
DrawTextContext::library
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:281
OFFSET
#define OFFSET(x)
Definition: vf_drawtext.c:320
fun2_names
static const char *const fun2_names[]
Definition: vf_drawtext.c:109
VAR_N
@ VAR_N
Definition: vf_drawtext.c:139
VAR_TEXT_H
@ VAR_TEXT_H
Definition: vf_drawtext.c:142
VAR_MAIN_H
@ VAR_MAIN_H
Definition: vf_drawtext.c:129
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
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:52
VAR_LINE_H
@ VAR_LINE_H
Definition: vf_drawtext.c:128
VAR_Y
@ VAR_Y
Definition: vf_drawtext.c:145
VAR_MAX_GLYPH_H
@ VAR_MAX_GLYPH_H
Definition: vf_drawtext.c:133
HarfbuzzData::font
hb_font_t * font
Definition: vf_drawtext.c:172
DrawTextContext::a_expr
char * a_expr
Definition: vf_drawtext.c:290
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:218
TextMetrics::height
int height
total height of the text - ceil(height64/64)
Definition: vf_drawtext.c:224
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_name
var_name
Definition: noise.c:46
out
static FILE * out
Definition: movenc.c:55
color
Definition: vf_paletteuse.c:513
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:659
VAR_TOP_A
@ VAR_TOP_A
Definition: vf_drawtext.c:137
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:1879
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1068
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:359
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
POS_CEIL
#define POS_CEIL(x, y)
Definition: vf_drawtext.c:81
DrawTextContext::default_fontsize
unsigned int default_fontsize
default font size to use
Definition: vf_drawtext.c:260
VAR_BOTTOM_D
@ VAR_BOTTOM_D
Definition: vf_drawtext.c:138
TA_RIGHT
@ TA_RIGHT
Definition: vf_drawtext.c:165
VAR_TW
@ VAR_TW
Definition: vf_drawtext.c:143
VAR_ASCENT
@ VAR_ASCENT
Definition: vf_drawtext.c:131
VAR_FONT_D
@ VAR_FONT_D
Definition: vf_drawtext.c:136
ff_set_common_formats2
int ff_set_common_formats2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, AVFilterFormats *formats)
Definition: formats.c:1137
av_cold
#define av_cold
Definition: attributes.h:119
int64_t
long long int64_t
Definition: coverity.c:34
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:297
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
draw_text
static int draw_text(AVFilterContext *ctx, AVFrame *frame)
Definition: vf_drawtext.c:1598
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:466
DrawTextContext::bordercolor
FFDrawColor bordercolor
border color
Definition: vf_drawtext.c:278
AVTreeNode::elem
void * elem
Definition: tree.c:28
DrawTextContext::bb_left
int bb_left
the size of the left box border
Definition: vf_drawtext.c:269
DrawTextContext::exp_mode
int exp_mode
expansion mode to use for the text
Definition: vf_drawtext.c:238
DrawTextContext::line_count
int line_count
the number of text lines
Definition: vf_drawtext.c:313
VAR_DESCENT
@ VAR_DESCENT
Definition: vf_drawtext.c:132
AVOption
AVOption.
Definition: opt.h:428
b
#define b
Definition: input.c:43
filters.h
TextMetrics
Global text metrics.
Definition: vf_drawtext.c:213
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
max
#define max(a, b)
Definition: cuda_runtime.h:33
AVDictionary
Definition: dict.c:32
func_pts
static int func_pts(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
Definition: qrencode.c:195
DrawTextContext::stroker
FT_Stroker stroker
freetype stroker handle
Definition: vf_drawtext.c:283
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:219
av_tree_node_alloc
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
VAR_MAX_GLYPH_W
@ VAR_MAX_GLYPH_W
Definition: vf_drawtext.c:134
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
AV_OPT_TYPE_RATIONAL
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
Definition: opt.h:279
DrawTextContext::prng
AVLFG prng
random
Definition: vf_drawtext.c:293
DrawTextContext::box_height
int box_height
the height of box
Definition: vf_drawtext.c:271
AVDetectionBBox::y
int y
Definition: detection_bbox.h:32
video.h
DrawTextContext::lines
TextLine * lines
computed information about text lines
Definition: vf_drawtext.c:312
VAR_MAIN_W
@ VAR_MAIN_W
Definition: vf_drawtext.c:130
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
dummy
static int dummy
Definition: ffplay.c:3751
TextLine::width64
int width64
width of the line
Definition: vf_drawtext.c:193
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:196
TextMetrics::min_y64
int min_y64
minimum value of bbox.yMin among glyphs (in 26.6 units)
Definition: vf_drawtext.c:226
formats.h
DrawTextContext::start_number
int start_number
starting frame number for n/frame_num var
Definition: vf_drawtext.c:299
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:735
DrawTextContext::text
uint8_t * text
text to be drawn
Definition: vf_drawtext.c:245
DrawTextContext::expanded_text
AVBPrint expanded_text
used to contain the expanded text
Definition: vf_drawtext.c:246
VAR_H
@ VAR_H
Definition: vf_drawtext.c:129
DrawTextContext::fontsize
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:259
expand_text_functions
static const FFExpandTextFunction expand_text_functions[]
Definition: qrencode.c:287
DrawTextContext::x_expr
char * x_expr
expression for x position
Definition: vf_drawtext.c:285
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:244
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:151
DrawTextContext::y_pexpr
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:287
VAR_VARS_NB
@ VAR_VARS_NB
Definition: vf_drawtext.c:148
GlyphInfo::y
int y
the y position of the glyph
Definition: vf_drawtext.c:182
DrawTextContext::expand_text
FFExpandTextContext expand_text
expand text in case exp_mode == NORMAL
Definition: vf_drawtext.c:239
timecode.h
Glyph::bglyph
FT_BitmapGlyph bglyph[16]
Glyph bitmaps with 1/4 pixel precision in both directions.
Definition: vf_drawtext.c:206
DrawTextContext::bb_top
int bb_top
the size of the top box border
Definition: vf_drawtext.c:266
EXP_NONE
@ EXP_NONE
Definition: vf_drawtext.c:152
av_opt_free
void av_opt_free(void *obj)
Free all allocated objects in obj.
Definition: opt.c:1942
hb_destroy
static void hb_destroy(HarfbuzzData *hb)
Definition: vf_drawtext.c:1416
pts
static int64_t pts
Definition: transcode_aac.c:649
ff_expand_text
int ff_expand_text(FFExpandTextContext *expand_text, const char *text, AVBPrint *bp)
Expand text template.
Definition: textutils.c:124
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:557
FFExpandTextFunction
Function used to expand a template sequence in the format %{FUNCTION_NAME[:PARAMS]},...
Definition: textutils.h:36
loop
static int loop
Definition: ffplay.c:337
av_expr_free
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:368
AVFrameSideDataType
AVFrameSideDataType
Definition: frame.h:49
FILTER_QUERY_FUNC2
#define FILTER_QUERY_FUNC2(func)
Definition: filters.h:241
TextMetrics::offset_top64
int offset_top64
ascender amount of the first line (in 26.6 units)
Definition: vf_drawtext.c:214
draw_glyphs
static int draw_glyphs(AVFilterContext *ctx, AVFrame *frame, FFDrawColor *color, TextMetrics *metrics, int x, int y, int borderw)
Definition: vf_drawtext.c:1281
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:40
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
TextMetrics::rect_y
int rect_y
y position of the box
Definition: vf_drawtext.c:233
DrawTextContext::var_values
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:289
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:477
TextMetrics::min_x64
int min_x64
minimum value of bbox.xMin among glyphs (in 26.6 units)
Definition: vf_drawtext.c:228
FLAGS
#define FLAGS
Definition: vf_drawtext.c:321
avfilter_vf_drawtext_inputs
static const AVFilterPad avfilter_vf_drawtext_inputs[]
Definition: vf_drawtext.c:1946
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
ff_load_textfile
int ff_load_textfile(void *log_ctx, const char *textfile, unsigned char **text, size_t *text_size)
Definition: textutils.c:354
DrawTextContext::dc
FFDrawContext dc
Definition: vf_drawtext.c:275
update_alpha
static void update_alpha(DrawTextContext *s)
Definition: vf_drawtext.c:1266
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
DrawTextContext::face
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:282
FFFilter
Definition: filters.h:267
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
s
#define s(width, name)
Definition: cbs_vp9.c:198
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:265
VAR_X
@ VAR_X
Definition: vf_drawtext.c:144
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:142
DrawTextContext::fontcolor
FFDrawColor fontcolor
foreground color
Definition: vf_drawtext.c:276
g
const char * g
Definition: vf_curves.c:128
ff_filter_link
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition: filters.h:199
DrawTextContext::a_pexpr
AVExpr * a_pexpr
Definition: vf_drawtext.c:291
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
info
MIPS optimizations info
Definition: mips.txt:2
lfg.h
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:179
FF_DRAW_PROCESS_ALPHA
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
Definition: drawutils.h:64
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition: opt.h:262
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
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:1810
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
TextMetrics::offset_right64
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph of each line (in 26....
Definition: vf_drawtext.c:219
av_expr_eval
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:824
VAR_SAR
@ VAR_SAR
Definition: vf_drawtext.c:140
AVExpr
Definition: eval.c:171
TA_TOP
@ TA_TOP
Definition: vf_drawtext.c:166
func_frame_num
static int func_frame_num(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
Definition: qrencode.c:217
DrawTextContext::fontsize_pexpr
AVExpr * fontsize_pexpr
parsed expressions for fontsize
Definition: vf_drawtext.c:258
YA_TEXT
@ YA_TEXT
Definition: vf_drawtext.c:158
eval_func2
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:118
ft_error::err
int err
Definition: vf_drawtext.c:415
key
const char * key
Definition: hwcontext_opencl.c:189
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
VAR_T
@ VAR_T
Definition: vf_drawtext.c:141
NAN
#define NAN
Definition: mathematics.h:115
shape_text_hb
static int shape_text_hb(AVFilterContext *ctx, DrawTextContext *s, HarfbuzzData *hb, const char *text, int textLen)
Definition: vf_drawtext.c:1371
command
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:1196
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
query_formats
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition: vf_drawtext.c:1082
arg
const char * arg
Definition: jacosubdec.c:65
Glyph
A glyph as loaded and rendered using libfreetype.
Definition: vf_drawtext.c:200
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
time_internal.h
if
if(ret)
Definition: filter_design.txt:179
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
DrawTextContext::blank_advance64
int blank_advance64
the size of the space character
Definition: vf_drawtext.c:316
fail
#define fail
Definition: test.h:478
VAR_VSUB
@ VAR_VSUB
Definition: vf_drawtext.c:127
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
DrawTextContext::tab_clusters
uint32_t * tab_clusters
the position of tab characters in the text
Definition: vf_drawtext.c:314
NULL
#define NULL
Definition: coverity.c:32
VAR_PICT_TYPE
@ VAR_PICT_TYPE
Definition: vf_drawtext.c:146
DrawTextContext::text_align
int text_align
the horizontal and vertical text alignment
Definition: vf_drawtext.c:309
ff_print_formatted_eval_expr
int ff_print_formatted_eval_expr(void *log_ctx, AVBPrint *bp, const char *expr, const char *const *fun_names, const ff_eval_func2 *fun_values, const char *const *var_names, const double *var_values, void *eval_ctx, const char format, int positions)
Definition: textutils.c:304
TextMetrics::offset_left64
int offset_left64
maximum offset between the origin and the leftmost pixel of the first glyph of each line (in 26....
Definition: vf_drawtext.c:216
GlyphInfo::code
uint32_t code
the glyph code point
Definition: vf_drawtext.c:180
DrawTextContext::basetime
int64_t basetime
base pts time in the real world for display
Definition: vf_drawtext.c:288
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:257
isnan
#define isnan(x)
Definition: libm.h:342
TextLine
Information about a single line of text.
Definition: vf_drawtext.c:188
AV_OPT_TYPE_COLOR
@ AV_OPT_TYPE_COLOR
Underlying C type is uint8_t[4].
Definition: opt.h:322
textutils.h
parseutils.h
AVTreeNode
Definition: tree.c:26
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: filters.h:59
DrawTextContext::tc_rate
AVRational tc_rate
frame rate for timecode
Definition: vf_drawtext.c:295
DrawTextContext::x_pexpr
AVExpr * x_pexpr
Definition: vf_drawtext.c:287
double
double
Definition: af_crystalizer.c:132
ff_vf_drawtext
const FFFilter ff_vf_drawtext
Definition: vf_drawtext.c:1956
time.h
Glyph::code
uint32_t code
Definition: vf_drawtext.c:203
VAR_MAX_GLYPH_A
@ VAR_MAX_GLYPH_A
Definition: vf_drawtext.c:131
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:166
TextLine::cluster_offset
int cluster_offset
the offset at which this line begins
Definition: vf_drawtext.c:196
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
DrawTextContext
Definition: vf_drawtext.c:236
HarfbuzzData
Definition: vf_drawtext.c:170
DrawTextContext::tabsize
int tabsize
tab size
Definition: vf_drawtext.c:272
index
int index
Definition: gxfenc.c:90
AVFilterFormatsConfig
Lists of formats / etc.
Definition: avfilter.h:120
var_names
static const char *const var_names[]
Definition: vf_drawtext.c:83
HarfbuzzData::glyph_info
hb_glyph_info_t * glyph_info
Definition: vf_drawtext.c:174
DrawTextContext::reload
int reload
reload text file at specified frame interval
Definition: vf_drawtext.c:298
source
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 source
Definition: filter_design.txt:256
DrawTextContext::text_source_string
char * text_source_string
the string to specify text data source
Definition: vf_drawtext.c:300
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2132
VAR_h
@ VAR_h
Definition: vf_drawtext.c:129
DrawTextContext::bb_right
int bb_right
the size of the right box border
Definition: vf_drawtext.c:267
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:1126
eval.h
TextLine::offset_left64
int offset_left64
offset between the origin and the leftmost pixel of the first glyph
Definition: vf_drawtext.c:189
AVLFG
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
Glyph::fontsize
unsigned int fontsize
Definition: vf_drawtext.c:204
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:88
height
#define height
Definition: dsp.h:89
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
shift
static int shift(int a, int b)
Definition: bonk.c:261
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:378
localtime_r
#define localtime_r
Definition: time_internal.h:46
ff_print_eval_expr
int ff_print_eval_expr(void *log_ctx, AVBPrint *bp, const char *expr, const char *const *fun_names, const ff_eval_func2 *fun_values, const char *const *var_names, const double *var_values, void *eval_ctx)
Definition: textutils.c:282
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
Glyph::glyph
FT_Glyph glyph
Definition: vf_drawtext.c:201
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:263
YA_FONT
@ YA_FONT
Definition: vf_drawtext.c:160
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:247
AVFrameSideData::data
uint8_t * data
Definition: frame.h:323
DrawTextContext::shadowy
int shadowy
Definition: vf_drawtext.c:255
drand
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:113
tree.h
TextMetrics::width
int width
width of the longest line - ceil(width64/64)
Definition: vf_drawtext.c:223
EXP_NORMAL
@ EXP_NORMAL
Definition: vf_drawtext.c:153
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:906
header
static const uint8_t header[24]
Definition: sdr2.c:68
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:166
VAR_TEXT_W
@ VAR_TEXT_W
Definition: vf_drawtext.c:143
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(drawtext)
AVDetectionBBox::classify_count
uint32_t classify_count
Definition: detection_bbox.h:51
TextMetrics::max_y64
int max_y64
maximum value of bbox.yMax among glyphs (in 26.6 units)
Definition: vf_drawtext.c:227
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
HarfbuzzData::buf
hb_buffer_t * buf
Definition: vf_drawtext.c:171
DrawTextContext::expanded_fontcolor
AVBPrint expanded_fontcolor
used to contain the expanded fontcolor spec
Definition: vf_drawtext.c:248
update_color_with_alpha
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
Definition: vf_drawtext.c:1259
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
line
Definition: graph2dot.c:48
HarfbuzzData::glyph_pos
hb_glyph_position_t * glyph_pos
Definition: vf_drawtext.c:175
VAR_LH
@ VAR_LH
Definition: vf_drawtext.c:128
fun2
static const eval_func2 fun2[]
Definition: vf_drawtext.c:120
measure_text
static int measure_text(AVFilterContext *ctx, TextMetrics *metrics)
Definition: vf_drawtext.c:1426
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:196
text_alignment
text_alignment
Definition: vf_drawtext.c:163
TA_BOTTOM
@ TA_BOTTOM
Definition: vf_drawtext.c:167
ff_print_pts
int ff_print_pts(void *log_ctx, AVBPrint *bp, double pts, const char *delta, const char *fmt, const char *strftime_fmt)
Definition: textutils.c:150
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
DrawTextContext::tab_warning_printed
int tab_warning_printed
ensure the tab warning to be printed only once
Definition: vf_drawtext.c:317
glyph_enu_free
static int glyph_enu_free(void *opaque, void *elem)
Definition: vf_drawtext.c:1107
bprint.h
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
TextMetrics::rect_x
int rect_x
x position of the box
Definition: vf_drawtext.c:232
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
DrawTextContext::tab_count
int tab_count
the number of tab characters
Definition: vf_drawtext.c:315
round
static av_always_inline av_const double round(double x)
Definition: libm.h:446
GlyphInfo
Information about a single glyph in a text line.
Definition: vf_drawtext.c:179
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:670
TFLAGS
#define TFLAGS
Definition: vf_drawtext.c:322
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
TA_LEFT
@ TA_LEFT
Definition: vf_drawtext.c:164
common.h
delta
float delta
Definition: vorbis_enc_data.h:430
DrawTextContext::shadowx
int shadowx
Definition: vf_drawtext.c:255
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
Glyph::border_glyph
FT_Glyph border_glyph
Definition: vf_drawtext.c:202
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:969
DrawTextContext::max_glyph_h
int max_glyph_h
max glyph height
Definition: vf_drawtext.c:254
FFDrawContext
Definition: drawutils.h:36
Glyph::border_bglyph
FT_BitmapGlyph border_bglyph[16]
Outlined glyph bitmaps with 1/4 pixel precision in both directions.
Definition: vf_drawtext.c:208
TextMetrics::max_x64
int max_x64
maximum value of bbox.xMax among glyphs (in 26.6 units)
Definition: vf_drawtext.c:229
DrawTextContext::borderw
int borderw
border width
Definition: vf_drawtext.c:256
VAR_MAX_GLYPH_D
@ VAR_MAX_GLYPH_D
Definition: vf_drawtext.c:132
len
int len
Definition: vorbis_enc_data.h:426
VAR_W
@ VAR_W
Definition: vf_drawtext.c:130
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:46
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:1149
DrawTextContext::box_width
int box_width
the width of box
Definition: vf_drawtext.c:270
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
GlyphInfo::shift_y64
int shift_y64
the vertical shift of the glyph in 26.6 units
Definition: vf_drawtext.c:184
ff_draw_color
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:179
DrawTextContext::bb_bottom
int bb_bottom
the size of the bottom box border
Definition: vf_drawtext.c:268
DrawTextContext::tc
AVTimecode tc
timecode context
Definition: vf_drawtext.c:296
DrawTextContext::y_align
int y_align
the value of the y_align parameter
Definition: vf_drawtext.c:310
ret
ret
Definition: filter_design.txt:187
EXP_STRFTIME
@ EXP_STRFTIME
Definition: vf_drawtext.c:154
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:265
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:264
VAR_HSUB
@ VAR_HSUB
Definition: vf_drawtext.c:127
TextMetrics::offset_bottom64
int offset_bottom64
descender amount of the last line (in 26.6 units)
Definition: vf_drawtext.c:215
VAR_DURATION
@ VAR_DURATION
Definition: vf_drawtext.c:147
DrawTextContext::ft_load_flags
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:249
GlyphInfo::x
int x
the x position of the glyph
Definition: vf_drawtext.c:181
random_seed.h
DrawTextContext::alpha
int alpha
Definition: vf_drawtext.c:292
DrawTextContext::boxborderw
char * boxborderw
box border width (padding) allowed formats: "all", "vert|oriz", "top|right|bottom|left"
Definition: vf_drawtext.c:264
ft_errors
static const struct ft_error ft_errors[]
VAR_w
@ VAR_w
Definition: vf_drawtext.c:130
drawtext_options
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:324
DrawTextContext::shadowcolor
FFDrawColor shadowcolor
shadow color
Definition: vf_drawtext.c:277
DrawTextContext::reinit
int reinit
tells if the filter is being reinited
Definition: vf_drawtext.c:240
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:258
avfilter.h
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
FFExpandTextContext
in a text template, followed by any character, always expands to the second character.
Definition: textutils.h:66
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
glyph_enu_border_free
static int glyph_enu_border_free(void *opaque, void *elem)
Definition: vf_drawtext.c:1090
Glyph::bbox
FT_BBox bbox
Definition: vf_drawtext.c:209
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
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
ff_draw_init_from_link
int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link, unsigned flags)
Init a draw context, taking the format, colorspace and range from the given filter link.
Definition: drawutils.c:168
AVFilterContext
An instance of a filter.
Definition: avfilter.h:273
av_realloc
#define av_realloc(p, s)
Definition: ops_asmgen.c:46
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
FFFilter::p
AVFilter p
The public AVFilter.
Definition: filters.h:271
DrawTextContext::glyphs
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
Definition: vf_drawtext.c:284
mem.h
DrawTextContext::textfile
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:250
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
DrawTextContext::boxw
int boxw
the value of the boxw parameter
Definition: vf_drawtext.c:307
HarfbuzzData::glyph_count
unsigned int glyph_count
Definition: vf_drawtext.c:173
TextLine::glyphs
GlyphInfo * glyphs
array of glyphs in this text line
Definition: vf_drawtext.c:195
TextMetrics::line_height64
int line_height64
the font-defined line height
Definition: vf_drawtext.c:222
AVFrameSideData
Structure to hold side data for an AVFrame.
Definition: frame.h:321
VAR_FONT_A
@ VAR_FONT_A
Definition: vf_drawtext.c:135
func_eval_expr
static int func_eval_expr(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
Definition: qrencode.c:248
GlyphInfo::shift_x64
int shift_x64
the horizontal shift of the glyph in 26.6 units
Definition: vf_drawtext.c:183
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
TextLine::offset_right64
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph
Definition: vf_drawtext.c:191
DrawTextContext::text_source
enum AVFrameSideDataType text_source
Definition: vf_drawtext.c:301
TextLine::hb_data
HarfbuzzData hb_data
libharfbuzz data of this text line
Definition: vf_drawtext.c:194
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:90
YA_BASELINE
@ YA_BASELINE
Definition: vf_drawtext.c:159
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
func_strftime
static int func_strftime(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
Definition: qrencode.c:226
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:326
DrawTextContext::y
double y
y position to start drawing text
Definition: vf_drawtext.c:252
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
VAR_DAR
@ VAR_DAR
Definition: vf_drawtext.c:126
FFMAX3
#define FFMAX3(a, b, c)
Definition: macros.h:48
DrawTextContext::boxcolor
FFDrawColor boxcolor
background color
Definition: vf_drawtext.c:279
AV_OPT_TYPE_FLAGS
@ AV_OPT_TYPE_FLAGS
Underlying C type is unsigned int.
Definition: opt.h:254
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:85
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
y_alignment
y_alignment
Definition: vf_drawtext.c:157
AVDetectionBBox
Definition: detection_bbox.h:26
DrawTextContext::x
double x
x position to start drawing text
Definition: vf_drawtext.c:251
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:241
DrawTextContext::metadata
AVDictionary * metadata
Definition: vf_drawtext.c:305
AVDictionaryEntry::value
char * value
Definition: dict.h:92
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:275
width
#define width
Definition: dsp.h:89
drawutils.h
ft_error::err_msg
const char * err_msg
Definition: vf_drawtext.c:416
ft_error
Definition: vf_drawtext.c:414
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:286
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:298
ff_print_time
int ff_print_time(void *log_ctx, AVBPrint *bp, const char *strftime_fmt, char localtime)
Definition: textutils.c:203
DrawTextContext::line_spacing
int line_spacing
lines spacing in pixels
Definition: vf_drawtext.c:262
detection_bbox.h
DrawTextContext::fontcolor_expr
uint8_t * fontcolor_expr
fontcolor expression to evaluate
Definition: vf_drawtext.c:247
drawtext
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
Definition: af_aiir.c:1035
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40
av_timecode_make_string
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum_arg)
Load timecode string in buf.
Definition: timecode.c:104
AV_FRAME_DATA_DETECTION_BBOXES
@ AV_FRAME_DATA_DETECTION_BBOXES
Bounding boxes for object detection and classification, as described by AVDetectionBBoxHeader.
Definition: frame.h:194
DrawTextContext::max_glyph_w
int max_glyph_w
max glyph width
Definition: vf_drawtext.c:253
DrawTextContext::tc_opt_string
char * tc_opt_string
specified timecode option string
Definition: vf_drawtext.c:294
DrawTextContext::fix_bounds
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:273
min
float min
Definition: vorbis_enc_data.h:429
DrawTextContext::boxh
int boxh
the value of the boxh parameter
Definition: vf_drawtext.c:308