Address trac issue #378.
Stefano Sabatini authored on 2011/09/18 09:41:56... | ... |
@@ -738,10 +738,13 @@ parameter @var{text}. |
738 | 738 |
If both text and textfile are specified, an error is thrown. |
739 | 739 |
|
740 | 740 |
@item x, y |
741 |
-The offsets where text will be drawn within the video frame. |
|
742 |
-Relative to the top/left border of the output image. |
|
741 |
+The expressions which specify the offsets where text will be drawn |
|
742 |
+within the video frame. They are relative to the top/left border of the |
|
743 |
+output image. |
|
743 | 744 |
|
744 |
-The default value of @var{x} and @var{y} is 0. |
|
745 |
+The default value of @var{x} and @var{y} is "0". |
|
746 |
+ |
|
747 |
+See below for the list of accepted constants. |
|
745 | 748 |
|
746 | 749 |
@item fontsize |
747 | 750 |
The font size to be used for drawing text. |
... | ... |
@@ -809,6 +812,66 @@ The size in number of spaces to use for rendering the tab. |
809 | 809 |
Default value is 4. |
810 | 810 |
@end table |
811 | 811 |
|
812 |
+The parameters for @var{x} and @var{y} are expressions containing the |
|
813 |
+following constants: |
|
814 |
+ |
|
815 |
+@table @option |
|
816 |
+@item E, PI, PHI |
|
817 |
+the corresponding mathematical approximated values for e |
|
818 |
+(euler number), pi (greek PI), PHI (golden ratio) |
|
819 |
+ |
|
820 |
+@item w, h |
|
821 |
+the input width and heigth |
|
822 |
+ |
|
823 |
+@item tw, text_w |
|
824 |
+the width of the rendered text |
|
825 |
+ |
|
826 |
+@item th, text_h |
|
827 |
+the height of the rendered text |
|
828 |
+ |
|
829 |
+@item lh, line_h |
|
830 |
+the height of each text line |
|
831 |
+ |
|
832 |
+@item sar |
|
833 |
+input sample aspect ratio |
|
834 |
+ |
|
835 |
+@item dar |
|
836 |
+input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar} |
|
837 |
+ |
|
838 |
+@item hsub, vsub |
|
839 |
+horizontal and vertical chroma subsample values. For example for the |
|
840 |
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1. |
|
841 |
+ |
|
842 |
+@item max_glyph_w |
|
843 |
+maximum glyph width, that is the maximum width for all the glyphs |
|
844 |
+contained in the rendered text |
|
845 |
+ |
|
846 |
+@item max_glyph_h |
|
847 |
+maximum glyph height, that is the maximum height for all the glyphs |
|
848 |
+contained in the rendered text, it is equivalent to @var{ascent} - |
|
849 |
+@var{descent}. |
|
850 |
+ |
|
851 |
+@item max_glyph_a, ascent |
|
852 |
+ |
|
853 |
+the maximum distance from the baseline to the highest/upper grid |
|
854 |
+coordinate used to place a glyph outline point, for all the rendered |
|
855 |
+glyphs. |
|
856 |
+It is a positive value, due to the grid's orientation with the Y axis |
|
857 |
+upwards. |
|
858 |
+ |
|
859 |
+@item max_glyph_d, descent |
|
860 |
+the maximum distance from the baseline to the lowest grid coordinate |
|
861 |
+used to place a glyph outline point, for all the rendered glyphs. |
|
862 |
+This is a negative value, due to the grid's orientation, with the Y axis |
|
863 |
+upwards. |
|
864 |
+ |
|
865 |
+@item n |
|
866 |
+the number of input frame, starting from 0 |
|
867 |
+ |
|
868 |
+@item t |
|
869 |
+timestamp expressed in seconds, NAN if the input timestamp is unknown |
|
870 |
+@end table |
|
871 |
+ |
|
812 | 872 |
Some examples follow. |
813 | 873 |
|
814 | 874 |
@itemize |
... | ... |
@@ -835,6 +898,33 @@ drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test |
835 | 835 |
Note that the double quotes are not necessary if spaces are not used |
836 | 836 |
within the parameter list. |
837 | 837 |
|
838 |
+@item |
|
839 |
+Show the text at the center of the video frame: |
|
840 |
+@example |
|
841 |
+drawtext=fontsize=30:fontfile=FreeSerif.ttf:text='hello world':x=(w-text_w)/2:y=(h-text_h-line_h)/2" |
|
842 |
+@end example |
|
843 |
+ |
|
844 |
+@item |
|
845 |
+Show a text line sliding from right to left in the last row of the video |
|
846 |
+frame. The file @file{LONG_LINE} is assumed to contain a single line |
|
847 |
+with no newlines. |
|
848 |
+@example |
|
849 |
+drawtext=fontsize=15:fontfile=FreeSerif.ttf:text=LONG_LINE:y=h-line_h:x=-50*t |
|
850 |
+@end example |
|
851 |
+ |
|
852 |
+@item |
|
853 |
+Show the content of file @file{CREDITS} off the bottom of the frame and scroll up. |
|
854 |
+@example |
|
855 |
+drawtext=fontsize=20:fontfile=FreeSerif.ttf:textfile=CREDITS:y=h-20*t" |
|
856 |
+@end example |
|
857 |
+ |
|
858 |
+@item |
|
859 |
+Draw a single green letter "g", at the center of the input video. |
|
860 |
+The glyph baseline is placed at half screen height. |
|
861 |
+@example |
|
862 |
+drawtext=fontsize=60:fontfile=FreeSerif.ttf:fontcolor=green:text=g:x=(w-max_glyph_w)/2:y=h/2-ascent |
|
863 |
+@end example |
|
864 |
+ |
|
838 | 865 |
@end itemize |
839 | 866 |
|
840 | 867 |
For more information about libfreetype, check: |
... | ... |
@@ -30,7 +30,7 @@ |
30 | 30 |
|
31 | 31 |
#define LIBAVFILTER_VERSION_MAJOR 2 |
32 | 32 |
#define LIBAVFILTER_VERSION_MINOR 43 |
33 |
-#define LIBAVFILTER_VERSION_MICRO 4 |
|
33 |
+#define LIBAVFILTER_VERSION_MICRO 5 |
|
34 | 34 |
|
35 | 35 |
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
36 | 36 |
LIBAVFILTER_VERSION_MINOR, \ |
... | ... |
@@ -30,6 +30,7 @@ |
30 | 30 |
#include <time.h> |
31 | 31 |
|
32 | 32 |
#include "libavutil/colorspace.h" |
33 |
+#include "libavutil/eval.h" |
|
33 | 34 |
#include "libavutil/file.h" |
34 | 35 |
#include "libavutil/opt.h" |
35 | 36 |
#include "libavutil/parseutils.h" |
... | ... |
@@ -45,6 +46,54 @@ |
45 | 45 |
#include FT_FREETYPE_H |
46 | 46 |
#include FT_GLYPH_H |
47 | 47 |
|
48 |
+static const char *var_names[] = { |
|
49 |
+ "E", |
|
50 |
+ "PHI", |
|
51 |
+ "PI", |
|
52 |
+ "w", ///< width of the input video |
|
53 |
+ "h", ///< height of the input video |
|
54 |
+ "tw", "text_w", ///< width of the rendered text |
|
55 |
+ "th", "text_h", ///< height of the rendered text |
|
56 |
+ "max_glyph_w", ///< max glyph width |
|
57 |
+ "max_glyph_h", ///< max glyph height |
|
58 |
+ "max_glyph_a", "ascent", ///< max glyph ascent |
|
59 |
+ "max_glyph_d", "descent", ///< min glyph descent |
|
60 |
+ "line_h", "lh", ///< line height, same as max_glyph_h |
|
61 |
+ "sar", |
|
62 |
+ "dar", |
|
63 |
+ "hsub", |
|
64 |
+ "vsub", |
|
65 |
+ "x", |
|
66 |
+ "y", |
|
67 |
+ "n", ///< number of frame |
|
68 |
+ "t", ///< timestamp expressed in seconds |
|
69 |
+ NULL |
|
70 |
+}; |
|
71 |
+ |
|
72 |
+enum var_name { |
|
73 |
+ VAR_E, |
|
74 |
+ VAR_PHI, |
|
75 |
+ VAR_PI, |
|
76 |
+ VAR_W, |
|
77 |
+ VAR_H, |
|
78 |
+ VAR_TW, VAR_TEXT_W, |
|
79 |
+ VAR_TH, VAR_TEXT_H, |
|
80 |
+ VAR_MAX_GLYPH_W, |
|
81 |
+ VAR_MAX_GLYPH_H, |
|
82 |
+ VAR_MAX_GLYPH_A, VAR_ASCENT, |
|
83 |
+ VAR_MAX_GLYPH_D, VAR_DESCENT, |
|
84 |
+ VAR_LINE_H, VAR_LH, |
|
85 |
+ VAR_SAR, |
|
86 |
+ VAR_DAR, |
|
87 |
+ VAR_HSUB, |
|
88 |
+ VAR_VSUB, |
|
89 |
+ VAR_X, |
|
90 |
+ VAR_Y, |
|
91 |
+ VAR_N, |
|
92 |
+ VAR_T, |
|
93 |
+ VAR_VARS_NB |
|
94 |
+}; |
|
95 |
+ |
|
48 | 96 |
typedef struct { |
49 | 97 |
const AVClass *class; |
50 | 98 |
uint8_t *fontfile; ///< font to be used |
... | ... |
@@ -57,6 +106,11 @@ typedef struct { |
57 | 57 |
char *textfile; ///< file with text to be drawn |
58 | 58 |
int x; ///< x position to start drawing text |
59 | 59 |
int y; ///< y position to start drawing text |
60 |
+ char *x_expr; ///< expression for x position |
|
61 |
+ char *y_expr; ///< expression for y position |
|
62 |
+ AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y |
|
63 |
+ int max_glyph_w; ///< max glyph width |
|
64 |
+ int max_glyph_h; ///< max glyph heigth |
|
60 | 65 |
int shadowx, shadowy; |
61 | 66 |
unsigned int fontsize; ///< font size to use |
62 | 67 |
char *fontcolor_string; ///< font color as string |
... | ... |
@@ -82,6 +136,7 @@ typedef struct { |
82 | 82 |
uint8_t rgba_map[4]; ///< map RGBA offsets to the positions in the packed RGBA format |
83 | 83 |
uint8_t *box_line[4]; ///< line used for filling the box background |
84 | 84 |
int64_t basetime; ///< base pts time in the real world for display |
85 |
+ double var_values[VAR_VARS_NB]; |
|
85 | 86 |
} DrawTextContext; |
86 | 87 |
|
87 | 88 |
#define OFFSET(x) offsetof(DrawTextContext, x) |
... | ... |
@@ -95,8 +150,8 @@ static const AVOption drawtext_options[]= { |
95 | 95 |
{"shadowcolor", "set shadow color", OFFSET(shadowcolor_string), FF_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX }, |
96 | 96 |
{"box", "set box", OFFSET(draw_box), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1 }, |
97 | 97 |
{"fontsize", "set font size", OFFSET(fontsize), FF_OPT_TYPE_INT, {.dbl=16}, 1, INT_MAX }, |
98 |
-{"x", "set x", OFFSET(x), FF_OPT_TYPE_INT, {.dbl=0}, 0, INT_MAX }, |
|
99 |
-{"y", "set y", OFFSET(y), FF_OPT_TYPE_INT, {.dbl=0}, 0, INT_MAX }, |
|
98 |
+{"x", "set x expression", OFFSET(x_expr), FF_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX }, |
|
99 |
+{"y", "set y expression", OFFSET(y_expr), FF_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX }, |
|
100 | 100 |
{"shadowx", "set x", OFFSET(shadowx), FF_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX }, |
101 | 101 |
{"shadowy", "set y", OFFSET(shadowy), FF_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX }, |
102 | 102 |
{"tabsize", "set tab size", OFFSET(tabsize), FF_OPT_TYPE_INT, {.dbl=4}, 0, INT_MAX }, |
... | ... |
@@ -348,12 +403,18 @@ static av_cold void uninit(AVFilterContext *ctx) |
348 | 348 |
DrawTextContext *dtext = ctx->priv; |
349 | 349 |
int i; |
350 | 350 |
|
351 |
+ av_expr_free(dtext->x_pexpr); dtext->x_pexpr = NULL; |
|
352 |
+ av_expr_free(dtext->y_pexpr); dtext->y_pexpr = NULL; |
|
353 |
+ |
|
351 | 354 |
av_freep(&dtext->fontfile); |
352 | 355 |
av_freep(&dtext->text); |
353 | 356 |
av_freep(&dtext->expanded_text); |
354 | 357 |
av_freep(&dtext->fontcolor_string); |
355 | 358 |
av_freep(&dtext->boxcolor_string); |
356 | 359 |
av_freep(&dtext->positions); |
360 |
+ av_freep(&dtext->x_expr); |
|
361 |
+ av_freep(&dtext->y_expr); |
|
362 |
+ |
|
357 | 363 |
dtext->nb_positions = 0; |
358 | 364 |
av_freep(&dtext->shadowcolor_string); |
359 | 365 |
av_tree_enumerate(dtext->glyphs, NULL, NULL, glyph_enu_free); |
... | ... |
@@ -371,6 +432,7 @@ static av_cold void uninit(AVFilterContext *ctx) |
371 | 371 |
|
372 | 372 |
static int config_input(AVFilterLink *inlink) |
373 | 373 |
{ |
374 |
+ AVFilterContext *ctx = inlink->dst; |
|
374 | 375 |
DrawTextContext *dtext = inlink->dst->priv; |
375 | 376 |
const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format]; |
376 | 377 |
int ret; |
... | ... |
@@ -398,6 +460,26 @@ static int config_input(AVFilterLink *inlink) |
398 | 398 |
dtext->shadowcolor[3] = rgba[3]; |
399 | 399 |
} |
400 | 400 |
|
401 |
+ dtext->var_values[VAR_E] = M_E; |
|
402 |
+ dtext->var_values[VAR_PHI] = M_PHI; |
|
403 |
+ dtext->var_values[VAR_PI] = M_PI; |
|
404 |
+ dtext->var_values[VAR_W] = inlink->w; |
|
405 |
+ dtext->var_values[VAR_H] = inlink->h; |
|
406 |
+ dtext->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1; |
|
407 |
+ dtext->var_values[VAR_DAR] = (double)inlink->w / inlink->h * dtext->var_values[VAR_SAR]; |
|
408 |
+ dtext->var_values[VAR_HSUB] = 1<<pix_desc->log2_chroma_w; |
|
409 |
+ dtext->var_values[VAR_VSUB] = 1<<pix_desc->log2_chroma_h; |
|
410 |
+ dtext->var_values[VAR_X] = NAN; |
|
411 |
+ dtext->var_values[VAR_Y] = NAN; |
|
412 |
+ dtext->var_values[VAR_N] = 0; |
|
413 |
+ dtext->var_values[VAR_T] = NAN; |
|
414 |
+ |
|
415 |
+ if ((ret = av_expr_parse(&dtext->x_pexpr, dtext->x_expr, var_names, |
|
416 |
+ NULL, NULL, NULL, NULL, 0, ctx)) < 0 || |
|
417 |
+ (ret = av_expr_parse(&dtext->y_pexpr, dtext->y_expr, var_names, |
|
418 |
+ NULL, NULL, NULL, NULL, 0, ctx)) < 0) |
|
419 |
+ return AVERROR(EINVAL); |
|
420 |
+ |
|
401 | 421 |
return 0; |
402 | 422 |
} |
403 | 423 |
|
... | ... |
@@ -441,6 +523,9 @@ static inline int draw_glyph_yuv(AVFilterBufferRef *picref, FT_Bitmap *bitmap, |
441 | 441 |
|
442 | 442 |
for (r = 0; r < bitmap->rows && r+y < height; r++) { |
443 | 443 |
for (c = 0; c < bitmap->width && c+x < width; c++) { |
444 |
+ if (c+x < 0 || r+y < 0) |
|
445 |
+ continue; |
|
446 |
+ |
|
444 | 447 |
/* get intensity value in the glyph bitmap (source) */ |
445 | 448 |
src_val = GET_BITMAP_VAL(r, c); |
446 | 449 |
if (!src_val) |
... | ... |
@@ -471,6 +556,8 @@ static inline int draw_glyph_rgb(AVFilterBufferRef *picref, FT_Bitmap *bitmap, |
471 | 471 |
|
472 | 472 |
for (r = 0; r < bitmap->rows && r+y < height; r++) { |
473 | 473 |
for (c = 0; c < bitmap->width && c+x < width; c++) { |
474 |
+ if (c+x < 0 || r+y < 0) |
|
475 |
+ continue; |
|
474 | 476 |
/* get intensity value in the glyph bitmap (source) */ |
475 | 477 |
src_val = GET_BITMAP_VAL(r, c); |
476 | 478 |
if (!src_val) |
... | ... |
@@ -521,7 +608,7 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref, |
521 | 521 |
{ |
522 | 522 |
char *text = dtext->expanded_text; |
523 | 523 |
uint32_t code = 0; |
524 |
- int i; |
|
524 |
+ int i, x1, y1; |
|
525 | 525 |
uint8_t *p; |
526 | 526 |
Glyph *glyph = NULL; |
527 | 527 |
|
... | ... |
@@ -540,13 +627,16 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref, |
540 | 540 |
glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) |
541 | 541 |
return AVERROR(EINVAL); |
542 | 542 |
|
543 |
+ x1 = dtext->positions[i].x+dtext->x+x; |
|
544 |
+ y1 = dtext->positions[i].y+dtext->y+y; |
|
545 |
+ |
|
543 | 546 |
if (dtext->is_packed_rgb) { |
544 | 547 |
draw_glyph_rgb(picref, &glyph->bitmap, |
545 |
- dtext->positions[i].x+x, dtext->positions[i].y+y, width, height, |
|
548 |
+ x1, y1, width, height, |
|
546 | 549 |
dtext->pixel_step[0], rgbcolor, dtext->rgba_map); |
547 | 550 |
} else { |
548 | 551 |
draw_glyph_yuv(picref, &glyph->bitmap, |
549 |
- dtext->positions[i].x+x, dtext->positions[i].y+y, width, height, |
|
552 |
+ x1, y1, width, height, |
|
550 | 553 |
yuvcolor, dtext->hsub, dtext->vsub); |
551 | 554 |
} |
552 | 555 |
} |
... | ... |
@@ -560,11 +650,12 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, |
560 | 560 |
DrawTextContext *dtext = ctx->priv; |
561 | 561 |
uint32_t code = 0, prev_code = 0; |
562 | 562 |
int x = 0, y = 0, i = 0, ret; |
563 |
- int text_height; |
|
563 |
+ int max_text_line_w = 0, len; |
|
564 |
+ int box_w, box_h; |
|
564 | 565 |
char *text = dtext->text; |
565 | 566 |
uint8_t *p; |
566 |
- int str_w = 0, len; |
|
567 | 567 |
int y_min = 32000, y_max = -32000; |
568 |
+ int x_min = 32000, x_max = -32000; |
|
568 | 569 |
FT_Vector delta; |
569 | 570 |
Glyph *glyph = NULL, *prev_glyph = NULL; |
570 | 571 |
Glyph dummy = { 0 }; |
... | ... |
@@ -607,8 +698,8 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, |
607 | 607 |
dtext->nb_positions = len; |
608 | 608 |
} |
609 | 609 |
|
610 |
- x = dtext->x; |
|
611 |
- y = dtext->y; |
|
610 |
+ x = 0; |
|
611 |
+ y = 0; |
|
612 | 612 |
|
613 | 613 |
/* load and cache glyphs */ |
614 | 614 |
for (i = 0, p = text; *p; i++) { |
... | ... |
@@ -622,8 +713,11 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, |
622 | 622 |
|
623 | 623 |
y_min = FFMIN(glyph->bbox.yMin, y_min); |
624 | 624 |
y_max = FFMAX(glyph->bbox.yMax, y_max); |
625 |
+ x_min = FFMIN(glyph->bbox.xMin, x_min); |
|
626 |
+ x_max = FFMAX(glyph->bbox.xMax, x_max); |
|
625 | 627 |
} |
626 |
- text_height = y_max - y_min; |
|
628 |
+ dtext->max_glyph_h = y_max - y_min; |
|
629 |
+ dtext->max_glyph_w = x_max - x_min; |
|
627 | 630 |
|
628 | 631 |
/* compute and save position for each glyph */ |
629 | 632 |
glyph = NULL; |
... | ... |
@@ -636,9 +730,9 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, |
636 | 636 |
|
637 | 637 |
prev_code = code; |
638 | 638 |
if (is_newline(code)) { |
639 |
- str_w = FFMAX(str_w, x - dtext->x); |
|
640 |
- y += text_height; |
|
641 |
- x = dtext->x; |
|
639 |
+ max_text_line_w = FFMAX(max_text_line_w, x); |
|
640 |
+ y += dtext->max_glyph_h; |
|
641 |
+ x = 0; |
|
642 | 642 |
continue; |
643 | 643 |
} |
644 | 644 |
|
... | ... |
@@ -661,12 +755,31 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, |
661 | 661 |
else x += glyph->advance; |
662 | 662 |
} |
663 | 663 |
|
664 |
- str_w = FFMIN(width - dtext->x - 1, FFMAX(str_w, x - dtext->x)); |
|
665 |
- y = FFMIN(y + text_height, height - 1); |
|
664 |
+ max_text_line_w = FFMAX(x, max_text_line_w); |
|
665 |
+ |
|
666 |
+ dtext->var_values[VAR_TW] = dtext->var_values[VAR_TEXT_W] = max_text_line_w; |
|
667 |
+ dtext->var_values[VAR_TH] = dtext->var_values[VAR_TEXT_H] = y + dtext->max_glyph_h; |
|
668 |
+ |
|
669 |
+ dtext->var_values[VAR_MAX_GLYPH_W] = dtext->max_glyph_w; |
|
670 |
+ dtext->var_values[VAR_MAX_GLYPH_H] = dtext->max_glyph_h; |
|
671 |
+ dtext->var_values[VAR_MAX_GLYPH_A] = dtext->var_values[VAR_ASCENT ] = y_max; |
|
672 |
+ dtext->var_values[VAR_MAX_GLYPH_D] = dtext->var_values[VAR_DESCENT] = y_min; |
|
673 |
+ |
|
674 |
+ dtext->var_values[VAR_LINE_H] = dtext->var_values[VAR_LH] = dtext->max_glyph_h; |
|
675 |
+ |
|
676 |
+ dtext->x = dtext->var_values[VAR_X] = av_expr_eval(dtext->x_pexpr, dtext->var_values, NULL); |
|
677 |
+ dtext->y = dtext->var_values[VAR_Y] = av_expr_eval(dtext->y_pexpr, dtext->var_values, NULL); |
|
678 |
+ dtext->x = dtext->var_values[VAR_X] = av_expr_eval(dtext->x_pexpr, dtext->var_values, NULL); |
|
679 |
+ |
|
680 |
+ dtext->x &= ~((1 << dtext->hsub) - 1); |
|
681 |
+ dtext->y &= ~((1 << dtext->vsub) - 1); |
|
682 |
+ |
|
683 |
+ box_w = FFMIN(width - 1 , max_text_line_w); |
|
684 |
+ box_h = FFMIN(height - 1, y + dtext->max_glyph_h); |
|
666 | 685 |
|
667 | 686 |
/* draw box */ |
668 | 687 |
if (dtext->draw_box) |
669 |
- drawbox(picref, dtext->x, dtext->y, str_w, y-dtext->y, |
|
688 |
+ drawbox(picref, dtext->x, dtext->y, box_w, box_h, |
|
670 | 689 |
dtext->box_line, dtext->pixel_step, dtext->boxcolor_rgba, |
671 | 690 |
dtext->hsub, dtext->vsub, dtext->is_packed_rgb, dtext->rgba_map); |
672 | 691 |
|
... | ... |
@@ -688,9 +801,21 @@ static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { } |
688 | 688 |
static void end_frame(AVFilterLink *inlink) |
689 | 689 |
{ |
690 | 690 |
AVFilterLink *outlink = inlink->dst->outputs[0]; |
691 |
+ AVFilterContext *ctx = inlink->dst; |
|
692 |
+ DrawTextContext *dtext = inlink->dst->priv; |
|
691 | 693 |
AVFilterBufferRef *picref = inlink->cur_buf; |
692 | 694 |
|
693 |
- draw_text(inlink->dst, picref, picref->video->w, picref->video->h); |
|
695 |
+ dtext->var_values[VAR_T] = picref->pts == AV_NOPTS_VALUE ? |
|
696 |
+ NAN : picref->pts * av_q2d(inlink->time_base); |
|
697 |
+ |
|
698 |
+ draw_text(ctx, picref, picref->video->w, picref->video->h); |
|
699 |
+ |
|
700 |
+ av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n", |
|
701 |
+ (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T], |
|
702 |
+ (int)dtext->var_values[VAR_TEXT_W], (int)dtext->var_values[VAR_TEXT_H], |
|
703 |
+ dtext->x, dtext->y); |
|
704 |
+ |
|
705 |
+ dtext->var_values[VAR_N] += 1.0; |
|
694 | 706 |
|
695 | 707 |
avfilter_draw_slice(outlink, 0, picref->video->h, 1); |
696 | 708 |
avfilter_end_frame(outlink); |