50 #include <freetype/config/ftheader.h>
51 #include FT_FREETYPE_H
73 static double drand(
void *opaque,
double min,
double max)
146 #define OFFSET(x) offsetof(DrawTextContext, x)
163 {
"fix_bounds",
"if true, check and fix text coords to avoid clipping",
167 {
"ft_load_flags",
"set font loading flags for libfreetype",
OFFSET(ft_load_flags),
AV_OPT_TYPE_FLAGS, {.i64=FT_LOAD_DEFAULT|FT_LOAD_RENDER}, 0, INT_MAX, 0,
"ft_load_flags" },
168 {
"default",
"set default", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_DEFAULT}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
169 {
"no_scale",
"set no_scale", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_NO_SCALE}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
170 {
"no_hinting",
"set no_hinting", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_NO_HINTING}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
171 {
"render",
"set render", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_RENDER}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
172 {
"no_bitmap",
"set no_bitmap", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_NO_BITMAP}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
173 {
"vertical_layout",
"set vertical_layout", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_VERTICAL_LAYOUT}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
174 {
"force_autohint",
"set force_autohint", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_FORCE_AUTOHINT}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
175 {
"crop_bitmap",
"set crop_bitmap", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_CROP_BITMAP}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
176 {
"pedantic",
"set pedantic", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_PEDANTIC}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
177 {
"ignore_global_advance_width",
"set ignore_global_advance_width", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
178 {
"no_recurse",
"set no_recurse", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_NO_RECURSE}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
179 {
"ignore_transform",
"set ignore_transform", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_IGNORE_TRANSFORM}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
180 {
"monochrome",
"set monochrome", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_MONOCHROME}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
181 {
"linear_design",
"set linear_design", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_LINEAR_DESIGN}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
182 {
"no_autohint",
"set no_autohint", 0,
AV_OPT_TYPE_CONST, {.i64 = FT_LOAD_NO_AUTOHINT}, INT_MIN, INT_MAX, 0,
"ft_load_flags" },
197 #undef __FTERRORS_H__
198 #define FT_ERROR_START_LIST {
199 #define FT_ERRORDEF(e, v, s) { (e), (s) },
200 #define FT_ERROR_END_LIST { 0, NULL } };
209 #define FT_ERRMSG(e) ft_errors[e].err_msg
223 const Glyph *
a = key, *bb =
b;
224 int64_t diff = (int64_t)a->code - (int64_t)bb->code;
225 return diff > 0 ? 1 : diff < 0 ? -1 : 0;
244 !(glyph->glyph =
av_mallocz(
sizeof(*glyph->glyph)))) {
250 if (FT_Get_Glyph(dtext->
face->glyph, glyph->glyph)) {
255 glyph->bitmap = dtext->
face->glyph->bitmap;
256 glyph->bitmap_left = dtext->
face->glyph->bitmap_left;
257 glyph->bitmap_top = dtext->
face->glyph->bitmap_top;
258 glyph->advance = dtext->
face->glyph->advance.x >> 6;
261 FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
310 "Both text and text file provided. Please provide only one\n");
315 "The text file '%s' could not be read or is empty\n",
322 memcpy(dtext->
text, textbuf, textbuf_size);
323 dtext->
text[textbuf_size] = 0;
329 "Either text or a valid file must be provided\n");
351 if ((err = FT_Init_FreeType(&(dtext->
library)))) {
353 "Could not load FreeType: %s\n",
FT_ERRMSG(err));
363 if ((err = FT_Set_Pixel_Sizes(dtext->
face, 0, dtext->
fontsize))) {
375 if ((err =
load_glyph(ctx, &glyph,
' ') < 0)) {
379 dtext->
tabsize *= glyph->advance;
381 #if !HAVE_LOCALTIME_R
425 FT_Done_Face(dtext->
face);
426 FT_Done_FreeType(dtext->
library);
428 for (i = 0; i < 4; i++) {
437 return c ==
'\n' || c ==
'\r' || c ==
'\f' || c ==
'\v';
443 uint32_t code = 0, prev_code = 0;
444 int x = 0, y = 0, i = 0, ret;
445 int text_height, baseline;
446 char *text = dtext->
text;
449 int y_min = 32000, y_max = -32000;
451 Glyph *glyph =
NULL, *prev_glyph =
NULL;
457 time_t now = time(0);
463 buf_size = 2*strlen(dtext->
text)+1;
465 localtime_r(&now, <ime);
469 if (strftime(buf, buf_size, dtext->
text, <ime) != 0 || *buf == 0)
494 for (i = 0, p = text; *p; i++) {
506 y_min =
FFMIN(glyph->bbox.yMin, y_min);
507 y_max =
FFMAX(glyph->bbox.yMax, y_max);
509 text_height = y_max - y_min;
514 for (i = 0, p = text; *p; i++) {
518 if (prev_code ==
'\r' && code ==
'\n')
523 str_w =
FFMAX(str_w, x - dtext->
x);
535 if (dtext->
use_kerning && prev_glyph && glyph->code) {
536 FT_Get_Kerning(dtext->
face, prev_glyph->code, glyph->code,
537 ft_kerning_default, &delta);
541 if (x + glyph->bbox.xMax >= width) {
542 str_w =
FFMAX(str_w, x);
548 dtext->
positions[i].x = x + glyph->bitmap_left;
549 dtext->
positions[i].y = y - glyph->bitmap_top + baseline;
551 else x += glyph->advance;
555 y =
FFMIN(y + text_height, height - 1);
625 #define GET_BITMAP_VAL(r, c) \
626 bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? \
627 (bitmap->buffer[(r) * bitmap->pitch + ((c)>>3)] & (0x80 >> ((c)&7))) * 255 : \
628 bitmap->buffer[(r) * bitmap->pitch + (c)]
630 #define SET_PIXEL_YUV(picref, yuva_color, val, x, y, hsub, vsub) { \
631 luma_pos = ((x) ) + ((y) ) * picref->linesize[0]; \
632 alpha = yuva_color[3] * (val) * 129; \
633 picref->data[0][luma_pos] = (alpha * yuva_color[0] + (255*255*129 - alpha) * picref->data[0][luma_pos] ) >> 23; \
634 if (((x) & ((1<<(hsub)) - 1)) == 0 && ((y) & ((1<<(vsub)) - 1)) == 0) {\
635 chroma_pos1 = ((x) >> (hsub)) + ((y) >> (vsub)) * picref->linesize[1]; \
636 chroma_pos2 = ((x) >> (hsub)) + ((y) >> (vsub)) * picref->linesize[2]; \
637 picref->data[1][chroma_pos1] = (alpha * yuva_color[1] + (255*255*129 - alpha) * picref->data[1][chroma_pos1]) >> 23; \
638 picref->data[2][chroma_pos2] = (alpha * yuva_color[2] + (255*255*129 - alpha) * picref->data[2][chroma_pos2]) >> 23; \
643 unsigned int y,
unsigned int width,
unsigned int height,
644 const uint8_t yuva_color[4],
int hsub,
int vsub)
647 unsigned int luma_pos, chroma_pos1, chroma_pos2;
650 for (r = 0; r < bitmap->rows && r+y <
height; r++) {
651 for (c = 0; c < bitmap->width && c+x <
width; c++) {
657 SET_PIXEL_YUV(picref, yuva_color, src_val, c+x, y+r, hsub, vsub);
664 #define SET_PIXEL_RGB(picref, rgba_color, val, x, y, pixel_step, r_off, g_off, b_off, a_off) { \
665 p = picref->data[0] + (x) * pixel_step + ((y) * picref->linesize[0]); \
666 alpha = rgba_color[3] * (val) * 129; \
667 *(p+r_off) = (alpha * rgba_color[0] + (255*255*129 - alpha) * *(p+r_off)) >> 23; \
668 *(p+g_off) = (alpha * rgba_color[1] + (255*255*129 - alpha) * *(p+g_off)) >> 23; \
669 *(p+b_off) = (alpha * rgba_color[2] + (255*255*129 - alpha) * *(p+b_off)) >> 23; \
673 unsigned int x,
unsigned int y,
674 unsigned int width,
unsigned int height,
int pixel_step,
681 for (r = 0; r < bitmap->rows && r+y <
height; r++) {
682 for (c = 0; c < bitmap->width && c+x <
width; c++) {
688 SET_PIXEL_RGB(picref, rgba_color, src_val, c+x, y+r, pixel_step,
689 rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
699 int hsub,
int vsub,
int is_rgba_packed,
uint8_t rgba_map[4])
703 if (color[3] != 0xFF) {
704 if (is_rgba_packed) {
706 for (j = 0; j <
height; j++)
707 for (i = 0; i <
width; i++)
709 rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
711 unsigned int luma_pos, chroma_pos1, chroma_pos2;
712 for (j = 0; j <
height; j++)
713 for (i = 0; i <
width; i++)
718 line, pixel_step, hsub, vsub,
719 x, y, width, height);
732 for (i = 0, p = text; *p; i++) {
737 if (code ==
'\n' || code ==
'\r' || code ==
'\t')
743 if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
744 glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
754 yuvcolor, dtext->
hsub, dtext->
vsub);
769 drawbox(picref, dtext->
x, dtext->
y, dtext->
w, dtext->
h,
775 if ((ret =
draw_glyphs(dtext, picref, width, height,
783 if ((ret =
draw_glyphs(dtext, picref, width, height,
799 }
else if (d > INT_MAX || d < INT_MIN) {
800 *n = d > INT_MAX ? INT_MAX : INT_MIN;
835 if (dtext->
x < 0) dtext->
x = 0;
836 if (dtext->
y < 0) dtext->
y = 0;
837 if ((
unsigned)dtext->
x + (
unsigned)dtext->
w > inlink->
w)
838 dtext->
x = inlink->
w - dtext->
w;
839 if ((
unsigned)dtext->
y + (
unsigned)dtext->
h > inlink->
h)
840 dtext->
y = inlink->
h - dtext->
h;
843 dtext->
x &= ~((1 << dtext->
hsub) - 1);
844 dtext->
y &= ~((1 << dtext->
vsub) - 1);
846 av_dlog(ctx,
"n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n",
848 dtext->
x, dtext->
y, dtext->
x+dtext->
w, dtext->
y+dtext->
h);
882 .description =
NULL_IF_CONFIG_SMALL(
"Draw text on top of video frames using libfreetype library."),
888 .
inputs = avfilter_vf_drawtext_inputs,
889 .
outputs = avfilter_vf_drawtext_outputs,