vf_drawtext.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Stefano Sabatini
3  * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
4  * Copyright (c) 2003 Gustavo Sverzut Barbieri <gsbarbieri@yahoo.com.br>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * drawtext filter, based on the original vhook/drawtext.c
26  * filter by Gustavo Sverzut Barbieri
27  */
28 
29 #include <sys/time.h>
30 #include <time.h>
31 
32 #include "config.h"
33 #include "libavutil/avstring.h"
34 #include "libavutil/bprint.h"
35 #include "libavutil/common.h"
36 #include "libavutil/file.h"
37 #include "libavutil/eval.h"
38 #include "libavutil/opt.h"
39 #include "libavutil/random_seed.h"
40 #include "libavutil/parseutils.h"
41 #include "libavutil/timecode.h"
42 #include "libavutil/tree.h"
43 #include "libavutil/lfg.h"
44 #include "avfilter.h"
45 #include "drawutils.h"
46 #include "formats.h"
47 #include "internal.h"
48 #include "video.h"
49 
50 #include <ft2build.h>
51 #include <freetype/config/ftheader.h>
52 #include FT_FREETYPE_H
53 #include FT_GLYPH_H
54 #if CONFIG_FONTCONFIG
55 #include <fontconfig/fontconfig.h>
56 #endif
57 
58 static const char *const var_names[] = {
59  "dar",
60  "hsub", "vsub",
61  "line_h", "lh", ///< line height, same as max_glyph_h
62  "main_h", "h", "H", ///< height of the input video
63  "main_w", "w", "W", ///< width of the input video
64  "max_glyph_a", "ascent", ///< max glyph ascent
65  "max_glyph_d", "descent", ///< min glyph descent
66  "max_glyph_h", ///< max glyph height
67  "max_glyph_w", ///< max glyph width
68  "n", ///< number of frame
69  "sar",
70  "t", ///< timestamp expressed in seconds
71  "text_h", "th", ///< height of the rendered text
72  "text_w", "tw", ///< width of the rendered text
73  "x",
74  "y",
75  NULL
76 };
77 
78 static const char *const fun2_names[] = {
79  "rand"
80 };
81 
82 static double drand(void *opaque, double min, double max)
83 {
84  return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
85 }
86 
87 typedef double (*eval_func2)(void *, double a, double b);
88 
89 static const eval_func2 fun2[] = {
90  drand,
91  NULL
92 };
93 
94 enum var_name {
112 };
113 
118 };
119 
120 typedef struct {
121  const AVClass *class;
122  enum expansion_mode exp_mode; ///< expansion mode to use for the text
123  int reinit; ///< tells if the filter is being reinited
124  uint8_t *fontfile; ///< font to be used
125  uint8_t *text; ///< text to be drawn
126  AVBPrint expanded_text; ///< used to contain the expanded text
127  int ft_load_flags; ///< flags used for loading fonts, see FT_LOAD_*
128  FT_Vector *positions; ///< positions for each element in the text
129  size_t nb_positions; ///< number of elements of positions array
130  char *textfile; ///< file with text to be drawn
131  int x; ///< x position to start drawing text
132  int y; ///< y position to start drawing text
133  int max_glyph_w; ///< max glyph width
134  int max_glyph_h; ///< max glyph height
135  int shadowx, shadowy;
136  unsigned int fontsize; ///< font size to use
137  char *fontcolor_string; ///< font color as string
138  char *boxcolor_string; ///< box color as string
139  char *shadowcolor_string; ///< shadow color as string
140 
141  short int draw_box; ///< draw box around text - true or false
142  int use_kerning; ///< font kerning is used - true/false
143  int tabsize; ///< tab size
144  int fix_bounds; ///< do we let it go out of frame bounds - t/f
145 
147  FFDrawColor fontcolor; ///< foreground color
148  FFDrawColor shadowcolor; ///< shadow color
149  FFDrawColor boxcolor; ///< background color
150 
151  FT_Library library; ///< freetype font library handle
152  FT_Face face; ///< freetype font face handle
153  struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
154  char *x_expr; ///< expression for x position
155  char *y_expr; ///< expression for y position
156  AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
157  int64_t basetime; ///< base pts time in the real world for display
158  double var_values[VAR_VARS_NB];
159  char *draw_expr; ///< expression for draw
160  AVExpr *draw_pexpr; ///< parsed expression for draw
161  int draw; ///< set to zero to prevent drawing
162  AVLFG prng; ///< random
163  char *tc_opt_string; ///< specified timecode option string
164  AVRational tc_rate; ///< frame rate for timecode
165  AVTimecode tc; ///< timecode context
166  int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
167  int frame_id;
168  int reload; ///< reload text file for each frame
170 
171 #define OFFSET(x) offsetof(DrawTextContext, x)
172 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
173 
174 static const AVOption drawtext_options[]= {
175  {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
176  {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
177  {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
178  {"fontcolor", "set foreground color", OFFSET(fontcolor_string), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
179  {"boxcolor", "set box color", OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
180  {"shadowcolor", "set shadow color", OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
181  {"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 , FLAGS},
182  {"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX , FLAGS},
183  {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
184  {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
185  {"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
186  {"shadowy", "set y", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
187  {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
188  {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
189  {"draw", "if false do not draw", OFFSET(draw_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS},
190 
191  {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, "expansion"},
192  {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
193  {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
194  {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
195 
196  {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
197  {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
198  {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
199  {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
200  {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
201  {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
202  {"fix_bounds", "if true, check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
203 
204  /* FT_LOAD_* flags */
205  { "ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT | FT_LOAD_RENDER}, 0, INT_MAX, FLAGS, "ft_load_flags" },
206  { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
207  { "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
208  { "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
209  { "render", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_RENDER }, .flags = FLAGS, .unit = "ft_load_flags" },
210  { "no_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
211  { "vertical_layout", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags = FLAGS, .unit = "ft_load_flags" },
212  { "force_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_FORCE_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
213  { "crop_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_CROP_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
214  { "pedantic", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_PEDANTIC }, .flags = FLAGS, .unit = "ft_load_flags" },
215  { "ignore_global_advance_width", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags = FLAGS, .unit = "ft_load_flags" },
216  { "no_recurse", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_RECURSE }, .flags = FLAGS, .unit = "ft_load_flags" },
217  { "ignore_transform", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags = FLAGS, .unit = "ft_load_flags" },
218  { "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
219  { "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
220  { "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
221  { NULL},
222 };
223 
225 
226 #undef __FTERRORS_H__
227 #define FT_ERROR_START_LIST {
228 #define FT_ERRORDEF(e, v, s) { (e), (s) },
229 #define FT_ERROR_END_LIST { 0, NULL } };
230 
231 struct ft_error
232 {
233  int err;
234  const char *err_msg;
235 } static ft_errors[] =
236 #include FT_ERRORS_H
237 
238 #define FT_ERRMSG(e) ft_errors[e].err_msg
239 
240 typedef struct {
241  FT_Glyph *glyph;
242  uint32_t code;
243  FT_Bitmap bitmap; ///< array holding bitmaps of font
244  FT_BBox bbox;
245  int advance;
246  int bitmap_left;
247  int bitmap_top;
248 } Glyph;
249 
250 static int glyph_cmp(void *key, const void *b)
251 {
252  const Glyph *a = key, *bb = b;
253  int64_t diff = (int64_t)a->code - (int64_t)bb->code;
254  return diff > 0 ? 1 : diff < 0 ? -1 : 0;
255 }
256 
257 /**
258  * Load glyphs corresponding to the UTF-32 codepoint code.
259  */
260 static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
261 {
262  DrawTextContext *dtext = ctx->priv;
263  Glyph *glyph;
264  struct AVTreeNode *node = NULL;
265  int ret;
266 
267  /* load glyph into dtext->face->glyph */
268  if (FT_Load_Char(dtext->face, code, dtext->ft_load_flags))
269  return AVERROR(EINVAL);
270 
271  /* save glyph */
272  if (!(glyph = av_mallocz(sizeof(*glyph))) ||
273  !(glyph->glyph = av_mallocz(sizeof(*glyph->glyph)))) {
274  ret = AVERROR(ENOMEM);
275  goto error;
276  }
277  glyph->code = code;
278 
279  if (FT_Get_Glyph(dtext->face->glyph, glyph->glyph)) {
280  ret = AVERROR(EINVAL);
281  goto error;
282  }
283 
284  glyph->bitmap = dtext->face->glyph->bitmap;
285  glyph->bitmap_left = dtext->face->glyph->bitmap_left;
286  glyph->bitmap_top = dtext->face->glyph->bitmap_top;
287  glyph->advance = dtext->face->glyph->advance.x >> 6;
288 
289  /* measure text height to calculate text_height (or the maximum text height) */
290  FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
291 
292  /* cache the newly created glyph */
293  if (!(node = av_tree_node_alloc())) {
294  ret = AVERROR(ENOMEM);
295  goto error;
296  }
297  av_tree_insert(&dtext->glyphs, glyph, glyph_cmp, &node);
298 
299  if (glyph_ptr)
300  *glyph_ptr = glyph;
301  return 0;
302 
303 error:
304  if (glyph)
305  av_freep(&glyph->glyph);
306  av_freep(&glyph);
307  av_freep(&node);
308  return ret;
309 }
310 
311 static int load_font_file(AVFilterContext *ctx, const char *path, int index,
312  const char **error)
313 {
314  DrawTextContext *dtext = ctx->priv;
315  int err;
316 
317  err = FT_New_Face(dtext->library, path, index, &dtext->face);
318  if (err) {
319  *error = FT_ERRMSG(err);
320  return AVERROR(EINVAL);
321  }
322  return 0;
323 }
324 
325 #if CONFIG_FONTCONFIG
326 static int load_font_fontconfig(AVFilterContext *ctx, const char **error)
327 {
328  DrawTextContext *dtext = ctx->priv;
329  FcConfig *fontconfig;
330  FcPattern *pattern, *fpat;
331  FcResult result = FcResultMatch;
332  FcChar8 *filename;
333  int err, index;
334  double size;
335 
336  fontconfig = FcInitLoadConfigAndFonts();
337  if (!fontconfig) {
338  *error = "impossible to init fontconfig\n";
339  return AVERROR(EINVAL);
340  }
341  pattern = FcNameParse(dtext->fontfile ? dtext->fontfile :
342  (uint8_t *)(intptr_t)"default");
343  if (!pattern) {
344  *error = "could not parse fontconfig pattern";
345  return AVERROR(EINVAL);
346  }
347  if (!FcConfigSubstitute(fontconfig, pattern, FcMatchPattern)) {
348  *error = "could not substitue fontconfig options"; /* very unlikely */
349  return AVERROR(EINVAL);
350  }
351  FcDefaultSubstitute(pattern);
352  fpat = FcFontMatch(fontconfig, pattern, &result);
353  if (!fpat || result != FcResultMatch) {
354  *error = "impossible to find a matching font";
355  return AVERROR(EINVAL);
356  }
357  if (FcPatternGetString (fpat, FC_FILE, 0, &filename) != FcResultMatch ||
358  FcPatternGetInteger(fpat, FC_INDEX, 0, &index ) != FcResultMatch ||
359  FcPatternGetDouble (fpat, FC_SIZE, 0, &size ) != FcResultMatch) {
360  *error = "impossible to find font information";
361  return AVERROR(EINVAL);
362  }
363  av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
364  if (!dtext->fontsize)
365  dtext->fontsize = size + 0.5;
366  err = load_font_file(ctx, filename, index, error);
367  if (err)
368  return err;
369  FcPatternDestroy(fpat);
370  FcPatternDestroy(pattern);
371  FcConfigDestroy(fontconfig);
372  return 0;
373 }
374 #endif
375 
376 static int load_font(AVFilterContext *ctx)
377 {
378  DrawTextContext *dtext = ctx->priv;
379  int err;
380  const char *error = "unknown error\n";
381 
382  /* load the face, and set up the encoding, which is by default UTF-8 */
383  err = load_font_file(ctx, dtext->fontfile, 0, &error);
384  if (!err)
385  return 0;
386 #if CONFIG_FONTCONFIG
387  err = load_font_fontconfig(ctx, &error);
388  if (!err)
389  return 0;
390 #endif
391  av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
392  dtext->fontfile, error);
393  return err;
394 }
395 
397 {
398  DrawTextContext *dtext = ctx->priv;
399  int err;
400  uint8_t *textbuf;
401  size_t textbuf_size;
402 
403  if ((err = av_file_map(dtext->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
404  av_log(ctx, AV_LOG_ERROR,
405  "The text file '%s' could not be read or is empty\n",
406  dtext->textfile);
407  return err;
408  }
409 
410  if (!(dtext->text = av_realloc(dtext->text, textbuf_size + 1)))
411  return AVERROR(ENOMEM);
412  memcpy(dtext->text, textbuf, textbuf_size);
413  dtext->text[textbuf_size] = 0;
414  av_file_unmap(textbuf, textbuf_size);
415 
416  return 0;
417 }
418 
419 static av_cold int init(AVFilterContext *ctx)
420 {
421  int err;
422  DrawTextContext *dtext = ctx->priv;
423  Glyph *glyph;
424 
425  if (!dtext->fontfile && !CONFIG_FONTCONFIG) {
426  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
427  return AVERROR(EINVAL);
428  }
429 
430  if (dtext->textfile) {
431  if (dtext->text) {
432  av_log(ctx, AV_LOG_ERROR,
433  "Both text and text file provided. Please provide only one\n");
434  return AVERROR(EINVAL);
435  }
436  if ((err = load_textfile(ctx)) < 0)
437  return err;
438  }
439 
440  if (dtext->reload && !dtext->textfile)
441  av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
442 
443  if (dtext->tc_opt_string) {
444  int ret = av_timecode_init_from_string(&dtext->tc, dtext->tc_rate,
445  dtext->tc_opt_string, ctx);
446  if (ret < 0)
447  return ret;
448  if (dtext->tc24hmax)
450  if (!dtext->text)
451  dtext->text = av_strdup("");
452  }
453 
454  if (!dtext->text) {
455  av_log(ctx, AV_LOG_ERROR,
456  "Either text, a valid file or a timecode must be provided\n");
457  return AVERROR(EINVAL);
458  }
459 
460  if ((err = av_parse_color(dtext->fontcolor.rgba, dtext->fontcolor_string, -1, ctx))) {
461  av_log(ctx, AV_LOG_ERROR,
462  "Invalid font color '%s'\n", dtext->fontcolor_string);
463  return err;
464  }
465 
466  if ((err = av_parse_color(dtext->boxcolor.rgba, dtext->boxcolor_string, -1, ctx))) {
467  av_log(ctx, AV_LOG_ERROR,
468  "Invalid box color '%s'\n", dtext->boxcolor_string);
469  return err;
470  }
471 
472  if ((err = av_parse_color(dtext->shadowcolor.rgba, dtext->shadowcolor_string, -1, ctx))) {
473  av_log(ctx, AV_LOG_ERROR,
474  "Invalid shadow color '%s'\n", dtext->shadowcolor_string);
475  return err;
476  }
477 
478  if ((err = FT_Init_FreeType(&(dtext->library)))) {
479  av_log(ctx, AV_LOG_ERROR,
480  "Could not load FreeType: %s\n", FT_ERRMSG(err));
481  return AVERROR(EINVAL);
482  }
483 
484  err = load_font(ctx);
485  if (err)
486  return err;
487  if (!dtext->fontsize)
488  dtext->fontsize = 16;
489  if ((err = FT_Set_Pixel_Sizes(dtext->face, 0, dtext->fontsize))) {
490  av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
491  dtext->fontsize, FT_ERRMSG(err));
492  return AVERROR(EINVAL);
493  }
494 
495  dtext->use_kerning = FT_HAS_KERNING(dtext->face);
496 
497  /* load the fallback glyph with code 0 */
498  load_glyph(ctx, NULL, 0);
499 
500  /* set the tabsize in pixels */
501  if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
502  av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
503  return err;
504  }
505  dtext->tabsize *= glyph->advance;
506 
507  if (dtext->exp_mode == EXP_STRFTIME &&
508  (strchr(dtext->text, '%') || strchr(dtext->text, '\\')))
509  av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
510 
512 
513  return 0;
514 }
515 
517 {
519  return 0;
520 }
521 
522 static int glyph_enu_free(void *opaque, void *elem)
523 {
524  Glyph *glyph = elem;
525 
526  FT_Done_Glyph(*glyph->glyph);
527  av_freep(&glyph->glyph);
528  av_free(elem);
529  return 0;
530 }
531 
532 static av_cold void uninit(AVFilterContext *ctx)
533 {
534  DrawTextContext *dtext = ctx->priv;
535 
536  av_expr_free(dtext->x_pexpr); dtext->x_pexpr = NULL;
537  av_expr_free(dtext->y_pexpr); dtext->y_pexpr = NULL;
538  av_expr_free(dtext->draw_pexpr); dtext->draw_pexpr = NULL;
539 
540  av_freep(&dtext->positions);
541  dtext->nb_positions = 0;
542 
543 
545  av_tree_destroy(dtext->glyphs);
546  dtext->glyphs = NULL;
547 
548  FT_Done_Face(dtext->face);
549  FT_Done_FreeType(dtext->library);
550 
552 }
553 
554 static inline int is_newline(uint32_t c)
555 {
556  return c == '\n' || c == '\r' || c == '\f' || c == '\v';
557 }
558 
559 static int config_input(AVFilterLink *inlink)
560 {
561  AVFilterContext *ctx = inlink->dst;
562  DrawTextContext *dtext = ctx->priv;
563  int ret;
564 
565  ff_draw_init(&dtext->dc, inlink->format, 0);
566  ff_draw_color(&dtext->dc, &dtext->fontcolor, dtext->fontcolor.rgba);
567  ff_draw_color(&dtext->dc, &dtext->shadowcolor, dtext->shadowcolor.rgba);
568  ff_draw_color(&dtext->dc, &dtext->boxcolor, dtext->boxcolor.rgba);
569 
570  dtext->var_values[VAR_w] = dtext->var_values[VAR_W] = dtext->var_values[VAR_MAIN_W] = inlink->w;
571  dtext->var_values[VAR_h] = dtext->var_values[VAR_H] = dtext->var_values[VAR_MAIN_H] = inlink->h;
572  dtext->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
573  dtext->var_values[VAR_DAR] = (double)inlink->w / inlink->h * dtext->var_values[VAR_SAR];
574  dtext->var_values[VAR_HSUB] = 1 << dtext->dc.hsub_max;
575  dtext->var_values[VAR_VSUB] = 1 << dtext->dc.vsub_max;
576  dtext->var_values[VAR_X] = NAN;
577  dtext->var_values[VAR_Y] = NAN;
578  if (!dtext->reinit)
579  dtext->var_values[VAR_N] = 0;
580  dtext->var_values[VAR_T] = NAN;
581 
582  av_lfg_init(&dtext->prng, av_get_random_seed());
583 
584  if ((ret = av_expr_parse(&dtext->x_pexpr, dtext->x_expr, var_names,
585  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
586  (ret = av_expr_parse(&dtext->y_pexpr, dtext->y_expr, var_names,
587  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
588  (ret = av_expr_parse(&dtext->draw_pexpr, dtext->draw_expr, var_names,
589  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
590 
591  return AVERROR(EINVAL);
592 
593  return 0;
594 }
595 
596 static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
597 {
598  DrawTextContext *dtext = ctx->priv;
599 
600  if (!strcmp(cmd, "reinit")) {
601  int ret;
602  uninit(ctx);
603  dtext->reinit = 1;
604  if ((ret = init(ctx)) < 0)
605  return ret;
606  return config_input(ctx->inputs[0]);
607  }
608 
609  return AVERROR(ENOSYS);
610 }
611 
612 static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
613  char *fct, unsigned argc, char **argv, int tag)
614 {
615  DrawTextContext *dtext = ctx->priv;
616 
617  av_bprintf(bp, "%.6f", dtext->var_values[VAR_T]);
618  return 0;
619 }
620 
622  char *fct, unsigned argc, char **argv, int tag)
623 {
624  DrawTextContext *dtext = ctx->priv;
625 
626  av_bprintf(bp, "%d", (int)dtext->var_values[VAR_N]);
627  return 0;
628 }
629 
630 #if !HAVE_LOCALTIME_R
631 static void localtime_r(const time_t *t, struct tm *tm)
632 {
633  *tm = *localtime(t);
634 }
635 #endif
636 
638  char *fct, unsigned argc, char **argv, int tag)
639 {
640  const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
641  time_t now;
642  struct tm tm;
643 
644  time(&now);
645  if (tag == 'L')
646  localtime_r(&now, &tm);
647  else
648  tm = *gmtime(&now);
649  av_bprint_strftime(bp, fmt, &tm);
650  return 0;
651 }
652 
654  char *fct, unsigned argc, char **argv, int tag)
655 {
656  DrawTextContext *dtext = ctx->priv;
657  double res;
658  int ret;
659 
660  ret = av_expr_parse_and_eval(&res, argv[0], var_names, dtext->var_values,
662  &dtext->prng, 0, ctx);
663  if (ret < 0)
664  av_log(ctx, AV_LOG_ERROR,
665  "Expression '%s' for the expr text expansion function is not valid\n",
666  argv[0]);
667  else
668  av_bprintf(bp, "%f", res);
669 
670  return ret;
671 }
672 
673 static const struct drawtext_function {
674  const char *name;
675  unsigned argc_min, argc_max;
676  int tag; /** opaque argument to func */
677  int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
678 } functions[] = {
679  { "expr", 1, 1, 0, func_eval_expr },
680  { "e", 1, 1, 0, func_eval_expr },
681  { "pts", 0, 0, 0, func_pts },
682  { "gmtime", 0, 1, 'G', func_strftime },
683  { "localtime", 0, 1, 'L', func_strftime },
684  { "frame_num", 0, 0, 0, func_frame_num },
685  { "n", 0, 0, 0, func_frame_num },
686 };
687 
688 static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
689  unsigned argc, char **argv)
690 {
691  unsigned i;
692 
693  for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
694  if (strcmp(fct, functions[i].name))
695  continue;
696  if (argc < functions[i].argc_min) {
697  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
698  fct, functions[i].argc_min);
699  return AVERROR(EINVAL);
700  }
701  if (argc > functions[i].argc_max) {
702  av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
703  fct, functions[i].argc_max);
704  return AVERROR(EINVAL);
705  }
706  break;
707  }
708  if (i >= FF_ARRAY_ELEMS(functions)) {
709  av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
710  return AVERROR(EINVAL);
711  }
712  return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
713 }
714 
715 static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
716 {
717  const char *text = *rtext;
718  char *argv[16] = { NULL };
719  unsigned argc = 0, i;
720  int ret;
721 
722  if (*text != '{') {
723  av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
724  return AVERROR(EINVAL);
725  }
726  text++;
727  while (1) {
728  if (!(argv[argc++] = av_get_token(&text, ":}"))) {
729  ret = AVERROR(ENOMEM);
730  goto end;
731  }
732  if (!*text) {
733  av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
734  ret = AVERROR(EINVAL);
735  goto end;
736  }
737  if (argc == FF_ARRAY_ELEMS(argv))
738  av_freep(&argv[--argc]); /* error will be caught later */
739  if (*text == '}')
740  break;
741  text++;
742  }
743 
744  if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
745  goto end;
746  ret = 0;
747  *rtext = (char *)text + 1;
748 
749 end:
750  for (i = 0; i < argc; i++)
751  av_freep(&argv[i]);
752  return ret;
753 }
754 
755 static int expand_text(AVFilterContext *ctx)
756 {
757  DrawTextContext *dtext = ctx->priv;
758  char *text = dtext->text;
759  AVBPrint *bp = &dtext->expanded_text;
760  int ret;
761 
762  av_bprint_clear(bp);
763  while (*text) {
764  if (*text == '\\' && text[1]) {
765  av_bprint_chars(bp, text[1], 1);
766  text += 2;
767  } else if (*text == '%') {
768  text++;
769  if ((ret = expand_function(ctx, bp, &text)) < 0)
770  return ret;
771  } else {
772  av_bprint_chars(bp, *text, 1);
773  text++;
774  }
775  }
776  if (!av_bprint_is_complete(bp))
777  return AVERROR(ENOMEM);
778  return 0;
779 }
780 
782  int width, int height, const uint8_t rgbcolor[4], FFDrawColor *color, int x, int y)
783 {
784  char *text = dtext->expanded_text.str;
785  uint32_t code = 0;
786  int i, x1, y1;
787  uint8_t *p;
788  Glyph *glyph = NULL;
789 
790  for (i = 0, p = text; *p; i++) {
791  Glyph dummy = { 0 };
792  GET_UTF8(code, *p++, continue;);
793 
794  /* skip new line chars, just go to new line */
795  if (code == '\n' || code == '\r' || code == '\t')
796  continue;
797 
798  dummy.code = code;
799  glyph = av_tree_find(dtext->glyphs, &dummy, (void *)glyph_cmp, NULL);
800 
801  if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
802  glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
803  return AVERROR(EINVAL);
804 
805  x1 = dtext->positions[i].x+dtext->x+x;
806  y1 = dtext->positions[i].y+dtext->y+y;
807 
808  ff_blend_mask(&dtext->dc, color,
809  frame->data, frame->linesize, width, height,
810  glyph->bitmap.buffer, glyph->bitmap.pitch,
811  glyph->bitmap.width, glyph->bitmap.rows,
812  glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
813  0, x1, y1);
814  }
815 
816  return 0;
817 }
818 
820  int width, int height)
821 {
822  DrawTextContext *dtext = ctx->priv;
823  uint32_t code = 0, prev_code = 0;
824  int x = 0, y = 0, i = 0, ret;
825  int max_text_line_w = 0, len;
826  int box_w, box_h;
827  char *text = dtext->text;
828  uint8_t *p;
829  int y_min = 32000, y_max = -32000;
830  int x_min = 32000, x_max = -32000;
831  FT_Vector delta;
832  Glyph *glyph = NULL, *prev_glyph = NULL;
833  Glyph dummy = { 0 };
834 
835  time_t now = time(0);
836  struct tm ltime;
837  AVBPrint *bp = &dtext->expanded_text;
838 
839  av_bprint_clear(bp);
840 
841  if(dtext->basetime != AV_NOPTS_VALUE)
842  now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + dtext->basetime/1000000;
843 
844  switch (dtext->exp_mode) {
845  case EXP_NONE:
846  av_bprintf(bp, "%s", dtext->text);
847  break;
848  case EXP_NORMAL:
849  if ((ret = expand_text(ctx)) < 0)
850  return ret;
851  break;
852  case EXP_STRFTIME:
853  localtime_r(&now, &ltime);
854  av_bprint_strftime(bp, dtext->text, &ltime);
855  break;
856  }
857 
858  if (dtext->tc_opt_string) {
859  char tcbuf[AV_TIMECODE_STR_SIZE];
860  av_timecode_make_string(&dtext->tc, tcbuf, dtext->frame_id++);
861  av_bprint_clear(bp);
862  av_bprintf(bp, "%s%s", dtext->text, tcbuf);
863  }
864 
865  if (!av_bprint_is_complete(bp))
866  return AVERROR(ENOMEM);
867  text = dtext->expanded_text.str;
868  if ((len = dtext->expanded_text.len) > dtext->nb_positions) {
869  if (!(dtext->positions =
870  av_realloc(dtext->positions, len*sizeof(*dtext->positions))))
871  return AVERROR(ENOMEM);
872  dtext->nb_positions = len;
873  }
874 
875  x = 0;
876  y = 0;
877 
878  /* load and cache glyphs */
879  for (i = 0, p = text; *p; i++) {
880  GET_UTF8(code, *p++, continue;);
881 
882  /* get glyph */
883  dummy.code = code;
884  glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
885  if (!glyph) {
886  load_glyph(ctx, &glyph, code);
887  }
888 
889  y_min = FFMIN(glyph->bbox.yMin, y_min);
890  y_max = FFMAX(glyph->bbox.yMax, y_max);
891  x_min = FFMIN(glyph->bbox.xMin, x_min);
892  x_max = FFMAX(glyph->bbox.xMax, x_max);
893  }
894  dtext->max_glyph_h = y_max - y_min;
895  dtext->max_glyph_w = x_max - x_min;
896 
897  /* compute and save position for each glyph */
898  glyph = NULL;
899  for (i = 0, p = text; *p; i++) {
900  GET_UTF8(code, *p++, continue;);
901 
902  /* skip the \n in the sequence \r\n */
903  if (prev_code == '\r' && code == '\n')
904  continue;
905 
906  prev_code = code;
907  if (is_newline(code)) {
908  max_text_line_w = FFMAX(max_text_line_w, x);
909  y += dtext->max_glyph_h;
910  x = 0;
911  continue;
912  }
913 
914  /* get glyph */
915  prev_glyph = glyph;
916  dummy.code = code;
917  glyph = av_tree_find(dtext->glyphs, &dummy, glyph_cmp, NULL);
918 
919  /* kerning */
920  if (dtext->use_kerning && prev_glyph && glyph->code) {
921  FT_Get_Kerning(dtext->face, prev_glyph->code, glyph->code,
922  ft_kerning_default, &delta);
923  x += delta.x >> 6;
924  }
925 
926  /* save position */
927  dtext->positions[i].x = x + glyph->bitmap_left;
928  dtext->positions[i].y = y - glyph->bitmap_top + y_max;
929  if (code == '\t') x = (x / dtext->tabsize + 1)*dtext->tabsize;
930  else x += glyph->advance;
931  }
932 
933  max_text_line_w = FFMAX(x, max_text_line_w);
934 
935  dtext->var_values[VAR_TW] = dtext->var_values[VAR_TEXT_W] = max_text_line_w;
936  dtext->var_values[VAR_TH] = dtext->var_values[VAR_TEXT_H] = y + dtext->max_glyph_h;
937 
938  dtext->var_values[VAR_MAX_GLYPH_W] = dtext->max_glyph_w;
939  dtext->var_values[VAR_MAX_GLYPH_H] = dtext->max_glyph_h;
940  dtext->var_values[VAR_MAX_GLYPH_A] = dtext->var_values[VAR_ASCENT ] = y_max;
941  dtext->var_values[VAR_MAX_GLYPH_D] = dtext->var_values[VAR_DESCENT] = y_min;
942 
943  dtext->var_values[VAR_LINE_H] = dtext->var_values[VAR_LH] = dtext->max_glyph_h;
944 
945  dtext->x = dtext->var_values[VAR_X] = av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng);
946  dtext->y = dtext->var_values[VAR_Y] = av_expr_eval(dtext->y_pexpr, dtext->var_values, &dtext->prng);
947  dtext->x = dtext->var_values[VAR_X] = av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng);
948  dtext->draw = av_expr_eval(dtext->draw_pexpr, dtext->var_values, &dtext->prng);
949 
950  if(!dtext->draw)
951  return 0;
952 
953  box_w = FFMIN(width - 1 , max_text_line_w);
954  box_h = FFMIN(height - 1, y + dtext->max_glyph_h);
955 
956  /* draw box */
957  if (dtext->draw_box)
958  ff_blend_rectangle(&dtext->dc, &dtext->boxcolor,
959  frame->data, frame->linesize, width, height,
960  dtext->x, dtext->y, box_w, box_h);
961 
962  if (dtext->shadowx || dtext->shadowy) {
963  if ((ret = draw_glyphs(dtext, frame, width, height, dtext->shadowcolor.rgba,
964  &dtext->shadowcolor, dtext->shadowx, dtext->shadowy)) < 0)
965  return ret;
966  }
967 
968  if ((ret = draw_glyphs(dtext, frame, width, height, dtext->fontcolor.rgba,
969  &dtext->fontcolor, 0, 0)) < 0)
970  return ret;
971 
972  return 0;
973 }
974 
975 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
976 {
977  AVFilterContext *ctx = inlink->dst;
978  AVFilterLink *outlink = ctx->outputs[0];
979  DrawTextContext *dtext = ctx->priv;
980  int ret;
981 
982  if (dtext->reload)
983  if ((ret = load_textfile(ctx)) < 0)
984  return ret;
985 
986  dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
987  NAN : frame->pts * av_q2d(inlink->time_base);
988 
989  draw_text(ctx, frame, frame->width, frame->height);
990 
991  av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
992  (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T],
993  (int)dtext->var_values[VAR_TEXT_W], (int)dtext->var_values[VAR_TEXT_H],
994  dtext->x, dtext->y);
995 
996  dtext->var_values[VAR_N] += 1.0;
997 
998  return ff_filter_frame(outlink, frame);
999 }
1000 
1002  {
1003  .name = "default",
1004  .type = AVMEDIA_TYPE_VIDEO,
1005  .get_video_buffer = ff_null_get_video_buffer,
1006  .filter_frame = filter_frame,
1007  .config_props = config_input,
1008  .needs_writable = 1,
1009  },
1010  { NULL }
1011 };
1012 
1014  {
1015  .name = "default",
1016  .type = AVMEDIA_TYPE_VIDEO,
1017  },
1018  { NULL }
1019 };
1020 
1022  .name = "drawtext",
1023  .description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
1024  .priv_size = sizeof(DrawTextContext),
1025  .priv_class = &drawtext_class,
1026  .init = init,
1027  .uninit = uninit,
1029 
1030  .inputs = avfilter_vf_drawtext_inputs,
1031  .outputs = avfilter_vf_drawtext_outputs,
1033 };
const char * name
Definition: avisynth_c.h:675
Definition: lfg.h:25
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, 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:429
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition: drawutils.c:501
int draw
set to zero to prevent drawing
Definition: vf_drawtext.c:161
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:621
char * y_expr
expression for y position
Definition: vf_drawtext.c:155
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
#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:296
int tc24hmax
1 if timecode is wrapped to 24 hours, 0 otherwise
Definition: vf_drawtext.c:166
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
AVOption.
Definition: opt.h:251
int x
x position to start drawing text
Definition: vf_drawtext.c:131
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:82
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:174
const char * fmt
Definition: avisynth_c.h:669
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:136
FFDrawColor boxcolor
background color
Definition: vf_drawtext.c:149
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
char * x_expr
expression for x position
Definition: vf_drawtext.c:154
external API header
uint8_t * fontfile
font to be used
Definition: vf_drawtext.c:124
if max(w)>1 w=0.9 *w/max(w)
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
#define FLAGS
Definition: vf_drawtext.c:172
int num
numerator
Definition: rational.h:44
static const struct drawtext_function functions[]
y1
Definition: lab5.m:33
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
AVFrame * ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
Definition: video.c:35
static int draw_text(AVFilterContext *ctx, AVFrame *frame, int width, int height)
Definition: vf_drawtext.c:819
uint8_t * text
text to be drawn
Definition: vf_drawtext.c:125
x1
Definition: genspecsines3.m:7
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
#define FF_ARRAY_ELEMS(a)
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:640
char * tc_opt_string
specified timecode option string
Definition: vf_drawtext.c:163
Timecode helpers header.
text(-8, 1,'a)')
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:193
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
initialize output if(nPeaks >3)%at least 3 peaks in spectrum for trying to find f0 nf0peaks
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:33
expansion_mode
Definition: vf_drawtext.c:114
const char * name
Pad name.
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:532
AVFilter avfilter_vf_drawtext
Definition: vf_drawtext.c:1021
static int glyph_enu_free(void *opaque, void *elem)
Definition: vf_drawtext.c:522
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(void *key, const void *b), void *next[2])
Definition: tree.c:38
uint8_t
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt,...)
Definition: f_ebur128.c:186
float delta
AVOptions.
A tree container.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
AVLFG prng
random
Definition: vf_drawtext.c:162
#define b
Definition: input.c:42
end end
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:152
#define NAN
Definition: math.h:7
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:419
#define CONFIG_FONTCONFIG
Definition: config.h:302
Definition: eval.c:140
Misc file utilities.
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
static const AVFilterPad avfilter_vf_drawtext_inputs[]
Definition: vf_drawtext.c:1001
uint32_t tag
Definition: movenc.c:894
const char * name
Definition: vf_drawtext.c:674
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:532
void 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:545
FT_Vector * positions
positions for each element in the text
Definition: vf_drawtext.c:128
AVExpr * x_pexpr
Definition: vf_drawtext.c:156
#define AV_TIMECODE_STR_SIZE
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:140
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:337
frame
Definition: stft.m:14
char * fontcolor_string
font color as string
Definition: vf_drawtext.c:137
static void localtime_r(const time_t *t, struct tm *tm)
Definition: vf_drawtext.c:631
A filter pad used for either input or output.
char * draw_expr
expression for draw
Definition: vf_drawtext.c:159
Discrete Time axis x
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:701
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:57
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:158
int width
width and height of the video frame
Definition: frame.h:122
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
AVBPrint expanded_text
used to contain the expanded text
Definition: vf_drawtext.c:126
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...
#define AV_BPRINT_SIZE_UNLIMITED
Convenience macros for special values for av_bprint_init() size_max parameter.
Definition: bprint.h:89
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:156
const char * err_msg
Definition: vf_drawtext.c:234
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Init a print buffer.
Definition: bprint.c:68
void * priv
private data for use by the filter
Definition: avfilter.h:545
int y
y position to start drawing text
Definition: vf_drawtext.c:132
static int av_bprint_is_complete(AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:166
const char * arg
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:179
static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
Definition: vf_drawtext.c:715
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
uint8_t vsub_max
Definition: drawutils.h:57
FFDrawColor fontcolor
foreground color
Definition: vf_drawtext.c:147
#define FFMAX(a, b)
Definition: common.h:56
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:148
static const char *const fun2_names[]
Definition: vf_drawtext.c:78
int size
int reload
reload text file for each frame
Definition: vf_drawtext.c:168
FFDrawContext dc
Definition: vf_drawtext.c:146
Buffer to print data progressively.
Definition: bprint.h:75
#define FFMIN(a, b)
Definition: common.h:58
var_name
ret
Definition: avfilter.c:821
int64_t basetime
base pts time in the real world for display
Definition: vf_drawtext.c:157
t
Definition: genspecsines3.m:6
int max_glyph_h
max glyph height
Definition: vf_drawtext.c:134
AVRational tc_rate
frame rate for timecode
Definition: vf_drawtext.c:164
AVExpr * draw_pexpr
parsed expression for draw
Definition: vf_drawtext.c:160
#define diff(a, as, b, bs)
Definition: vf_phase.c:80
static int process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: af_atempo.c:1141
static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:653
static int expand_text(AVFilterContext *ctx)
Definition: vf_drawtext.c:755
AVTimecode tc
timecode context
Definition: vf_drawtext.c:165
NULL
Definition: eval.c:55
or the Software in violation of any applicable export control laws in any jurisdiction Except as provided by mandatorily applicable UPF has no obligation to provide you with source code to the Software In the event Software contains any source code
static int width
Definition: tests/utils.c:158
char * boxcolor_string
box color as string
Definition: vf_drawtext.c:138
misc drawing utilities
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:302
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:220
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
static int load_font(AVFilterContext *ctx)
Definition: vf_drawtext.c:376
timecode wraps after 24 hours
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Definition: vf_drawtext.c:596
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:38
uint8_t hsub_max
Definition: drawutils.h:56
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
int tabsize
tab size
Definition: vf_drawtext.c:143
int index
Definition: gxfenc.c:89
synthesis window for stochastic i
static int func_strftime(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:637
rational number numerator/denominator
Definition: rational.h:43
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:331
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
Definition: vf_drawtext.c:153
static int is_newline(uint32_t c)
Definition: vf_drawtext.c:554
const char * name
filter name
Definition: avfilter.h:437
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:30
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:135
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
misc parsing utilities
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
struct ft_error ft_errors[]
short int draw_box
draw box around text - true or false
Definition: vf_drawtext.c:141
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:559
static int flags
Definition: cpu.c:23
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
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:134
AVFILTER_DEFINE_CLASS(drawtext)
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:185
int(* func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int)
opaque argument to func
Definition: vf_drawtext.c:677
static int load_font_file(AVFilterContext *ctx, const char *path, int index, const char **error)
Definition: vf_drawtext.c:311
static const char *const var_names[]
Definition: vf_drawtext.c:58
int use_kerning
font kerning is used - true/false
Definition: vf_drawtext.c:142
char * shadowcolor_string
shadow color as string
Definition: vf_drawtext.c:139
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
common internal and external API header
static int glyph_cmp(void *key, const void *b)
Definition: vf_drawtext.c:250
static double c[64]
static int query_formats(AVFilterContext *ctx)
Definition: vf_drawtext.c:516
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:151
static int draw_glyphs(DrawTextContext *dtext, AVFrame *frame, int width, int height, const uint8_t rgbcolor[4], FFDrawColor *color, int x, int y)
Definition: vf_drawtext.c:781
function y
Definition: D.m:1
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:87
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:975
static const AVFilterPad avfilter_vf_drawtext_outputs[]
Definition: vf_drawtext.c:1013
int len
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:691
#define FT_ERRMSG(e)
int reinit
tells if the filter is being reinited
Definition: vf_drawtext.c:123
FFDrawColor shadowcolor
shadow color
Definition: vf_drawtext.c:148
#define OFFSET(x)
Definition: vf_drawtext.c:171
An instance of a filter.
Definition: avfilter.h:524
int max_glyph_w
max glyph width
Definition: vf_drawtext.c:133
static const eval_func2 fun2[]
Definition: vf_drawtext.c:89
int height
Definition: frame.h:122
static int func_pts(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv, int tag)
Definition: vf_drawtext.c:612
#define AV_LOG_INFO
Definition: log.h:156
enum expansion_mode exp_mode
expansion mode to use for the text
Definition: vf_drawtext.c:122
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:144
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:105
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:130
internal API functions
static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
Load glyphs corresponding to the UTF-32 codepoint code.
Definition: vf_drawtext.c:260
static int load_textfile(AVFilterContext *ctx)
Definition: vf_drawtext.c:396
int dummy
Definition: motion-test.c:64
static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv)
Definition: vf_drawtext.c:688
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:127
uint32_t flags
flags such as drop frame, +24 hours support, ...
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:149
float min
size_t nb_positions
number of elements of positions array
Definition: vf_drawtext.c:129
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 inputs
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190
void * elem
Definition: tree.c:27
simple arithmetic expression evaluator
uint8_t rgba[4]
Definition: drawutils.h:61
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:116