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