mirror of https://git.ffmpeg.org/ffmpeg.git
avfilter/vf_drawtext: add y_align option
The new y_align option specifies if the user provided y value is referred to the top of the text, to the font baseline or to the top of the font
This commit is contained in:
parent
5f2d907de2
commit
692d37d2e9
|
@ -12390,6 +12390,16 @@ The value must contain exactly two letters, one for the vertical alignment (T=to
|
||||||
M=middle, B=bottom) and one for the horizontal alignment (L=left, C=center, R=right).
|
M=middle, B=bottom) and one for the horizontal alignment (L=left, C=center, R=right).
|
||||||
Please note that tab characters are only supported with the left horizontal alignment.
|
Please note that tab characters are only supported with the left horizontal alignment.
|
||||||
|
|
||||||
|
@item y_align
|
||||||
|
Specify what the @var{y} value is referred to. Possible values are:
|
||||||
|
@itemize @bullet
|
||||||
|
@item @code{text} the top of the highest glyph of the first text line is placed at @var{y}
|
||||||
|
@item @code{baseline} the baseline of the first text line is placed at @var{y}
|
||||||
|
@item @code{font} the baseline of the first text line is placed at @var{y} plus the
|
||||||
|
ascent (in pixels) defined in the font metrics
|
||||||
|
@end itemize
|
||||||
|
The default value of @var{y_align} is "text" for backward compatibility.
|
||||||
|
|
||||||
@item borderw
|
@item borderw
|
||||||
Set the width of the border to be drawn around the text using @var{bordercolor}.
|
Set the width of the border to be drawn around the text using @var{bordercolor}.
|
||||||
The default value of @var{borderw} is 0.
|
The default value of @var{borderw} is 0.
|
||||||
|
|
|
@ -171,6 +171,12 @@ enum expansion_mode {
|
||||||
EXP_STRFTIME,
|
EXP_STRFTIME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum y_alignment {
|
||||||
|
YA_TEXT,
|
||||||
|
YA_BASELINE,
|
||||||
|
YA_FONT,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct HarfbuzzData {
|
typedef struct HarfbuzzData {
|
||||||
hb_buffer_t* buf;
|
hb_buffer_t* buf;
|
||||||
hb_font_t* font;
|
hb_font_t* font;
|
||||||
|
@ -310,6 +316,7 @@ typedef struct DrawTextContext {
|
||||||
int boxw; ///< the value of the boxw parameter
|
int boxw; ///< the value of the boxw parameter
|
||||||
int boxh; ///< the value of the boxh parameter
|
int boxh; ///< the value of the boxh parameter
|
||||||
uint8_t *text_align; ///< the horizontal and vertical text alignment
|
uint8_t *text_align; ///< the horizontal and vertical text alignment
|
||||||
|
int y_align; ///< the value of the y_align parameter
|
||||||
|
|
||||||
TextLine *lines; ///< computed information about text lines
|
TextLine *lines; ///< computed information about text lines
|
||||||
int line_count; ///< the number of text lines
|
int line_count; ///< the number of text lines
|
||||||
|
@ -353,6 +360,10 @@ static const AVOption drawtext_options[]= {
|
||||||
{"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
|
{"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
|
||||||
{"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
|
{"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
|
||||||
{"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
|
{"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
|
||||||
|
{"y_align", "set the y alignment", OFFSET(y_align), AV_OPT_TYPE_INT, {.i64=YA_TEXT}, 0, 2, FLAGS, "y_align"},
|
||||||
|
{"text", "y is referred to the top of the first text line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_TEXT}, 0, 0, FLAGS, "y_align"},
|
||||||
|
{"baseline", "y is referred to the baseline of the first line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_BASELINE}, 0, 0, FLAGS, "y_align"},
|
||||||
|
{"font", "y is referred to the font defined line metrics", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_FONT}, 0, 0, FLAGS, "y_align"},
|
||||||
|
|
||||||
{"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
|
{"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
|
||||||
{"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
|
{"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
|
||||||
|
@ -958,11 +969,13 @@ static av_cold int init(AVFilterContext *ctx)
|
||||||
if ((err = update_fontsize(ctx)) < 0)
|
if ((err = update_fontsize(ctx)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
// Always init the stroker, may be needed if borderw is set via command
|
||||||
|
if (FT_Stroker_New(s->library, &s->stroker)) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "Could not init FT stroker\n");
|
||||||
|
return AVERROR_EXTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->borderw) {
|
if (s->borderw) {
|
||||||
if (FT_Stroker_New(s->library, &s->stroker)) {
|
|
||||||
av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
|
|
||||||
return AVERROR_EXTERNAL;
|
|
||||||
}
|
|
||||||
FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
|
FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
|
||||||
FT_STROKER_LINEJOIN_ROUND, 0);
|
FT_STROKER_LINEJOIN_ROUND, 0);
|
||||||
}
|
}
|
||||||
|
@ -1634,7 +1647,6 @@ static int measure_text(AVFilterContext *ctx, TextMetrics *metrics)
|
||||||
int line_count = 0;
|
int line_count = 0;
|
||||||
uint32_t code = 0;
|
uint32_t code = 0;
|
||||||
Glyph *glyph = NULL;
|
Glyph *glyph = NULL;
|
||||||
int height64;
|
|
||||||
|
|
||||||
int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
|
int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
|
||||||
char* p;
|
char* p;
|
||||||
|
@ -1753,10 +1765,13 @@ continue_on_failed2:
|
||||||
metrics->line_height64 = s->face->size->metrics.height;
|
metrics->line_height64 = s->face->size->metrics.height;
|
||||||
|
|
||||||
metrics->width = POS_CEIL(width64, 64);
|
metrics->width = POS_CEIL(width64, 64);
|
||||||
height64 = (metrics->line_height64 + s->line_spacing * 64) *
|
if (s->y_align == YA_FONT) {
|
||||||
(FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
|
metrics->height = POS_CEIL(metrics->line_height64 * line_count, 64);
|
||||||
metrics->height = POS_CEIL(height64, 64);
|
} else {
|
||||||
|
int height64 = (metrics->line_height64 + s->line_spacing * 64) *
|
||||||
|
(FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64;
|
||||||
|
metrics->height = POS_CEIL(height64, 64);
|
||||||
|
}
|
||||||
metrics->offset_top64 = first_max_y64;
|
metrics->offset_top64 = first_max_y64;
|
||||||
metrics->offset_right64 = last_max_x64;
|
metrics->offset_right64 = last_max_x64;
|
||||||
metrics->offset_bottom64 = cur_min_y64;
|
metrics->offset_bottom64 = cur_min_y64;
|
||||||
|
@ -1929,7 +1944,13 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
|
||||||
x = 0;
|
x = 0;
|
||||||
y = 0;
|
y = 0;
|
||||||
x64 = (int)(s->x * 64.);
|
x64 = (int)(s->x * 64.);
|
||||||
y64 = (int)(s->y * 64. + metrics.offset_top64);
|
if (s->y_align == YA_FONT) {
|
||||||
|
y64 = (int)(s->y * 64. + s->face->size->metrics.ascender);
|
||||||
|
} else if (s->y_align == YA_BASELINE) {
|
||||||
|
y64 = (int)(s->y * 64.);
|
||||||
|
} else {
|
||||||
|
y64 = (int)(s->y * 64. + metrics.offset_top64);
|
||||||
|
}
|
||||||
|
|
||||||
for (int l = 0; l < s->line_count; ++l) {
|
for (int l = 0; l < s->line_count; ++l) {
|
||||||
TextLine *line = &s->lines[l];
|
TextLine *line = &s->lines[l];
|
||||||
|
@ -1973,7 +1994,11 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics.rect_x = s->x;
|
metrics.rect_x = s->x;
|
||||||
metrics.rect_y = s->y;
|
if (s->y_align == YA_BASELINE) {
|
||||||
|
metrics.rect_y = s->y - metrics.offset_top64 / 64;
|
||||||
|
} else {
|
||||||
|
metrics.rect_y = s->y;
|
||||||
|
}
|
||||||
|
|
||||||
s->box_width = s->boxw == 0 ? metrics.width : s->boxw;
|
s->box_width = s->boxw == 0 ? metrics.width : s->boxw;
|
||||||
s->box_height = s->boxh == 0 ? metrics.height : s->boxh;
|
s->box_height = s->boxh == 0 ? metrics.height : s->boxh;
|
||||||
|
|
Loading…
Reference in New Issue