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