Libav
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 Libav.
7  *
8  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
29 #include "config.h"
30 
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/stat.h>
34 #include <time.h>
35 #include <unistd.h>
36 
37 #if CONFIG_LIBFONTCONFIG
38 #include <fontconfig/fontconfig.h>
39 #endif
40 
41 #include "libavutil/colorspace.h"
42 #include "libavutil/common.h"
43 #include "libavutil/file.h"
44 #include "libavutil/eval.h"
45 #include "libavutil/opt.h"
46 #include "libavutil/mathematics.h"
47 #include "libavutil/random_seed.h"
48 #include "libavutil/parseutils.h"
49 #include "libavutil/pixdesc.h"
50 #include "libavutil/tree.h"
51 #include "libavutil/lfg.h"
52 #include "avfilter.h"
53 #include "drawutils.h"
54 #include "formats.h"
55 #include "internal.h"
56 #include "video.h"
57 
58 #include <ft2build.h>
59 #include FT_FREETYPE_H
60 #include FT_GLYPH_H
61 
62 static const char *const var_names[] = {
63  "E",
64  "PHI",
65  "PI",
66  "main_w", "W",
67  "main_h", "H",
68  "text_w", "w",
69  "text_h", "h",
70  "x",
71  "y",
72  "n",
73  "t",
74  NULL
75 };
76 
77 static const char *const fun2_names[] = {
78  "rand"
79 };
80 
81 static double drand(void *opaque, double min, double max)
82 {
83  return min + (max-min) / UINT_MAX * av_lfg_get(opaque);
84 }
85 
86 typedef double (*eval_func2)(void *, double a, double b);
87 
88 static const eval_func2 fun2[] = {
89  drand,
90  NULL
91 };
92 
93 enum var_name {
106 };
107 
108 typedef struct DrawTextContext {
109  const AVClass *class;
110 #if CONFIG_LIBFONTCONFIG
111  uint8_t *font;
112 #endif
118  FT_Vector *positions;
119  size_t nb_positions;
120  char *textfile;
121  int x, y;
122  int w, h;
124  unsigned int fontsize;
134 
135  short int draw_box;
137  int tabsize;
139 
140  FT_Library library;
141  FT_Face face;
142  struct AVTreeNode *glyphs;
143  int hsub, vsub;
145  int pixel_step[4];
148  char *x_expr, *y_expr;
151  char *d_expr;
153  int draw;
156 
157 #define OFFSET(x) offsetof(DrawTextContext, x)
158 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM
159 
160 static const AVOption drawtext_options[]= {
161 #if CONFIG_LIBFONTCONFIG
162  { "font", "Font name", OFFSET(font), AV_OPT_TYPE_STRING, { .str = "Sans" }, .flags = FLAGS },
163 #endif
164  { "fontfile", NULL, OFFSET(fontfile), AV_OPT_TYPE_STRING, .flags = FLAGS },
165  { "text", NULL, OFFSET(text), AV_OPT_TYPE_STRING, .flags = FLAGS },
166  { "textfile", NULL, OFFSET(textfile), AV_OPT_TYPE_STRING, .flags = FLAGS },
167  { "fontcolor", NULL, OFFSET(fontcolor_string), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
168  { "boxcolor", NULL, OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, { .str = "white" }, .flags = FLAGS },
169  { "shadowcolor", NULL, OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
170  { "box", NULL, OFFSET(draw_box), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
171  { "fontsize", NULL, OFFSET(fontsize), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, 72, FLAGS },
172  { "x", NULL, OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
173  { "y", NULL, OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
174  { "shadowx", NULL, OFFSET(shadowx), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
175  { "shadowy", NULL, OFFSET(shadowy), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
176  { "tabsize", NULL, OFFSET(tabsize), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, INT_MAX, FLAGS },
177  { "draw", "if false do not draw", OFFSET(d_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
178  { "fix_bounds", "if true, check and fix text coords to avoid clipping",
179  OFFSET(fix_bounds), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
180 
181  /* FT_LOAD_* flags */
182  { "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" },
183  { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
184  { "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
185  { "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
186  { "render", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_RENDER }, .flags = FLAGS, .unit = "ft_load_flags" },
187  { "no_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
188  { "vertical_layout", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags = FLAGS, .unit = "ft_load_flags" },
189  { "force_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_FORCE_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
190  { "crop_bitmap", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_CROP_BITMAP }, .flags = FLAGS, .unit = "ft_load_flags" },
191  { "pedantic", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_PEDANTIC }, .flags = FLAGS, .unit = "ft_load_flags" },
192  { "ignore_global_advance_width", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags = FLAGS, .unit = "ft_load_flags" },
193  { "no_recurse", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_RECURSE }, .flags = FLAGS, .unit = "ft_load_flags" },
194  { "ignore_transform", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags = FLAGS, .unit = "ft_load_flags" },
195  { "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
196  { "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
197  { "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
198  { NULL},
199 };
200 
201 static const char *drawtext_get_name(void *ctx)
202 {
203  return "drawtext";
204 }
205 
206 static const AVClass drawtext_class = {
207  "DrawTextContext",
209  drawtext_options
210 };
211 
212 #undef __FTERRORS_H__
213 #define FT_ERROR_START_LIST {
214 #define FT_ERRORDEF(e, v, s) { (e), (s) },
215 #define FT_ERROR_END_LIST { 0, NULL } };
216 
217 struct ft_error
218 {
219  int err;
220  const char *err_msg;
221 } static ft_errors[] =
222 #include FT_ERRORS_H
223 
224 #define FT_ERRMSG(e) ft_errors[e].err_msg
225 
226 typedef struct Glyph {
227  FT_Glyph *glyph;
228  uint32_t code;
229  FT_Bitmap bitmap;
230  FT_BBox bbox;
231  int advance;
232  int bitmap_left;
233  int bitmap_top;
234 } Glyph;
235 
236 static int glyph_cmp(void *key, const void *b)
237 {
238  const Glyph *a = key, *bb = b;
239  int64_t diff = (int64_t)a->code - (int64_t)bb->code;
240  return diff > 0 ? 1 : diff < 0 ? -1 : 0;
241 }
242 
246 static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
247 {
248  DrawTextContext *s = ctx->priv;
249  Glyph *glyph;
250  struct AVTreeNode *node = NULL;
251  int ret;
252 
253  /* load glyph into s->face->glyph */
254  if (FT_Load_Char(s->face, code, s->ft_load_flags))
255  return AVERROR(EINVAL);
256 
257  /* save glyph */
258  if (!(glyph = av_mallocz(sizeof(*glyph))) ||
259  !(glyph->glyph = av_mallocz(sizeof(*glyph->glyph)))) {
260  ret = AVERROR(ENOMEM);
261  goto error;
262  }
263  glyph->code = code;
264 
265  if (FT_Get_Glyph(s->face->glyph, glyph->glyph)) {
266  ret = AVERROR(EINVAL);
267  goto error;
268  }
269 
270  glyph->bitmap = s->face->glyph->bitmap;
271  glyph->bitmap_left = s->face->glyph->bitmap_left;
272  glyph->bitmap_top = s->face->glyph->bitmap_top;
273  glyph->advance = s->face->glyph->advance.x >> 6;
274 
275  /* measure text height to calculate text_height (or the maximum text height) */
276  FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
277 
278  /* cache the newly created glyph */
279  if (!(node = av_tree_node_alloc())) {
280  ret = AVERROR(ENOMEM);
281  goto error;
282  }
283  av_tree_insert(&s->glyphs, glyph, glyph_cmp, &node);
284 
285  if (glyph_ptr)
286  *glyph_ptr = glyph;
287  return 0;
288 
289 error:
290  if (glyph)
291  av_freep(&glyph->glyph);
292  av_freep(&glyph);
293  av_freep(&node);
294  return ret;
295 }
296 
297 static int parse_font(AVFilterContext *ctx)
298 {
299  DrawTextContext *s = ctx->priv;
300 #if !CONFIG_LIBFONTCONFIG
301  if (!s->fontfile) {
302  av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
303  return AVERROR(EINVAL);
304  }
305 
306  return 0;
307 #else
308  FcPattern *pat, *best;
309  FcResult result = FcResultMatch;
310 
311  FcBool fc_bool;
312  FcChar8* fc_string;
313  int err = AVERROR(ENOENT);
314 
315  if (s->fontfile)
316  return 0;
317 
318  if (!FcInit())
319  return AVERROR_UNKNOWN;
320 
321  if (!(pat = FcPatternCreate()))
322  return AVERROR(ENOMEM);
323 
324  FcPatternAddString(pat, FC_FAMILY, s->font);
325  FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
326  FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize);
327 
328  FcDefaultSubstitute(pat);
329 
330  if (!FcConfigSubstitute(NULL, pat, FcMatchPattern)) {
331  FcPatternDestroy(pat);
332  return AVERROR(ENOMEM);
333  }
334 
335  best = FcFontMatch(NULL, pat, &result);
336  FcPatternDestroy(pat);
337 
338  if (!best || result == FcResultNoMatch) {
339  av_log(ctx, AV_LOG_ERROR,
340  "Cannot find a valid font for the family %s\n",
341  s->font);
342  goto fail;
343  }
344 
345  if (FcPatternGetBool(best, FC_OUTLINE, 0, &fc_bool) != FcResultMatch ||
346  !fc_bool) {
347  av_log(ctx, AV_LOG_ERROR, "Outline not available for %s\n",
348  s->font);
349  goto fail;
350  }
351 
352  if (FcPatternGetString(best, FC_FAMILY, 0, &fc_string) != FcResultMatch) {
353  av_log(ctx, AV_LOG_ERROR, "No matches for %s\n",
354  s->font);
355  goto fail;
356  }
357 
358  if (FcPatternGetString(best, FC_FILE, 0, &fc_string) != FcResultMatch) {
359  av_log(ctx, AV_LOG_ERROR, "No file path for %s\n",
360  s->font);
361  goto fail;
362  }
363 
364  s->fontfile = av_strdup(fc_string);
365  if (!s->fontfile)
366  err = AVERROR(ENOMEM);
367  else
368  err = 0;
369 
370 fail:
371  FcPatternDestroy(best);
372  return err;
373 #endif
374 }
375 
376 static av_cold int init(AVFilterContext *ctx)
377 {
378  int err;
379  DrawTextContext *s = ctx->priv;
380  Glyph *glyph;
381 
382  if ((err = parse_font(ctx)) < 0)
383  return err;
384 
385  if (s->textfile) {
386  uint8_t *textbuf;
387  size_t textbuf_size;
388 
389  if (s->text) {
390  av_log(ctx, AV_LOG_ERROR,
391  "Both text and text file provided. Please provide only one\n");
392  return AVERROR(EINVAL);
393  }
394  if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
395  av_log(ctx, AV_LOG_ERROR,
396  "The text file '%s' could not be read or is empty\n",
397  s->textfile);
398  return err;
399  }
400 
401  if (!(s->text = av_malloc(textbuf_size+1)))
402  return AVERROR(ENOMEM);
403  memcpy(s->text, textbuf, textbuf_size);
404  s->text[textbuf_size] = 0;
405  av_file_unmap(textbuf, textbuf_size);
406  }
407 
408  if (!s->text) {
409  av_log(ctx, AV_LOG_ERROR,
410  "Either text or a valid file must be provided\n");
411  return AVERROR(EINVAL);
412  }
413 
414  if ((err = av_parse_color(s->fontcolor_rgba, s->fontcolor_string, -1, ctx))) {
415  av_log(ctx, AV_LOG_ERROR,
416  "Invalid font color '%s'\n", s->fontcolor_string);
417  return err;
418  }
419 
420  if ((err = av_parse_color(s->boxcolor_rgba, s->boxcolor_string, -1, ctx))) {
421  av_log(ctx, AV_LOG_ERROR,
422  "Invalid box color '%s'\n", s->boxcolor_string);
423  return err;
424  }
425 
426  if ((err = av_parse_color(s->shadowcolor_rgba, s->shadowcolor_string, -1, ctx))) {
427  av_log(ctx, AV_LOG_ERROR,
428  "Invalid shadow color '%s'\n", s->shadowcolor_string);
429  return err;
430  }
431 
432  if ((err = FT_Init_FreeType(&(s->library)))) {
433  av_log(ctx, AV_LOG_ERROR,
434  "Could not load FreeType: %s\n", FT_ERRMSG(err));
435  return AVERROR(EINVAL);
436  }
437 
438  /* load the face, and set up the encoding, which is by default UTF-8 */
439  if ((err = FT_New_Face(s->library, s->fontfile, 0, &s->face))) {
440  av_log(ctx, AV_LOG_ERROR, "Could not load fontface from file '%s': %s\n",
441  s->fontfile, FT_ERRMSG(err));
442  return AVERROR(EINVAL);
443  }
444  if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
445  av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
446  s->fontsize, FT_ERRMSG(err));
447  return AVERROR(EINVAL);
448  }
449 
450  s->use_kerning = FT_HAS_KERNING(s->face);
451 
452  /* load the fallback glyph with code 0 */
453  load_glyph(ctx, NULL, 0);
454 
455  /* set the tabsize in pixels */
456  if ((err = load_glyph(ctx, &glyph, ' ') < 0)) {
457  av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
458  return err;
459  }
460  s->tabsize *= glyph->advance;
461 
462 #if !HAVE_LOCALTIME_R
463  av_log(ctx, AV_LOG_WARNING, "strftime() expansion unavailable!\n");
464 #endif
465 
466  return 0;
467 }
468 
470 {
471  static const enum AVPixelFormat pix_fmts[] = {
479  };
480 
482  return 0;
483 }
484 
485 static int glyph_enu_free(void *opaque, void *elem)
486 {
487  av_free(elem);
488  return 0;
489 }
490 
491 static av_cold void uninit(AVFilterContext *ctx)
492 {
493  DrawTextContext *s = ctx->priv;
494  int i;
495 
496  av_expr_free(s->x_pexpr);
497  av_expr_free(s->y_pexpr);
498  av_expr_free(s->d_pexpr);
499  s->x_pexpr = s->y_pexpr = s->d_pexpr = NULL;
500  av_freep(&s->expanded_text);
501  av_freep(&s->positions);
504  s->glyphs = 0;
505  FT_Done_Face(s->face);
506  FT_Done_FreeType(s->library);
507 
508  for (i = 0; i < 4; i++) {
509  av_freep(&s->box_line[i]);
510  s->pixel_step[i] = 0;
511  }
512 
513 }
514 
515 static inline int is_newline(uint32_t c)
516 {
517  return c == '\n' || c == '\r' || c == '\f' || c == '\v';
518 }
519 
521 {
522  DrawTextContext *s = ctx->priv;
523  uint32_t code = 0, prev_code = 0;
524  int x = 0, y = 0, i = 0, ret;
525  int text_height, baseline;
526  char *text = s->text;
527  uint8_t *p;
528  int str_w = 0, len;
529  int y_min = 32000, y_max = -32000;
530  FT_Vector delta;
531  Glyph *glyph = NULL, *prev_glyph = NULL;
532  Glyph dummy = { 0 };
533  int width = ctx->inputs[0]->w;
534  int height = ctx->inputs[0]->h;
535 
536 #if HAVE_LOCALTIME_R
537  time_t now = time(0);
538  struct tm ltime;
539  uint8_t *buf = s->expanded_text;
540  int buf_size = s->expanded_text_size;
541 
542  if (!buf)
543  buf_size = 2*strlen(s->text)+1;
544 
545  localtime_r(&now, &ltime);
546 
547  while ((buf = av_realloc(buf, buf_size))) {
548  *buf = 1;
549  if (strftime(buf, buf_size, s->text, &ltime) != 0 || *buf == 0)
550  break;
551  buf_size *= 2;
552  }
553 
554  if (!buf)
555  return AVERROR(ENOMEM);
556  text = s->expanded_text = buf;
557  s->expanded_text_size = buf_size;
558 #endif
559 
560  if ((len = strlen(text)) > s->nb_positions) {
561  FT_Vector *p = av_realloc(s->positions,
562  len * sizeof(*s->positions));
563  if (!p) {
564  av_freep(s->positions);
565  s->nb_positions = 0;
566  return AVERROR(ENOMEM);
567  } else {
568  s->positions = p;
569  s->nb_positions = len;
570  }
571  }
572 
573  /* load and cache glyphs */
574  for (i = 0, p = text; *p; i++) {
575  GET_UTF8(code, *p++, continue;);
576 
577  /* get glyph */
578  dummy.code = code;
579  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
580  if (!glyph) {
581  ret = load_glyph(ctx, &glyph, code);
582  if (ret)
583  return ret;
584  }
585 
586  y_min = FFMIN(glyph->bbox.yMin, y_min);
587  y_max = FFMAX(glyph->bbox.yMax, y_max);
588  }
589  text_height = y_max - y_min;
590  baseline = y_max;
591 
592  /* compute and save position for each glyph */
593  glyph = NULL;
594  for (i = 0, p = text; *p; i++) {
595  GET_UTF8(code, *p++, continue;);
596 
597  /* skip the \n in the sequence \r\n */
598  if (prev_code == '\r' && code == '\n')
599  continue;
600 
601  prev_code = code;
602  if (is_newline(code)) {
603  str_w = FFMAX(str_w, x - s->x);
604  y += text_height;
605  x = 0;
606  continue;
607  }
608 
609  /* get glyph */
610  prev_glyph = glyph;
611  dummy.code = code;
612  glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
613 
614  /* kerning */
615  if (s->use_kerning && prev_glyph && glyph->code) {
616  FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
617  ft_kerning_default, &delta);
618  x += delta.x >> 6;
619  }
620 
621  if (x + glyph->bbox.xMax >= width) {
622  str_w = FFMAX(str_w, x);
623  y += text_height;
624  x = 0;
625  }
626 
627  /* save position */
628  s->positions[i].x = x + glyph->bitmap_left;
629  s->positions[i].y = y - glyph->bitmap_top + baseline;
630  if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
631  else x += glyph->advance;
632  }
633 
634  str_w = FFMIN(width - 1, FFMAX(str_w, x));
635  y = FFMIN(y + text_height, height - 1);
636 
637  s->w = str_w;
638  s->var_values[VAR_TEXT_W] = s->var_values[VAR_TW] = s->w;
639  s->h = y;
640  s->var_values[VAR_TEXT_H] = s->var_values[VAR_TH] = s->h;
641 
642  return 0;
643 }
644 
645 
646 static int config_input(AVFilterLink *inlink)
647 {
648  AVFilterContext *ctx = inlink->dst;
649  DrawTextContext *s = ctx->priv;
650  const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
651  int ret;
652 
653  s->hsub = pix_desc->log2_chroma_w;
654  s->vsub = pix_desc->log2_chroma_h;
655 
656  s->var_values[VAR_E ] = M_E;
657  s->var_values[VAR_PHI] = M_PHI;
658  s->var_values[VAR_PI ] = M_PI;
659 
660  s->var_values[VAR_MAIN_W] =
661  s->var_values[VAR_MW] = ctx->inputs[0]->w;
662  s->var_values[VAR_MAIN_H] =
663  s->var_values[VAR_MH] = ctx->inputs[0]->h;
664 
665  s->var_values[VAR_X] = 0;
666  s->var_values[VAR_Y] = 0;
667  s->var_values[VAR_T] = NAN;
668 
670 
671  av_expr_free(s->x_pexpr);
672  av_expr_free(s->y_pexpr);
673  av_expr_free(s->d_pexpr);
674  s->x_pexpr = s->y_pexpr = s->d_pexpr = NULL;
675  if ((ret = av_expr_parse(&s->x_pexpr, s->x_expr, var_names,
676  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
677  (ret = av_expr_parse(&s->y_pexpr, s->y_expr, var_names,
678  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
679  (ret = av_expr_parse(&s->d_pexpr, s->d_expr, var_names,
680  NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
681  return AVERROR(EINVAL);
682 
683  if ((ret =
685  inlink->w, s->boxcolor,
686  inlink->format, s->boxcolor_rgba,
687  &s->is_packed_rgb, s->rgba_map)) < 0)
688  return ret;
689 
690  if (!s->is_packed_rgb) {
691  uint8_t *rgba = s->fontcolor_rgba;
692  s->fontcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
693  s->fontcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
694  s->fontcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
695  s->fontcolor[3] = rgba[3];
696  rgba = s->shadowcolor_rgba;
697  s->shadowcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
698  s->shadowcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
699  s->shadowcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
700  s->shadowcolor[3] = rgba[3];
701  }
702 
703  s->draw = 1;
704 
705  return dtext_prepare_text(ctx);
706 }
707 
708 #define GET_BITMAP_VAL(r, c) \
709  bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? \
710  (bitmap->buffer[(r) * bitmap->pitch + ((c)>>3)] & (0x80 >> ((c)&7))) * 255 : \
711  bitmap->buffer[(r) * bitmap->pitch + (c)]
712 
713 #define SET_PIXEL_YUV(frame, yuva_color, val, x, y, hsub, vsub) { \
714  luma_pos = ((x) ) + ((y) ) * frame->linesize[0]; \
715  alpha = yuva_color[3] * (val) * 129; \
716  frame->data[0][luma_pos] = (alpha * yuva_color[0] + (255*255*129 - alpha) * frame->data[0][luma_pos] ) >> 23; \
717  if (((x) & ((1<<(hsub)) - 1)) == 0 && ((y) & ((1<<(vsub)) - 1)) == 0) {\
718  chroma_pos1 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[1]; \
719  chroma_pos2 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[2]; \
720  frame->data[1][chroma_pos1] = (alpha * yuva_color[1] + (255*255*129 - alpha) * frame->data[1][chroma_pos1]) >> 23; \
721  frame->data[2][chroma_pos2] = (alpha * yuva_color[2] + (255*255*129 - alpha) * frame->data[2][chroma_pos2]) >> 23; \
722  }\
723 }
724 
725 static inline int draw_glyph_yuv(AVFrame *frame, FT_Bitmap *bitmap, unsigned int x,
726  unsigned int y, unsigned int width, unsigned int height,
727  const uint8_t yuva_color[4], int hsub, int vsub)
728 {
729  int r, c, alpha;
730  unsigned int luma_pos, chroma_pos1, chroma_pos2;
731  uint8_t src_val;
732 
733  for (r = 0; r < bitmap->rows && r+y < height; r++) {
734  for (c = 0; c < bitmap->width && c+x < width; c++) {
735  /* get intensity value in the glyph bitmap (source) */
736  src_val = GET_BITMAP_VAL(r, c);
737  if (!src_val)
738  continue;
739 
740  SET_PIXEL_YUV(frame, yuva_color, src_val, c+x, y+r, hsub, vsub);
741  }
742  }
743 
744  return 0;
745 }
746 
747 #define SET_PIXEL_RGB(frame, rgba_color, val, x, y, pixel_step, r_off, g_off, b_off, a_off) { \
748  p = frame->data[0] + (x) * pixel_step + ((y) * frame->linesize[0]); \
749  alpha = rgba_color[3] * (val) * 129; \
750  *(p+r_off) = (alpha * rgba_color[0] + (255*255*129 - alpha) * *(p+r_off)) >> 23; \
751  *(p+g_off) = (alpha * rgba_color[1] + (255*255*129 - alpha) * *(p+g_off)) >> 23; \
752  *(p+b_off) = (alpha * rgba_color[2] + (255*255*129 - alpha) * *(p+b_off)) >> 23; \
753 }
754 
755 static inline int draw_glyph_rgb(AVFrame *frame, FT_Bitmap *bitmap,
756  unsigned int x, unsigned int y,
757  unsigned int width, unsigned int height, int pixel_step,
758  const uint8_t rgba_color[4], const uint8_t rgba_map[4])
759 {
760  int r, c, alpha;
761  uint8_t *p;
762  uint8_t src_val;
763 
764  for (r = 0; r < bitmap->rows && r+y < height; r++) {
765  for (c = 0; c < bitmap->width && c+x < width; c++) {
766  /* get intensity value in the glyph bitmap (source) */
767  src_val = GET_BITMAP_VAL(r, c);
768  if (!src_val)
769  continue;
770 
771  SET_PIXEL_RGB(frame, rgba_color, src_val, c+x, y+r, pixel_step,
772  rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
773  }
774  }
775 
776  return 0;
777 }
778 
779 static inline void drawbox(AVFrame *frame, unsigned int x, unsigned int y,
780  unsigned int width, unsigned int height,
781  uint8_t *line[4], int pixel_step[4], uint8_t color[4],
782  int hsub, int vsub, int is_rgba_packed, uint8_t rgba_map[4])
783 {
784  int i, j, alpha;
785 
786  if (color[3] != 0xFF) {
787  if (is_rgba_packed) {
788  uint8_t *p;
789  for (j = 0; j < height; j++)
790  for (i = 0; i < width; i++)
791  SET_PIXEL_RGB(frame, color, 255, i+x, y+j, pixel_step[0],
792  rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
793  } else {
794  unsigned int luma_pos, chroma_pos1, chroma_pos2;
795  for (j = 0; j < height; j++)
796  for (i = 0; i < width; i++)
797  SET_PIXEL_YUV(frame, color, 255, i+x, y+j, hsub, vsub);
798  }
799  } else {
800  ff_draw_rectangle(frame->data, frame->linesize,
801  line, pixel_step, hsub, vsub,
802  x, y, width, height);
803  }
804 }
805 
806 static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
807  int width, int height, const uint8_t rgbcolor[4], const uint8_t yuvcolor[4], int x, int y)
808 {
809  char *text = HAVE_LOCALTIME_R ? s->expanded_text : s->text;
810  uint32_t code = 0;
811  int i;
812  uint8_t *p;
813  Glyph *glyph = NULL;
814 
815  for (i = 0, p = text; *p; i++) {
816  Glyph dummy = { 0 };
817  GET_UTF8(code, *p++, continue;);
818 
819  /* skip new line chars, just go to new line */
820  if (code == '\n' || code == '\r' || code == '\t')
821  continue;
822 
823  dummy.code = code;
824  glyph = av_tree_find(s->glyphs, &dummy, (void *)glyph_cmp, NULL);
825 
826  if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
827  glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
828  return AVERROR(EINVAL);
829 
830  if (s->is_packed_rgb) {
831  draw_glyph_rgb(frame, &glyph->bitmap,
832  s->positions[i].x+x, s->positions[i].y+y, width, height,
833  s->pixel_step[0], rgbcolor, s->rgba_map);
834  } else {
835  draw_glyph_yuv(frame, &glyph->bitmap,
836  s->positions[i].x+x, s->positions[i].y+y, width, height,
837  yuvcolor, s->hsub, s->vsub);
838  }
839  }
840 
841  return 0;
842 }
843 
844 static int draw_text(AVFilterContext *ctx, AVFrame *frame,
845  int width, int height)
846 {
847  DrawTextContext *s = ctx->priv;
848  int ret;
849 
850  /* draw box */
851  if (s->draw_box)
852  drawbox(frame, s->x, s->y, s->w, s->h,
853  s->box_line, s->pixel_step, s->boxcolor,
854  s->hsub, s->vsub, s->is_packed_rgb,
855  s->rgba_map);
856 
857  if (s->shadowx || s->shadowy) {
858  if ((ret = draw_glyphs(s, frame, width, height,
859  s->shadowcolor_rgba,
860  s->shadowcolor,
861  s->x + s->shadowx,
862  s->y + s->shadowy)) < 0)
863  return ret;
864  }
865 
866  if ((ret = draw_glyphs(s, frame, width, height,
867  s->fontcolor_rgba,
868  s->fontcolor,
869  s->x,
870  s->y)) < 0)
871  return ret;
872 
873  return 0;
874 }
875 
876 static inline int normalize_double(int *n, double d)
877 {
878  int ret = 0;
879 
880  if (isnan(d)) {
881  ret = AVERROR(EINVAL);
882  } else if (d > INT_MAX || d < INT_MIN) {
883  *n = d > INT_MAX ? INT_MAX : INT_MIN;
884  ret = AVERROR(EINVAL);
885  } else
886  *n = round(d);
887 
888  return ret;
889 }
890 
891 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
892 {
893  AVFilterContext *ctx = inlink->dst;
894  DrawTextContext *s = ctx->priv;
895  int ret = 0;
896 
897  if ((ret = dtext_prepare_text(ctx)) < 0) {
898  av_log(ctx, AV_LOG_ERROR, "Can't draw text\n");
899  av_frame_free(&frame);
900  return ret;
901  }
902 
903  s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
904  NAN : frame->pts * av_q2d(inlink->time_base);
905  s->var_values[VAR_X] =
906  av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
907  s->var_values[VAR_Y] =
908  av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
909  s->var_values[VAR_X] =
910  av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
911 
912  s->draw = av_expr_eval(s->d_pexpr, s->var_values, &s->prng);
913 
916 
917  if (s->fix_bounds) {
918  if (s->x < 0) s->x = 0;
919  if (s->y < 0) s->y = 0;
920  if ((unsigned)s->x + (unsigned)s->w > inlink->w)
921  s->x = inlink->w - s->w;
922  if ((unsigned)s->y + (unsigned)s->h > inlink->h)
923  s->y = inlink->h - s->h;
924  }
925 
926  s->x &= ~((1 << s->hsub) - 1);
927  s->y &= ~((1 << s->vsub) - 1);
928 
929  av_dlog(ctx, "n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n",
930  (int)s->var_values[VAR_N], s->var_values[VAR_T],
931  s->x, s->y, s->x+s->w, s->y+s->h);
932 
933  if (s->draw)
934  draw_text(inlink->dst, frame, frame->width, frame->height);
935 
936  s->var_values[VAR_N] += 1.0;
937 
938  return ff_filter_frame(inlink->dst->outputs[0], frame);
939 }
940 
942  {
943  .name = "default",
944  .type = AVMEDIA_TYPE_VIDEO,
945  .get_video_buffer = ff_null_get_video_buffer,
946  .filter_frame = filter_frame,
947  .config_props = config_input,
948  .needs_writable = 1,
949  },
950  { NULL }
951 };
952 
954  {
955  .name = "default",
956  .type = AVMEDIA_TYPE_VIDEO,
957  },
958  { NULL }
959 };
960 
962  .name = "drawtext",
963  .description = NULL_IF_CONFIG_SMALL("Draw text on top of video frames using libfreetype library."),
964  .priv_size = sizeof(DrawTextContext),
965  .priv_class = &drawtext_class,
966  .init = init,
967  .uninit = uninit,
969 
970  .inputs = avfilter_vf_drawtext_inputs,
971  .outputs = avfilter_vf_drawtext_outputs,
972 };
Definition: lfg.h:25
int draw
set to zero to prevent drawing
Definition: vf_drawtext.c:153
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
#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:252
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:1599
This structure describes decoded (raw) audio or video data.
Definition: frame.h:135
AVOption.
Definition: opt.h:234
static double drand(void *opaque, double min, double max)
Definition: vf_drawtext.c:81
static const AVOption drawtext_options[]
Definition: vf_drawtext.c:160
unsigned int fontsize
font size to use
Definition: vf_drawtext.c:124
static const char * drawtext_get_name(void *ctx)
Definition: vf_drawtext.c:201
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:70
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:129
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:232
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:67
uint8_t * fontfile
font to be used
Definition: vf_drawtext.c:113
#define FLAGS
Definition: vf_drawtext.c:158
static int draw_glyphs(DrawTextContext *s, AVFrame *frame, int width, int height, const uint8_t rgbcolor[4], const uint8_t yuvcolor[4], int x, int y)
Definition: vf_drawtext.c:806
Various defines for YUV<->RGB conversion.
AVFrame * ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
Definition: video.c:30
static int draw_text(AVFilterContext *ctx, AVFrame *frame, int width, int height)
Definition: vf_drawtext.c:844
uint8_t * text
text to be drawn
Definition: vf_drawtext.c:114
uint8_t * box_line[4]
line used for filling the box background
Definition: vf_drawtext.c:147
av_dlog(ac->avr,"%d samples - audio_convert: %s to %s (%s)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic?ac->func_descr_generic:ac->func_descr)
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:492
#define SET_PIXEL_RGB(frame, rgba_color, val, x, y, pixel_step, r_off, g_off, b_off, a_off)
Definition: vf_drawtext.c:747
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:80
uint8_t shadowcolor[4]
shadow color
Definition: vf_drawtext.c:130
uint8_t boxcolor_rgba[4]
background color in RGBA
Definition: vf_drawtext.c:132
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
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:165
uint8_t fontcolor_rgba[4]
foreground color in RGBA
Definition: vf_drawtext.c:131
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:36
const char * name
Pad name.
Definition: internal.h:42
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:571
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:728
static int glyph_enu_free(void *opaque, void *elem)
Definition: vf_drawtext.c:485
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(void *key, const void *b), void *next[2])
Definition: tree.c:41
uint8_t
#define av_cold
Definition: attributes.h:66
float delta
AVOptions.
A tree container.
AVLFG prng
random
Definition: vf_drawtext.c:154
static av_always_inline av_const int isnan(float x)
Definition: libm.h:85
#define b
Definition: input.c:52
FT_Face face
freetype font face handle
Definition: vf_drawtext.c:141
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:211
static av_cold int init(AVFilterContext *ctx)
Definition: vf_drawtext.c:376
Definition: eval.c:128
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:97
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:941
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_drawtext.c:491
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:379
FT_Vector * positions
positions for each element in the text
Definition: vf_drawtext.c:118
AVExpr * x_pexpr
Definition: vf_drawtext.c:149
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:148
#define r
Definition: input.c:51
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:300
char * fontcolor_string
font color as string
Definition: vf_drawtext.c:125
A filter pad used for either input or output.
Definition: internal.h:36
uint8_t fontcolor[4]
foreground color
Definition: vf_drawtext.c:128
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:61
double var_values[VAR_VARS_NB]
Definition: vf_drawtext.c:150
int width
width and height of the video frame
Definition: frame.h:174
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:123
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
Definition: file.c:129
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:186
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:49
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:69
AVExpr * y_pexpr
parsed expressions for x and y
Definition: vf_drawtext.c:149
const char * err_msg
Definition: vf_drawtext.c:220
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:150
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:98
void * priv
private data for use by the filter
Definition: avfilter.h:584
int y
position to start drawing text
Definition: vf_drawtext.c:121
#define HAVE_LOCALTIME_R
Definition: config.h:227
Definition: graph2dot.c:49
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:168
static av_always_inline av_const double round(double x)
Definition: libm.h:151
static int dtext_prepare_text(AVFilterContext *ctx)
Definition: vf_drawtext.c:520
#define GET_BITMAP_VAL(r, c)
Definition: vf_drawtext.c:708
#define FFMAX(a, b)
Definition: common.h:55
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:95
static const char *const fun2_names[]
Definition: vf_drawtext.c:77
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:96
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:69
#define FFMIN(a, b)
Definition: common.h:57
#define M_E
Definition: ratecontrol.c:39
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:68
static int draw_glyph_yuv(AVFrame *frame, FT_Bitmap *bitmap, unsigned int x, unsigned int y, unsigned int width, unsigned int height, const uint8_t yuva_color[4], int hsub, int vsub)
Definition: vf_drawtext.c:725
double(* eval_func2)(void *, double a, double b)
Definition: vf_drawtext.c:86
NULL
Definition: eval.c:55
static int width
Definition: utils.c:156
char * boxcolor_string
box color as string
Definition: vf_drawtext.c:126
misc drawing utilities
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:195
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:213
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:153
size_t expanded_text_size
size in bytes of the expanded_text buffer
Definition: vf_drawtext.c:116
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
int pixel_step[4]
distance in bytes between the component of each pixel
Definition: vf_drawtext.c:145
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition: lfg.h:38
static int draw_glyph_rgb(AVFrame *frame, FT_Bitmap *bitmap, unsigned int x, unsigned int y, unsigned int width, unsigned int height, int pixel_step, const uint8_t rgba_color[4], const uint8_t rgba_map[4])
Definition: vf_drawtext.c:755
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:71
Describe the class of an AVClass context structure.
Definition: log.h:33
Filter definition.
Definition: avfilter.h:421
int tabsize
tab size
Definition: vf_drawtext.c:137
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:221
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
Definition: vf_drawtext.c:142
#define M_PHI
Definition: mathematics.h:34
int h
dimension of the text block
Definition: vf_drawtext.c:122
static int is_newline(uint32_t c)
Definition: vf_drawtext.c:515
const char * name
Filter name.
Definition: avfilter.h:425
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:30
misc parsing utilities
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:578
struct ft_error ft_errors[]
short int draw_box
draw box around text - true or false
Definition: vf_drawtext.c:135
static int config_input(AVFilterLink *inlink)
Definition: vf_drawtext.c:646
static void drawbox(AVFrame *frame, unsigned int x, unsigned int y, unsigned int width, unsigned int height, uint8_t *line[4], int pixel_step[4], uint8_t color[4], int hsub, int vsub, int is_rgba_packed, uint8_t rgba_map[4])
Definition: vf_drawtext.c:779
#define RGB_TO_U_CCIR(r1, g1, b1, shift)
Definition: colorspace.h:103
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:141
#define RGB_TO_V_CCIR(r1, g1, b1, shift)
Definition: colorspace.h:107
int height
Definition: gxfenc.c:72
uint8_t shadowcolor_rgba[4]
shadow color in RGBA
Definition: vf_drawtext.c:133
uint8_t rgba_map[4]
map RGBA offsets to the positions in the packed RGBA format
Definition: vf_drawtext.c:146
static const AVClass drawtext_class
Definition: vf_drawtext.c:206
static const char *const var_names[]
Definition: vf_drawtext.c:62
int use_kerning
font kerning is used - true/false
Definition: vf_drawtext.c:136
static int parse_font(AVFilterContext *ctx)
Definition: vf_drawtext.c:297
int vsub
chroma subsampling values
Definition: vf_drawtext.c:143
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:65
char * shadowcolor_string
shadow color as string
Definition: vf_drawtext.c:127
common internal and external API header
static int glyph_cmp(void *key, const void *b)
Definition: vf_drawtext.c:236
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:117
static int query_formats(AVFilterContext *ctx)
Definition: vf_drawtext.c:469
FT_Library library
freetype font library handle
Definition: vf_drawtext.c:140
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:72
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:61
static const uint8_t color[]
Definition: log.c:55
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_drawtext.c:891
static const AVFilterPad avfilter_vf_drawtext_outputs[]
Definition: vf_drawtext.c:953
AVFilter ff_vf_drawtext
Definition: vf_drawtext.c:961
#define RGB_TO_Y_CCIR(r, g, b)
Definition: colorspace.h:99
#define NAN
Definition: math.h:28
int len
uint8_t * expanded_text
used to contain the strftime()-expanded text
Definition: vf_drawtext.c:115
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:542
#define FT_ERRMSG(e)
int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4], enum AVPixelFormat pix_fmt, uint8_t rgba_color[4], int *is_packed_rgba, uint8_t rgba_map_ptr[4])
Definition: drawutils.c:29
#define OFFSET(x)
Definition: vf_drawtext.c:157
uint8_t boxcolor[4]
background color
Definition: vf_drawtext.c:129
An instance of a filter.
Definition: avfilter.h:563
static const eval_func2 fun2[]
Definition: vf_drawtext.c:88
int height
Definition: frame.h:174
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:102
int fix_bounds
do we let it go out of frame bounds - t/f
Definition: vf_drawtext.c:138
uint32_t av_get_random_seed(void)
Get random data.
Definition: random_seed.c:95
char * textfile
file with text to be drawn
Definition: vf_drawtext.c:120
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:246
void ff_draw_rectangle(uint8_t *dst[4], int dst_linesize[4], uint8_t *src[4], int pixelstep[4], int hsub, int vsub, int x, int y, int w, int h)
Definition: drawutils.c:82
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
Definition: vf_drawtext.c:117
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:157
float min
size_t nb_positions
number of elements of positions array
Definition: vf_drawtext.c:119
AVPixelFormat
Pixel format.
Definition: pixfmt.h:63
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 normalize_double(int *n, double d)
Definition: vf_drawtext.c:876
var_name
Definition: setpts.c:60
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:228
#define SET_PIXEL_YUV(frame, yuva_color, val, x, y, hsub, vsub)
Definition: vf_drawtext.c:713
void * elem
Definition: tree.c:28
simple arithmetic expression evaluator
AVExpr * d_pexpr
Definition: vf_drawtext.c:152