]> git.sesse.net Git - vlc/blobdiff - modules/gui/fbosd.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / modules / gui / fbosd.c
index c1a7008fa53111bb1ddfeea1898d71541e30f3c8..ccc747ee467211a83820e886f456860f4c7d03ec 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
  * fbosd.c : framebuffer osd plugin for vlc
  *****************************************************************************
- * Copyright (C) 2007, the VideoLAN team
- * $Id: vlc-fb-overlay.patch,v 1.8 2007/10/19 14:33:23 jeanpaul.saman Exp $
+ * Copyright (C) 2007-2008, the VideoLAN team
+ * $Id$
  *
  * Authors: Jean-Paul Saman
  * Copied from modules/video_output/fb.c by Samuel Hocevar <sam@zoy.org>
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_fs.h>
+#include <vlc_modules.h>
 
-#include <errno.h>
 #include <stdlib.h>                                                /* free() */
 #include <string.h>                                            /* strerror() */
 #include <fcntl.h>                                                 /* open() */
@@ -50,7 +52,8 @@
 #include <vlc_osd.h>
 #include <vlc_strings.h>
 
-// #define FBOSD_BLENDING 1
+#undef FBOSD_BLENDING
+#undef FBOSD_DEBUG
 
 /*****************************************************************************
  * Local prototypes
@@ -66,32 +69,25 @@ static int  OpenDisplay    ( intf_thread_t * );
 static void CloseDisplay   ( intf_thread_t * );
 
 /* Load modules needed for rendering and blending */
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
 static int  OpenBlending     ( intf_thread_t * );
 static void CloseBlending    ( intf_thread_t * );
 #endif
 static int  OpenTextRenderer ( intf_thread_t * );
 static void CloseTextRenderer( intf_thread_t * );
 
-#if 0
-static int  OpenScaling      ( intf_thread_t * );
-static int  CloseScaling     ( intf_thread_t * );
-#endif
-
 /* Manipulate the overlay buffer */
 static int  OverlayCallback( vlc_object_t *, char const *,
                              vlc_value_t, vlc_value_t, void * );
 
-static picture_t *AllocatePicture( vlc_object_t *,
-                                         video_format_t * );
-static void DeAllocatePicture( vlc_object_t *, picture_t *,
-                                     video_format_t * );
+static picture_t *AllocatePicture( video_format_t * );
+static void DeAllocatePicture( picture_t *, video_format_t * );
 static void SetOverlayTransparency( intf_thread_t *,
-                                    vlc_bool_t );
+                                    bool );
 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
                              char * );
 
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
 static int BlendPicture( intf_thread_t *, video_format_t *,
                          video_format_t *, picture_t *, picture_t * );
 #else
@@ -101,7 +97,7 @@ static picture_t *ConvertImage( intf_thread_t *, picture_t *,
 static int RenderPicture( intf_thread_t *, int, int,
                           picture_t *, picture_t * );
 static picture_t *RenderText( intf_thread_t *, const char *,
-                              video_format_t * );
+                              text_style_t *, video_format_t * );
 
 #define DEVICE_TEXT N_("Framebuffer device")
 #define DEVICE_LONGTEXT N_( \
@@ -162,68 +158,94 @@ static picture_t *RenderText( intf_thread_t *, const char *,
 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
     "displayed on the overlay framebuffer." )
 
-static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
-static const char *ppsz_pos_descriptions[] =
+static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
+static const char *const ppsz_pos_descriptions[] =
 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
 
-static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
+static const int pi_color_values[] = {
+               0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
                0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
                0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
                0x00000080, 0x000000FF, 0x0000FFFF};
-static const char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
+static const char *const ppsz_color_descriptions[] = {
+               N_("Default"), N_("Black"),
                N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
                N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
                N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
                N_("Aqua") };
 
-vlc_module_begin();
-    set_shortname( "fbosd" );
-    set_category( CAT_INTERFACE );
-    set_subcategory( SUBCAT_INTERFACE_MAIN );
+vlc_module_begin ()
+    set_shortname( "fbosd" )
+    set_category( CAT_INTERFACE )
+    set_subcategory( SUBCAT_INTERFACE_MAIN )
 
-    add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
-              VLC_FALSE );
+    add_file( "fbosd-dev", "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
+              false )
     add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
-                ASPECT_RATIO_LONGTEXT, VLC_TRUE );
+                ASPECT_RATIO_LONGTEXT, true )
 
     add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
-                FBOSD_IMAGE_LONGTEXT, VLC_TRUE );
+                FBOSD_IMAGE_LONGTEXT, true )
     add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
-                FBOSD_LONGTEXT, VLC_TRUE );
+                FBOSD_LONGTEXT, true )
 
-#ifdef FBOSD_BLENDING
     add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
-                            ALPHA_LONGTEXT, VLC_TRUE );
-
-#endif
+                            ALPHA_LONGTEXT, true )
 
-    set_section( N_("Position"), NULL );
+    set_section( N_("Position"), NULL )
     add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
-                 POSX_LONGTEXT, VLC_FALSE );
+                 POSX_LONGTEXT, false )
     add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
-                 POSY_LONGTEXT, VLC_FALSE );
-    add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
-        change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
+                 POSY_LONGTEXT, false )
+    add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
+        change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
 
-    set_section( N_("Font"), NULL );
+    set_section( N_("Font"), NULL )
     add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
-        OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
+        OPACITY_TEXT, OPACITY_LONGTEXT, false )
     add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
-                 VLC_FALSE );
-        change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
+                 false )
+        change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
     add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
-                 VLC_FALSE );
+                 false )
 
-    set_section( N_("Commands"), NULL );
-    add_bool( "fbosd-clear", VLC_FALSE, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, VLC_TRUE );
-    add_bool( "fbosd-render", VLC_FALSE, NULL, RENDER_TEXT, RENDER_LONGTEXT, VLC_TRUE );
-    add_bool( "fbosd-display", VLC_FALSE, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
+    set_section( N_("Commands"), NULL )
+    add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
+    add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
+    add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
 
-    set_description( _("GNU/Linux osd/overlay framebuffer interface") );
-    set_capability( "interface", 10 );
-    set_callbacks( Create, Destroy );
-vlc_module_end();
+    set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
+    set_capability( "interface", 10 )
+    set_callbacks( Create, Destroy )
+vlc_module_end ()
+
+/*****************************************************************************
+ * fbosd_render_t: render descriptor
+ *****************************************************************************/
+struct fbosd_render_t
+{
+#define FBOSD_RENDER_IMAGE 0
+#define FBOSD_RENDER_TEXT  1
+    int             i_type;
+
+#define FBOSD_STATE_FREE     0
+#define FBOSD_STATE_RESERVED 1
+#define FBOSD_STATE_RENDER   2
+    int             i_state;
+
+    /* Font style */
+    text_style_t*   p_text_style;                            /* font control */
+    char            *psz_string;
+
+    /* Position */
+    bool            b_absolute;
+    int             i_x;
+    int             i_y;
+    int             i_pos;
+    int             i_alpha;                      /* transparency for images */
+};
+#define FBOSD_RENDER_MAX 10
 
 /*****************************************************************************
  * intf_sys_t: interface framebuffer method descriptor
@@ -233,7 +255,7 @@ struct intf_sys_t
     /* Framebuffer information */
     int                         i_fd;                       /* device handle */
     struct fb_var_screeninfo    var_info;        /* current mode information */
-    vlc_bool_t                  b_pan;     /* does device supports panning ? */
+    bool                  b_pan;     /* does device supports panning ? */
     struct fb_cmap              fb_cmap;                /* original colormap */
     uint16_t                    *p_palette;              /* original palette */
 
@@ -248,38 +270,29 @@ struct intf_sys_t
 
     /* Image and Picture rendering */
     image_handler_t *p_image;
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
     filter_t *p_blend;                              /* alpha blending module */
 #endif
     filter_t *p_text;                                /* text renderer module */
-#if 0
-    filter_t *p_scale;                                     /* scaling module */
-#endif
-    vlc_bool_t b_force_crop;                    /* force cropping of picture */
-    int i_crop_x, i_crop_y, i_crop_width, i_crop_height;         /* cropping */
 
-    /* Misc */
-    char            *psz_file;
-    char            *psz_text;
-
-    vlc_bool_t      b_image;
-    vlc_bool_t      b_text;
+    /* Render */
+    struct fbosd_render_t render[FBOSD_RENDER_MAX];
 
     /* Font style */
     text_style_t    *p_style;                                /* font control */
 
-    /* Positon of image/text */
-    vlc_bool_t      b_absolute;
-    int             i_x;
-    int             i_y;
-    int             i_pos;
+    /* Position */
+    bool      b_absolute;
+    int       i_x;
+    int       i_y;
+    int       i_pos;
 
-    int             i_alpha;                      /* transparency for images */
+    int       i_alpha;                      /* transparency for images */
 
     /* commands control */
-    vlc_bool_t      b_need_update;    /* update display with \overlay buffer */
-    vlc_bool_t      b_clear;      /* clear overlay buffer make it tranparent */
-    vlc_bool_t      b_render;   /* render an image or text in overlay buffer */
+    bool      b_need_update;    /* update display with \overlay buffer */
+    bool      b_clear;      /* clear overlay buffer make it tranparent */
+    bool      b_render;   /* render an image or text in overlay buffer */
 };
 
 /*****************************************************************************
@@ -290,42 +303,38 @@ static int Create( vlc_object_t *p_this )
     intf_thread_t *p_intf = (intf_thread_t *)p_this;
     intf_sys_t    *p_sys;
     char          *psz_aspect;
+    char          *psz_tmp;
+    int i;
 
     /* Allocate instance and initialize some members */
-    p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
+    p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
     if( !p_intf->p_sys )
-    {
-        msg_Err( p_intf, "out of memory" );
         return VLC_ENOMEM;
-    };
-    memset( p_sys, 0, sizeof(intf_sys_t) );
 
-    p_sys->p_style = malloc( sizeof( text_style_t ) );
+    p_sys->p_style = text_style_New();
     if( !p_sys->p_style )
     {
         free( p_intf->p_sys );
-        msg_Err( p_intf, "out of memory" );
         return VLC_ENOMEM;
     }
-    p_intf->p_libvlc->pf_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
 
     p_intf->pf_run = Run;
 
     p_sys->p_image = image_HandlerCreate( p_this );
     if( !p_sys->p_image )
     {
-        free( p_intf->p_sys->p_style );
-        free( p_intf->p_sys );
-        msg_Err( p_intf, "out of memory" );
+        text_style_Delete( p_sys->p_style );
+        free( p_sys );
         return VLC_ENOMEM;
     }
 
-#ifdef FBOSD_BLENDING
     p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
     var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
-#else
-    p_sys->i_alpha = 255;
-#endif
+
+    /* Use PAL by default */
+    p_sys->i_width  = p_sys->fmt_out.i_width  = 704;
+    p_sys->i_height = p_sys->fmt_out.i_height = 576;
+
     p_sys->i_aspect = -1;
     psz_aspect =
             var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
@@ -338,30 +347,34 @@ static int Create( vlc_object_t *p_this )
             *psz_parser++ = '\0';
             p_sys->i_aspect = ( atoi( psz_aspect )
                               * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
-            p_sys->fmt_out.i_aspect = p_sys->i_aspect;
+            p_sys->fmt_out.i_sar_num = p_sys->i_aspect    * p_sys->i_height;
+            p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
         }
         msg_Dbg( p_intf, "using aspect ratio %d:%d",
                   atoi( psz_aspect ), atoi( psz_parser ) );
 
         free( psz_aspect );
-        psz_aspect = NULL;
     }
 
-    /* Use PAL by default */
-    p_sys->i_width  = p_sys->fmt_out.i_width  = 704;
-    p_sys->i_height = p_sys->fmt_out.i_height = 576;
-
-    p_sys->psz_file =
-            var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
+    psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
     var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
-    if( p_sys->psz_file &&  *p_sys->psz_file )
-        p_sys->b_image = VLC_TRUE;
+    if( psz_tmp && *psz_tmp )
+    {
+        p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
+        p_sys->render[0].i_state = FBOSD_STATE_RENDER;
+        p_sys->render[0].psz_string = strdup( psz_tmp );
+    }
+    free( psz_tmp );
 
-    p_sys->psz_text =
-            var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
+    psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
     var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
-    if( p_sys->psz_text &&  *p_sys->psz_text )
-        p_sys->b_text = VLC_TRUE;
+    if( psz_tmp && *psz_tmp )
+    {
+        p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
+        p_sys->render[1].i_state = FBOSD_STATE_RENDER;
+        p_sys->render[1].psz_string = strdup( psz_tmp );
+    }
+    free( psz_tmp );
 
     p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
     p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
@@ -382,6 +395,9 @@ static int Create( vlc_object_t *p_this )
     var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
     var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
 
+    for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+        p_sys->render[i].p_text_style = text_style_New();
+
     p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
     p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
     p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
@@ -391,16 +407,21 @@ static int Create( vlc_object_t *p_this )
     var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
 
     /* Check if picture position was overridden */
-    p_sys->b_absolute = VLC_TRUE;
+    p_sys->b_absolute = true;
     if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
     {
-        p_sys->b_absolute = VLC_FALSE;
+        p_sys->b_absolute = false;
         p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
                         p_sys->i_y : p_sys->i_height;
         p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
                         p_sys->i_x : p_sys->i_width;
     }
 
+    p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
+    p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
+    p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
+    p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
+
     /* Initialize framebuffer */
     if( OpenDisplay( p_intf ) )
     {
@@ -410,7 +431,7 @@ static int Create( vlc_object_t *p_this )
 
     Init( p_intf );
 
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
     /* Load the blending module */
     if( OpenBlending( p_intf ) )
     {
@@ -427,17 +448,9 @@ static int Create( vlc_object_t *p_this )
         Destroy( VLC_OBJECT(p_intf) );
         return VLC_EGENERIC;
     }
-#if 0
-    /* Load scaling module */
-    if( OpenScaling( p_intf ) )
-    {
-        msg_Err( p_intf, "Unable to load image scaling module" );
-        Destroy( VLC_OBJECT(p_intf) );
-        return VLC_EGENERIC;
-    }
-#endif
-    p_sys->b_render = VLC_TRUE;
-    p_sys->b_need_update = VLC_TRUE;
+
+    p_sys->b_render = true;
+    p_sys->b_need_update = true;
 
     return VLC_SUCCESS;
 }
@@ -450,16 +463,16 @@ static int Create( vlc_object_t *p_this )
 static void Destroy( vlc_object_t *p_this )
 {
     intf_thread_t *p_intf = (intf_thread_t *)p_this;
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    int i;
+
 
-    p_sys->b_need_update = VLC_FALSE;
-    p_sys->b_render = VLC_FALSE;
-    p_sys->b_clear = VLC_FALSE;
+    p_sys->b_need_update = false;
+    p_sys->b_render = false;
+    p_sys->b_clear = false;
 
-#ifdef FBOSD_BLENDING
     var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
     var_Destroy( p_intf, "fbosd-alpha" );
-#endif
 
     var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
     var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
@@ -489,47 +502,52 @@ static void Destroy( vlc_object_t *p_this )
 
     CloseDisplay( p_intf );
 
-#ifdef FBOSD_BLENDING
+    for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+    {
+        free( p_sys->render[i].psz_string );
+        p_sys->render[i].i_state = FBOSD_STATE_FREE;
+        text_style_Delete( p_sys->render[i].p_text_style );
+    }
+
+#if defined(FBOSD_BLENDING)
     if( p_sys->p_blend ) CloseBlending( p_intf );
 #endif
     if( p_sys->p_text )  CloseTextRenderer( p_intf );
-#if 0
-    if( p_sys->p_scale ) CloseScaling( p_intf );
-#endif
+
     if( p_sys->p_image )
         image_HandlerDelete( p_sys->p_image );
     if( p_sys->p_overlay )
-        p_sys->p_overlay->pf_release( p_sys->p_overlay );
+        picture_Release( p_sys->p_overlay );
 
-    free( p_sys->psz_file );
-    free( p_sys->psz_text );
-    free( p_sys->p_style );
+    text_style_Delete( p_sys->p_style );
     free( p_sys );
 }
 
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
 static int OpenBlending( intf_thread_t *p_intf )
 {
     if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
 
     p_intf->p_sys->p_blend =
-            vlc_object_create( p_intf, VLC_OBJECT_FILTER );
+            vlc_object_create( p_intf, sizeof(filter_t) );
     vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
     p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
         p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
-    p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
-            p_intf->p_sys->fmt_out.i_aspect;
+    p_intf->p_sys->p_blend->fmt_out.video.i_sar_num =
+            p_intf->p_sys->fmt_out.i_sar_num;
+    p_intf->p_sys->p_blend->fmt_out.video.i_sar_den =
+            p_intf->p_sys->fmt_out.i_sar_den;
     p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
             p_intf->p_sys->fmt_out.i_chroma;
-    if( config_GetInt( p_intf, "freetype-yuvp" ) )
+    if( var_InheritBool( p_intf, "freetype-yuvp" ) )
         p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
-                VLC_FOURCC('Y','U','V','P');
+                VLC_CODEC_YUVP;
     else
         p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
-                VLC_FOURCC('Y','U','V','A');
+                VLC_CODEC_YUVA;
 
     p_intf->p_sys->p_blend->p_module =
-        module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
+        module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
 
     if( !p_intf->p_sys->p_blend->p_module )
         return VLC_EGENERIC;
@@ -542,11 +560,10 @@ static void CloseBlending( intf_thread_t *p_intf )
     if( p_intf->p_sys->p_blend )
     {
         if( p_intf->p_sys->p_blend->p_module )
-            module_Unneed( p_intf->p_sys->p_blend,
+            module_unneed( p_intf->p_sys->p_blend,
                            p_intf->p_sys->p_blend->p_module );
 
-        vlc_object_detach( p_intf->p_sys->p_blend );
-        vlc_object_destroy( p_intf->p_sys->p_blend );
+        vlc_object_release( p_intf->p_sys->p_blend );
     }
 }
 #endif
@@ -558,7 +575,7 @@ static int OpenTextRenderer( intf_thread_t *p_intf )
     if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
 
     p_intf->p_sys->p_text =
-            vlc_object_create( p_intf, VLC_OBJECT_FILTER );
+            vlc_object_create( p_intf, sizeof(filter_t) );
     vlc_object_attach( p_intf->p_sys->p_text, p_intf );
 
     p_intf->p_sys->p_text->fmt_out.video.i_width =
@@ -572,15 +589,15 @@ static int OpenTextRenderer( intf_thread_t *p_intf )
     if( psz_modulename && *psz_modulename )
     {
         p_intf->p_sys->p_text->p_module =
-            module_Need( p_intf->p_sys->p_text, "text renderer",
-                            psz_modulename, VLC_TRUE );
+            module_need( p_intf->p_sys->p_text, "text renderer",
+                            psz_modulename, true );
     }
     if( !p_intf->p_sys->p_text->p_module )
     {
         p_intf->p_sys->p_text->p_module =
-            module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
+            module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
     }
-    if( psz_modulename ) free( psz_modulename );
+    free( psz_modulename );
 
     if( !p_intf->p_sys->p_text->p_module )
         return VLC_EGENERIC;
@@ -593,116 +610,66 @@ static void CloseTextRenderer( intf_thread_t *p_intf )
     if( p_intf->p_sys->p_text )
     {
         if( p_intf->p_sys->p_text->p_module )
-            module_Unneed( p_intf->p_sys->p_text,
+            module_unneed( p_intf->p_sys->p_text,
                            p_intf->p_sys->p_text->p_module );
 
-        vlc_object_detach( p_intf->p_sys->p_text );
-        vlc_object_destroy( p_intf->p_sys->p_text );
+        vlc_object_release( p_intf->p_sys->p_text );
     }
 }
-#if 0
-static int OpenScaling( intf_thread_t *p_intf )
-{
-    if( p_intf->p_sys->p_scale ) return VLC_EGENERIC;
-
-    p_intf->p_sys->p_scale =
-            vlc_object_create( p_intf, VLC_OBJECT_FILTER );
-    vlc_object_attach( p_intf->p_sys->p_scale, p_intf );
-    p_intf->p_sys->p_scale->fmt_out.video.i_chroma =
-        p_intf->p_sys->p_scale->fmt_in.video.i_chroma =
-            p_intf->p_sys->fmt_out.i_chroma;
-
-    /* XXX: We'll also be using it for YUVA and RGBA blending ... */
-    p_intf->p_sys->p_scale->fmt_in.video.i_width =
-        p_intf->p_sys->p_scale->fmt_in.video.i_height = 32;
-    p_intf->p_sys->p_scale->fmt_out.video.i_width =
-        p_intf->p_sys->p_scale->fmt_out.video.i_height = 16;
-
-    p_intf->p_sys->p_scale->p_module =
-        module_Need( p_intf->p_sys->p_scale, "video filter2", 0, 0 );
-
-    if( !p_intf->p_sys->p_scale->p_module )
-        return VLC_EGENERIC;
-
-    return VLC_SUCCESS;
-}
-
-static int CloseScaling( intf_thread_t *p_intf )
-{
-    if( p_intf->p_sys->p_scale )
-    {
-        if( p_intf->p_sys->p_scale->p_module )
-            module_Unneed( p_intf->p_sys->p_scale,
-                           p_intf->p_sys->p_scale->p_module );
-
-        vlc_object_detach( p_intf->p_sys->p_scale );
-        vlc_object_destroy( p_intf->p_sys->p_scale );
-    }
-}
-#endif
 
 /*****************************************************************************
  * AllocatePicture:
  * allocate a picture buffer for use with the overlay fb.
  *****************************************************************************/
-static picture_t *AllocatePicture( vlc_object_t *p_this,
-                                   video_format_t *p_fmt )
+static picture_t *AllocatePicture( video_format_t *p_fmt )
 {
-    picture_t *p_pic = malloc( sizeof( picture_t ) );
-    if( !p_pic ) return NULL;
+    picture_t *p_picture = picture_NewFromFormat( p_fmt );
+    if( !p_picture )
+        return NULL;
 
     if( !p_fmt->p_palette &&
-        ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
+        ( p_fmt->i_chroma == VLC_CODEC_YUVP ) )
     {
         p_fmt->p_palette = malloc( sizeof(video_palette_t) );
         if( !p_fmt->p_palette )
         {
-            free( p_pic );
+            picture_Release( p_picture );
             return NULL;
         }
     }
-    else p_fmt->p_palette = NULL;
-
-    p_pic->p_data_orig = NULL;
-
-    vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
-                          p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
-
-    if( !p_pic->i_planes )
+    else
     {
-        free( p_pic );
-        free( p_fmt->p_palette );
-        return NULL;
+        p_fmt->p_palette = NULL;
     }
-    return p_pic;
+
+    return p_picture;
 }
 
 /*****************************************************************************
  * DeAllocatePicture:
  * Deallocate a picture buffer and free all associated memory.
  *****************************************************************************/
-static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
-                               video_format_t *p_fmt )
+static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
 {
-    if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
-    if( p_pic && p_pic->pf_release ) p_pic->pf_release( p_pic );
-    if( p_fmt && p_fmt->p_palette )
+    if( p_fmt )
     {
         free( p_fmt->p_palette );
         p_fmt->p_palette = NULL;
     }
-    p_pic = NULL;
+
+    if( p_pic )
+        picture_Release( p_pic );
 }
 
 /*****************************************************************************
  * SetOverlayTransparency: Set the transparency for this overlay fb,
- * - VLC_TRUE is make transparent
- * - VLC_FALSE is make non tranparent
+ * - true is make transparent
+ * - false is make non tranparent
  *****************************************************************************/
 static void SetOverlayTransparency( intf_thread_t *p_intf,
-                                    vlc_bool_t b_transparent )
+                                    bool b_transparent )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
     size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
                         * p_sys->i_bytes_per_pixel;
     size_t i_page_size = (p_sys->i_page_size > i_size) ?
@@ -712,13 +679,14 @@ static void SetOverlayTransparency( intf_thread_t *p_intf,
     {
         msg_Dbg( p_intf, "Make overlay %s",
                  b_transparent ? "transparent" : "opaque" );
-        memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
         if( b_transparent )
             memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
+        else
+            memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
     }
 }
 
-#ifdef FBOSD_BLENDING
+#if defined(FBOSD_BLENDING)
 /*****************************************************************************
  * BlendPicture: Blend two pictures together..
  *****************************************************************************/
@@ -726,29 +694,14 @@ static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
                          video_format_t *p_fmt_dst, picture_t *p_pic_src,
                          picture_t *p_pic_dst )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
     if( p_sys->p_blend && p_sys->p_blend->p_module )
     {
         int i_x_offset = p_sys->i_x;
         int i_y_offset = p_sys->i_y;
 
         memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
-#if 0
-        msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
-                 p_pic_src, (char*)&p_fmt_src->i_chroma,
-                 p_sys->p_blend->fmt_in.video.i_width, p_sys->p_blend->fmt_in.video.i_height,
-                 p_fmt_src->i_bits_per_pixel,
-                 p_pic_src->i_planes,
-                 p_pic_src->p[0].p_pixels, p_pic_src->p[1].p_pixels,
-                 p_pic_src->p[2].p_pixels, p_pic_src->p[3].p_pixels );
-        msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
-                 p_pic_dst, (char*)&p_fmt_dst->i_chroma,
-                 p_fmt_dst->i_width, p_fmt_dst->i_height,
-                 p_fmt_dst->i_bits_per_pixel,
-                 p_pic_dst->i_planes,
-                 p_pic_dst->p[0].p_pixels, p_pic_dst->p[1].p_pixels,
-                 p_pic_dst->p[2].p_pixels, p_pic_dst->p[3].p_pixels );
-#endif
+
         /* Update the output picture size */
         p_sys->p_blend->fmt_out.video.i_width =
             p_sys->p_blend->fmt_out.video.i_visible_width =
@@ -768,6 +721,51 @@ static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
     }
     return VLC_EGENERIC;
 }
+
+static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
+{
+    uint8_t *p_begin = NULL, *p_end = NULL;
+    uint8_t i_skip = 0;
+
+    if( *p_pic && ((*p_pic)->i_planes != 1) )
+    {
+        msg_Err( p_intf,
+                 "cannot invert alpha channel too many planes %d (only 1 supported)",
+                 (*p_pic)->i_planes );
+        return VLC_EGENERIC;
+    }
+
+    switch( fmt.i_chroma )
+    {
+        case VLC_CODEC_RGB24:
+            p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
+            p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
+                      ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
+            i_skip = 3;
+            break;
+        case VLC_CODEC_RGB32:
+            p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
+            p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
+                      ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
+            i_skip = 4;
+            break;
+        default:
+            msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
+                    (char *)&fmt.i_chroma );
+            return VLC_EGENERIC;
+    }
+
+    for( ; p_begin < p_end; p_begin += i_skip )
+    {
+        uint8_t i_opacity = 0;
+
+        if( *p_begin != 0xFF )
+            i_opacity = 255 - *p_begin;
+        *p_begin = i_opacity;
+    }
+    /* end of kludge */
+    return VLC_SUCCESS;
+}
 #endif
 
 /*****************************************************************************
@@ -779,6 +777,7 @@ static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
                           picture_t *p_src, picture_t *p_dest )
 {
     int i;
+    VLC_UNUSED( p_intf );
 
     if( !p_dest && !p_src ) return VLC_EGENERIC;
 
@@ -787,9 +786,8 @@ static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
         if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
         {
             /* There are margins, but with the same width : perfect ! */
-            p_intf->p_libvlc->pf_memcpy(
-                         p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
-                         p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
+            vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
+                        p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
         }
         else
         {
@@ -806,7 +804,7 @@ static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
 
             i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
             i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
-#if 0
+#if defined(FBOSD_DEBUG)
             msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
                      p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
                      i_x_offset, i_y_offset, i_x, i_x_clip );
@@ -819,8 +817,8 @@ static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
                 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
                 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
                 {
-                    p_intf->p_libvlc->pf_memcpy( p_out + i_x, p_in,
-                                                 p_src->p[i].i_visible_pitch - i_x_clip );
+                    vlc_memcpy( p_out + i_x, p_in,
+                                p_src->p[i].i_visible_pitch - i_x_clip );
                     p_in += p_src->p[i].i_pitch;
                     p_out += p_dest->p[i].i_pitch;
                 }
@@ -833,34 +831,38 @@ static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
 /*****************************************************************************
  * RenderText - Render text to the desired picture format
  *****************************************************************************/
-static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_text,
-                              video_format_t *p_fmt )
+static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
+                              text_style_t *p_style, video_format_t *p_fmt )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
     subpicture_region_t *p_region;
     picture_t *p_dest = NULL;
 
-    if( !psz_text ) return p_dest;
+    if( !psz_string ) return p_dest;
 
     if( p_sys->p_text && p_sys->p_text->p_module )
     {
-        p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
-        if( !p_region )
-            return p_dest;
+        video_format_t fmt;
 
-        memset( p_region, 0, sizeof(subpicture_region_t) );
+        memset( &fmt, 0, sizeof(fmt) );
+        fmt.i_chroma = VLC_CODEC_TEXT;
+        fmt.i_width  = fmt.i_visible_width = 0;
+        fmt.i_height = fmt.i_visible_height = 0;
+        fmt.i_x_offset = 0;
+        fmt.i_y_offset = 0;
 
-        p_region->psz_text = strdup( p_sys->psz_text );
-        p_region->p_style = p_sys->p_style;
-
-        p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
-        p_region->fmt.i_aspect = 0;
-        p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
-        p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
-        p_region->fmt.i_x_offset = 0;
-        p_region->fmt.i_y_offset = 0;
+        p_region = subpicture_region_New( &fmt );
+        if( !p_region )
+            return p_dest;
 
-        p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
+        p_region->psz_text = strdup( psz_string );
+        if( !p_region->psz_text )
+        {
+            subpicture_region_Delete( p_region );
+            return NULL;
+        }
+        p_region->p_style = text_style_Duplicate( p_style );
+        p_region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
 
         if( p_sys->p_text->pf_render_text )
         {
@@ -871,33 +873,28 @@ static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_text,
             p_sys->p_text->pf_render_text( p_sys->p_text,
                                            p_region, p_region );
 
-#ifndef FBOSD_BLENDING
-            fmt_out.i_chroma = p_fmt->i_chroma;
-            p_dest = ConvertImage( p_intf, &p_region->picture,
-                                   &p_region->fmt, &fmt_out );
-#else
+#if defined(FBOSD_BLENDING)
             fmt_out = p_region->fmt;
             fmt_out.i_bits_per_pixel = 32;
-            memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
+            vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
+
+            /* FIXME not needed to copy the picture anymore no ? */
             p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
             if( !p_dest )
             {
-                if( p_region->picture.pf_release )
-                    p_region->picture.pf_release( &p_region->picture );
-                free( p_region->psz_text  );
-                free( p_region );
+                subpicture_region_Delete( p_region );
                 return NULL;
             }
-            vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
+            picture_Copy( p_dest, p_region->p_picture );
+#else
+            fmt_out.i_chroma = p_fmt->i_chroma;
+            p_dest = ConvertImage( p_intf, p_region->p_picture,
+                                   &p_region->fmt, &fmt_out );
 #endif
-            if( p_region->picture.pf_release )
-                p_region->picture.pf_release( &p_region->picture );
-            free( p_region->psz_text  );
-            free( p_region );
+            subpicture_region_Delete( p_region );
             return p_dest;
         }
-        free( p_region->psz_text );
-        free( p_region );
+        subpicture_region_Delete( p_region );
     }
     return p_dest;
 }
@@ -928,14 +925,14 @@ static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
     return p_pic;
 }
 
-#ifndef FBOSD_BLENDING
+#if ! defined(FBOSD_BLENDING)
 /*****************************************************************************
  * Convertmage: Convert image to another fourcc
  *****************************************************************************/
 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
                          video_format_t *p_fmt_in, video_format_t *p_fmt_out )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
     picture_t  *p_old = NULL;
 
     if( p_sys->p_image )
@@ -955,22 +952,22 @@ static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
  *****************************************************************************/
 static int Init( intf_thread_t *p_intf )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     /* Initialize the output structure: RGB with square pixels, whatever
      * the input format is, since it's the only format we know */
     switch( p_sys->var_info.bits_per_pixel )
     {
     case 8: /* FIXME: set the palette */
-        p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
+        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB8; break;
     case 15:
-        p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
+        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB15; break;
     case 16:
-        p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
+        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB16; break;
     case 24:
-        p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
+        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB24; break;
     case 32:
-        p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
+        p_sys->fmt_out.i_chroma = VLC_CODEC_RGB32; break;
     default:
         msg_Err( p_intf, "unknown screen depth %i",
                  p_sys->var_info.bits_per_pixel );
@@ -984,19 +981,20 @@ static int Init( intf_thread_t *p_intf )
     /* Assume we have square pixels */
     if( p_sys->i_aspect < 0 )
     {
-        p_sys->fmt_out.i_aspect = ( p_sys->i_width
-                                  * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
+        p_sys->fmt_out.i_sar_num = 1;
+        p_sys->fmt_out.i_sar_den = 1;
+    }
+    else
+    {
+        p_sys->fmt_out.i_sar_num = p_sys->i_aspect    * p_sys->i_height;
+        p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
     }
-    else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
-
-    p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
 
     /* Allocate overlay buffer */
-    p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
-                                        &p_sys->fmt_out );
+    p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
     if( !p_sys->p_overlay ) return VLC_EGENERIC;
 
-    SetOverlayTransparency( p_intf, VLC_TRUE );
+    SetOverlayTransparency( p_intf, true );
 
     /* We know the chroma, allocate a buffer which will be used
      * to write to the overlay framebuffer */
@@ -1028,16 +1026,20 @@ static int Init( intf_thread_t *p_intf )
  *****************************************************************************/
 static void End( intf_thread_t *p_intf )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     /* CleanUp */
-    SetOverlayTransparency( p_intf, VLC_FALSE );
+    SetOverlayTransparency( p_intf, false );
     if( p_sys->p_overlay )
     {
-        write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size );
+        int ret;
+        ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
+                     p_sys->i_page_size );
+        if( ret < 0 )
+            msg_Err( p_intf, "unable to clear overlay" );
     }
 
-    DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
+    DeAllocatePicture( p_intf->p_sys->p_overlay,
                        &p_intf->p_sys->fmt_out );
     p_intf->p_sys->p_overlay = NULL;
 }
@@ -1047,21 +1049,21 @@ static void End( intf_thread_t *p_intf )
  *****************************************************************************/
 static int OpenDisplay( intf_thread_t *p_intf )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
     char *psz_device;                             /* framebuffer device path */
     struct fb_fix_screeninfo    fix_info;     /* framebuffer fix information */
 
     /* Open framebuffer device */
-    if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
+    if( !(psz_device = var_InheritString( p_intf, "fbosd-dev" )) )
     {
         msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
         return VLC_EGENERIC;
     }
 
-    p_sys->i_fd = open( psz_device, O_RDWR );
+    p_sys->i_fd = vlc_open( psz_device, O_RDWR );
     if( p_sys->i_fd == -1 )
     {
-        msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
+        msg_Err( p_intf, "cannot open %s (%m)", psz_device );
         free( psz_device );
         return VLC_EGENERIC;
     }
@@ -1070,7 +1072,7 @@ static int OpenDisplay( intf_thread_t *p_intf )
     /* Get framebuffer device information */
     if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
     {
-        msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
+        msg_Err( p_intf, "cannot get fb info (%m)" );
         close( p_sys->i_fd );
         return VLC_EGENERIC;
     }
@@ -1101,7 +1103,6 @@ static int OpenDisplay( intf_thread_t *p_intf )
         p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
         if( !p_sys->p_palette )
         {
-            msg_Err( p_intf, "out of memory" );
             close( p_sys->i_fd );
             return VLC_ENOMEM;
         }
@@ -1153,7 +1154,7 @@ static int OpenDisplay( intf_thread_t *p_intf )
  *****************************************************************************/
 static void CloseDisplay( intf_thread_t *p_intf )
 {
-    intf_sys_t *p_sys = (intf_sys_t *) p_intf;
+    intf_sys_t *p_sys = p_intf->p_sys;
 
     /* Restore palette */
     if( p_sys->var_info.bits_per_pixel == 8 )
@@ -1167,157 +1168,249 @@ static void CloseDisplay( intf_thread_t *p_intf )
     close( p_sys->i_fd );
 }
 
+static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    if( render->i_state != FBOSD_STATE_RENDER ) return;
+    if( !render->psz_string ) return;
+
+    if( render->i_type == FBOSD_RENDER_IMAGE )
+    {
+        picture_t *p_pic;
+        p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
+        if( p_pic )
+        {
+            RenderPicture( p_intf, render->i_x, render->i_y,
+                           p_pic, p_sys->p_overlay );
+            picture_Release( p_pic );
+        }
+    }
+    else if( render->i_type == FBOSD_RENDER_TEXT )
+    {
+        picture_t *p_text;
+#if defined(FBOSD_BLENDING)
+        video_format_t fmt_in;
+        memset( &fmt_in, 0, sizeof(video_format_t) );
+        p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
+                             &fmt_in );
+        if( p_text )
+        {
+            BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
+                          p_text, p_sys->p_overlay );
+            msg_Dbg( p_intf, "releasing picture" );
+            DeAllocatePicture( p_text, &fmt_in );
+        }
+#else
+        p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
+                             &p_sys->fmt_out );
+        if( p_text )
+        {
+            RenderPicture( p_intf, render->i_x, render->i_y,
+                           p_text, p_sys->p_overlay );
+            picture_Release( p_text );
+        }
+#endif
+    }
+}
+
+static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    text_style_Delete( render->p_text_style );
+    render->p_text_style = text_style_New();
+    free( render->psz_string );
+    render->psz_string = NULL;
+
+    render->i_x = p_sys->i_x;
+    render->i_y = p_sys->i_y;
+    render->i_pos = p_sys->i_pos;
+    render->i_alpha = p_sys->i_alpha;
+    render->b_absolute = p_sys->b_absolute;
+    render->i_state = FBOSD_STATE_FREE;
+}
+
+static bool isRendererReady( intf_thread_t *p_intf )
+{
+    intf_sys_t *p_sys = p_intf->p_sys;
+    int i;
+
+    /* Check if there are more items to render */
+    for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+    {
+        if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
+            return false;
+    }
+    return true;
+}
+
 /*****************************************************************************
- * Run: rc thread
+ * Run: thread
  *****************************************************************************
  * This part of the interface is in a separate thread so that we can call
  * exec() from within it without annoying the rest of the program.
  *****************************************************************************/
 static void Run( intf_thread_t *p_intf )
 {
-    intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    int canc = vlc_savecancel();
 
-    while( !intf_ShouldDie( p_intf ) )
+    while( vlc_object_alive( p_intf ) )
     {
-        if( p_sys->b_render )
+        int i;
+
+        /* Is there somthing to render? */
+        for( i = 0; i < FBOSD_RENDER_MAX; i++ )
         {
-            if( p_sys->b_image )
+            if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
             {
-                picture_t *p_pic;
-                p_pic = LoadImage( p_intf, &p_sys->fmt_out, p_sys->psz_file );
-                if( p_pic )
-                {
-                    RenderPicture( p_intf, p_sys->i_x, p_sys->i_y,
-                                   p_pic, p_sys->p_overlay );
-                    p_pic->pf_release( p_pic );
-                }
-                var_SetString( p_intf, "fbosd-image", "" );
-                p_sys->b_image = VLC_FALSE;
+                Render( p_intf, &p_sys->render[i] );
+                RenderClear( p_intf, &p_sys->render[i] );
             }
-
-            if( p_sys->b_text )
-            {
-                picture_t *p_text;
-#ifndef FBOSD_BLENDING
-                p_text = RenderText( p_intf, p_sys->psz_text, &p_sys->fmt_out );
-                if( p_text )
-                {
-                    RenderPicture( p_intf, p_sys->i_x, p_sys->i_y,
-                                   p_text, p_sys->p_overlay );
-                    p_text->pf_release( p_text );
-                }
-#else
-                video_format_t fmt_in;
-                memset( &fmt_in, 0, sizeof(video_format_t) );
-                p_text = RenderText( p_intf, p_sys->psz_text, &fmt_in );
-                if( p_text )
-                {
-                    BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
-                                  p_text, p_sys->p_overlay );
-                    msg_Dbg( p_intf, "releasing picture" );
-                    DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
-                }
-#endif
-                var_SetString( p_intf, "fbosd-text", "" );
-                p_sys->b_text = VLC_FALSE;
-            }
-            p_sys->b_render = VLC_FALSE;
         }
 
         if( p_sys->b_clear )
         {
-            SetOverlayTransparency( p_intf, VLC_TRUE );
+            SetOverlayTransparency( p_intf, true );
 
             var_SetString( p_intf, "fbosd-image", "" );
             var_SetString( p_intf, "fbosd-text", "" );
 
-            p_sys->b_image = VLC_FALSE;
-            p_sys->b_text = VLC_FALSE;
-            p_sys->b_clear = VLC_FALSE;
-            p_sys->b_need_update = VLC_TRUE;
+            p_sys->b_clear = false;
+            p_sys->b_need_update = true;
         }
 
-        if( p_sys->b_need_update && p_sys->p_overlay )
+        if( p_sys->b_need_update && p_sys->p_overlay &&
+            isRendererReady( p_intf ) )
         {
-            write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
-                   p_sys->i_page_size );
+            int ret;
+#if defined(FBOSD_BLENDING)
+            /* Reverse alpha channel to work around FPGA bug */
+            InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
+#endif
+            ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
+                         p_sys->i_page_size );
+            if( ret < 0 )
+                msg_Err( p_intf, "unable to write to overlay" );
             lseek( p_sys->i_fd, 0, SEEK_SET );
-            p_sys->b_need_update = VLC_FALSE;
+
+            /* clear the picture */
+            memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
+            p_sys->b_need_update = false;
         }
 
-        if( vlc_CPU() & CPU_CAPABILITY_FPU )
-            msleep( INTF_IDLE_SLEEP );
-        else
-            msleep( 1000 );
+        msleep( INTF_IDLE_SLEEP );
     }
 
     End( p_intf );
+    vlc_restorecancel( canc );
 }
 
 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
     intf_thread_t *p_intf = (intf_thread_t *) p_this;
-    intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    VLC_UNUSED(oldval); VLC_UNUSED(p_data);
 
-    if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
-    {
-        free( p_sys->psz_file );
-        p_sys->psz_file = strdup( newval.psz_string );
-        p_sys->b_image = VLC_TRUE;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
-    {
-        free( p_sys->psz_text );
-        p_sys->psz_text = strdup( newval.psz_string );
-        p_sys->b_text = VLC_TRUE;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
-    {
-        p_sys->b_absolute = VLC_FALSE;
-        p_sys->i_x = (newval.i_int < p_sys->i_width) ?
-                        newval.i_int : p_sys->i_width;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
-    {
-        p_sys->b_absolute = VLC_FALSE;
-        p_sys->i_y = (newval.i_int < p_sys->i_height) ?
-                        newval.i_int : p_sys->i_height;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
-    {
-        p_sys->b_absolute = VLC_TRUE;
-        p_sys->i_pos = newval.i_int;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
-    {
-        p_sys->p_style->i_font_size = newval.i_int;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
+    if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
     {
-        p_sys->p_style->i_font_color = newval.i_int;
+        p_sys->b_need_update = true;
     }
-    else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
-    {
-        p_sys->p_style->i_font_alpha = 255 - newval.i_int;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
+    else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
     {
-        p_sys->b_need_update = VLC_TRUE;
+        int i;
+        /* Clear the entire render list */
+        for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+        {
+            RenderClear( p_intf, &p_sys->render[i] );
+        }
+        p_sys->b_clear = true;
     }
     else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
     {
-        p_sys->b_render = VLC_TRUE;
-    }
-    else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
-    {
-        p_sys->b_clear = VLC_TRUE;
+        int i;
+        /* Are we already busy with on slot ? */
+        for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+        {
+            if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
+            {
+                p_sys->render[i].i_state = FBOSD_STATE_RENDER;
+                break;
+            }
+        }
     }
-#ifdef FBOSD_BLENDING
-    else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
+    else
     {
-        p_sys->i_alpha = newval.i_int;
+        int i;
+        /* Are we already busy with on slot ? */
+        for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+        {
+            if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
+                break;
+        }
+        /* No, then find first FREE slot */
+        if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
+        {
+            for( i = 0; i < FBOSD_RENDER_MAX; i++ )
+            {
+                if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
+                    break;
+            }
+            if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
+            {
+                msg_Warn( p_this, "render space depleated" );
+                return VLC_SUCCESS;
+            }
+        }
+        /* Found a free slot */
+        p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
+        if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
+        {
+            free( p_sys->render[i].psz_string );
+            p_sys->render[i].psz_string = strdup( newval.psz_string );
+            p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
+        {
+            free( p_sys->render[i].psz_string );
+            p_sys->render[i].psz_string = strdup( newval.psz_string );
+            p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
+        {
+            p_sys->render[i].b_absolute = false;
+            p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
+                                    newval.i_int : p_sys->i_width;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
+        {
+            p_sys->render[i].b_absolute = false;
+            p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
+                                    newval.i_int : p_sys->i_height;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
+        {
+            p_sys->render[i].b_absolute = true;
+            p_sys->render[i].i_pos = newval.i_int;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
+        {
+            p_sys->render[i].p_text_style->i_font_size = newval.i_int;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
+        {
+            p_sys->render[i].p_text_style->i_font_color = newval.i_int;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
+        {
+            p_sys->render[i].p_text_style->i_font_alpha = 255 - newval.i_int;
+        }
+        else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
+        {
+            p_sys->render[i].i_alpha = newval.i_int;
+        }
     }
-#endif
     return VLC_SUCCESS;
 }