... | ... |
@@ -166,6 +166,7 @@ Individual component options: |
166 | 166 |
External library support: |
167 | 167 |
--enable-avisynth enable reading of AVISynth script files [no] |
168 | 168 |
--enable-bzlib enable bzlib [autodetect] |
169 |
+ --enable-fontconfig enable fontconfig |
|
169 | 170 |
--enable-frei0r enable frei0r video filtering |
170 | 171 |
--enable-gnutls enable gnutls [no] |
171 | 172 |
--enable-libaacplus enable AAC+ encoding via libaacplus [no] |
... | ... |
@@ -1022,6 +1023,7 @@ CONFIG_LIST=" |
1022 | 1022 |
dxva2 |
1023 | 1023 |
fastdiv |
1024 | 1024 |
fft |
1025 |
+ fontconfig |
|
1025 | 1026 |
frei0r |
1026 | 1027 |
gnutls |
1027 | 1028 |
gpl |
... | ... |
@@ -3164,6 +3166,7 @@ check_mathfunc truncf |
3164 | 3164 |
|
3165 | 3165 |
# these are off by default, so fail if requested and not available |
3166 | 3166 |
enabled avisynth && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32 |
3167 |
+enabled fontconfig && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit |
|
3167 | 3168 |
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; } |
3168 | 3169 |
enabled gnutls && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init |
3169 | 3170 |
enabled libaacplus && require "libaacplus >= 2.0.0" aacplus.h aacplusEncOpen -laacplus |
... | ... |
@@ -1414,6 +1414,9 @@ with or without text parameter. @var{rate} option must be specified. |
1414 | 1414 |
frame rate (timecode only) |
1415 | 1415 |
@end table |
1416 | 1416 |
|
1417 |
+If libavfilter was built with @code{--enable-fontconfig}, then |
|
1418 |
+@option{fontfile} can be a fontconfig pattern or omitted. |
|
1419 |
+ |
|
1417 | 1420 |
Some examples follow. |
1418 | 1421 |
|
1419 | 1422 |
@itemize |
... | ... |
@@ -1467,11 +1470,20 @@ The glyph baseline is placed at half screen height. |
1467 | 1467 |
drawtext=fontsize=60:fontfile=FreeSerif.ttf:fontcolor=green:text=g:x=(w-max_glyph_w)/2:y=h/2-ascent |
1468 | 1468 |
@end example |
1469 | 1469 |
|
1470 |
+@item |
|
1471 |
+Use fontconfig to set the font. Note that the colons need to be escaped. |
|
1472 |
+@example |
|
1473 |
+drawtext='fontfile=Linux Libertine O-40\\:style=Semibold:text=FFmpeg' |
|
1474 |
+@end example |
|
1475 |
+ |
|
1470 | 1476 |
@end itemize |
1471 | 1477 |
|
1472 | 1478 |
For more information about libfreetype, check: |
1473 | 1479 |
@url{http://www.freetype.org/}. |
1474 | 1480 |
|
1481 |
+For more information about fontconfig, check: |
|
1482 |
+@url{http://freedesktop.org/software/fontconfig/fontconfig-user.html}. |
|
1483 |
+ |
|
1475 | 1484 |
@section fade |
1476 | 1485 |
|
1477 | 1486 |
Apply fade-in/out effect to input video. |
... | ... |
@@ -48,6 +48,9 @@ |
48 | 48 |
#include <freetype/config/ftheader.h> |
49 | 49 |
#include FT_FREETYPE_H |
50 | 50 |
#include FT_GLYPH_H |
51 |
+#if CONFIG_FONTCONFIG |
|
52 |
+#include <fontconfig/fontconfig.h> |
|
53 |
+#endif |
|
51 | 54 |
|
52 | 55 |
static const char *const var_names[] = { |
53 | 56 |
"main_w", "w", "W", ///< width of the input video |
... | ... |
@@ -167,7 +170,7 @@ static const AVOption drawtext_options[]= { |
167 | 167 |
{"boxcolor", "set box color", OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX }, |
168 | 168 |
{"shadowcolor", "set shadow color", OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX }, |
169 | 169 |
{"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 }, |
170 |
-{"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.dbl=16}, 1, INT_MAX }, |
|
170 |
+{"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.dbl=0}, 0, INT_MAX }, |
|
171 | 171 |
{"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX }, |
172 | 172 |
{"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX }, |
173 | 173 |
{"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX }, |
... | ... |
@@ -298,6 +301,91 @@ error: |
298 | 298 |
return ret; |
299 | 299 |
} |
300 | 300 |
|
301 |
+static int load_font_file(AVFilterContext *ctx, const char *path, int index, |
|
302 |
+ const char **error) |
|
303 |
+{ |
|
304 |
+ DrawTextContext *dtext = ctx->priv; |
|
305 |
+ int err; |
|
306 |
+ |
|
307 |
+ err = FT_New_Face(dtext->library, path, index, &dtext->face); |
|
308 |
+ if (err) { |
|
309 |
+ *error = FT_ERRMSG(err); |
|
310 |
+ return AVERROR(EINVAL); |
|
311 |
+ } |
|
312 |
+ return 0; |
|
313 |
+} |
|
314 |
+ |
|
315 |
+#if CONFIG_FONTCONFIG |
|
316 |
+static int load_font_fontconfig(AVFilterContext *ctx, const char **error) |
|
317 |
+{ |
|
318 |
+ DrawTextContext *dtext = ctx->priv; |
|
319 |
+ FcConfig *fontconfig; |
|
320 |
+ FcPattern *pattern, *fpat; |
|
321 |
+ FcResult result = FcResultMatch; |
|
322 |
+ FcChar8 *filename; |
|
323 |
+ int err, index; |
|
324 |
+ double size; |
|
325 |
+ |
|
326 |
+ fontconfig = FcInitLoadConfigAndFonts(); |
|
327 |
+ if (!fontconfig) { |
|
328 |
+ *error = "impossible to init fontconfig\n"; |
|
329 |
+ return AVERROR(EINVAL); |
|
330 |
+ } |
|
331 |
+ pattern = FcNameParse(dtext->fontfile ? dtext->fontfile : |
|
332 |
+ (uint8_t *)(intptr_t)"default"); |
|
333 |
+ if (!pattern) { |
|
334 |
+ *error = "could not parse fontconfig pattern"; |
|
335 |
+ return AVERROR(EINVAL); |
|
336 |
+ } |
|
337 |
+ if (!FcConfigSubstitute(fontconfig, pattern, FcMatchPattern)) { |
|
338 |
+ *error = "could not substitue fontconfig options"; /* very unlikely */ |
|
339 |
+ return AVERROR(EINVAL); |
|
340 |
+ } |
|
341 |
+ FcDefaultSubstitute(pattern); |
|
342 |
+ fpat = FcFontMatch(fontconfig, pattern, &result); |
|
343 |
+ if (!fpat || result != FcResultMatch) { |
|
344 |
+ *error = "impossible to find a matching font"; |
|
345 |
+ return AVERROR(EINVAL); |
|
346 |
+ } |
|
347 |
+ if (FcPatternGetString (fpat, FC_FILE, 0, &filename) != FcResultMatch || |
|
348 |
+ FcPatternGetInteger(fpat, FC_INDEX, 0, &index ) != FcResultMatch || |
|
349 |
+ FcPatternGetDouble (fpat, FC_SIZE, 0, &size ) != FcResultMatch) { |
|
350 |
+ *error = "impossible to find font information"; |
|
351 |
+ return AVERROR(EINVAL); |
|
352 |
+ } |
|
353 |
+ av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename); |
|
354 |
+ if (!dtext->fontsize) |
|
355 |
+ dtext->fontsize = size + 0.5; |
|
356 |
+ err = load_font_file(ctx, filename, index, error); |
|
357 |
+ if (err) |
|
358 |
+ return err; |
|
359 |
+ FcPatternDestroy(fpat); |
|
360 |
+ FcPatternDestroy(pattern); |
|
361 |
+ FcConfigDestroy(fontconfig); |
|
362 |
+ return 0; |
|
363 |
+} |
|
364 |
+#endif |
|
365 |
+ |
|
366 |
+static int load_font(AVFilterContext *ctx) |
|
367 |
+{ |
|
368 |
+ DrawTextContext *dtext = ctx->priv; |
|
369 |
+ int err; |
|
370 |
+ const char *error = "unknown error\n"; |
|
371 |
+ |
|
372 |
+ /* load the face, and set up the encoding, which is by default UTF-8 */ |
|
373 |
+ err = load_font_file(ctx, dtext->fontfile, 0, &error); |
|
374 |
+ if (!err) |
|
375 |
+ return 0; |
|
376 |
+#if CONFIG_FONTCONFIG |
|
377 |
+ err = load_font_fontconfig(ctx, &error); |
|
378 |
+ if (!err) |
|
379 |
+ return 0; |
|
380 |
+#endif |
|
381 |
+ av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n", |
|
382 |
+ dtext->fontfile, error); |
|
383 |
+ return err; |
|
384 |
+} |
|
385 |
+ |
|
301 | 386 |
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
302 | 387 |
{ |
303 | 388 |
int err; |
... | ... |
@@ -312,7 +400,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
312 | 312 |
return err; |
313 | 313 |
} |
314 | 314 |
|
315 |
- if (!dtext->fontfile) { |
|
315 |
+ if (!dtext->fontfile && !CONFIG_FONTCONFIG) { |
|
316 | 316 |
av_log(ctx, AV_LOG_ERROR, "No font filename provided\n"); |
317 | 317 |
return AVERROR(EINVAL); |
318 | 318 |
} |
... | ... |
@@ -381,12 +469,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
381 | 381 |
return AVERROR(EINVAL); |
382 | 382 |
} |
383 | 383 |
|
384 |
- /* load the face, and set up the encoding, which is by default UTF-8 */ |
|
385 |
- if ((err = FT_New_Face(dtext->library, dtext->fontfile, 0, &dtext->face))) { |
|
386 |
- av_log(ctx, AV_LOG_ERROR, "Could not load fontface from file '%s': %s\n", |
|
387 |
- dtext->fontfile, FT_ERRMSG(err)); |
|
388 |
- return AVERROR(EINVAL); |
|
389 |
- } |
|
384 |
+ err = load_font(ctx); |
|
385 |
+ if (err) |
|
386 |
+ return err; |
|
387 |
+ if (!dtext->fontsize) |
|
388 |
+ dtext->fontsize = 16; |
|
390 | 389 |
if ((err = FT_Set_Pixel_Sizes(dtext->face, 0, dtext->fontsize))) { |
391 | 390 |
av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n", |
392 | 391 |
dtext->fontsize, FT_ERRMSG(err)); |