[FFmpeg-cvslog] avfilter/vf_drawtext: add y_align option

yethie git at videolan.org
Mon Jun 19 23:41:42 EEST 2023


ffmpeg | branch: master | yethie <klimklim at tiscali.it> | Wed Jun 14 18:58:32 2023 +0200| [692d37d2e9ac641fa477c7a039f4d1e3beb3bd47] | committer: Paul B Mahol

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

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=692d37d2e9ac641fa477c7a039f4d1e3beb3bd47
---

 doc/filters.texi          | 10 ++++++++++
 libavfilter/vf_drawtext.c | 47 ++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 891c051029..9730444337 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -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).
 Please note that tab characters are only supported with the left horizontal alignment.
 
+ at item y_align
+Specify what the @var{y} value is referred to. Possible values are:
+ at itemize @bullet
+ at item @code{text} the top of the highest glyph of the first text line is placed at @var{y}
+ at item @code{baseline} the baseline of the first text line is placed at @var{y}
+ at 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
+ at end itemize
+The default value of @var{y_align} is "text" for backward compatibility.
+
 @item borderw
 Set the width of the border to be drawn around the text using @var{bordercolor}.
 The default value of @var{borderw} is 0.
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index e147196844..59ba3e40c0 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -171,6 +171,12 @@ enum expansion_mode {
     EXP_STRFTIME,
 };
 
+enum y_alignment {
+    YA_TEXT,
+    YA_BASELINE,
+    YA_FONT,
+};
+
 typedef struct HarfbuzzData {
     hb_buffer_t* buf;
     hb_font_t* font;
@@ -310,6 +316,7 @@ typedef struct DrawTextContext {
     int boxw;                       ///< the value of the boxw parameter
     int boxh;                       ///< the value of the boxh parameter
     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
     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"},
         {"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"},
+    {"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},
     {"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)
         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 (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_LINEJOIN_ROUND, 0);
     }
@@ -1634,7 +1647,6 @@ static int measure_text(AVFilterContext *ctx, TextMetrics *metrics)
     int line_count = 0;
     uint32_t code = 0;
     Glyph *glyph = NULL;
-    int height64;
 
     int i, tab_idx = 0, last_tab_idx = 0, line_offset = 0;
     char* p;
@@ -1753,10 +1765,13 @@ continue_on_failed2:
     metrics->line_height64 = s->face->size->metrics.height;
 
     metrics->width = POS_CEIL(width64, 64);
-    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);
-
+    if (s->y_align == YA_FONT) {
+        metrics->height = POS_CEIL(metrics->line_height64 * line_count, 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_right64 = last_max_x64;
     metrics->offset_bottom64 = cur_min_y64;
@@ -1929,7 +1944,13 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
     x = 0;
     y = 0;
     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) {
         TextLine *line = &s->lines[l];
@@ -1973,7 +1994,11 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame)
     }
 
     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_height = s->boxh == 0 ? metrics.height : s->boxh;



More information about the ffmpeg-cvslog mailing list