Go to the documentation of this file.
35 #include <sys/types.h>
43 #if CONFIG_LIBFONTCONFIG
44 #include <fontconfig/fontconfig.h>
72 #include FT_FREETYPE_H
80 #define POS_CEIL(x, y) ((x)/(y) + ((x)%(y) != 0))
88 "max_glyph_a",
"ascent",
89 "max_glyph_d",
"descent",
107 #if FF_API_PKT_DURATION
158 #if FF_API_PKT_DURATION
257 #if CONFIG_LIBFONTCONFIG
318 #if CONFIG_LIBFRIBIDI
336 #define OFFSET(x) offsetof(DrawTextContext, x)
337 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
338 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
375 #if CONFIG_LIBFONTCONFIG
396 {
"start_number",
"start frame number for n/frame_num variable",
OFFSET(start_number),
AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX,
FLAGS},
399 #if CONFIG_LIBFRIBIDI
404 {
"ft_load_flags",
"set font loading flags for libfreetype",
OFFSET(ft_load_flags),
AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT }, 0, INT_MAX,
FLAGS,
"ft_load_flags" },
410 {
"vertical_layout",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags =
FLAGS, .unit =
"ft_load_flags" },
414 {
"ignore_global_advance_width",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags =
FLAGS, .unit =
"ft_load_flags" },
416 {
"ignore_transform",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags =
FLAGS, .unit =
"ft_load_flags" },
425 #undef __FTERRORS_H__
426 #define FT_ERROR_START_LIST {
427 #define FT_ERRORDEF(e, v, s) { (e), (s) },
428 #define FT_ERROR_END_LIST { 0, NULL } };
436 #define FT_ERRMSG(e) ft_errors[e].err_msg
438 static int glyph_cmp(
const void *
key,
const void *
b)
441 int64_t
diff = (int64_t)
a->code - (int64_t)bb->code;
444 return diff > 0 ? 1 : -1;
446 return FFDIFFSIGN((int64_t)
a->fontsize, (int64_t)bb->fontsize);
454 if ((err = FT_Set_Pixel_Sizes(
s->face, 0, fontsize))) {
460 s->fontsize = fontsize;
470 if (
s->fontsize_pexpr)
473 if (
s->fontsize_expr ==
NULL)
486 unsigned int fontsize =
s->default_fontsize;
488 double size, roundedsize;
491 if (
s->fontsize_expr !=
NULL) {
492 if ((err = parse_fontsize(
ctx)) < 0)
499 if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
503 fontsize = roundedsize;
511 if (fontsize ==
s->fontsize)
514 return set_fontsize(
ctx, fontsize);
522 err = FT_New_Face(
s->library, path,
index, &
s->face);
524 #if !CONFIG_LIBFONTCONFIG
533 #if CONFIG_LIBFONTCONFIG
537 FcConfig *fontconfig;
538 FcPattern *pat, *best;
539 FcResult
result = FcResultMatch;
546 fontconfig = FcInitLoadConfigAndFonts();
551 pat = FcNameParse(
s->fontfile ?
s->fontfile :
552 (uint8_t *)(intptr_t)
"default");
558 FcPatternAddString(pat, FC_FAMILY,
s->font);
560 parse_err = parse_fontsize(
ctx);
569 FcPatternAddDouble(pat, FC_SIZE,
size);
572 FcDefaultSubstitute(pat);
574 if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
576 FcPatternDestroy(pat);
580 best = FcFontMatch(fontconfig, pat, &
result);
581 FcPatternDestroy(pat);
583 if (!best ||
result != FcResultMatch) {
585 "Cannot find a valid font for the family %s\n",
591 FcPatternGetInteger(best, FC_INDEX, 0, &
index ) != FcResultMatch ||
592 FcPatternGetDouble (best, FC_SIZE, 0, &
size ) != FcResultMatch) {
597 if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
605 s->default_fontsize =
size + 0.5;
607 err = load_font_file(
ctx, filename,
index);
610 FcConfigDestroy(fontconfig);
612 FcPatternDestroy(best);
623 err = load_font_file(
ctx,
s->fontfile, 0);
626 #if CONFIG_LIBFONTCONFIG
627 err = load_font_fontconfig(
ctx);
634 static inline int is_newline(uint32_t
c)
636 return c ==
'\n' ||
c ==
'\r' ||
c ==
'\f' ||
c ==
'\v';
647 if ((err =
av_file_map(
s->textfile, &textbuf, &textbuf_size, 0,
ctx)) < 0) {
649 "The text file '%s' could not be read or is empty\n",
654 if (textbuf_size > 0 && is_newline(textbuf[textbuf_size - 1]))
656 if (textbuf_size > SIZE_MAX - 1 || !(
tmp =
av_realloc(
s->text, textbuf_size + 1))) {
661 memcpy(
s->text, textbuf, textbuf_size);
662 s->text[textbuf_size] = 0;
668 #if CONFIG_LIBFRIBIDI
674 static const FriBidiFlags
flags = FRIBIDI_FLAGS_DEFAULT |
675 FRIBIDI_FLAGS_ARABIC;
676 FriBidiChar *unicodestr =
NULL;
678 FriBidiParType direction = FRIBIDI_PAR_LTR;
679 FriBidiStrIndex line_start = 0;
680 FriBidiStrIndex line_end = 0;
681 FriBidiLevel *embedding_levels =
NULL;
682 FriBidiArabicProp *ar_props =
NULL;
683 FriBidiCharType *bidi_types =
NULL;
686 len = strlen(
s->text);
690 len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
691 s->text,
len, unicodestr);
698 fribidi_get_bidi_types(unicodestr,
len, bidi_types);
701 if (!embedding_levels) {
705 if (!fribidi_get_par_embedding_levels(bidi_types,
len, &direction,
715 fribidi_get_joining_types(unicodestr,
len, ar_props);
716 fribidi_join_arabic(bidi_types,
len, embedding_levels, ar_props);
717 fribidi_shape(
flags, embedding_levels,
len, ar_props, unicodestr);
719 for (line_end = 0, line_start = 0; line_end <
len; line_end++) {
720 if (is_newline(unicodestr[line_end]) || line_end ==
len - 1) {
721 if (!fribidi_reorder_line(
flags, bidi_types,
722 line_end - line_start + 1, line_start,
723 direction, embedding_levels, unicodestr,
727 line_start = line_end + 1;
732 for (
i = 0, j = 0;
i <
len;
i++)
733 if (unicodestr[
i] != FRIBIDI_CHAR_FILL)
734 unicodestr[j++] = unicodestr[
i];
743 len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
744 unicodestr,
len,
s->text);
760 if (!strcmp(text_source_string,
"side_data_detection_bboxes")) {
767 static inline int get_subpixel_idx(
int shift_x64,
int shift_y64)
769 int idx = (shift_x64 >> 2) + (shift_y64 >> 4);
785 dummy.fontsize =
s->fontsize;
788 if (FT_Load_Glyph(
s->face,
code,
s->ft_load_flags)) {
798 if (FT_Get_Glyph(
s->face->glyph, &glyph->
glyph)) {
804 if (FT_Glyph_StrokeBorder(&glyph->
border_glyph,
s->stroker, 0, 0)) {
810 FT_Glyph_Get_CBox(glyph->
glyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph->
bbox);
821 if (FT_Glyph_StrokeBorder(&glyph->
border_glyph,
s->stroker, 0, 0)) {
829 if (shift_x64 >= 0 && shift_y64 >= 0) {
831 int idx = get_subpixel_idx(shift_x64, shift_y64);
835 if (!glyph->
bglyph[idx]) {
836 FT_Glyph tmp_glyph = glyph->
glyph;
837 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
841 glyph->
bglyph[idx] = (FT_BitmapGlyph)tmp_glyph;
842 if (glyph->
bglyph[idx]->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
850 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
863 if (glyph && glyph->
glyph)
864 FT_Done_Glyph(glyph->
glyph);
872 static int string_to_array(
const char *
source,
int *
result,
int result_size)
879 if (result_size > 0 && (curval =
av_strtok(dup,
"|", &saveptr))) {
881 result[counter++] = atoi(curval);
882 }
while ((curval =
av_strtok(
NULL,
"|", &saveptr)) && counter < result_size);
894 s->fontsize_pexpr =
NULL;
897 s->default_fontsize = 16;
899 if (!
s->fontfile && !CONFIG_LIBFONTCONFIG) {
907 "Both text and text file provided. Please provide only one\n");
910 if ((err = load_textfile(
ctx)) < 0)
914 if (
s->reload && !
s->textfile)
917 if (
s->tc_opt_string) {
919 s->tc_opt_string,
ctx);
928 if (
s->text_source_string) {
929 s->text_source = text_source_string_parse(
s->text_source_string);
930 if ((
int)
s->text_source < 0) {
949 "Either text, a valid file, a timecode or text source must be provided\n");
953 #if CONFIG_LIBFRIBIDI
955 if ((err = shape_text(
ctx)) < 0)
959 if ((err = FT_Init_FreeType(&(
s->library)))) {
961 "Could not load FreeType: %s\n",
FT_ERRMSG(err));
965 if ((err = load_font(
ctx)) < 0)
968 if ((err = update_fontsize(
ctx)) < 0)
972 if (FT_Stroker_New(
s->library, &
s->stroker)) {
978 FT_Stroker_Set(
s->stroker,
s->borderw << 6, FT_STROKER_LINECAP_ROUND,
979 FT_STROKER_LINEJOIN_ROUND, 0);
983 load_glyph(
ctx,
NULL, 0, 0, 0);
986 (strchr(
s->text,
'%') || strchr(
s->text,
'\\')))
1000 static int glyph_enu_border_free(
void *opaque,
void *
elem)
1005 for (
int t = 0; t < 16; ++t) {
1017 static int glyph_enu_free(
void *opaque,
void *
elem)
1021 FT_Done_Glyph(glyph->
glyph);
1023 for (
int t = 0; t < 16; ++t) {
1025 FT_Done_Glyph((FT_Glyph)glyph->
bglyph[t]);
1044 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
s->fontsize_pexpr =
NULL;
1050 FT_Done_Face(
s->face);
1051 FT_Stroker_Done(
s->stroker);
1052 FT_Done_FreeType(
s->library);
1075 s->var_values[
VAR_HSUB] = 1 <<
s->dc.hsub_max;
1076 s->var_values[
VAR_VSUB] = 1 <<
s->dc.vsub_max;
1086 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
NULL;
1107 if (!strcmp(cmd,
"reinit")) {
1112 new->class = &drawtext_class;
1140 int old_borderw = old->
borderw;
1144 if (old->
borderw != old_borderw) {
1145 FT_Stroker_Set(old->
stroker, old->
borderw << 6, FT_STROKER_LINECAP_ROUND,
1146 FT_STROKER_LINEJOIN_ROUND, 0);
1149 }
else if (strcmp(cmd,
"fontsize") == 0) {
1164 char *fct,
unsigned argc,
char **argv,
int tag)
1173 char *fct,
unsigned argc,
char **argv,
int tag)
1180 fmt = argc >= 1 ? argv[0] :
"flt";
1189 if (!strcmp(fmt,
"flt")) {
1191 }
else if (!strcmp(fmt,
"hms")) {
1202 if (!strcmp(argv[2],
"24HH")) {
1203 ms %= 24 * 60 * 60 * 1000;
1209 av_bprintf(bp,
"%c%02d:%02d:%02d.%03d", sign,
1210 (
int)(ms / (60 * 60 * 1000)),
1211 (
int)(ms / (60 * 1000)) % 60,
1212 (
int)(ms / 1000) % 60,
1215 }
else if (!strcmp(fmt,
"localtime") ||
1216 !strcmp(fmt,
"gmtime")) {
1218 time_t ms = (time_t)
pts;
1219 const char *timefmt = argc >= 3 ? argv[2] :
"%Y-%m-%d %H:%M:%S";
1220 if (!strcmp(fmt,
"localtime"))
1233 char *fct,
unsigned argc,
char **argv,
int tag)
1242 char *fct,
unsigned argc,
char **argv,
int tag)
1255 char *fct,
unsigned argc,
char **argv,
int tag)
1257 const char *fmt = argc ? argv[0] :
"%Y-%m-%d %H:%M:%S";
1258 const char *fmt_begin = fmt;
1271 now = unow / 1000000;
1272 if (
tag ==
'L' ||
tag ==
'm')
1279 while ((begin = strchr(begin,
'%'))) {
1301 num_digits =
av_clip(*(begin + 1) -
'0', 1, 6);
1302 }
else if (
len > 1) {
1308 div = pow(10, 6 - num_digits);
1310 av_bprintf(&fmt_bp,
"%.*s%0*d", (
int)(begin - fmt_begin), fmt_begin, num_digits, (
int)(unow % 1000000) / div);
1334 char *fct,
unsigned argc,
char **argv,
int tag)
1345 "Expression '%s' for the expr text expansion function is not valid\n",
1354 char *fct,
unsigned argc,
char **argv,
int tag)
1361 char fmt_str[30] =
"%";
1374 "Expression '%s' for the expr text expansion function is not valid\n",
1379 if (!strchr(
"xXdu", argv[1][0])) {
1381 " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
1389 " to print: '%s'\n", argv[2]);
1394 feclearexcept(FE_ALL_EXCEPT);
1396 #if defined(FE_INVALID) && defined(FE_OVERFLOW) && defined(FE_UNDERFLOW)
1397 if ((
ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
1398 av_log(
ctx,
AV_LOG_ERROR,
"Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n",
ret, intval);
1405 av_strlcatf(fmt_str,
sizeof(fmt_str),
"%c", argv[1][0]);
1408 res, argv[0], fmt_str);
1415 static const struct drawtext_function {
1417 unsigned argc_min, argc_max;
1421 {
"expr", 1, 1, 0, func_eval_expr },
1422 {
"e", 1, 1, 0, func_eval_expr },
1423 {
"expr_int_format", 2, 3, 0, func_eval_expr_int_format },
1424 {
"eif", 2, 3, 0, func_eval_expr_int_format },
1425 {
"pict_type", 0, 0, 0, func_pict_type },
1426 {
"pts", 0, 3, 0, func_pts },
1427 {
"gmtime", 0, 1,
'G', func_strftime },
1428 {
"localtime", 0, 1,
'L', func_strftime },
1429 {
"frame_num", 0, 0, 0, func_frame_num },
1430 {
"n", 0, 0, 0, func_frame_num },
1431 {
"metadata", 1, 2, 0, func_metadata },
1435 unsigned argc,
char **argv)
1440 if (strcmp(fct, functions[
i].
name))
1442 if (argc < functions[
i].argc_min) {
1444 fct, functions[
i].argc_min);
1447 if (argc > functions[
i].argc_max) {
1449 fct, functions[
i].argc_max);
1458 return functions[
i].func(
ctx, bp, fct, argc, argv, functions[
i].
tag);
1463 const char *text = *rtext;
1464 char *argv[16] = {
NULL };
1465 unsigned argc = 0,
i;
1493 *rtext = (
char *)text + 1;
1496 for (
i = 0;
i < argc;
i++)
1507 if (*text ==
'\\' && text[1]) {
1510 }
else if (*text ==
'%') {
1527 color->rgba[3] = (
color->rgba[3] *
s->alpha) / 255;
1540 else if (
alpha <= 0)
1549 int x,
int y,
int borderw)
1551 int g, l, x1, y1, w1, h1, idx;
1552 int dx = 0, dy = 0, pdx = 0;
1556 FT_BitmapGlyph b_glyph;
1557 uint8_t j_left = 0, j_right = 0, j_top = 0, j_bottom = 0;
1558 int line_w, offset_y = 0;
1559 int clip_x = 0, clip_y = 0;
1561 j_left = !!(
s->text_align &
TA_LEFT);
1563 j_top = !!(
s->text_align &
TA_TOP);
1566 if (j_top && j_bottom) {
1567 offset_y = (
s->box_height - metrics->
height) / 2;
1568 }
else if (j_bottom) {
1569 offset_y =
s->box_height - metrics->
height;
1572 if ((!j_left || j_right) && !
s->tab_warning_printed &&
s->tab_count > 0) {
1573 s->tab_warning_printed = 1;
1580 for (l = 0; l <
s->line_count; ++l) {
1583 for (
g = 0;
g <
line->hb_data.glyph_count; ++
g) {
1585 dummy.fontsize =
s->fontsize;
1592 idx = get_subpixel_idx(
info->shift_x64,
info->shift_y64);
1594 bitmap = b_glyph->bitmap;
1595 x1 = x +
info->x + b_glyph->left;
1596 y1 = y +
info->y - b_glyph->top + offset_y;
1600 if (j_left && j_right) {
1601 x1 += (
s->box_width - line_w) / 2;
1602 }
else if (j_right) {
1603 x1 +=
s->box_width - line_w;
1608 if (x1 < metrics->rect_x -
s->bb_left) {
1609 dx = metrics->
rect_x -
s->bb_left - x1;
1610 x1 = metrics->
rect_x -
s->bb_left;
1612 if (y1 < metrics->rect_y -
s->bb_top) {
1613 dy = metrics->
rect_y -
s->bb_top - y1;
1614 y1 = metrics->
rect_y -
s->bb_top;
1618 if (dx >= w1 || dy >= h1 || x1 >= clip_x || y1 >= clip_y) {
1622 pdx = dx + dy * bitmap.pitch;
1623 w1 =
FFMIN(clip_x - x1, w1 - dx);
1624 h1 =
FFMIN(clip_y - y1, h1 - dy);
1627 bitmap.buffer + pdx, bitmap.pitch, w1, h1, 3, 0, x1, y1);
1637 hb->
buf = hb_buffer_create();
1638 if(!hb_buffer_allocation_successful(hb->
buf)) {
1641 hb_buffer_set_direction(hb->
buf, HB_DIRECTION_LTR);
1642 hb_buffer_set_script(hb->
buf, HB_SCRIPT_LATIN);
1643 hb_buffer_set_language(hb->
buf, hb_language_from_string(
"en", -1));
1644 hb_buffer_guess_segment_properties(hb->
buf);
1645 hb->
font = hb_ft_font_create(
s->face,
NULL);
1649 hb_ft_font_set_funcs(hb->
font);
1650 hb_buffer_add_utf8(hb->
buf, text, textLen, 0, -1);
1660 hb_buffer_destroy(hb->
buf);
1661 hb_font_destroy(hb->
font);
1671 char *text =
s->expanded_text.str;
1672 char *textdup =
NULL, *start =
NULL;
1674 int width64 = 0, w64 = 0;
1675 int cur_min_y64 = 0, first_max_y64 = -32000;
1676 int first_min_x64 = 32000, last_max_x64 = -32000;
1677 int min_y64 = 32000, max_y64 = -32000, min_x64 = 32000, max_x64 = -32000;
1682 int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
1688 for (
i = 0, p = text; 1;
i++) {
1691 if (is_newline(
code) ||
code == 0) {
1696 }
else if (
code ==
'\t') {
1702 if (
s->tab_count > 0 && !
s->blank_advance64) {
1708 s->blank_advance64 = hb_data.
glyph_pos[0].x_advance;
1712 s->line_count = line_count;
1714 s->tab_clusters =
av_mallocz(
s->tab_count *
sizeof(uint32_t));
1715 for (
i = 0;
i <
s->tab_count; ++
i) {
1716 s->tab_clusters[
i] = -1;
1720 if (textdup ==
NULL) {
1725 for (
i = 0, p = textdup; 1;
i++) {
1727 s->tab_clusters[tab_idx++] =
i;
1731 continue_on_failed2:
1732 if (is_newline(
code) ||
code == 0) {
1733 TextLine *cur_line = &
s->lines[line_count];
1741 cur_min_y64 = 32000;
1743 uint8_t is_tab = last_tab_idx <
s->tab_count &&
1744 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] - line_offset;
1752 if (line_count == 0) {
1753 first_max_y64 =
FFMAX(glyph->
bbox.yMax, first_max_y64);
1757 first_min_x64 =
FFMIN(glyph->
bbox.xMin, first_min_x64);
1762 int last_char_width = hb->
glyph_pos[t].x_advance;
1768 w64 += last_char_width;
1769 last_max_x64 =
FFMAX(last_char_width, last_max_x64);
1773 int size =
s->blank_advance64 *
s->tabsize;
1779 cur_min_y64 =
FFMIN(glyph->
bbox.yMin, cur_min_y64);
1780 min_y64 =
FFMIN(glyph->
bbox.yMin, min_y64);
1781 max_y64 =
FFMAX(glyph->
bbox.yMax, max_y64);
1782 min_x64 =
FFMIN(glyph->
bbox.xMin, min_x64);
1783 max_x64 =
FFMAX(glyph->
bbox.xMax, max_x64);
1788 av_log(
s,
AV_LOG_DEBUG,
" Line: %d -- glyphs count: %d - width64: %d - offset_left64: %d - offset_right64: %d)\n",
1791 if (w64 > width64) {
1797 line_offset =
i + 1;
1800 if (
code == 0)
break;
1811 (
FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
1832 int x = 0, y = 0,
ret;
1833 int shift_x64, shift_y64;
1837 time_t now = time(0);
1839 AVBPrint *bp = &
s->expanded_text;
1848 int rec_x = 0, rec_y = 0, rec_width = 0, rec_height = 0;
1850 int last_tab_idx = 0;
1859 switch (
s->exp_mode) {
1873 if (
s->tc_opt_string) {
1883 if (
s->fontcolor_expr[0]) {
1897 if ((
ret = update_fontsize(
ctx)) < 0) {
1914 s->var_values[
VAR_FONT_A] =
s->face->size->metrics.ascender / 64;
1916 s->var_values[
VAR_FONT_D] = -
s->face->size->metrics.descender / 64;
1938 if (
s->draw_box &&
s->boxborderw) {
1941 count = string_to_array(
s->boxborderw, bbsize, 4);
1943 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = bbsize[0];
1944 }
else if (count == 2) {
1945 s->bb_top =
s->bb_bottom = bbsize[0];
1946 s->bb_right =
s->bb_left = bbsize[1];
1947 }
else if (count == 3) {
1948 s->bb_top = bbsize[0];
1949 s->bb_right =
s->bb_left = bbsize[1];
1950 s->bb_bottom = bbsize[2];
1951 }
else if (count == 4) {
1952 s->bb_top = bbsize[0];
1953 s->bb_right = bbsize[1];
1954 s->bb_bottom = bbsize[2];
1955 s->bb_left = bbsize[3];
1958 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = 0;
1961 if (
s->fix_bounds) {
1963 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
1965 int offsetleft =
FFMAX3(
FFMAX(
s->bb_left, 0), borderoffset,
1966 (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0));
1967 int offsettop =
FFMAX3(
FFMAX(
s->bb_top, 0), borderoffset,
1968 (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0));
1969 int offsetright =
FFMAX3(
FFMAX(
s->bb_right, 0), borderoffset,
1970 (
s->shadowx > 0 ?
s->shadowx : 0));
1971 int offsetbottom =
FFMAX3(
FFMAX(
s->bb_bottom, 0), borderoffset,
1972 (
s->shadowy > 0 ?
s->shadowy : 0));
1974 if (
s->x - offsetleft < 0)
s->x = offsetleft;
1975 if (
s->y - offsettop < 0)
s->y = offsettop;
1985 x64 = (
int)(
s->x * 64.);
1987 y64 = (
int)(
s->y * 64. +
s->face->size->metrics.ascender);
1989 y64 = (
int)(
s->y * 64.);
1994 for (
int l = 0; l <
s->line_count; ++l) {
2001 uint8_t is_tab = last_tab_idx <
s->tab_count &&
2002 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] -
line->cluster_offset;
2009 shift_x64 = (((x64 + true_x) >> 4) & 0b0011) << 4;
2010 shift_y64 = ((4 - (((y64 + true_y) >> 4) & 0b0011)) & 0b0011) << 4;
2012 ret = load_glyph(
ctx, &glyph, hb->
glyph_info[t].codepoint, shift_x64, shift_y64);
2017 g_info->
x = (x64 + true_x) >> 6;
2018 g_info->
y = ((y64 + true_y) >> 6) + (shift_y64 > 0 ? 1 : 0);
2025 int size =
s->blank_advance64 *
s->tabsize;
2042 s->box_width =
s->boxw == 0 ? metrics.
width :
s->boxw;
2043 s->box_height =
s->boxh == 0 ? metrics.
height :
s->boxh;
2048 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
2049 s->bb_left = borderoffset + (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0) + 1;
2050 s->bb_top = borderoffset + (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0) + 1;
2051 s->bb_right = borderoffset + (
s->shadowx > 0 ?
s->shadowx : 0) + 1;
2052 s->bb_bottom = borderoffset + (
s->shadowy > 0 ?
s->shadowy : 0) + 1;
2058 metrics.
rect_x +
s->box_width +
s->bb_right <= 0 ||
2059 metrics.
rect_y +
s->box_height +
s->bb_bottom <= 0;
2064 rec_x = metrics.
rect_x -
s->bb_left;
2065 rec_y = metrics.
rect_y -
s->bb_top;
2066 rec_width =
s->box_width +
s->bb_right +
s->bb_left;
2067 rec_height =
s->box_height +
s->bb_bottom +
s->bb_top;
2070 rec_x, rec_y, rec_width, rec_height);
2073 if (
s->shadowx ||
s->shadowy) {
2075 s->shadowx,
s->shadowy,
s->borderw)) < 0) {
2082 0, 0,
s->borderw)) < 0) {
2094 for (
int l = 0; l <
s->line_count; ++l) {
2127 if (
s->reload && !(
inlink->frame_count_out %
s->reload)) {
2128 if ((
ret = load_textfile(
ctx)) < 0) {
2132 #if CONFIG_LIBFRIBIDI
2133 if (
s->text_shaping)
2134 if ((
ret = shape_text(
ctx)) < 0) {
2141 s->var_values[
VAR_N] =
inlink->frame_count_out +
s->start_number;
2146 #if FF_API_FRAME_PKT
2152 #if FF_API_PKT_DURATION
2165 for (
int i = 0;
i <
loop;
i++) {
2170 strcat(
s->text,
", ");
2174 s->y = bbox->
y -
s->fontsize;
2194 .description =
NULL_IF_CONFIG_SMALL(
"Draw text on top of video frames using libfreetype library."),
2196 .priv_class = &drawtext_class,
2202 .process_command = command,
static void error(const char *err)
FT_Library library
freetype font library handle
int(* func)(AVBPrint *dst, const char *in, const char *arg)
#define FF_ENABLE_DEPRECATION_WARNINGS
static const char *const fun2_names[]
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_BPRINT_SIZE_UNLIMITED
#define AV_TIMECODE_STR_SIZE
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
int height
total height of the text - ceil(height64/64)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
const AVFilter ff_vf_drawtext
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int64_t duration
Duration of the frame, in the same units as pts.
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.
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
unsigned int default_fontsize
default font size to use
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
int tc24hmax
1 if timecode is wrapped to 24 hours, 0 otherwise
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
static int draw_text(AVFilterContext *ctx, AVFrame *frame)
This structure describes decoded (raw) audio or video data.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
FFDrawColor bordercolor
border color
int bb_left
the size of the left box border
int exp_mode
expansion mode to use for the text
int line_count
the number of text lines
static int shape_text_hb(DrawTextContext *s, HarfbuzzData *hb, const char *text, int textLen)
#define FILTER_QUERY_FUNC(func)
#define AV_LOG_VERBOSE
Detailed information.
FT_Stroker stroker
freetype stroker handle
const char * name
Filter name.
static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
int box_height
the height of box
TextLine * lines
computed information about text lines
A link between two filters.
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
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.
int width64
width of the line
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
int min_y64
minimum value of bbox.yMin among glyphs (in 26.6 units)
int start_number
starting frame number for n/frame_num var
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.
uint8_t * text
text to be drawn
AVBPrint expanded_text
used to contain the expanded text
int av_set_options_string(void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep)
Parse the key/value pairs list in opts.
unsigned int fontsize
font size to use
char * x_expr
expression for x position
const static uint16_t positions[][14][3]
#define AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE
uint8_t * fontfile
font to be used
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...
char detect_label[AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
Detect result with confidence.
AVExpr * y_pexpr
parsed expressions for x and y
int y
the y position of the glyph
FT_BitmapGlyph bglyph[16]
Glyph bitmaps with 1/4 pixel precision in both directions.
int bb_top
the size of the top box border
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
static void hb_destroy(HarfbuzzData *hb)
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0)
Blend an alpha mask with an uniform color.
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
int offset_top64
ascender amount of the first line (in 26.6 units)
A filter pad used for either input or output.
#define FFDIFFSIGN(x, y)
Comparator.
static av_always_inline AVDetectionBBox * av_get_detection_bbox(const AVDetectionBBoxHeader *header, unsigned int idx)
int rect_y
y position of the box
double var_values[VAR_VARS_NB]
#define GET_UTF8(val, GET_BYTE, ERROR)
Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.
int min_x64
minimum value of bbox.xMin among glyphs (in 26.6 units)
static const AVFilterPad avfilter_vf_drawtext_inputs[]
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define FF_ARRAY_ELEMS(a)
static void update_alpha(DrawTextContext *s)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
FT_Face face
freetype font face handle
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
FFDrawColor fontcolor
foreground color
static double av_q2d(AVRational a)
Convert an AVRational to a double.
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
int(* init)(AVBSFContext *ctx)
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph of each line (in 26....
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
attribute_deprecated int pkt_size
size of the corresponding packet containing the compressed frame.
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
AVExpr * fontsize_pexpr
parsed expressions for fontsize
double(* eval_func2)(void *, double a, double b)
#define FILTER_INPUTS(array)
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
A glyph as loaded and rendered using libfreetype.
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
int blank_advance64
the size of the space character
Describe the class of an AVClass context structure.
and forward the result(frame or status change) to the corresponding input. If nothing is possible
uint32_t * tab_clusters
the position of tab characters in the text
static int draw_glyphs(DrawTextContext *s, AVFrame *frame, FFDrawColor *color, TextMetrics *metrics, int x, int y, int borderw)
int text_align
the horizontal and vertical text alignment
static int config_input(AVFilterLink *inlink)
int offset_left64
maximum offset between the origin and the leftmost pixel of the first glyph of each line (in 26....
uint32_t code
the glyph code point
int64_t basetime
base pts time in the real world for display
Rational number (pair of numerator and denominator).
char classify_labels[AV_NUM_DETECTION_BBOX_CLASSIFY][AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
char * fontsize_expr
expression for fontsize
Information about a single line of text.
AVRational tc_rate
frame rate for timecode
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
Parse timestr and return in *time a corresponding number of microseconds.
void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
Append a formatted date and time to a print buffer.
int cluster_offset
the offset at which this line begins
void av_tree_destroy(AVTreeNode *t)
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
static const char *const var_names[]
hb_glyph_info_t * glyph_info
int reload
reload text file at specified frame interval
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a source
char * text_source_string
the string to specify text data source
int bb_right
the size of the right box border
int offset_left64
offset between the origin and the leftmost pixel of the first glyph
Context structure for the Lagged Fibonacci PRNG.
enum AVPictureType pict_type
Picture type of the frame.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
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.
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
static int shift(int a, int b)
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.
short int draw_box
draw box around text - true or false
#define AV_NOPTS_VALUE
Undefined timestamp value.
attribute_deprecated int64_t pkt_pos
reordered pos from the last AVPacket that has been input into the decoder
static double drand(void *opaque, double min, double max)
int width
width of the longest line - ceil(width64/64)
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
static const uint8_t header[24]
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
AVFILTER_DEFINE_CLASS(drawtext)
static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
int max_y64
maximum value of bbox.yMax among glyphs (in 26.6 units)
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
@ AV_TIMECODE_FLAG_24HOURSMAX
timecode wraps after 24 hours
AVBPrint expanded_fontcolor
used to contain the expanded fontcolor spec
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
#define AVERROR_EXTERNAL
Generic error in an external library.
hb_glyph_position_t * glyph_pos
static const eval_func2 fun2[]
static int measure_text(AVFilterContext *ctx, TextMetrics *metrics)
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
char av_get_picture_type_char(enum AVPictureType pict_type)
Return a single letter to describe the given picture type pict_type.
int tab_warning_printed
ensure the tab warning to be printed only once
int rect_x
x position of the box
#define i(width, name, range_min, range_max)
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
int tab_count
the number of tab characters
static av_always_inline av_const double round(double x)
Information about a single glyph in a text line.
#define AV_TIME_BASE
Internal time base represented as integer.
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
#define av_malloc_array(a, b)
int max_glyph_h
max glyph height
attribute_deprecated int64_t pkt_duration
duration of the corresponding packet, expressed in AVStream->time_base units, 0 if unknown.
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
FT_BitmapGlyph border_bglyph[16]
Outlined glyph bitmaps with 1/4 pixel precision in both directions.
int max_x64
maximum value of bbox.xMax among glyphs (in 26.6 units)
const char * name
Pad name.
int box_width
the width of box
int shift_y64
the vertical shift of the glyph in 26.6 units
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
int bb_bottom
the size of the bottom box border
AVTimecode tc
timecode context
int y_align
the value of the y_align parameter
void av_bprintf(AVBPrint *buf, const char *fmt,...)
int offset_bottom64
descender amount of the last line (in 26.6 units)
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
int x
the x position of the glyph
char * boxborderw
box border width (padding) allowed formats: "all", "vert|oriz", "top|right|bottom|left"
static const struct ft_error ft_errors[]
static const AVOption drawtext_options[]
FFDrawColor shadowcolor
shadow color
static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct, unsigned argc, char **argv)
int reinit
tells if the filter is being reinited
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...
AVDictionary * metadata
metadata.
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
int x
Distance in pixels from the left/top edge of the frame, together with width and height,...
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
int64_t av_gettime(void)
Get the current time in microseconds.
#define FF_DISABLE_DEPRECATION_WARNINGS
char * av_strdup(const char *s)
Duplicate a string.
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
char * textfile
file with text to be drawn
int boxw
the value of the boxw parameter
GlyphInfo * glyphs
array of glyphs in this text line
int line_height64
the font-defined line height
Structure to hold side data for an AVFrame.
int shift_x64
the horizontal shift of the glyph in 26.6 units
#define AV_NUM_DETECTION_BBOX_CLASSIFY
At most 4 classifications based on the detected bounding box.
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
enum AVFrameSideDataType text_source
HarfbuzzData hb_data
libharfbuzz data of this text line
static const int16_t alpha[]
double y
y position to start drawing text
#define FILTER_OUTPUTS(array)
FFDrawColor boxcolor
background color
static int query_formats(AVFilterContext *ctx)
#define flags(name, subs,...)
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
static av_cold int uninit(AVCodecContext *avctx)
double x
x position to start drawing text
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
char * y_expr
expression for y position
int line_spacing
lines spacing in pixels
uint8_t * fontcolor_expr
fontcolor expression to evaluate
@ AV_FRAME_DATA_DETECTION_BBOXES
Bounding boxes for object detection and classification, as described by AVDetectionBBoxHeader.
int max_glyph_w
max glyph width
char * tc_opt_string
specified timecode option string
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
int fix_bounds
do we let it go out of frame bounds - t/f
int boxh
the value of the boxh parameter
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.