]> git.sesse.net Git - vlc/blobdiff - modules/misc/freetype.c
Select frames to drop a bit smarter.
[vlc] / modules / misc / freetype.c
index 5a4820de8c6969b22ed919840f5aa4a2126ccce3..3d76be2a4d95637a7f00fe4ed58db4eafb9b34ce 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
  *          Gildas Bazin <gbazin@videolan.org>
- *          Bernie Purcell <b dot purcell at adbglobal dot com>
+ *          Bernie Purcell <bitmap@videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <stdlib.h>                                      /* malloc(), free() */
-#include <string.h>
-
-#ifdef HAVE_LINUX_LIMITS_H
-#   include <linux/limits.h>
-#endif
 
 #include <vlc/vlc.h>
 #include <vlc_vout.h>
 #include <vlc_filter.h>
 #include <vlc_stream.h>
 #include <vlc_xml.h>
+#include <vlc_input.h>
 
-#include <math.h>
-
-#ifdef HAVE_ERRNO_H
-#   include <errno.h>
+#ifdef HAVE_LINUX_LIMITS_H
+#   include <linux/limits.h>
 #endif
 
+#include <time.h>
+#include <math.h>
+#include <errno.h>
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -84,6 +81,8 @@ typedef struct line_desc_t line_desc_t;
 static int  Create ( vlc_object_t * );
 static void Destroy( vlc_object_t * );
 
+static int LoadFontsFromAttachments( filter_t *p_filter );
+
 /* The RenderText call maps to pf_render_string, defined in vlc_filter.h */
 static int RenderText( filter_t *, subpicture_region_t *,
                        subpicture_region_t * );
@@ -95,6 +94,7 @@ static char *FontConfig_Select( FcConfig *, const char *,
 #endif
 static line_desc_t *NewLine( int );
 
+static int GetFontSize( filter_t *p_filter );
 static int SetFontSize( filter_t *, int );
 static void YUVFromRGB( uint32_t i_argb,
                         uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v );
@@ -236,6 +236,9 @@ typedef struct
 static int Render( filter_t *, subpicture_region_t *, line_desc_t *, int, int);
 static void FreeLines( line_desc_t * );
 static void FreeLine( line_desc_t * );
+#ifdef HAVE_FONTCONFIG
+static void FontBuilder( vlc_object_t *p_this);
+#endif
 
 /*****************************************************************************
  * filter_sys_t: freetype local data
@@ -257,7 +260,12 @@ struct filter_sys_t
     int            i_display_height;
 #ifdef HAVE_FONTCONFIG
     FcConfig      *p_fontconfig;
+    vlc_bool_t     b_fontconfig_ok;
+    vlc_mutex_t    fontconfig_lock;
 #endif
+
+    input_attachment_t **pp_font_attachments;
+    int                  i_font_attachments;
 };
 
 /*****************************************************************************
@@ -326,12 +334,6 @@ static int Create( vlc_object_t *p_this )
 #endif
     }
 
-#ifdef HAVE_FONTCONFIG
-    if( FcInit() )
-        p_sys->p_fontconfig = FcConfigGetCurrent();
-    else
-        p_sys->p_fontconfig = NULL;
-#endif
     i_error = FT_Init_FreeType( &p_sys->p_library );
     if( i_error )
     {
@@ -358,6 +360,39 @@ static int Create( vlc_object_t *p_this )
         goto error;
     }
 
+#ifdef HAVE_FONTCONFIG
+    vlc_mutex_init( p_filter, &p_sys->fontconfig_lock );
+    p_sys->b_fontconfig_ok = VLC_FALSE;
+
+    p_sys->p_fontconfig = FcInitLoadConfig();
+
+    if( p_sys->p_fontconfig )
+    {
+        /* Normally this doesn't take very long, but an initial build of
+         * the fontconfig database or the addition of a lot of new fonts
+         * can cause it to take several minutes for a large number of fonts.
+         * Even a small number can take several seconds - much longer than
+         * we can afford to block, so we build the list in the background
+         * and if it succeeds we allow fontconfig to be used.
+         */
+        if( vlc_thread_create( p_filter, "fontlist builder", FontBuilder,
+                       VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
+        {
+            /* Don't destroy the fontconfig object - we won't be able to do
+             * italics or bold or change the font face, but we will still
+             * be able to do underline and change the font size.
+             */
+            msg_Warn( p_filter, "fontconfig database builder thread can't "
+                    "be launched. Font styling support will be limited." );
+        };
+    }
+    else
+    {
+        msg_Warn( p_filter, "Couldn't initialise Fontconfig. "
+                            "Font styling won't be available." );
+    }
+#endif
+
     p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face );
 
     var_Get( p_filter, "freetype-fontsize", &val );
@@ -365,12 +400,20 @@ static int Create( vlc_object_t *p_this )
     if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error;
 
     if( psz_fontfile ) free( psz_fontfile );
+
+    p_sys->pp_font_attachments = NULL;
+    p_sys->i_font_attachments = 0;
+
     p_filter->pf_render_text = RenderText;
 #ifdef HAVE_FONTCONFIG
-    p_filter->pf_render_html = RenderHtml;
-#else
-    p_filter->pf_render_html = NULL;
+    if( p_sys->p_fontconfig )
+        p_filter->pf_render_html = RenderHtml;
+    else
 #endif
+        p_filter->pf_render_html = NULL;
+
+    LoadFontsFromAttachments( p_filter );
+
     return VLC_SUCCESS;
 
  error:
@@ -391,9 +434,28 @@ static void Destroy( vlc_object_t *p_this )
     filter_t *p_filter = (filter_t *)p_this;
     filter_sys_t *p_sys = p_filter->p_sys;
 
+    if( p_sys->pp_font_attachments )
+    {
+        int   k;
+
+        for( k = 0; k < p_sys->i_font_attachments; k++ )
+        {
+            vlc_input_attachment_Delete( p_sys->pp_font_attachments[k] );
+        }
+
+        free( p_sys->pp_font_attachments );
+    }
+
 #ifdef HAVE_FONTCONFIG
-    FcConfigDestroy( p_sys->p_fontconfig );
-    p_sys->p_fontconfig = NULL;
+    /* wait for the FontBuilder thread to terminate */
+    vlc_thread_join( p_this );
+    vlc_mutex_destroy( &p_sys->fontconfig_lock );
+
+    if( p_sys->p_fontconfig )
+    {
+        FcConfigDestroy( p_sys->p_fontconfig );
+        p_sys->p_fontconfig = NULL;
+    }
     /* FcFini asserts calling the subfunction FcCacheFini()
      * even if no other library functions have been made since FcInit(),
      * so don't call it. */
@@ -403,6 +465,99 @@ static void Destroy( vlc_object_t *p_this )
     free( p_sys );
 }
 
+#ifdef HAVE_FONTCONFIG
+
+static void FontBuilder( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t*)p_this;
+    filter_sys_t *p_sys = p_filter->p_sys;
+    time_t    t1, t2;
+
+    /* Find the session to announce */
+    vlc_mutex_lock( &p_sys->fontconfig_lock );
+
+    msg_Dbg( p_filter, "Building font database..." );
+    time(&t1);
+    if(! FcConfigBuildFonts( p_sys->p_fontconfig ))
+    {
+        /* Don't destroy the fontconfig object - we won't be able to do
+         * italics or bold or change the font face, but we will still
+         * be able to do underline and change the font size.
+         */
+        msg_Err( p_filter, "fontconfig database can't be built. "
+                                "Font styling won't be available" );
+    }
+    time(&t2);
+
+    msg_Dbg( p_filter, "Finished building font database." );
+    if( t1 > 0 && t2 > 0 )
+        msg_Dbg( p_filter, "Took %ld seconds", t2 - t1 );
+
+    p_sys->b_fontconfig_ok = VLC_TRUE;
+
+    vlc_mutex_unlock( &p_sys->fontconfig_lock );
+}
+
+#endif
+
+/*****************************************************************************
+ * Make any TTF/OTF fonts present in the attachments of the media file
+ * and store them for later use by the FreeType Engine
+ *****************************************************************************/
+static int LoadFontsFromAttachments( filter_t *p_filter )
+{
+    filter_sys_t         *p_sys = p_filter->p_sys;
+    input_thread_t       *p_input;
+    input_attachment_t  **pp_attachments;
+    int                   i_attachments_cnt;
+    int                   k;
+    int                   rv = VLC_SUCCESS;
+
+    p_input = (input_thread_t *)vlc_object_find( p_filter, VLC_OBJECT_INPUT, FIND_PARENT );
+    if( ! p_input )
+        return VLC_EGENERIC;
+
+    if( VLC_SUCCESS != input_Control( p_input, INPUT_GET_ATTACHMENTS, &pp_attachments, &i_attachments_cnt ))
+    {
+        vlc_object_release(p_input);
+        return VLC_EGENERIC;
+    }
+
+    p_sys->i_font_attachments = 0;
+    p_sys->pp_font_attachments = malloc( i_attachments_cnt * sizeof( input_attachment_t * ));
+    if(! p_sys->pp_font_attachments )
+        rv = VLC_ENOMEM;
+
+    for( k = 0; k < i_attachments_cnt; k++ )
+    {
+        input_attachment_t *p_attach = pp_attachments[k];
+
+        if( p_sys->pp_font_attachments )
+        {
+            if(( !strcmp( p_attach->psz_mime, "application/x-truetype-font" ) || // TTF
+                 !strcmp( p_attach->psz_mime, "application/x-font-otf" ) ) &&    // OTF
+               ( p_attach->i_data > 0 ) &&
+               ( p_attach->p_data != NULL ) )
+            {
+                p_sys->pp_font_attachments[ p_sys->i_font_attachments++ ] = p_attach;
+            }
+            else
+            {
+                vlc_input_attachment_Delete( p_attach );
+            }
+        }
+        else
+        {
+            vlc_input_attachment_Delete( p_attach );
+        }
+    }
+    free( pp_attachments );
+
+    vlc_object_release(p_input);
+
+    return rv;
+}
+
 /*****************************************************************************
  * Render: place string in picture
  *****************************************************************************
@@ -886,6 +1041,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
     char *psz_string;
     vlc_iconv_t iconv_handle = (vlc_iconv_t)(-1);
     int i_font_color, i_font_alpha, i_font_size, i_red, i_green, i_blue;
+    vlc_value_t val;
+    int i_scale = 1000;
 
     FT_BBox line;
     FT_BBox glyph_size;
@@ -897,17 +1054,20 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
     psz_string = p_region_in->psz_text;
     if( !psz_string || !*psz_string ) return VLC_EGENERIC;
 
+    if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
+        i_scale = val.i_int;
+
     if( p_region_in->p_style )
     {
         i_font_color = __MAX( __MIN( p_region_in->p_style->i_font_color, 0xFFFFFF ), 0 );
         i_font_alpha = __MAX( __MIN( p_region_in->p_style->i_font_alpha, 255 ), 0 );
-        i_font_size  = __MAX( __MIN( p_region_in->p_style->i_font_size, 255 ), 0 );
+        i_font_size  = __MAX( __MIN( p_region_in->p_style->i_font_size, 255 ), 0 ) * i_scale / 1000;
     }
     else
     {
         i_font_color = p_sys->i_font_color;
         i_font_alpha = 255 - p_sys->i_font_opacity;
-        i_font_size  = p_sys->i_default_font_size;
+        i_font_size  = p_sys->i_default_font_size * i_scale / 1000;
     }
 
     if( i_font_color == 0xFFFFFF ) i_font_color = p_sys->i_font_color;
@@ -954,8 +1114,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
 
         if( i_in_bytes )
         {
-            msg_Warn( p_filter, "failed to convert string to unicode (%s), "
-                      "bytes left %d", strerror(errno), (int)i_in_bytes );
+            msg_Warn( p_filter, "failed to convert string to unicode (%m), "
+                      "bytes left %u", (unsigned)i_in_bytes );
             goto error;
         }
         *(uint32_t*)p_out_buffer = 0;
@@ -1338,8 +1498,8 @@ static void IconvText( filter_t *p_filter, const char *psz_string,
 
             if( i_in_bytes )
             {
-                msg_Warn( p_filter, "failed to convert string to unicode (%s), "
-                          "bytes left %d", strerror(errno), (int)i_in_bytes );
+                msg_Warn( p_filter, "failed to convert string to unicode (%m), "
+                          "bytes left %u", (unsigned)i_in_bytes );
             }
             else
             {
@@ -1356,7 +1516,7 @@ static void IconvText( filter_t *p_filter, const char *psz_string,
 }
 
 static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys,
-        font_stack_t **p_fonts, vlc_bool_t b_bold, vlc_bool_t b_italic, 
+        font_stack_t **p_fonts, vlc_bool_t b_bold, vlc_bool_t b_italic,
         vlc_bool_t b_uline )
 {
     ft_style_t   *p_style = NULL;
@@ -1555,7 +1715,7 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
 }
 
 static int HandleFontAttributes( xml_reader_t *p_xml_reader,
-                                  font_stack_t **p_fonts )
+                                  font_stack_t **p_fonts, int i_scale )
 {
     int        rv;
     char      *psz_fontname = NULL;
@@ -1574,6 +1734,7 @@ static int HandleFontAttributes( xml_reader_t *p_xml_reader,
                                  &i_karaoke_bg_color ))
     {
         psz_fontname = strdup( psz_fontname );
+        i_font_size = i_font_size * 1000 / i_scale;
     }
     i_font_alpha = (i_font_color >> 24) & 0xff;
     i_font_color &= 0x00ffffff;
@@ -1624,7 +1785,7 @@ static int HandleFontAttributes( xml_reader_t *p_xml_reader,
     }
     rv = PushFont( p_fonts,
                    psz_fontname,
-                   i_font_size,
+                   i_font_size * i_scale / 1000,
                    (i_font_color & 0xffffff) | ((i_font_alpha & 0xff) << 24),
                    i_karaoke_bg_color );
 
@@ -1757,7 +1918,7 @@ static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs,
                 }
                 if( *ppi_k_durations )
                     (*ppi_k_durations)[ *pi_k_runs - 1 ] = atoi( psz_value );
-                
+
                 if( *ppi_k_run_lengths )
                     (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0;
             }
@@ -1786,6 +1947,8 @@ static int ProcessNodes( filter_t *p_filter,
     filter_sys_t *p_sys          = p_filter->p_sys;
     uint32_t     *psz_text_orig  = psz_text;
     font_stack_t *p_fonts        = NULL;
+    vlc_value_t   val;
+    int           i_scale        = 1000;
 
     char *psz_node  = NULL;
 
@@ -1793,11 +1956,14 @@ static int ProcessNodes( filter_t *p_filter,
     vlc_bool_t b_bold   = VLC_FALSE;
     vlc_bool_t b_uline  = VLC_FALSE;
 
+    if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
+        i_scale = val.i_int;
+
     if( p_font_style )
     {
         rv = PushFont( &p_fonts,
                p_font_style->psz_fontname,
-               p_font_style->i_font_size,
+               p_font_style->i_font_size * i_scale / 1000,
                (p_font_style->i_font_color & 0xffffff) |
                    ((p_font_style->i_font_alpha & 0xff) << 24),
                (p_font_style->i_karaoke_background_color & 0xffffff) |
@@ -1849,7 +2015,7 @@ static int ProcessNodes( filter_t *p_filter,
                 if( psz_node )
                 {
                     if( !strcasecmp( "font", psz_node ) )
-                        rv = HandleFontAttributes( p_xml_reader, &p_fonts );
+                        rv = HandleFontAttributes( p_xml_reader, &p_fonts, i_scale );
                     else if( !strcasecmp( "b", psz_node ) )
                         b_bold = VLC_TRUE;
                     else if( !strcasecmp( "i", psz_node ) )
@@ -1932,6 +2098,51 @@ static int ProcessNodes( filter_t *p_filter,
     return rv;
 }
 
+static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style_t *p_style )
+{
+    int k;
+
+    for( k=0; k < p_sys->i_font_attachments; k++ )
+    {
+        input_attachment_t *p_attach   = p_sys->pp_font_attachments[k];
+        int                 i_font_idx = 0;
+        FT_Face             p_face = NULL;
+
+        while( 0 == FT_New_Memory_Face( p_sys->p_library,
+                                        p_attach->p_data,
+                                        p_attach->i_data,
+                                        i_font_idx,
+                                        &p_face ))
+        {
+            if( p_face )
+            {
+                vlc_bool_t match = !strcasecmp( p_face->family_name,
+                                                p_style->psz_fontname );
+
+                if( p_face->style_flags & FT_STYLE_FLAG_BOLD )
+                    match = match && p_style->b_bold;
+                else
+                    match = match && !p_style->b_bold;
+
+                if( p_face->style_flags & FT_STYLE_FLAG_ITALIC )
+                    match = match && p_style->b_italic;
+                else
+                    match = match && !p_style->b_italic;
+
+                if(  match )
+                {
+                    *pp_face = p_face;
+                    return VLC_SUCCESS;
+                }
+
+                FT_Done_Face( p_face );
+            }
+            i_font_idx++;
+        }
+    }
+    return VLC_EGENERIC;
+}
+
 static int ProcessLines( filter_t *p_filter,
                          uint32_t *psz_text,
                          int i_len,
@@ -1940,13 +2151,13 @@ static int ProcessLines( filter_t *p_filter,
                          uint32_t *pi_run_lengths,
                          ft_style_t **pp_styles,
                          line_desc_t **pp_lines,
-                         
+
                          FT_Vector *p_result,
 
                          vlc_bool_t b_karaoke,
                          uint32_t i_k_runs,
                          uint32_t *pi_k_run_lengths,
-                         uint32_t *pi_k_durations ) 
+                         uint32_t *pi_k_durations )
 {
     filter_sys_t   *p_sys = p_filter->p_sys;
     ft_style_t    **pp_char_styles;
@@ -2064,7 +2275,7 @@ static int ProcessLines( filter_t *p_filter,
         int64_t i_duration = 0;
         int64_t i_start_pos = 0;
         int64_t i_elapsed  = var_GetTime( p_filter, "spu-elapsed" ) / 1000;
-        
+
         for( k = 0; k< i_k_runs; k++ )
         {
              double fraction = 0.0;
@@ -2112,7 +2323,7 @@ static int ProcessLines( filter_t *p_filter,
                                    ((p_levels ? (p_levels[ j ] % 2) : 0 ) << 7);
                  }
              }
-             
+
              i_last_duration = i_duration;
              i_start_pos += pi_k_run_lengths[ k ];
         }
@@ -2144,26 +2355,60 @@ static int ProcessLines( filter_t *p_filter,
             /* End of the current style run */
             FT_Face p_face = NULL;
             int      i_idx = 0;
-            char *psz_fontfile = FontConfig_Select( p_sys->p_fontconfig,
-                                                    p_style->psz_fontname,
-                                                    p_style->b_bold,
-                                                    p_style->b_italic,
-                                                    &i_idx );
-            if( psz_fontfile )
+
+            /* Look for a match amongst our attachments first */
+            CheckForEmbeddedFont( p_sys, &p_face, p_style );
+
+            if( ! p_face && p_sys->b_fontconfig_ok )
             {
-                if( FT_New_Face( p_sys->p_library,
-                            psz_fontfile ? psz_fontfile : "", i_idx, &p_face ) )
+                char *psz_fontfile;
+
+                vlc_mutex_lock( &p_sys->fontconfig_lock );
+
+                psz_fontfile = FontConfig_Select( p_sys->p_fontconfig,
+                                                  p_style->psz_fontname,
+                                                  p_style->b_bold,
+                                                  p_style->b_italic,
+                                                  &i_idx );
+
+                vlc_mutex_unlock( &p_sys->fontconfig_lock );
+
+                if( psz_fontfile && ! *psz_fontfile )
                 {
+                    msg_Warn( p_filter, "Fontconfig was unable to find a font: \"%s\" %s"
+                        " so using default font", p_style->psz_fontname,
+                        ((p_style->b_bold && p_style->b_italic) ? "(Bold,Italic)" :
+                                               (p_style->b_bold ? "(Bold)" :
+                                             (p_style->b_italic ? "(Italic)" : ""))) );
                     free( psz_fontfile );
-                    free( pp_char_styles );
+                    psz_fontfile = NULL;
+                }
+
+                if( psz_fontfile )
+                {
+                    if( FT_New_Face( p_sys->p_library,
+                                psz_fontfile, i_idx, &p_face ) )
+                    {
+                        free( psz_fontfile );
+                        free( pp_char_styles );
 #if defined(HAVE_FRIBIDI)
-                    free( psz_text );
+                        free( psz_text );
 #endif
-                    if( pi_karaoke_bar )
-                        free( pi_karaoke_bar );
-                    return VLC_EGENERIC;
+                        if( pi_karaoke_bar )
+                            free( pi_karaoke_bar );
+                        return VLC_EGENERIC;
+                    }
+                    free( psz_fontfile );
                 }
-                free( psz_fontfile );
+            }
+            if( p_face &&
+                FT_Select_Charmap( p_face, ft_encoding_unicode ) )
+            {
+                /* We've loaded a font face which is unhelpful for actually
+                 * rendering text - fallback to the default one.
+                 */
+                 FT_Done_Face( p_face );
+                 p_face = NULL;
             }
 
             if( FT_Select_Charmap( p_face ? p_face : p_sys->p_face,
@@ -2333,6 +2578,9 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
     if( !p_region_in || !p_region_in->psz_html )
         return VLC_EGENERIC;
 
+    /* Reset the default fontsize in case screen metrics have changed */
+    p_filter->p_sys->i_font_size = GetFontSize( p_filter );
+
     p_sub = stream_MemoryNew( VLC_OBJECT(p_filter),
                               (uint8_t *) p_region_in->psz_html,
                               strlen( p_region_in->psz_html ),
@@ -2367,6 +2615,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
                     else
                     {
                         /* Only text and karaoke tags are supported */
+                        msg_Dbg( p_filter, "Unsupported top-level tag '%s' ignored.", psz_node );
                         xml_ReaderDelete( p_xml, p_xml_reader );
                         p_xml_reader = NULL;
                         rv = VLC_EGENERIC;
@@ -2379,7 +2628,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
             if( p_xml_reader )
             {
                 uint32_t   *psz_text;
-                int         i_len;
+                int         i_len = 0;
                 uint32_t    i_runs = 0;
                 uint32_t    i_k_runs = 0;
                 uint32_t   *pi_run_lengths = NULL;
@@ -2404,7 +2653,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
                     p_region_out->i_x = p_region_in->i_x;
                     p_region_out->i_y = p_region_in->i_y;
 
-                    if( rv == VLC_SUCCESS )
+                    if(( rv == VLC_SUCCESS ) && ( i_len > 0 ))
                     {
                         rv = ProcessLines( p_filter, psz_text, i_len, i_runs,
                                 pi_run_lengths, pp_styles, &p_lines, &result,
@@ -2421,7 +2670,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
                     /* Don't attempt to render text that couldn't be layed out
                      * properly.
                      */
-                    if( rv == VLC_SUCCESS )
+                    if(( rv == VLC_SUCCESS ) && ( i_len > 0 ))
                     {
                         if( config_GetInt( p_filter, "freetype-yuvp" ) )
                         {
@@ -2581,36 +2830,44 @@ static line_desc_t *NewLine( int i_count )
     return p_line;
 }
 
-static int SetFontSize( filter_t *p_filter, int i_size )
+static int GetFontSize( filter_t *p_filter )
 {
     filter_sys_t *p_sys = p_filter->p_sys;
+    vlc_value_t   val;
+    int           i_size = 0;
 
-    if( i_size && i_size == p_sys->i_font_size ) return VLC_SUCCESS;
-
-    if( !i_size )
+    if( p_sys->i_default_font_size )
     {
-        vlc_value_t val;
-
-        if( !p_sys->i_default_font_size &&
-            p_sys->i_display_height == (int)p_filter->fmt_out.video.i_height )
-            return VLC_SUCCESS;
-
-        if( p_sys->i_default_font_size )
-        {
+        if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
+            i_size = p_sys->i_default_font_size * val.i_int / 1000;
+        else
             i_size = p_sys->i_default_font_size;
-        }
+    }
+    else
+    {
+        var_Get( p_filter, "freetype-rel-fontsize", &val );
+        i_size = (int)p_filter->fmt_out.video.i_height / val.i_int;
+        p_filter->p_sys->i_display_height =
+            p_filter->fmt_out.video.i_height;
+    }
+    if( i_size <= 0 )
+    {
+        msg_Warn( p_filter, "invalid fontsize, using 12" );
+        if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
+            i_size = 12 * val.i_int / 1000;
         else
-        {
-            var_Get( p_filter, "freetype-rel-fontsize", &val );
-            i_size = (int)p_filter->fmt_out.video.i_height / val.i_int;
-            p_filter->p_sys->i_display_height =
-                p_filter->fmt_out.video.i_height;
-        }
-        if( i_size <= 0 )
-        {
-            msg_Warn( p_filter, "invalid fontsize, using 12" );
             i_size = 12;
-        }
+    }
+    return i_size;
+}
+
+static int SetFontSize( filter_t *p_filter, int i_size )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if( !i_size )
+    {
+        i_size = GetFontSize( p_filter );
 
         msg_Dbg( p_filter, "using fontsize: %i", i_size );
     }