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