43#if CONFIG_LIBFONTCONFIG
44#include <fontconfig/fontconfig.h>
81#define POS_CEIL(x, y) ((x)/(y) + ((x)%(y) != 0))
89 "max_glyph_a",
"ascent",
90 "max_glyph_d",
"descent",
241#if CONFIG_LIBFONTCONFIG
320#define OFFSET(x) offsetof(DrawTextContext, x)
321#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
322#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
359#if CONFIG_LIBFONTCONFIG
380 {
"start_number",
"start frame number for n/frame_num variable",
OFFSET(start_number),
AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX,
FLAGS},
388 {
"ft_load_flags",
"set font loading flags for libfreetype",
OFFSET(ft_load_flags),
AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT }, 0, INT_MAX,
FLAGS, .unit =
"ft_load_flags" },
394 {
"vertical_layout",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags =
FLAGS, .unit =
"ft_load_flags" },
398 {
"ignore_global_advance_width",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags =
FLAGS, .unit =
"ft_load_flags" },
400 {
"ignore_transform",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags =
FLAGS, .unit =
"ft_load_flags" },
410#define FT_ERROR_START_LIST {
411#define FT_ERRORDEF(e, v, s) { (e), (s) },
412#define FT_ERROR_END_LIST { 0, NULL } };
420#define FT_ERRMSG(e) ft_errors[e].err_msg
422static int glyph_cmp(
const void *
key,
const void *
b)
428 return diff > 0 ? 1 : -1;
438 if ((err = FT_Set_Pixel_Sizes(
s->face, 0, fontsize))) {
450 s->fontsize = fontsize;
460 if (
s->fontsize_pexpr)
463 if (
s->fontsize_expr ==
NULL)
476 unsigned int fontsize =
s->default_fontsize;
478 double size, roundedsize;
481 if (
s->fontsize_expr !=
NULL) {
482 if ((err = parse_fontsize(
ctx)) < 0)
489 if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
493 fontsize = roundedsize;
501 if (fontsize ==
s->fontsize)
504 return set_fontsize(
ctx, fontsize);
512 err = FT_New_Face(
s->library, path,
index, &
s->face);
514#if !CONFIG_LIBFONTCONFIG
523#if CONFIG_LIBFONTCONFIG
527 FcConfig *fontconfig;
528 FcPattern *pat, *best;
529 FcResult result = FcResultMatch;
536 fontconfig = FcInitLoadConfigAndFonts();
541 pat = FcNameParse(
s->fontfile ?
s->fontfile :
542 (uint8_t *)(intptr_t)
"default");
548 FcPatternAddString(pat, FC_FAMILY,
s->font);
550 parse_err = parse_fontsize(
ctx);
559 FcPatternAddDouble(pat, FC_SIZE,
size);
562 FcDefaultSubstitute(pat);
564 if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
566 FcPatternDestroy(pat);
570 best = FcFontMatch(fontconfig, pat, &result);
571 FcPatternDestroy(pat);
573 if (!best || result != FcResultMatch) {
575 "Cannot find a valid font for the family %s\n",
581 FcPatternGetInteger(best, FC_INDEX, 0, &
index ) != FcResultMatch ||
582 FcPatternGetDouble (best, FC_SIZE, 0, &
size ) != FcResultMatch) {
587 if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
595 s->default_fontsize =
size + 0.5;
597 err = load_font_file(
ctx, filename,
index);
600 FcConfigDestroy(fontconfig);
602 FcPatternDestroy(best);
613 err = load_font_file(
ctx,
s->fontfile, 0);
616#if CONFIG_LIBFONTCONFIG
617 err = load_font_fontconfig(
ctx);
630 static const FriBidiFlags
flags = FRIBIDI_FLAGS_DEFAULT |
631 FRIBIDI_FLAGS_ARABIC;
632 FriBidiChar *unicodestr =
NULL;
634 FriBidiParType direction = FRIBIDI_PAR_LTR;
635 FriBidiStrIndex line_start = 0;
636 FriBidiStrIndex line_end = 0;
637 FriBidiLevel *embedding_levels =
NULL;
638 FriBidiArabicProp *ar_props =
NULL;
639 FriBidiCharType *bidi_types =
NULL;
642 len = strlen(
s->text);
646 len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
647 s->text,
len, unicodestr);
654 fribidi_get_bidi_types(unicodestr,
len, bidi_types);
657 if (!embedding_levels) {
661 if (!fribidi_get_par_embedding_levels(bidi_types,
len, &direction,
671 fribidi_get_joining_types(unicodestr,
len, ar_props);
672 fribidi_join_arabic(bidi_types,
len, embedding_levels, ar_props);
673 fribidi_shape(
flags, embedding_levels,
len, ar_props, unicodestr);
675 for (line_end = 0, line_start = 0; line_end <
len; line_end++) {
676 if (ff_is_newline(unicodestr[line_end]) || line_end ==
len - 1) {
677 if (!fribidi_reorder_line(
flags, bidi_types,
678 line_end - line_start + 1, line_start,
679 direction, embedding_levels, unicodestr,
683 line_start = line_end + 1;
688 for (
i = 0, j = 0;
i <
len;
i++)
689 if (unicodestr[
i] != FRIBIDI_CHAR_FILL)
690 unicodestr[j++] = unicodestr[
i];
699 len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
700 unicodestr,
len,
s->text);
716 if (!strcmp(text_source_string,
"side_data_detection_bboxes")) {
723static inline int get_subpixel_idx(
int shift_x64,
int shift_y64)
725 int idx = (shift_x64 >> 2) + (shift_y64 >> 4);
742 dummy.fontsize =
s->fontsize;
746 if (FT_Load_Glyph(
s->face,
code,
s->ft_load_flags)) {
756 if (FT_Get_Glyph(
s->face->glyph, &glyph->
glyph)) {
762 if (FT_Glyph_StrokeBorder(&
tmp,
s->stroker, 0, 0)) {
769 FT_Glyph_Get_CBox(glyph->
glyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph->
bbox);
781 if (FT_Glyph_StrokeBorder(&
tmp,
s->stroker, 0, 0)) {
790 if (shift_x64 >= 0 && shift_y64 >= 0) {
792 int idx = get_subpixel_idx(shift_x64, shift_y64);
796 if (!glyph->
bglyph[idx]) {
797 FT_Glyph tmp_glyph = glyph->
glyph;
798 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
802 glyph->
bglyph[idx] = (FT_BitmapGlyph)tmp_glyph;
804 if (glyph->
bglyph[idx]->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
811 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
824 if (glyph && !cached) {
828 FT_Done_Glyph(glyph->
glyph);
836static int string_to_array(
const char *source,
int *result,
int result_size)
838 int counter = 0,
size = strlen(source) + 1;
843 if (result_size > 0 && (curval =
av_strtok(dup,
"|", &saveptr))) {
845 result[counter++] = atoi(curval);
846 }
while ((curval =
av_strtok(
NULL,
"|", &saveptr)) && counter < result_size);
852static int func_pict_type(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
860static int func_pts(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
864 const char *strftime_fmt =
NULL;
870 fmt = argc >= 1 ? argv[0] :
"flt";
875 if (!strcmp(fmt,
"hms")) {
876 if (!strcmp(argv[2],
"24HH")) {
884 strftime_fmt = argv[2];
891static int func_frame_num(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
899static int func_metadata(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
911static int func_strftime(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
913 const char *strftime_fmt = argc ? argv[0] :
NULL;
915 return ff_print_time(
ctx, bp, strftime_fmt, !strcmp(function_name,
"localtime"));
918static int func_eval_expr(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
927static int func_eval_expr_int_format(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
943 " to print: '%s'\n", argv[2]);
957 {
"eif", 2, 3, func_eval_expr_int_format },
959 {
"expr_int_format", 2, 3, func_eval_expr_int_format },
963 {
"metadata", 1, 2, func_metadata },
965 {
"pict_type", 0, 0, func_pict_type },
975 s->fontsize_pexpr =
NULL;
978 s->default_fontsize = 16;
980 if (!
s->fontfile && !CONFIG_LIBFONTCONFIG) {
988 "Both text and text file provided. Please provide only one\n");
995 if (
s->reload && !
s->textfile)
998 if (
s->tc_opt_string) {
1000 s->tc_opt_string,
ctx);
1009 if (
s->text_source_string) {
1010 s->text_source = text_source_string_parse(
s->text_source_string);
1011 if ((
int)
s->text_source < 0) {
1030 "Either text, a valid file, a timecode or text source must be provided\n");
1040#if CONFIG_LIBFRIBIDI
1041 if (
s->text_shaping)
1042 if ((err = shape_text(
ctx)) < 0)
1046 if ((err = FT_Init_FreeType(&(
s->library)))) {
1048 "Could not load FreeType: %s\n",
FT_ERRMSG(err));
1052 if ((err = load_font(
ctx)) < 0)
1055 if ((err = update_fontsize(
ctx)) < 0)
1059 if (FT_Stroker_New(
s->library, &
s->stroker)) {
1065 FT_Stroker_Set(
s->stroker,
s->borderw << 6, FT_STROKER_LINECAP_ROUND,
1066 FT_STROKER_LINEJOIN_ROUND, 0);
1070 load_glyph(
ctx,
NULL, 0, 0, 0);
1073 (strchr(
s->text,
'%') || strchr(
s->text,
'\\')))
1095 for (
int t = 0; t < 16; ++t) {
1111 for (
int t = 0; t < 16; ++t) {
1112 FT_Glyph bg = (FT_Glyph)glyph->
bglyph[t];
1121 FT_Done_Glyph(glyph->
glyph);
1135 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
s->fontsize_pexpr =
NULL;
1141 FT_Done_Face(
s->face);
1142 FT_Stroker_Done(
s->stroker);
1143 FT_Done_FreeType(
s->library);
1170 s->var_values[
VAR_HSUB] = 1 <<
s->dc.hsub_max;
1171 s->var_values[
VAR_VSUB] = 1 <<
s->dc.vsub_max;
1181 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
NULL;
1202 if (!strcmp(cmd,
"reinit")) {
1207 new->class = &drawtext_class;
1236 int old_borderw = old->
borderw;
1240 if (old->
borderw != old_borderw) {
1241 FT_Stroker_Set(old->
stroker, old->
borderw << 6, FT_STROKER_LINECAP_ROUND,
1242 FT_STROKER_LINEJOIN_ROUND, 0);
1245 }
else if (strcmp(cmd,
"fontsize") == 0) {
1262 color->rgba[3] = (
color->rgba[3] *
s->alpha) / 255;
1275 else if (
alpha <= 0)
1284 int x,
int y,
int borderw)
1287 int g, l, x1, y1, w1, h1, idx;
1288 int dx = 0, dy = 0, pdx = 0;
1292 FT_BitmapGlyph b_glyph;
1293 uint8_t j_left = 0, j_right = 0, j_top = 0, j_bottom = 0;
1294 int line_w, offset_y = 0;
1295 int clip_x = 0, clip_y = 0;
1297 j_left = !!(
s->text_align &
TA_LEFT);
1299 j_top = !!(
s->text_align &
TA_TOP);
1302 if (j_top && j_bottom) {
1303 offset_y = (
s->box_height - metrics->
height) / 2;
1304 }
else if (j_bottom) {
1305 offset_y =
s->box_height - metrics->
height;
1308 if ((!j_left || j_right) && !
s->tab_warning_printed &&
s->tab_count > 0) {
1309 s->tab_warning_printed = 1;
1316 for (l = 0; l <
s->line_count; ++l) {
1319 for (
g = 0;
g <
line->hb_data.glyph_count; ++
g) {
1320 info = &
line->glyphs[
g];
1321 dummy.fontsize =
s->fontsize;
1330 bitmap = b_glyph->bitmap;
1331 x1 = x + info->
x + b_glyph->left;
1332 y1 = y + info->
y - b_glyph->top + offset_y;
1336 if (j_left && j_right) {
1337 x1 += (
s->box_width - line_w) / 2;
1338 }
else if (j_right) {
1339 x1 +=
s->box_width - line_w;
1344 if (x1 < metrics->rect_x -
s->bb_left) {
1345 dx = metrics->
rect_x -
s->bb_left - x1;
1346 x1 = metrics->
rect_x -
s->bb_left;
1348 if (y1 < metrics->rect_y -
s->bb_top) {
1349 dy = metrics->
rect_y -
s->bb_top - y1;
1350 y1 = metrics->
rect_y -
s->bb_top;
1354 if (dx >= w1 || dy >= h1 || x1 >= clip_x || y1 >= clip_y) {
1358 pdx = dx + dy * bitmap.pitch;
1359 w1 =
FFMIN(clip_x - x1, w1 - dx);
1360 h1 =
FFMIN(clip_y - y1, h1 - dy);
1363 bitmap.buffer + pdx, bitmap.pitch, w1, h1, 3, 0, x1, y1);
1374 unsigned codepoints;
1376 hb->
buf = hb_buffer_create();
1377 if (!hb_buffer_allocation_successful(hb->
buf))
1379 hb_buffer_add_utf8(hb->
buf, text, textLen, 0, -1);
1385 hb_buffer_set_direction(hb->
buf, HB_DIRECTION_LTR);
1386 hb_buffer_set_language(hb->
buf, hb_language_from_string(
"en", -1));
1387 hb_buffer_guess_segment_properties(hb->
buf);
1390 codepoints = hb_buffer_get_length(hb->
buf);
1391 hb->
font = hb_ft_font_create_referenced(
s->face);
1399 char script_tag[5] = { 0 };
1400 hb_script_t script = hb_buffer_get_script(hb->
buf);
1401 hb_direction_t dir = hb_buffer_get_direction(hb->
buf);
1402 hb_tag_to_string(hb_script_to_iso15924_tag(script), script_tag);
1404 "shape: script=%s direction=%s codepoints=%u glyphs=%u\n",
1405 script_tag, hb_direction_to_string(dir),
1411 hb_buffer_destroy(hb->
buf);
1418 hb_font_destroy(hb->
font);
1419 hb_buffer_destroy(hb->
buf);
1429 char *text =
s->expanded_text.str;
1430 char *textdup =
NULL;
1431 int width64 = 0, w64 = 0;
1432 int cur_min_y64 = 0, first_max_y64 = -32000;
1433 int first_min_x64 = 32000, last_max_x64 = -32000;
1434 int min_y64 = 32000, max_y64 = -32000, min_x64 = 32000, max_x64 = -32000;
1439 int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
1445 for (
i = 0, p = text; 1;
i++) {
1448 if (ff_is_newline(
code) ||
code == 0) {
1453 }
else if (
code ==
'\t') {
1459 if (
s->tab_count > 0 && !
s->blank_advance64) {
1465 s->blank_advance64 = hb_data.
glyph_pos[0].x_advance;
1469 s->line_count = line_count;
1471 s->tab_clusters =
av_calloc(
s->tab_count,
sizeof(uint32_t));
1472 if ((line_count > 0 && !
s->lines) ||
1473 (
s->tab_count > 0 && !
s->tab_clusters)) {
1477 for (
i = 0;
i <
s->tab_count; ++
i) {
1478 s->tab_clusters[
i] = -1;
1482 if (textdup ==
NULL) {
1487 for (
i = 0, p = textdup; 1;
i++) {
1489 s->tab_clusters[tab_idx++] =
i;
1492 size_t len = p - start;
1495 if (ff_is_newline(
code) ||
code == 0) {
1496 TextLine *cur_line = &
s->lines[line_count];
1504 cur_min_y64 = 32000;
1506 uint8_t is_tab = last_tab_idx <
s->tab_count &&
1507 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] - line_offset;
1511 ret = load_glyph(
ctx, &glyph, hb->
glyph_info[t].codepoint, -1, -1);
1515 if (line_count == 0) {
1516 first_max_y64 =
FFMAX(glyph->
bbox.yMax, first_max_y64);
1520 first_min_x64 =
FFMIN(glyph->
bbox.xMin, first_min_x64);
1525 int last_char_width = hb->
glyph_pos[t].x_advance;
1531 w64 += last_char_width;
1532 last_max_x64 =
FFMAX(last_char_width, last_max_x64);
1536 int size =
s->blank_advance64 *
s->tabsize;
1542 cur_min_y64 =
FFMIN(glyph->
bbox.yMin, cur_min_y64);
1543 min_y64 =
FFMIN(glyph->
bbox.yMin, min_y64);
1544 max_y64 =
FFMAX(glyph->
bbox.yMax, max_y64);
1545 min_x64 =
FFMIN(glyph->
bbox.xMin, min_x64);
1546 max_x64 =
FFMAX(glyph->
bbox.xMax, max_x64);
1551 av_log(
ctx,
AV_LOG_DEBUG,
" Line: %d -- glyphs count: %d - width64: %d - offset_left64: %d - offset_right64: %d)\n",
1554 if (w64 > width64) {
1559 line_offset =
i + 1;
1562 if (
code == 0)
break;
1572 (
FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
1588 for (
int l = 0; l <
s->line_count; ++l)
1603 int x = 0, y = 0, ret;
1604 int shift_x64, shift_y64;
1608 time_t now = time(0);
1610 AVBPrint *bp = &
s->expanded_text;
1619 int rec_x = 0, rec_y = 0, rec_width = 0, rec_height = 0;
1621 int last_tab_idx = 0;
1628 now=
frame->pts*
av_q2d(
ctx->inputs[0]->time_base) +
s->basetime/1000000;
1630 switch (
s->exp_mode) {
1644 if (
s->tc_opt_string) {
1654 if (
s->fontcolor_expr[0]) {
1657 if ((ret =
ff_expand_text(&
s->expand_text,
s->fontcolor_expr, &
s->expanded_fontcolor)) < 0)
1668 if ((ret = update_fontsize(
ctx)) < 0) {
1685 s->var_values[
VAR_FONT_A] =
s->face->size->metrics.ascender / 64;
1687 s->var_values[
VAR_FONT_D] = -
s->face->size->metrics.descender / 64;
1709 if (
s->draw_box &&
s->boxborderw) {
1712 count = string_to_array(
s->boxborderw, bbsize, 4);
1714 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = bbsize[0];
1715 }
else if (count == 2) {
1716 s->bb_top =
s->bb_bottom = bbsize[0];
1717 s->bb_right =
s->bb_left = bbsize[1];
1718 }
else if (count == 3) {
1719 s->bb_top = bbsize[0];
1720 s->bb_right =
s->bb_left = bbsize[1];
1721 s->bb_bottom = bbsize[2];
1722 }
else if (count == 4) {
1723 s->bb_top = bbsize[0];
1724 s->bb_right = bbsize[1];
1725 s->bb_bottom = bbsize[2];
1726 s->bb_left = bbsize[3];
1729 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = 0;
1732 if (
s->fix_bounds) {
1734 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
1736 int offsetleft =
FFMAX3(
FFMAX(
s->bb_left, 0), borderoffset,
1737 (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0));
1738 int offsettop =
FFMAX3(
FFMAX(
s->bb_top, 0), borderoffset,
1739 (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0));
1740 int offsetright =
FFMAX3(
FFMAX(
s->bb_right, 0), borderoffset,
1741 (
s->shadowx > 0 ?
s->shadowx : 0));
1742 int offsetbottom =
FFMAX3(
FFMAX(
s->bb_bottom, 0), borderoffset,
1743 (
s->shadowy > 0 ?
s->shadowy : 0));
1745 if (
s->x - offsetleft < 0)
s->x = offsetleft;
1746 if (
s->y - offsettop < 0)
s->y = offsettop;
1756 x64 = (int)(
s->x * 64.);
1758 y64 = (int)(
s->y * 64. +
s->face->size->metrics.ascender);
1760 y64 = (int)(
s->y * 64.);
1765 for (
int l = 0; l <
s->line_count; ++l) {
1772 uint8_t is_tab = last_tab_idx <
s->tab_count &&
1773 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] -
line->cluster_offset;
1780 shift_x64 = (((x64 + true_x) >> 4) & 0b0011) << 4;
1781 shift_y64 = ((4 - (((y64 + true_y) >> 4) & 0b0011)) & 0b0011) << 4;
1783 ret = load_glyph(
ctx, &glyph, hb->
glyph_info[t].codepoint, shift_x64, shift_y64);
1788 g_info->
x = (x64 + true_x) >> 6;
1789 g_info->
y = ((y64 + true_y) >> 6) + (shift_y64 > 0 ? 1 : 0);
1796 int size =
s->blank_advance64 *
s->tabsize;
1813 s->box_width =
s->boxw == 0 ? metrics.
width :
s->boxw;
1814 s->box_height =
s->boxh == 0 ? metrics.
height :
s->boxh;
1819 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
1820 s->bb_left = borderoffset + (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0) + 1;
1821 s->bb_top = borderoffset + (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0) + 1;
1822 s->bb_right = borderoffset + (
s->shadowx > 0 ?
s->shadowx : 0) + 1;
1823 s->bb_bottom = borderoffset + (
s->shadowy > 0 ?
s->shadowy : 0) + 1;
1829 metrics.
rect_x +
s->box_width +
s->bb_right <= 0 ||
1830 metrics.
rect_y +
s->box_height +
s->bb_bottom <= 0;
1835 rec_x = metrics.
rect_x -
s->bb_left;
1836 rec_y = metrics.
rect_y -
s->bb_top;
1837 rec_width =
s->box_width +
s->bb_right +
s->bb_left;
1838 rec_height =
s->box_height +
s->bb_bottom +
s->bb_top;
1841 rec_x, rec_y, rec_width, rec_height);
1844 if (
s->shadowx ||
s->shadowy) {
1846 s->shadowx,
s->shadowy,
s->borderw)) < 0) {
1853 0, 0,
s->borderw)) < 0) {
1867 for (
int l = 0; l <
s->line_count; ++l) {
1907#if CONFIG_LIBFRIBIDI
1908 if (
s->text_shaping)
1909 if ((ret = shape_text(
ctx)) < 0) {
1923 s->metadata =
frame->metadata;
1925 for (
int i = 0;
i <
loop;
i++) {
1930 strcat(
s->text,
", ");
1934 s->y = bbox->
y -
s->fontsize;
1957 .p.name =
"drawtext",
1958 .p.description =
NULL_IF_CONFIG_SMALL(
"Draw text on top of video frames using libfreetype library."),
1959 .p.priv_class = &drawtext_class,
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int config_input(AVFilterLink *inlink)
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
const FFFilter ff_vf_drawtext
static AVFormatContext * ctx
#define av_assert0(cond)
assert() equivalent, that is always enabled.
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
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.
Main libavfilter public API header.
void av_bprintf(AVBPrint *buf, const char *fmt,...)
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
#define AV_BPRINT_SIZE_UNLIMITED
#define flags(name, subs,...)
#define i(width, name, range_min, range_max)
common internal and external API header
#define GET_UTF8(val, GET_BYTE, ERROR)
Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
#define AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE
#define AV_NUM_DETECTION_BBOX_CLASSIFY
At most 4 classifications based on the detected bounding box.
static av_always_inline AVDetectionBBox * av_get_detection_bbox(const AVDetectionBBoxHeader *header, unsigned int idx)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
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.
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link, unsigned flags)
Init a draw context, taking the format, colorspace and range from the given filter link.
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.
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
int(* init)(AVBSFContext *ctx)
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
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.
simple arithmetic expression evaluator
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
@ AV_OPT_TYPE_FLAGS
Underlying C type is unsigned int.
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
@ AV_OPT_TYPE_INT
Underlying C type is int.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
@ AV_OPT_TYPE_COLOR
Underlying C type is uint8_t[4].
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
Append a formatted date and time to a print buffer.
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
#define AVERROR_EXTERNAL
Generic error in an external library.
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
@ AV_FRAME_DATA_DETECTION_BBOXES
Bounding boxes for object detection and classification, as described by AVDetectionBBoxHeader.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_VERBOSE
Detailed information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
int av_log_get_level(void)
Get the current log level.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
char av_get_picture_type_char(enum AVPictureType pict_type)
Return a single letter to describe the given picture type pict_type.
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().
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.
#define AV_NOPTS_VALUE
Undefined timestamp value.
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.
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
void av_tree_destroy(AVTreeNode *t)
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
void av_opt_free(void *obj)
Free all allocated objects in obj.
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
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.
static const int16_t alpha[]
static av_cold void uninit(AVBitStreamFilterContext *ctx)
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
static int shift(int a, int b)
#define FILTER_INPUTS(array)
#define FILTER_OUTPUTS(array)
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
static FilterLink * ff_filter_link(AVFilterLink *link)
#define AVFILTER_DEFINE_CLASS(fname)
#define FILTER_QUERY_FUNC2(func)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static av_always_inline av_const double round(double x)
#define FFDIFFSIGN(x, y)
Comparator.
void * av_calloc(size_t nmemb, size_t size)
Memory handling functions.
static const char *const var_names[]
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.
static int func_eval_expr(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
static int func_strftime(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
static const ff_eval_func2 fun2[]
static int func_pts(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
static double drand(void *opaque, double min, double max)
static int func_frame_num(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
static const char *const fun2_names[]
static const FFExpandTextFunction expand_text_functions[]
static const uint8_t header[24]
#define FF_ARRAY_ELEMS(a)
Describe the class of an AVClass context structure.
char detect_label[AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
Detect result with confidence.
int x
Distance in pixels from the left/top edge of the frame, together with width and height,...
char classify_labels[AV_NUM_DETECTION_BBOX_CLASSIFY][AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]
A link between two filters.
int w
agreed upon image width
int h
agreed upon image height
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
AVRational sample_aspect_ratio
agreed upon sample aspect ratio
AVFilterContext * dst
dest filter
A filter pad used for either input or output.
Structure to hold side data for an AVFrame.
This structure describes decoded (raw) audio or video data.
Context structure for the Lagged Fibonacci PRNG.
Rational number (pair of numerator and denominator).
double y
y position to start drawing text
int start_number
starting frame number for n/frame_num var
int text_align
the horizontal and vertical text alignment
FFDrawColor shadowcolor
shadow color
int max_glyph_w
max glyph width
AVRational tc_rate
frame rate for timecode
int box_width
the width of box
int box_height
the height of box
FT_Stroker stroker
freetype stroker handle
FFDrawColor bordercolor
border color
char * text_source_string
the string to specify text data source
int tab_warning_printed
ensure the tab warning to be printed only once
int reinit
tells if the filter is being reinited
int fix_bounds
do we let it go out of frame bounds - t/f
uint8_t * fontcolor_expr
fontcolor expression to evaluate
FFDrawColor boxcolor
background color
AVExpr * fontsize_pexpr
parsed expressions for fontsize
uint8_t * fontfile
font to be used
char * fontsize_expr
expression for fontsize
AVBPrint expanded_text
used to contain the expanded text
int max_glyph_h
max glyph height
double var_values[VAR_VARS_NB]
FFDrawColor fontcolor
foreground color
FT_Face face
freetype font face handle
short int draw_box
draw box around text - true or false
int bb_bottom
the size of the bottom box border
double x
x position to start drawing text
AVBPrint expanded_fontcolor
used to contain the expanded fontcolor spec
char * x_expr
expression for x position
struct AVTreeNode * glyphs
rendered glyphs, stored using the UTF-32 char code
uint32_t * tab_clusters
the position of tab characters in the text
char * textfile
file with text to be drawn
TextLine * lines
computed information about text lines
int bb_top
the size of the top box border
int bb_left
the size of the left box border
int ft_load_flags
flags used for loading fonts, see FT_LOAD_*
int bb_right
the size of the right box border
int exp_mode
expansion mode to use for the text
unsigned int default_fontsize
default font size to use
int line_spacing
lines spacing in pixels
int boxw
the value of the boxw parameter
int reload
reload text file at specified frame interval
FFExpandTextContext expand_text
expand text in case exp_mode == NORMAL
char * y_expr
expression for y position
int line_count
the number of text lines
uint8_t * text
text to be drawn
int tab_count
the number of tab characters
unsigned int fontsize
font size to use
int64_t basetime
base pts time in the real world for display
int blank_advance64
the size of the space character
int boxh
the value of the boxh parameter
enum AVFrameSideDataType text_source
int y_align
the value of the y_align parameter
char * tc_opt_string
specified timecode option string
char * boxborderw
box border width (padding) allowed formats: "all", "vert|oriz", "top|right|bottom|left"
int tc24hmax
1 if timecode is wrapped to 24 hours, 0 otherwise
AVExpr * y_pexpr
parsed expressions for x and y
AVTimecode tc
timecode context
FT_Library library
freetype font library handle
Text expander context, used to encapsulate the logic to expand a given text template.
Function used to expand a template sequence in the format %{FUNCTION_NAME[:PARAMS]}...
Link properties exposed to filter code, but not external callers.
Information about a single glyph in a text line.
int x
the x position of the glyph
int y
the y position of the glyph
int shift_x64
the horizontal shift of the glyph in 26.6 units
uint32_t code
the glyph code point
int shift_y64
the vertical shift of the glyph in 26.6 units
A glyph as loaded and rendered using libfreetype.
FT_BitmapGlyph border_bglyph[16]
Outlined glyph bitmaps with 1/4 pixel precision in both directions.
FT_BitmapGlyph bglyph[16]
Glyph bitmaps with 1/4 pixel precision in both directions.
hb_glyph_info_t * glyph_info
hb_glyph_position_t * glyph_pos
Information about a single line of text.
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph
int offset_left64
offset between the origin and the leftmost pixel of the first glyph
GlyphInfo * glyphs
array of glyphs in this text line
int width64
width of the line
int cluster_offset
the offset at which this line begins
HarfbuzzData hb_data
libharfbuzz data of this text line
int offset_right64
maximum offset between the origin and the rightmost pixel of the last glyph of each line (in 26....
int offset_left64
maximum offset between the origin and the leftmost pixel of the first glyph of each line (in 26....
int min_x64
minimum value of bbox.xMin among glyphs (in 26.6 units)
int rect_y
y position of the box
int line_height64
the font-defined line height
int offset_top64
ascender amount of the first line (in 26.6 units)
int width
width of the longest line - ceil(width64/64)
int min_y64
minimum value of bbox.yMin among glyphs (in 26.6 units)
int offset_bottom64
descender amount of the last line (in 26.6 units)
int max_x64
maximum value of bbox.xMax among glyphs (in 26.6 units)
int max_y64
maximum value of bbox.yMax among glyphs (in 26.6 units)
int height
total height of the text - ceil(height64/64)
int rect_x
x position of the box
#define av_malloc_array(a, b)
static void error(const char *err)
int ff_print_pts(void *log_ctx, AVBPrint *bp, double pts, const char *delta, const char *fmt, const char *strftime_fmt)
int ff_load_textfile(void *log_ctx, const char *textfile, unsigned char **text, size_t *text_size)
int ff_expand_text(FFExpandTextContext *expand_text, const char *text, AVBPrint *bp)
Expand text template.
int ff_print_time(void *log_ctx, AVBPrint *bp, const char *strftime_fmt, char localtime)
int ff_print_formatted_eval_expr(void *log_ctx, AVBPrint *bp, const char *expr, const char *const *fun_names, const ff_eval_func2 *fun_values, const char *const *var_names, const double *var_values, void *eval_ctx, const char format, int positions)
int ff_print_eval_expr(void *log_ctx, AVBPrint *bp, const char *expr, const char *const *fun_names, const ff_eval_func2 *fun_values, const char *const *var_names, const double *var_values, void *eval_ctx)
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum_arg)
Load timecode string in buf.
#define AV_TIMECODE_STR_SIZE
@ AV_TIMECODE_FLAG_24HOURSMAX
timecode wraps after 24 hours
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
static const AVFilterPad avfilter_vf_drawtext_inputs[]
double(* eval_func2)(void *, double a, double b)
static const AVOption drawtext_options[]
static int config_input(AVFilterLink *inlink)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
static void update_alpha(DrawTextContext *s)
static int glyph_enu_border_free(void *opaque, void *elem)
static double drand(void *opaque, double min, double max)
static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static int draw_text(AVFilterContext *ctx, AVFrame *frame)
static void hb_destroy(HarfbuzzData *hb)
static av_cold void uninit(AVFilterContext *ctx)
static const struct ft_error ft_errors[]
static int measure_text(AVFilterContext *ctx, TextMetrics *metrics)
static int shape_text_hb(AVFilterContext *ctx, DrawTextContext *s, HarfbuzzData *hb, const char *text, int textLen)
static int draw_glyphs(AVFilterContext *ctx, AVFrame *frame, FFDrawColor *color, TextMetrics *metrics, int x, int y, int borderw)
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
static int glyph_enu_free(void *opaque, void *elem)
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
static const uint16_t positions[][14][3]
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.