[FFmpeg-devel] [PATCH v2] drawtext: Add basic text shaping using libfribidi - Fixes ticket #3758

Michael Niedermayer michaelni at gmx.at
Sat Jul 12 17:00:13 CEST 2014


On Thu, Jul 10, 2014 at 11:47:16AM +0100, Marc Jeffreys wrote:
> Changes since last time:
> I've made the changes to configure, and squashed the patches together.
> Option changed from fribidi=1 (default 0) to text_shaping=1 (default 1).
> (Ideas for better names are definitely welcome.)
> Hopefully I've made the documentation more understandable.
> No longer testing for NULL before av_free.
> 
> ---
>  configure                 |   3 ++
>  doc/filters.texi          |  11 ++++
>  libavfilter/vf_drawtext.c | 130 +++++++++++++++++++++++++++++++++++++++++++---
>  3 files changed, 138 insertions(+), 6 deletions(-)
> 
> diff --git a/configure b/configure
> index 658efb2..6777d91 100755
> --- a/configure
> +++ b/configure
> @@ -209,6 +209,7 @@ External library support:
>    --enable-libfdk-aac      enable AAC de/encoding via libfdk-aac [no]
>    --enable-libflite        enable flite (voice synthesis) support via libflite [no]
>    --enable-libfreetype     enable libfreetype [no]
> +  --enable-libfribidi      enable libfribidi [no]
>    --enable-libgme          enable Game Music Emu via libgme [no]
>    --enable-libgsm          enable GSM de/encoding via libgsm [no]
>    --enable-libiec61883     enable iec61883 via libiec61883 [no]
> @@ -1332,6 +1333,7 @@ EXTERNAL_LIBRARY_LIST="
>      libflite
>      libfontconfig
>      libfreetype
> +    libfribidi
>      libgme
>      libgsm
>      libiec61883
> @@ -4724,6 +4726,7 @@ enabled libflite          && require2 libflite "flite/flite.h" flite_init $flite
>  enabled fontconfig        && enable libfontconfig
>  enabled libfontconfig     && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
>  enabled libfreetype       && require_libfreetype
> +enabled libfribidi        && require_pkg_config fribidi fribidi.h fribidi_version_info
>  enabled libgme            && require  libgme gme/gme.h gme_new_emu -lgme -lstdc++
>  enabled libgsm            && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
>                                     check_lib "${gsm_hdr}" gsm_create -lgsm && break;
> diff --git a/doc/filters.texi b/doc/filters.texi
> index ada33a7..1b6f85e 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -3653,6 +3653,8 @@ To enable compilation of this filter, you need to configure FFmpeg with
>  @code{--enable-libfreetype}.
>  To enable default font fallback and the @var{font} option you need to
>  configure FFmpeg with @code{--enable-libfontconfig}.
> +To enable the @var{text_shaping} option, you need to configure FFmpeg with
> + at code{--enable-libfribidi}.
>  
>  @subsection Syntax
>  
> @@ -3707,6 +3709,12 @@ This parameter is mandatory if the fontconfig support is disabled.
>  The font size to be used for drawing text.
>  The default value of @var{fontsize} is 16.
>  
> + at item text_shaping
> +If set to 1, attempt to shape the text (for example, reverse the order of
> +right-to-left text and join Arabic characters) before drawing it.
> +Otherwise, just draw the text exactly as given.
> +By default 1 (if supported).
> +
>  @item ft_load_flags
>  The flags to be used for loading the fonts.
>  
> @@ -4010,6 +4018,9 @@ For more information about libfreetype, check:
>  For more information about fontconfig, check:
>  @url{http://freedesktop.org/software/fontconfig/fontconfig-user.html}.
>  
> +For more information about libfribidi, check:
> + at url{http://fribidi.org/}.
> +
>  @section edgedetect
>  
>  Detect and draw edges. The filter uses the Canny Edge Detection algorithm.
> diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
> index 0d829a6..b29411e 100644
> --- a/libavfilter/vf_drawtext.c
> +++ b/libavfilter/vf_drawtext.c
> @@ -59,6 +59,10 @@
>  #include "internal.h"
>  #include "video.h"
>  
> +#if CONFIG_LIBFRIBIDI
> +#include <fribidi.h>
> +#endif
> +
>  #include <ft2build.h>
>  #include FT_FREETYPE_H
>  #include FT_GLYPH_H
> @@ -182,6 +186,9 @@ typedef struct DrawTextContext {
>      int tc24hmax;                   ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
>      int reload;                     ///< reload text file for each frame
>      int start_number;               ///< starting frame number for n/frame_num var
> +#if CONFIG_LIBFRIBIDI
> +    int text_shaping;               ///< 1 to shape the text before drawing it
> +#endif
>      AVDictionary *metadata;
>  } DrawTextContext;
>  
> @@ -226,6 +233,10 @@ static const AVOption drawtext_options[]= {
>      {"fix_bounds", "if true, check and fix text coords to avoid clipping",  OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
>      {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
>  
> +#if CONFIG_LIBFRIBIDI
> +    {"text_shaping", "attempt to shape text before drawing", OFFSET(text_shaping), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
> +#endif
> +
>      /* FT_LOAD_* flags */
>      { "ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT }, 0, INT_MAX, FLAGS, "ft_load_flags" },
>          { "default",                     NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT },                     .flags = FLAGS, .unit = "ft_load_flags" },
> @@ -482,6 +493,106 @@ static int load_textfile(AVFilterContext *ctx)
>      return 0;
>  }
>  
> +static inline int is_newline(uint32_t c)
> +{
> +    return c == '\n' || c == '\r' || c == '\f' || c == '\v';
> +}
> +
> +#if CONFIG_LIBFRIBIDI
> +static int shape_text(AVFilterContext *ctx)
> +{
> +    DrawTextContext *s = ctx->priv;
> +    uint8_t *tmp;
> +    int ret = 0;

> +    static FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT       | \
> +                                FRIBIDI_FLAGS_ARABIC        ;

static const


> +    FriBidiChar *unicodestr = NULL;
> +    FriBidiStrIndex len;
> +    FriBidiParType direction = FRIBIDI_PAR_LTR;
> +    FriBidiStrIndex line_start = 0;
> +    FriBidiStrIndex line_end = 0;
> +    FriBidiLevel *embedding_levels = NULL;
> +    FriBidiArabicProp *ar_props = NULL;
> +    FriBidiCharType *bidi_types = NULL;
> +    FriBidiStrIndex i,j;
> +
> +    len = strlen(s->text);
> +    if (!(unicodestr = av_malloc(len * sizeof(*unicodestr)))) {
> +        ret = AVERROR(ENOMEM);
> +        goto out;
> +    }
> +    len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
> +                                     s->text, len, unicodestr);
> +
> +    bidi_types = av_malloc(len * sizeof(*bidi_types));
> +    if (!bidi_types) {
> +        ret = AVERROR(ENOMEM);
> +        goto out;
> +    }
> +
> +    fribidi_get_bidi_types(unicodestr, len, bidi_types);
> +
> +    embedding_levels = av_malloc(len * sizeof(*embedding_levels));
> +    if (!embedding_levels) {
> +        ret = AVERROR(ENOMEM);
> +        goto out;
> +    }
> +
> +    if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
> +                                         embedding_levels)) {
> +        ret = AVERROR(ENOMEM);
> +        goto out;
> +    }
> +

> +    ar_props = av_malloc(len * sizeof(*ar_props));

this and others could use av_malloc_array()

thanks

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Democracy is the form of government in which you can choose your dictator
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140712/30a9e06b/attachment.asc>


More information about the ffmpeg-devel mailing list