Go to the documentation of this file.
35 #include <sys/types.h>
43 #if CONFIG_LIBFONTCONFIG
44 #include <fontconfig/fontconfig.h>
73 #include FT_FREETYPE_H
81 #define POS_CEIL(x, y) ((x)/(y) + ((x)%(y) != 0))
89 "max_glyph_a",
"ascent",
90 "max_glyph_d",
"descent",
253 #if CONFIG_LIBFONTCONFIG
314 #if CONFIG_LIBFRIBIDI
332 #define OFFSET(x) offsetof(DrawTextContext, x)
333 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
334 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
371 #if CONFIG_LIBFONTCONFIG
392 {
"start_number",
"start frame number for n/frame_num variable",
OFFSET(start_number),
AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX,
FLAGS},
395 #if CONFIG_LIBFRIBIDI
400 {
"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" },
406 {
"vertical_layout",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_VERTICAL_LAYOUT }, .flags =
FLAGS, .unit =
"ft_load_flags" },
410 {
"ignore_global_advance_width",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH }, .flags =
FLAGS, .unit =
"ft_load_flags" },
412 {
"ignore_transform",
NULL, 0,
AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_IGNORE_TRANSFORM }, .flags =
FLAGS, .unit =
"ft_load_flags" },
421 #undef __FTERRORS_H__
422 #define FT_ERROR_START_LIST {
423 #define FT_ERRORDEF(e, v, s) { (e), (s) },
424 #define FT_ERROR_END_LIST { 0, NULL } };
432 #define FT_ERRMSG(e) ft_errors[e].err_msg
434 static int glyph_cmp(
const void *
key,
const void *
b)
440 return diff > 0 ? 1 : -1;
450 if ((err = FT_Set_Pixel_Sizes(
s->face, 0, fontsize))) {
462 s->fontsize = fontsize;
472 if (
s->fontsize_pexpr)
475 if (
s->fontsize_expr ==
NULL)
488 unsigned int fontsize =
s->default_fontsize;
490 double size, roundedsize;
493 if (
s->fontsize_expr !=
NULL) {
494 if ((err = parse_fontsize(
ctx)) < 0)
501 if (!(roundedsize > INT_MIN && roundedsize < INT_MAX)) {
505 fontsize = roundedsize;
513 if (fontsize ==
s->fontsize)
516 return set_fontsize(
ctx, fontsize);
524 err = FT_New_Face(
s->library, path,
index, &
s->face);
526 #if !CONFIG_LIBFONTCONFIG
535 #if CONFIG_LIBFONTCONFIG
539 FcConfig *fontconfig;
540 FcPattern *pat, *best;
541 FcResult
result = FcResultMatch;
548 fontconfig = FcInitLoadConfigAndFonts();
553 pat = FcNameParse(
s->fontfile ?
s->fontfile :
554 (uint8_t *)(intptr_t)
"default");
560 FcPatternAddString(pat, FC_FAMILY,
s->font);
562 parse_err = parse_fontsize(
ctx);
571 FcPatternAddDouble(pat, FC_SIZE,
size);
574 FcDefaultSubstitute(pat);
576 if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
578 FcPatternDestroy(pat);
582 best = FcFontMatch(fontconfig, pat, &
result);
583 FcPatternDestroy(pat);
585 if (!best ||
result != FcResultMatch) {
587 "Cannot find a valid font for the family %s\n",
593 FcPatternGetInteger(best, FC_INDEX, 0, &
index ) != FcResultMatch ||
594 FcPatternGetDouble (best, FC_SIZE, 0, &
size ) != FcResultMatch) {
599 if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
607 s->default_fontsize =
size + 0.5;
609 err = load_font_file(
ctx, filename,
index);
612 FcConfigDestroy(fontconfig);
614 FcPatternDestroy(best);
625 err = load_font_file(
ctx,
s->fontfile, 0);
628 #if CONFIG_LIBFONTCONFIG
629 err = load_font_fontconfig(
ctx);
636 #if CONFIG_LIBFRIBIDI
642 static const FriBidiFlags
flags = FRIBIDI_FLAGS_DEFAULT |
643 FRIBIDI_FLAGS_ARABIC;
644 FriBidiChar *unicodestr =
NULL;
646 FriBidiParType direction = FRIBIDI_PAR_LTR;
647 FriBidiStrIndex line_start = 0;
648 FriBidiStrIndex line_end = 0;
649 FriBidiLevel *embedding_levels =
NULL;
650 FriBidiArabicProp *ar_props =
NULL;
651 FriBidiCharType *bidi_types =
NULL;
654 len = strlen(
s->text);
658 len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
659 s->text,
len, unicodestr);
666 fribidi_get_bidi_types(unicodestr,
len, bidi_types);
669 if (!embedding_levels) {
673 if (!fribidi_get_par_embedding_levels(bidi_types,
len, &direction,
683 fribidi_get_joining_types(unicodestr,
len, ar_props);
684 fribidi_join_arabic(bidi_types,
len, embedding_levels, ar_props);
685 fribidi_shape(
flags, embedding_levels,
len, ar_props, unicodestr);
687 for (line_end = 0, line_start = 0; line_end <
len; line_end++) {
688 if (ff_is_newline(unicodestr[line_end]) || line_end ==
len - 1) {
689 if (!fribidi_reorder_line(
flags, bidi_types,
690 line_end - line_start + 1, line_start,
691 direction, embedding_levels, unicodestr,
695 line_start = line_end + 1;
700 for (
i = 0, j = 0;
i <
len;
i++)
701 if (unicodestr[
i] != FRIBIDI_CHAR_FILL)
702 unicodestr[j++] = unicodestr[
i];
711 len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
712 unicodestr,
len,
s->text);
728 if (!strcmp(text_source_string,
"side_data_detection_bboxes")) {
735 static inline int get_subpixel_idx(
int shift_x64,
int shift_y64)
737 int idx = (shift_x64 >> 2) + (shift_y64 >> 4);
753 dummy.fontsize =
s->fontsize;
756 if (FT_Load_Glyph(
s->face,
code,
s->ft_load_flags)) {
766 if (FT_Get_Glyph(
s->face->glyph, &glyph->
glyph)) {
772 if (FT_Glyph_StrokeBorder(&glyph->
border_glyph,
s->stroker, 0, 0)) {
778 FT_Glyph_Get_CBox(glyph->
glyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph->
bbox);
789 if (FT_Glyph_StrokeBorder(&glyph->
border_glyph,
s->stroker, 0, 0)) {
797 if (shift_x64 >= 0 && shift_y64 >= 0) {
799 int idx = get_subpixel_idx(shift_x64, shift_y64);
803 if (!glyph->
bglyph[idx]) {
804 FT_Glyph tmp_glyph = glyph->
glyph;
805 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
809 glyph->
bglyph[idx] = (FT_BitmapGlyph)tmp_glyph;
810 if (glyph->
bglyph[idx]->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
818 if (FT_Glyph_To_Bitmap(&tmp_glyph, FT_RENDER_MODE_NORMAL, &
shift, 0)) {
831 if (glyph && glyph->
glyph)
832 FT_Done_Glyph(glyph->
glyph);
840 static int string_to_array(
const char *
source,
int *
result,
int result_size)
847 if (result_size > 0 && (curval =
av_strtok(dup,
"|", &saveptr))) {
849 result[counter++] = atoi(curval);
850 }
while ((curval =
av_strtok(
NULL,
"|", &saveptr)) && counter < result_size);
856 static int func_pict_type(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
864 static int func_pts(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
868 const char *strftime_fmt =
NULL;
874 fmt = argc >= 1 ? argv[0] :
"flt";
879 if (!strcmp(fmt,
"hms")) {
880 if (!strcmp(argv[2],
"24HH")) {
888 strftime_fmt = argv[2];
895 static int func_frame_num(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
903 static int func_metadata(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
915 static int func_strftime(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
917 const char *strftime_fmt = argc ? argv[0] :
NULL;
919 return ff_print_time(
ctx, bp, strftime_fmt, !strcmp(function_name,
"localtime"));
922 static int func_eval_expr(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
931 static int func_eval_expr_int_format(
void *
ctx, AVBPrint *bp,
const char *function_name,
unsigned argc,
char **argv)
947 " to print: '%s'\n", argv[2]);
961 {
"eif", 2, 3, func_eval_expr_int_format },
963 {
"expr_int_format", 2, 3, func_eval_expr_int_format },
967 {
"metadata", 1, 2, func_metadata },
969 {
"pict_type", 0, 0, func_pict_type },
979 s->fontsize_pexpr =
NULL;
982 s->default_fontsize = 16;
984 if (!
s->fontfile && !CONFIG_LIBFONTCONFIG) {
992 "Both text and text file provided. Please provide only one\n");
999 if (
s->reload && !
s->textfile)
1002 if (
s->tc_opt_string) {
1004 s->tc_opt_string,
ctx);
1013 if (
s->text_source_string) {
1014 s->text_source = text_source_string_parse(
s->text_source_string);
1015 if ((
int)
s->text_source < 0) {
1034 "Either text, a valid file, a timecode or text source must be provided\n");
1044 #if CONFIG_LIBFRIBIDI
1045 if (
s->text_shaping)
1046 if ((err = shape_text(
ctx)) < 0)
1050 if ((err = FT_Init_FreeType(&(
s->library)))) {
1052 "Could not load FreeType: %s\n",
FT_ERRMSG(err));
1056 if ((err = load_font(
ctx)) < 0)
1059 if ((err = update_fontsize(
ctx)) < 0)
1063 if (FT_Stroker_New(
s->library, &
s->stroker)) {
1069 FT_Stroker_Set(
s->stroker,
s->borderw << 6, FT_STROKER_LINECAP_ROUND,
1070 FT_STROKER_LINEJOIN_ROUND, 0);
1074 load_glyph(
ctx,
NULL, 0, 0, 0);
1077 (strchr(
s->text,
'%') || strchr(
s->text,
'\\')))
1099 for (
int t = 0; t < 16; ++t) {
1115 FT_Done_Glyph(glyph->
glyph);
1117 for (
int t = 0; t < 16; ++t) {
1119 FT_Done_Glyph((FT_Glyph)glyph->
bglyph[t]);
1138 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
s->fontsize_pexpr =
NULL;
1144 FT_Done_Face(
s->face);
1145 FT_Stroker_Done(
s->stroker);
1146 FT_Done_FreeType(
s->library);
1169 s->var_values[
VAR_HSUB] = 1 <<
s->dc.hsub_max;
1170 s->var_values[
VAR_VSUB] = 1 <<
s->dc.vsub_max;
1180 s->x_pexpr =
s->y_pexpr =
s->a_pexpr =
NULL;
1201 if (!strcmp(cmd,
"reinit")) {
1206 new->class = &drawtext_class;
1234 int old_borderw = old->
borderw;
1238 if (old->
borderw != old_borderw) {
1239 FT_Stroker_Set(old->
stroker, old->
borderw << 6, FT_STROKER_LINECAP_ROUND,
1240 FT_STROKER_LINEJOIN_ROUND, 0);
1243 }
else if (strcmp(cmd,
"fontsize") == 0) {
1260 color->rgba[3] = (
color->rgba[3] *
s->alpha) / 255;
1273 else if (
alpha <= 0)
1282 int x,
int y,
int borderw)
1284 int g, l, x1, y1, w1, h1, idx;
1285 int dx = 0, dy = 0, pdx = 0;
1289 FT_BitmapGlyph b_glyph;
1290 uint8_t j_left = 0, j_right = 0, j_top = 0, j_bottom = 0;
1291 int line_w, offset_y = 0;
1292 int clip_x = 0, clip_y = 0;
1294 j_left = !!(
s->text_align &
TA_LEFT);
1296 j_top = !!(
s->text_align &
TA_TOP);
1299 if (j_top && j_bottom) {
1300 offset_y = (
s->box_height - metrics->
height) / 2;
1301 }
else if (j_bottom) {
1302 offset_y =
s->box_height - metrics->
height;
1305 if ((!j_left || j_right) && !
s->tab_warning_printed &&
s->tab_count > 0) {
1306 s->tab_warning_printed = 1;
1313 for (l = 0; l <
s->line_count; ++l) {
1316 for (
g = 0;
g <
line->hb_data.glyph_count; ++
g) {
1318 dummy.fontsize =
s->fontsize;
1325 idx = get_subpixel_idx(
info->shift_x64,
info->shift_y64);
1327 bitmap = b_glyph->bitmap;
1328 x1 = x +
info->x + b_glyph->left;
1329 y1 = y +
info->y - b_glyph->top + offset_y;
1333 if (j_left && j_right) {
1334 x1 += (
s->box_width - line_w) / 2;
1335 }
else if (j_right) {
1336 x1 +=
s->box_width - line_w;
1341 if (x1 < metrics->rect_x -
s->bb_left) {
1342 dx = metrics->
rect_x -
s->bb_left - x1;
1343 x1 = metrics->
rect_x -
s->bb_left;
1345 if (y1 < metrics->rect_y -
s->bb_top) {
1346 dy = metrics->
rect_y -
s->bb_top - y1;
1347 y1 = metrics->
rect_y -
s->bb_top;
1351 if (dx >= w1 || dy >= h1 || x1 >= clip_x || y1 >= clip_y) {
1355 pdx = dx + dy * bitmap.pitch;
1356 w1 =
FFMIN(clip_x - x1, w1 - dx);
1357 h1 =
FFMIN(clip_y - y1, h1 - dy);
1360 bitmap.buffer + pdx, bitmap.pitch, w1, h1, 3, 0, x1, y1);
1370 hb->
buf = hb_buffer_create();
1371 if(!hb_buffer_allocation_successful(hb->
buf)) {
1374 hb_buffer_set_direction(hb->
buf, HB_DIRECTION_LTR);
1375 hb_buffer_set_script(hb->
buf, HB_SCRIPT_LATIN);
1376 hb_buffer_set_language(hb->
buf, hb_language_from_string(
"en", -1));
1377 hb_buffer_guess_segment_properties(hb->
buf);
1378 hb->
font = hb_ft_font_create_referenced(
s->face);
1382 hb_buffer_add_utf8(hb->
buf, text, textLen, 0, -1);
1392 hb_font_destroy(hb->
font);
1393 hb_buffer_destroy(hb->
buf);
1403 char *text =
s->expanded_text.str;
1404 char *textdup =
NULL, *start =
NULL;
1406 int width64 = 0, w64 = 0;
1407 int cur_min_y64 = 0, first_max_y64 = -32000;
1408 int first_min_x64 = 32000, last_max_x64 = -32000;
1409 int min_y64 = 32000, max_y64 = -32000, min_x64 = 32000, max_x64 = -32000;
1414 int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
1420 for (
i = 0, p = text; 1;
i++) {
1423 if (ff_is_newline(
code) ||
code == 0) {
1428 }
else if (
code ==
'\t') {
1434 if (
s->tab_count > 0 && !
s->blank_advance64) {
1440 s->blank_advance64 = hb_data.
glyph_pos[0].x_advance;
1444 s->line_count = line_count;
1446 s->tab_clusters =
av_mallocz(
s->tab_count *
sizeof(uint32_t));
1447 for (
i = 0;
i <
s->tab_count; ++
i) {
1448 s->tab_clusters[
i] = -1;
1452 if (textdup ==
NULL) {
1457 for (
i = 0, p = textdup; 1;
i++) {
1459 s->tab_clusters[tab_idx++] =
i;
1463 continue_on_failed2:
1464 if (ff_is_newline(
code) ||
code == 0) {
1465 TextLine *cur_line = &
s->lines[line_count];
1473 cur_min_y64 = 32000;
1475 uint8_t is_tab = last_tab_idx <
s->tab_count &&
1476 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] - line_offset;
1484 if (line_count == 0) {
1485 first_max_y64 =
FFMAX(glyph->
bbox.yMax, first_max_y64);
1489 first_min_x64 =
FFMIN(glyph->
bbox.xMin, first_min_x64);
1494 int last_char_width = hb->
glyph_pos[t].x_advance;
1500 w64 += last_char_width;
1501 last_max_x64 =
FFMAX(last_char_width, last_max_x64);
1505 int size =
s->blank_advance64 *
s->tabsize;
1511 cur_min_y64 =
FFMIN(glyph->
bbox.yMin, cur_min_y64);
1512 min_y64 =
FFMIN(glyph->
bbox.yMin, min_y64);
1513 max_y64 =
FFMAX(glyph->
bbox.yMax, max_y64);
1514 min_x64 =
FFMIN(glyph->
bbox.xMin, min_x64);
1515 max_x64 =
FFMAX(glyph->
bbox.xMax, max_x64);
1520 av_log(
s,
AV_LOG_DEBUG,
" Line: %d -- glyphs count: %d - width64: %d - offset_left64: %d - offset_right64: %d)\n",
1523 if (w64 > width64) {
1529 line_offset =
i + 1;
1532 if (
code == 0)
break;
1543 (
FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
1565 int x = 0, y = 0,
ret;
1566 int shift_x64, shift_y64;
1570 time_t now = time(0);
1572 AVBPrint *bp = &
s->expanded_text;
1581 int rec_x = 0, rec_y = 0, rec_width = 0, rec_height = 0;
1583 int last_tab_idx = 0;
1590 now=
frame->pts*
av_q2d(
ctx->inputs[0]->time_base) +
s->basetime/1000000;
1592 switch (
s->exp_mode) {
1606 if (
s->tc_opt_string) {
1616 if (
s->fontcolor_expr[0]) {
1630 if ((
ret = update_fontsize(
ctx)) < 0) {
1647 s->var_values[
VAR_FONT_A] =
s->face->size->metrics.ascender / 64;
1649 s->var_values[
VAR_FONT_D] = -
s->face->size->metrics.descender / 64;
1671 if (
s->draw_box &&
s->boxborderw) {
1674 count = string_to_array(
s->boxborderw, bbsize, 4);
1676 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = bbsize[0];
1677 }
else if (count == 2) {
1678 s->bb_top =
s->bb_bottom = bbsize[0];
1679 s->bb_right =
s->bb_left = bbsize[1];
1680 }
else if (count == 3) {
1681 s->bb_top = bbsize[0];
1682 s->bb_right =
s->bb_left = bbsize[1];
1683 s->bb_bottom = bbsize[2];
1684 }
else if (count == 4) {
1685 s->bb_top = bbsize[0];
1686 s->bb_right = bbsize[1];
1687 s->bb_bottom = bbsize[2];
1688 s->bb_left = bbsize[3];
1691 s->bb_top =
s->bb_right =
s->bb_bottom =
s->bb_left = 0;
1694 if (
s->fix_bounds) {
1696 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
1698 int offsetleft =
FFMAX3(
FFMAX(
s->bb_left, 0), borderoffset,
1699 (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0));
1700 int offsettop =
FFMAX3(
FFMAX(
s->bb_top, 0), borderoffset,
1701 (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0));
1702 int offsetright =
FFMAX3(
FFMAX(
s->bb_right, 0), borderoffset,
1703 (
s->shadowx > 0 ?
s->shadowx : 0));
1704 int offsetbottom =
FFMAX3(
FFMAX(
s->bb_bottom, 0), borderoffset,
1705 (
s->shadowy > 0 ?
s->shadowy : 0));
1707 if (
s->x - offsetleft < 0)
s->x = offsetleft;
1708 if (
s->y - offsettop < 0)
s->y = offsettop;
1718 x64 = (int)(
s->x * 64.);
1720 y64 = (int)(
s->y * 64. +
s->face->size->metrics.ascender);
1722 y64 = (int)(
s->y * 64.);
1727 for (
int l = 0; l <
s->line_count; ++l) {
1734 uint8_t is_tab = last_tab_idx <
s->tab_count &&
1735 hb->
glyph_info[t].cluster ==
s->tab_clusters[last_tab_idx] -
line->cluster_offset;
1742 shift_x64 = (((x64 + true_x) >> 4) & 0b0011) << 4;
1743 shift_y64 = ((4 - (((y64 + true_y) >> 4) & 0b0011)) & 0b0011) << 4;
1745 ret = load_glyph(
ctx, &glyph, hb->
glyph_info[t].codepoint, shift_x64, shift_y64);
1750 g_info->
x = (x64 + true_x) >> 6;
1751 g_info->
y = ((y64 + true_y) >> 6) + (shift_y64 > 0 ? 1 : 0);
1758 int size =
s->blank_advance64 *
s->tabsize;
1775 s->box_width =
s->boxw == 0 ? metrics.
width :
s->boxw;
1776 s->box_height =
s->boxh == 0 ? metrics.
height :
s->boxh;
1781 int borderoffset =
s->borderw ?
FFMAX(
s->borderw, 0) : 0;
1782 s->bb_left = borderoffset + (
s->shadowx < 0 ?
FFABS(
s->shadowx) : 0) + 1;
1783 s->bb_top = borderoffset + (
s->shadowy < 0 ?
FFABS(
s->shadowy) : 0) + 1;
1784 s->bb_right = borderoffset + (
s->shadowx > 0 ?
s->shadowx : 0) + 1;
1785 s->bb_bottom = borderoffset + (
s->shadowy > 0 ?
s->shadowy : 0) + 1;
1791 metrics.
rect_x +
s->box_width +
s->bb_right <= 0 ||
1792 metrics.
rect_y +
s->box_height +
s->bb_bottom <= 0;
1797 rec_x = metrics.
rect_x -
s->bb_left;
1798 rec_y = metrics.
rect_y -
s->bb_top;
1799 rec_width =
s->box_width +
s->bb_right +
s->bb_left;
1800 rec_height =
s->box_height +
s->bb_bottom +
s->bb_top;
1803 rec_x, rec_y, rec_width, rec_height);
1806 if (
s->shadowx ||
s->shadowy) {
1808 s->shadowx,
s->shadowy,
s->borderw)) < 0) {
1815 0, 0,
s->borderw)) < 0) {
1827 for (
int l = 0; l <
s->line_count; ++l) {
1866 #if CONFIG_LIBFRIBIDI
1867 if (
s->text_shaping)
1868 if ((
ret = shape_text(
ctx)) < 0) {
1880 #if FF_API_FRAME_PKT
1882 s->var_values[VAR_PKT_POS] =
frame->pkt_pos;
1883 s->var_values[VAR_PKT_SIZE] =
frame->pkt_size;
1888 s->metadata =
frame->metadata;
1890 for (
int i = 0;
i <
loop;
i++) {
1895 strcat(
s->text,
", ");
1899 s->y = bbox->
y -
s->fontsize;
1919 .description =
NULL_IF_CONFIG_SMALL(
"Draw text on top of video frames using libfreetype library."),
1921 .priv_class = &drawtext_class,
static void error(const char *err)
FT_Library library
freetype font library handle
#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
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.
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)
#define FILTER_INPUTS(array)
This structure describes decoded (raw) audio or video data.
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 AV_LOG_VERBOSE
Detailed information.
static int func_pts(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
FT_Stroker stroker
freetype stroker handle
const char * name
Filter name.
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
int box_height
the height of box
TextLine * lines
computed information about text lines
A link between two filters.
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
Link properties exposed to filter code, but not external callers.
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
unsigned int fontsize
font size to use
static const FFExpandTextFunction expand_text_functions[]
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
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
FFExpandTextContext expand_text
expand text in case exp_mode == NORMAL
FT_BitmapGlyph bglyph[16]
Glyph bitmaps with 1/4 pixel precision in both directions.
int bb_top
the size of the top box border
static void hb_destroy(HarfbuzzData *hb)
int ff_expand_text(FFExpandTextContext *expand_text, const char *text, AVBPrint *bp)
Expand text template.
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.
Function used to expand a template sequence in the format %{FUNCTION_NAME[:PARAMS]},...
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)
int ff_load_textfile(void *log_ctx, const char *textfile, unsigned char **text, size_t *text_size)
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().
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
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.
#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.
static int func_frame_num(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
AVExpr * fontsize_pexpr
parsed expressions for fontsize
double(* eval_func2)(void *, double a, double b)
#define FILTER_OUTPUTS(array)
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
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
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 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.
@ AV_OPT_TYPE_COLOR
Underlying C type is uint8_t[4].
AVRational tc_rate
frame rate for timecode
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)
static FilterLink * ff_filter_link(AVFilterLink *link)
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 av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
int bb_right
the size of the right box border
static av_cold void uninit(AVFilterContext *ctx)
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
int offset_left64
offset between the origin and the leftmost pixel of the first glyph
Context structure for the Lagged Fibonacci PRNG.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
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.
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 ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, enum AVColorRange range, unsigned flags)
Init a draw context.
short int draw_box
draw box around text - true or false
#define AV_NOPTS_VALUE
Undefined timestamp value.
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)
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...
int ff_print_pts(void *log_ctx, AVBPrint *bp, double pts, const char *delta, const char *fmt, const char *strftime_fmt)
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
static int glyph_enu_free(void *opaque, void *elem)
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.
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)
#define FILTER_QUERY_FUNC2(func)
static av_cold int init(AVFilterContext *ctx)
int max_glyph_h
max glyph height
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.
static int config_input(AVFilterLink *inlink)
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
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 it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
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
int reinit
tells if the filter is being reinited
@ AV_OPT_TYPE_INT
Underlying C type is int.
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
in a text template, followed by any character, always expands to the second character.
int x
Distance in pixels from the left/top edge of the frame, together with width and height,...
static int glyph_enu_border_free(void *opaque, void *elem)
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
#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.
static int func_eval_expr(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
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
enum AVFrameSideDataType text_source
HarfbuzzData hb_data
libharfbuzz data of this text line
static const int16_t alpha[]
static int func_strftime(void *ctx, AVBPrint *bp, const char *function_name, unsigned argc, char **argv)
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
double y
y position to start drawing text
FFDrawColor boxcolor
background color
@ AV_OPT_TYPE_FLAGS
Underlying C type is unsigned int.
#define flags(name, subs,...)
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.
double x
x position to start drawing text
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
@ 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...
char * y_expr
expression for y position
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
int ff_print_time(void *log_ctx, AVBPrint *bp, const char *strftime_fmt, char localtime)
int line_spacing
lines spacing in pixels
uint8_t * fontcolor_expr
fontcolor expression to evaluate
static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color)
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum_arg)
Load timecode string in buf.
@ 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
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