From: Jean-Paul Saman Date: Fri, 26 Oct 2007 15:08:08 +0000 (+0000) Subject: Add new gui module for use with overlay framebuffer devices. X-Git-Tag: 0.9.0-test0~4784 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=3e08d9550f7c0851cb0501f7c59a3afd4a9cc181;p=vlc Add new gui module for use with overlay framebuffer devices. --- diff --git a/configure.ac b/configure.ac index 589b23fe62..282d4e299b 100644 --- a/configure.ac +++ b/configure.ac @@ -5385,6 +5385,18 @@ then fi fi +dnl +dnl Framebuffer (overlay) plugin +dnl +AC_ARG_ENABLE(fbosd, + [ --enable-fbosd fbosd interface supprt (default disabled)]) +if test "${enable_fbosd}" = "yes" +then + AC_CHECK_HEADERS(linux/fb.h, [ + VLC_ADD_PLUGINS([fbosd]) + ]) +fi + dnl dnl Visualisation plugin dnl diff --git a/modules/gui/Modules.am b/modules/gui/Modules.am index 9520c3e0d9..dc3b93cc59 100644 --- a/modules/gui/Modules.am +++ b/modules/gui/Modules.am @@ -1 +1,2 @@ SOURCES_ncurses = ncurses.c +SOURCES_fbosd = fbosd.c diff --git a/modules/gui/fbosd.c b/modules/gui/fbosd.c new file mode 100644 index 0000000000..8560a5aa31 --- /dev/null +++ b/modules/gui/fbosd.c @@ -0,0 +1,1319 @@ +/***************************************************************************** + * 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 $ + * + * Authors: Jean-Paul Saman + * Copied from modules/video_output/fb.c by Samuel Hocevar + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include + +#include +#include /* free() */ +#include /* strerror() */ +#include /* open() */ +#include /* close() */ + +#include +#include /* mmap() */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +// #define FBOSD_BLENDING 1 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Create ( vlc_object_t * ); +static void Destroy ( vlc_object_t * ); +static void Run ( intf_thread_t * ); + +static int Init ( intf_thread_t * ); +static void End ( intf_thread_t * ); + +static int OpenDisplay ( intf_thread_t * ); +static void CloseDisplay ( intf_thread_t * ); + +/* Load modules needed for rendering and blending */ +#ifdef 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 void SetOverlayTransparency( intf_thread_t *, + vlc_bool_t ); +static picture_t *LoadImage( intf_thread_t *, video_format_t *, + char * ); + +#ifdef FBOSD_BLENDING +static int BlendPicture( intf_thread_t *, video_format_t *, + video_format_t *, picture_t *, picture_t * ); +#else +static picture_t *ConvertImage( intf_thread_t *, picture_t *, + video_format_t *, video_format_t * ); +#endif +static int RenderPicture( intf_thread_t *, int, int, + picture_t *, picture_t * ); +static picture_t *RenderText( intf_thread_t *, const char *, + video_format_t * ); + +#define DEVICE_TEXT N_("Framebuffer device") +#define DEVICE_LONGTEXT N_( \ + "Framebuffer device to use for rendering (usually /dev/fb0).") + +#define ASPECT_RATIO_TEXT N_("Video aspect ratio") +#define ASPECT_RATIO_LONGTEXT N_( \ + "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." ) + +#define FBOSD_IMAGE_TEXT N_("Image file") +#define FBOSD_IMAGE_LONGTEXT N_( \ + "Filename of image file to use on the overlay framebuffer." ) + +#define ALPHA_TEXT N_("Transparency of the image") +#define ALPHA_LONGTEXT N_( "Transparency value of the new image " \ + "used in blending. By default it set to fully opaque (255). " \ + "(from 0 for full transparency to 255 for full opacity)" ) + +#define FBOSD_TEXT N_("Text") +#define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." ) + +#define POSX_TEXT N_("X coordinate") +#define POSX_LONGTEXT N_("X coordinate of the rendered image") + +#define POSY_TEXT N_("Y coordinate") +#define POSY_LONGTEXT N_("Y coordinate of the rendered image") + +#define POS_TEXT N_("Position") +#define POS_LONGTEXT N_( \ + "You can enforce the picture position on the overlay " \ + "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \ + "also use combinations of these values, e.g. 6=top-right).") + +#define OPACITY_TEXT N_("Opacity") +#define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \ + "overlayed text. 0 = transparent, 255 = totally opaque. " ) + +#define SIZE_TEXT N_("Font size, pixels") +#define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \ + "font size)." ) + +#define COLOR_TEXT N_("Color") +#define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\ + "the video. This must be an hexadecimal (like HTML colors). The first two "\ + "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\ + " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" ) + +#define CLEAR_TEXT N_( "Clear overlay framebuffer" ) +#define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \ + "making the overlay completely transparent. All previously rendered " \ + "images and text will be cleared from the cache." ) + +#define RENDER_TEXT N_( "Render text or image" ) +#define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \ + "buffer." ) + +#define DISPLAY_TEXT N_( "Display on overlay framebuffer" ) +#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[] = +{ 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, + 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00, + 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080, + 0x00000080, 0x000000FF, 0x0000FFFF}; +static const char *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 ); + + add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT, + VLC_FALSE ); + add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT, + ASPECT_RATIO_LONGTEXT, VLC_TRUE ); + + add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT, + FBOSD_IMAGE_LONGTEXT, VLC_TRUE ); + add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT, + FBOSD_LONGTEXT, VLC_TRUE ); + +#ifdef FBOSD_BLENDING + add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT, + ALPHA_LONGTEXT, VLC_TRUE ); + +#endif + + set_section( N_("Position"), NULL ); + add_integer( "fbosd-x", 0, NULL, POSX_TEXT, + POSX_LONGTEXT, VLC_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 ); + + set_section( N_("Font"), NULL ); + add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL, + OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE ); + add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT, + VLC_FALSE ); + change_integer_list( pi_color_values, ppsz_color_descriptions, 0 ); + add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, + VLC_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_description( _("GNU/Linux osd/overlay framebuffer interface") ); + set_capability( "interface", 10 ); + set_callbacks( Create, Destroy ); +vlc_module_end(); + +/***************************************************************************** + * intf_sys_t: interface framebuffer method descriptor + *****************************************************************************/ +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 ? */ + struct fb_cmap fb_cmap; /* original colormap */ + uint16_t *p_palette; /* original palette */ + + /* Overlay framebuffer format */ + video_format_t fmt_out; + picture_t *p_overlay; + size_t i_page_size; /* page size */ + int i_width; + int i_height; + int i_aspect; + int i_bytes_per_pixel; + + /* Image and Picture rendering */ + image_handler_t *p_image; +#ifdef 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; + + /* 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; + + 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 */ +}; + +/***************************************************************************** + * Create: allocates FB interface thread output method + *****************************************************************************/ +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; + + /* Allocate instance and initialize some members */ + p_intf->p_sys = p_sys = malloc( 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 ) ); + 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" ); + 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 + p_sys->i_aspect = -1; + psz_aspect = + var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" ); + if( psz_aspect ) + { + char *psz_parser = strchr( psz_aspect, ':' ); + + if( psz_parser ) + { + *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; + } + 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" ); + var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL ); + if( p_sys->psz_file && *p_sys->psz_file ) + p_sys->b_image = VLC_TRUE; + + p_sys->psz_text = + 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; + + p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" ); + p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" ); + p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" ); + + var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL ); + + p_sys->p_style->i_font_size = + var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" ); + p_sys->p_style->i_font_color = + var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" ); + p_sys->p_style->i_font_alpha = 255 - + var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" ); + + var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL ); + + 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" ); + + var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL ); + var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL ); + + /* Check if picture position was overridden */ + p_sys->b_absolute = VLC_TRUE; + if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) ) + { + p_sys->b_absolute = VLC_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; + } + + /* Initialize framebuffer */ + if( OpenDisplay( p_intf ) ) + { + Destroy( VLC_OBJECT(p_intf) ); + return VLC_EGENERIC; + } + + Init( p_intf ); + +#ifdef FBOSD_BLENDING + /* Load the blending module */ + if( OpenBlending( p_intf ) ) + { + msg_Err( p_intf, "Unable to load image blending module" ); + Destroy( VLC_OBJECT(p_intf) ); + return VLC_EGENERIC; + } +#endif + + /* Load text renderer module */ + if( OpenTextRenderer( p_intf ) ) + { + msg_Err( p_intf, "Unable to load text rendering module" ); + 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; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Destroy: destroy FB interface thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +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; + + p_sys->b_need_update = VLC_FALSE; + p_sys->b_render = VLC_FALSE; + p_sys->b_clear = VLC_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 ); + var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL ); + var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL ); + + var_Destroy( p_intf, "fbosd-x" ); + var_Destroy( p_intf, "fbosd-y" ); + var_Destroy( p_intf, "fbosd-position" ); + var_Destroy( p_intf, "fbosd-image" ); + var_Destroy( p_intf, "fbosd-text" ); + var_Destroy( p_intf, "fbosd-font-size" ); + var_Destroy( p_intf, "fbosd-font-color" ); + var_Destroy( p_intf, "fbosd-font-opacity" ); + var_Destroy( p_intf, "fbosd-clear" ); + var_Destroy( p_intf, "fbosd-render" ); + var_Destroy( p_intf, "fbosd-display" ); + + var_Destroy( p_intf, "fbosd-aspect-ratio" ); + + CloseDisplay( p_intf ); + +#ifdef 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 ); + + free( p_sys->psz_file ); + free( p_sys->psz_text ); + free( p_sys->p_style ); + free( p_sys ); +} + +#ifdef 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_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_chroma = + p_intf->p_sys->fmt_out.i_chroma; + if( config_GetInt( p_intf, "freetype-yuvp" ) ) + p_intf->p_sys->p_blend->fmt_in.video.i_chroma = + VLC_FOURCC('Y','U','V','P'); + else + p_intf->p_sys->p_blend->fmt_in.video.i_chroma = + VLC_FOURCC('Y','U','V','A'); + + p_intf->p_sys->p_blend->p_module = + module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 ); + + if( !p_intf->p_sys->p_blend->p_module ) + return VLC_EGENERIC; + + return VLC_SUCCESS; +} + +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, + 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 ); + } +} +#endif + +static int OpenTextRenderer( intf_thread_t *p_intf ) +{ + char *psz_modulename = NULL; + + 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_attach( p_intf->p_sys->p_text, p_intf ); + + p_intf->p_sys->p_text->fmt_out.video.i_width = + p_intf->p_sys->p_text->fmt_out.video.i_visible_width = + p_intf->p_sys->i_width; + p_intf->p_sys->p_text->fmt_out.video.i_height = + p_intf->p_sys->p_text->fmt_out.video.i_visible_height = + p_intf->p_sys->i_height; + + psz_modulename = var_CreateGetString( p_intf, "text-renderer" ); + 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 ); + } + 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 ); + } + if( psz_modulename ) free( psz_modulename ); + + if( !p_intf->p_sys->p_text->p_module ) + return VLC_EGENERIC; + + return VLC_SUCCESS; +} + +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, + 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 ); + } +} +#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 ) +{ + picture_t *p_pic = malloc( sizeof( picture_t ) ); + if( !p_pic ) return NULL; + + if( !p_fmt->p_palette && + ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) ) + { + p_fmt->p_palette = malloc( sizeof(video_palette_t) ); + if( !p_fmt->p_palette ) + { + free( p_pic ); + 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 ) + { + free( p_pic ); + free( p_fmt->p_palette ); + return NULL; + } + return p_pic; +} + +/***************************************************************************** + * 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 ) +{ + 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 ) + { + free( p_fmt->p_palette ); + p_fmt->p_palette = NULL; + } + p_pic = NULL; +} + +/***************************************************************************** + * SetOverlayTransparency: Set the transparency for this overlay fb, + * - VLC_TRUE is make transparent + * - VLC_FALSE is make non tranparent + *****************************************************************************/ +static void SetOverlayTransparency( intf_thread_t *p_intf, + vlc_bool_t b_transparent ) +{ + intf_sys_t *p_sys = (intf_sys_t *) 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) ? + i_size : p_sys->i_page_size; + + if( p_sys->p_overlay ) + { + 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 ); + } +} + +#ifdef FBOSD_BLENDING +/***************************************************************************** + * BlendPicture: Blend two pictures together.. + *****************************************************************************/ +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; + 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 = + p_fmt_dst->i_width; + p_sys->p_blend->fmt_out.video.i_height = + p_sys->p_blend->fmt_out.video.i_visible_height = + p_fmt_dst->i_height; + + i_x_offset = __MAX( i_x_offset, 0 ); + i_y_offset = __MAX( i_y_offset, 0 ); + + p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst, + p_pic_src, p_pic_dst, i_x_offset, i_y_offset, + p_sys->i_alpha ); + + return VLC_SUCCESS; + } + return VLC_EGENERIC; +} +#endif + +/***************************************************************************** + * RenderPicture: Render the picture into the p_dest buffer. + * We don't take transparent pixels into account, so we don't have to blend + * the two images together. + *****************************************************************************/ +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; + + if( !p_dest && !p_src ) return VLC_EGENERIC; + + for( i = 0; i < p_src->i_planes ; i++ ) + { + 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 ); + } + else + { + /* We need to proceed line by line */ + uint8_t *p_in = p_src->p[i].p_pixels; + uint8_t *p_out = p_dest->p[i].p_pixels; + + int i_x = i_x_offset * p_src->p[i].i_pixel_pitch; + int i_x_clip, i_y_clip; + + /* Check boundaries, clip the image if necessary */ + i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch; + i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0; + + 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 + 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 ); +#endif + if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) && + ( i_x <= p_dest->p[i].i_visible_pitch ) ) + { + int i_line; + + 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 ); + p_in += p_src->p[i].i_pitch; + p_out += p_dest->p[i].i_pitch; + } + } + } + } + return VLC_SUCCESS; +} + +/***************************************************************************** + * 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 ) +{ + intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys; + subpicture_region_t *p_region; + picture_t *p_dest = NULL; + + if( !psz_text ) 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; + + memset( p_region, 0, sizeof(subpicture_region_t) ); + + 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->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP; + + if( p_sys->p_text->pf_render_text ) + { + video_format_t fmt_out; + + memset( &fmt_out, 0, sizeof(video_format_t) ); + + 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 + fmt_out = p_region->fmt; + fmt_out.i_bits_per_pixel = 32; + memcpy( p_fmt, &fmt_out, sizeof(video_format_t) ); + 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 ); + return NULL; + } + vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture ); +#endif + if( p_region->picture.pf_release ) + p_region->picture.pf_release( &p_region->picture ); + free( p_region->psz_text ); + free( p_region ); + return p_dest; + } + free( p_region->psz_text ); + free( p_region ); + } + return p_dest; +} + +/***************************************************************************** + * LoadImage: Load an image from file into a picture buffer. + *****************************************************************************/ +static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt, + char *psz_file ) +{ + picture_t *p_pic = NULL; + + if( psz_file && p_intf->p_sys->p_image ) + { + video_format_t fmt_in, fmt_out; + + memset( &fmt_in, 0, sizeof(fmt_in) ); + memset( &fmt_out, 0, sizeof(fmt_out) ); + + fmt_out.i_chroma = p_fmt->i_chroma; + p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file, + &fmt_in, &fmt_out ); + + msg_Dbg( p_intf, "image size %dx%d chroma %4.4s", + fmt_out.i_width, fmt_out.i_height, + (char *)&p_fmt->i_chroma ); + } + return p_pic; +} + +#ifndef 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; + picture_t *p_old = NULL; + + if( p_sys->p_image ) + { + p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out ); + + msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s", + p_fmt_out->i_width, p_fmt_out->i_height, + (char *)&p_fmt_out->i_chroma ); + } + return p_old; +} +#endif + +/***************************************************************************** + * Init: initialize framebuffer video thread output method + *****************************************************************************/ +static int Init( intf_thread_t *p_intf ) +{ + intf_sys_t *p_sys = (intf_sys_t *) 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; + case 15: + p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break; + case 16: + p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break; + case 24: + p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break; + case 32: + p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break; + default: + msg_Err( p_intf, "unknown screen depth %i", + p_sys->var_info.bits_per_pixel ); + return VLC_EGENERIC; + } + + p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel; + p_sys->fmt_out.i_width = p_sys->i_width; + p_sys->fmt_out.i_height = p_sys->i_height; + + /* 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; + } + 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 ); + if( !p_sys->p_overlay ) return VLC_EGENERIC; + + SetOverlayTransparency( p_intf, VLC_TRUE ); + + /* We know the chroma, allocate a buffer which will be used + * to write to the overlay framebuffer */ + p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel; + p_sys->p_overlay->p->i_lines = p_sys->var_info.yres; + p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres; + + if( p_sys->var_info.xres_virtual ) + { + p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual + * p_sys->i_bytes_per_pixel; + } + else + { + p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres + * p_sys->i_bytes_per_pixel; + } + + p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres + * p_sys->i_bytes_per_pixel; + + p_sys->p_overlay->i_planes = 1; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * End: terminate framebuffer interface + *****************************************************************************/ +static void End( intf_thread_t *p_intf ) +{ + intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys; + + /* CleanUp */ + SetOverlayTransparency( p_intf, VLC_FALSE ); + if( p_sys->p_overlay ) + { + write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size ); + } + + DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay, + &p_intf->p_sys->fmt_out ); + p_intf->p_sys->p_overlay = NULL; +} + +/***************************************************************************** + * OpenDisplay: initialize framebuffer + *****************************************************************************/ +static int OpenDisplay( intf_thread_t *p_intf ) +{ + intf_sys_t *p_sys = (intf_sys_t *) 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" )) ) + { + 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 ); + if( p_sys->i_fd == -1 ) + { + msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) ); + free( psz_device ); + return VLC_EGENERIC; + } + free( psz_device ); + + /* 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) ); + close( p_sys->i_fd ); + return VLC_EGENERIC; + } + + /* Get some info on the framebuffer itself */ + if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 ) + { + p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres; + p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres; + } + + /* FIXME: if the image is full-size, it gets cropped on the left + * because of the xres / xres_virtual slight difference */ + msg_Dbg( p_intf, "%ix%i (virtual %ix%i)", + p_sys->var_info.xres, p_sys->var_info.yres, + p_sys->var_info.xres_virtual, + p_sys->var_info.yres_virtual ); + + p_sys->fmt_out.i_width = p_sys->i_width; + p_sys->fmt_out.i_height = p_sys->i_height; + + p_sys->p_palette = NULL; + p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep ); + + switch( p_sys->var_info.bits_per_pixel ) + { + case 8: + 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; + } + p_sys->fb_cmap.start = 0; + p_sys->fb_cmap.len = 256; + p_sys->fb_cmap.red = p_sys->p_palette; + p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t ); + p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t ); + p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t ); + + /* Save the colormap */ + ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap ); + + p_sys->i_bytes_per_pixel = 1; + break; + + case 15: + case 16: + p_sys->i_bytes_per_pixel = 2; + break; + + case 24: + p_sys->i_bytes_per_pixel = 3; + break; + + case 32: + p_sys->i_bytes_per_pixel = 4; + break; + + default: + msg_Err( p_intf, "screen depth %d is not supported", + p_sys->var_info.bits_per_pixel ); + + close( p_sys->i_fd ); + return VLC_EGENERIC; + } + + p_sys->i_page_size = p_sys->i_width * p_sys->i_height + * p_sys->i_bytes_per_pixel; + + msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, " + "ywrap=%d, accel=%d", fix_info.type, fix_info.visual, + fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel ); + return VLC_SUCCESS; +} + +/***************************************************************************** + * CloseDisplay: terminate FB interface thread + *****************************************************************************/ +static void CloseDisplay( intf_thread_t *p_intf ) +{ + intf_sys_t *p_sys = (intf_sys_t *) p_intf; + + /* Restore palette */ + if( p_sys->var_info.bits_per_pixel == 8 ) + { + ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap ); + free( p_sys->p_palette ); + p_sys->p_palette = NULL; + } + + /* Close fb */ + close( p_sys->i_fd ); +} + +/***************************************************************************** + * Run: rc 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; + + while( !intf_ShouldDie( p_intf ) ) + { + if( p_sys->b_render ) + { + if( p_sys->b_image ) + { + 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; + } + + 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 ); + + 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; + } + + if( p_sys->b_need_update && p_sys->p_overlay ) + { + write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, + p_sys->i_page_size ); + lseek( p_sys->i_fd, 0, SEEK_SET ); + p_sys->b_need_update = VLC_FALSE; + } + + if( vlc_CPU() & CPU_CAPABILITY_FPU ) + msleep( INTF_IDLE_SLEEP ); + else + msleep( 1000 ); + } + + End( p_intf ); +} + +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; + + 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 ) ) + { + p_sys->p_style->i_font_color = newval.i_int; + } + 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 ) ) + { + p_sys->b_need_update = VLC_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; + } +#ifdef FBOSD_BLENDING + else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) ) + { + p_sys->i_alpha = newval.i_int; + } +#endif + return VLC_SUCCESS; +}