mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-28 20:53:54 +02:00
vf_drawtext: fontconfig support.
This commit is contained in:
parent
be9b0d2c5a
commit
40b7a27bad
@ -23,6 +23,7 @@ version next:
|
||||
- OpenEXR image decoder
|
||||
- removelogo filter
|
||||
- drop support for ffmpeg without libavfilter
|
||||
- drawtext video filter: fontconfig support
|
||||
|
||||
|
||||
version 0.10:
|
||||
|
3
configure
vendored
3
configure
vendored
@ -166,6 +166,7 @@ Individual component options:
|
||||
External library support:
|
||||
--enable-avisynth enable reading of AVISynth script files [no]
|
||||
--enable-bzlib enable bzlib [autodetect]
|
||||
--enable-fontconfig enable fontconfig
|
||||
--enable-frei0r enable frei0r video filtering
|
||||
--enable-gnutls enable gnutls [no]
|
||||
--enable-libaacplus enable AAC+ encoding via libaacplus [no]
|
||||
@ -1022,6 +1023,7 @@ CONFIG_LIST="
|
||||
dxva2
|
||||
fastdiv
|
||||
fft
|
||||
fontconfig
|
||||
frei0r
|
||||
gnutls
|
||||
gpl
|
||||
@ -3164,6 +3166,7 @@ check_mathfunc truncf
|
||||
|
||||
# these are off by default, so fail if requested and not available
|
||||
enabled avisynth && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32
|
||||
enabled fontconfig && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
|
||||
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
|
||||
enabled gnutls && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
|
||||
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.
|
||||
frame rate (timecode only)
|
||||
@end table
|
||||
|
||||
If libavfilter was built with @code{--enable-fontconfig}, then
|
||||
@option{fontfile} can be a fontconfig pattern or omitted.
|
||||
|
||||
Some examples follow.
|
||||
|
||||
@itemize
|
||||
@ -1467,11 +1470,20 @@ The glyph baseline is placed at half screen height.
|
||||
drawtext=fontsize=60:fontfile=FreeSerif.ttf:fontcolor=green:text=g:x=(w-max_glyph_w)/2:y=h/2-ascent
|
||||
@end example
|
||||
|
||||
@item
|
||||
Use fontconfig to set the font. Note that the colons need to be escaped.
|
||||
@example
|
||||
drawtext='fontfile=Linux Libertine O-40\\:style=Semibold:text=FFmpeg'
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
|
||||
For more information about libfreetype, check:
|
||||
@url{http://www.freetype.org/}.
|
||||
|
||||
For more information about fontconfig, check:
|
||||
@url{http://freedesktop.org/software/fontconfig/fontconfig-user.html}.
|
||||
|
||||
@section fade
|
||||
|
||||
Apply fade-in/out effect to input video.
|
||||
|
@ -48,6 +48,9 @@
|
||||
#include <freetype/config/ftheader.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
#if CONFIG_FONTCONFIG
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#endif
|
||||
|
||||
static const char *const var_names[] = {
|
||||
"main_w", "w", "W", ///< width of the input video
|
||||
@ -167,7 +170,7 @@ static const AVOption drawtext_options[]= {
|
||||
{"boxcolor", "set box color", OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, {.str="white"}, CHAR_MIN, CHAR_MAX },
|
||||
{"shadowcolor", "set shadow color", OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX },
|
||||
{"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1 },
|
||||
{"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.dbl=16}, 1, INT_MAX },
|
||||
{"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.dbl=0}, 0, INT_MAX },
|
||||
{"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX },
|
||||
{"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX },
|
||||
{"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.dbl=0}, INT_MIN, INT_MAX },
|
||||
@ -298,6 +301,91 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int load_font_file(AVFilterContext *ctx, const char *path, int index,
|
||||
const char **error)
|
||||
{
|
||||
DrawTextContext *dtext = ctx->priv;
|
||||
int err;
|
||||
|
||||
err = FT_New_Face(dtext->library, path, index, &dtext->face);
|
||||
if (err) {
|
||||
*error = FT_ERRMSG(err);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_FONTCONFIG
|
||||
static int load_font_fontconfig(AVFilterContext *ctx, const char **error)
|
||||
{
|
||||
DrawTextContext *dtext = ctx->priv;
|
||||
FcConfig *fontconfig;
|
||||
FcPattern *pattern, *fpat;
|
||||
FcResult result = FcResultMatch;
|
||||
FcChar8 *filename;
|
||||
int err, index;
|
||||
double size;
|
||||
|
||||
fontconfig = FcInitLoadConfigAndFonts();
|
||||
if (!fontconfig) {
|
||||
*error = "impossible to init fontconfig\n";
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
pattern = FcNameParse(dtext->fontfile ? dtext->fontfile :
|
||||
(uint8_t *)(intptr_t)"default");
|
||||
if (!pattern) {
|
||||
*error = "could not parse fontconfig pattern";
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (!FcConfigSubstitute(fontconfig, pattern, FcMatchPattern)) {
|
||||
*error = "could not substitue fontconfig options"; /* very unlikely */
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
FcDefaultSubstitute(pattern);
|
||||
fpat = FcFontMatch(fontconfig, pattern, &result);
|
||||
if (!fpat || result != FcResultMatch) {
|
||||
*error = "impossible to find a matching font";
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (FcPatternGetString (fpat, FC_FILE, 0, &filename) != FcResultMatch ||
|
||||
FcPatternGetInteger(fpat, FC_INDEX, 0, &index ) != FcResultMatch ||
|
||||
FcPatternGetDouble (fpat, FC_SIZE, 0, &size ) != FcResultMatch) {
|
||||
*error = "impossible to find font information";
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
|
||||
if (!dtext->fontsize)
|
||||
dtext->fontsize = size + 0.5;
|
||||
err = load_font_file(ctx, filename, index, error);
|
||||
if (err)
|
||||
return err;
|
||||
FcPatternDestroy(fpat);
|
||||
FcPatternDestroy(pattern);
|
||||
FcConfigDestroy(fontconfig);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int load_font(AVFilterContext *ctx)
|
||||
{
|
||||
DrawTextContext *dtext = ctx->priv;
|
||||
int err;
|
||||
const char *error = "unknown error\n";
|
||||
|
||||
/* load the face, and set up the encoding, which is by default UTF-8 */
|
||||
err = load_font_file(ctx, dtext->fontfile, 0, &error);
|
||||
if (!err)
|
||||
return 0;
|
||||
#if CONFIG_FONTCONFIG
|
||||
err = load_font_fontconfig(ctx, &error);
|
||||
if (!err)
|
||||
return 0;
|
||||
#endif
|
||||
av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
|
||||
dtext->fontfile, error);
|
||||
return err;
|
||||
}
|
||||
|
||||
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
||||
{
|
||||
int err;
|
||||
@ -312,7 +400,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!dtext->fontfile) {
|
||||
if (!dtext->fontfile && !CONFIG_FONTCONFIG) {
|
||||
av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
@ -381,12 +469,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
/* load the face, and set up the encoding, which is by default UTF-8 */
|
||||
if ((err = FT_New_Face(dtext->library, dtext->fontfile, 0, &dtext->face))) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Could not load fontface from file '%s': %s\n",
|
||||
dtext->fontfile, FT_ERRMSG(err));
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
err = load_font(ctx);
|
||||
if (err)
|
||||
return err;
|
||||
if (!dtext->fontsize)
|
||||
dtext->fontsize = 16;
|
||||
if ((err = FT_Set_Pixel_Sizes(dtext->face, 0, dtext->fontsize))) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
|
||||
dtext->fontsize, FT_ERRMSG(err));
|
||||
|
Loading…
Reference in New Issue
Block a user