[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