fbosd.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:49k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * fbosd.c : framebuffer osd plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2007-2008, the VideoLAN team
  5.  * $Id: 9af2a75873aeed672c3bc0508633a66fe3debeb3 $
  6.  *
  7.  * Authors: Jean-Paul Saman
  8.  * Copied from modules/video_output/fb.c by Samuel Hocevar <sam@zoy.org>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <vlc_plugin.h>
  32. #include <errno.h>
  33. #include <stdlib.h>                                                /* free() */
  34. #include <string.h>                                            /* strerror() */
  35. #include <fcntl.h>                                                 /* open() */
  36. #include <unistd.h>                                               /* close() */
  37. #include <sys/ioctl.h>
  38. #include <sys/mman.h>                                              /* mmap() */
  39. #include <linux/fb.h>
  40. #include <vlc_image.h>
  41. #include <vlc_interface.h>
  42. #include <vlc_input.h>
  43. #include <vlc_vout.h>
  44. #include <vlc_filter.h>
  45. #include <vlc_osd.h>
  46. #include <vlc_strings.h>
  47. #undef FBOSD_BLENDING
  48. #undef FBOSD_DEBUG
  49. /*****************************************************************************
  50.  * Local prototypes
  51.  *****************************************************************************/
  52. static int  Create    ( vlc_object_t * );
  53. static void Destroy   ( vlc_object_t * );
  54. static void Run       ( intf_thread_t * );
  55. static int  Init      ( intf_thread_t * );
  56. static void End       ( intf_thread_t * );
  57. static int  OpenDisplay    ( intf_thread_t * );
  58. static void CloseDisplay   ( intf_thread_t * );
  59. /* Load modules needed for rendering and blending */
  60. #if defined(FBOSD_BLENDING)
  61. static int  OpenBlending     ( intf_thread_t * );
  62. static void CloseBlending    ( intf_thread_t * );
  63. #endif
  64. static int  OpenTextRenderer ( intf_thread_t * );
  65. static void CloseTextRenderer( intf_thread_t * );
  66. /* Manipulate the overlay buffer */
  67. static int  OverlayCallback( vlc_object_t *, char const *,
  68.                              vlc_value_t, vlc_value_t, void * );
  69. static picture_t *AllocatePicture( video_format_t * );
  70. static void DeAllocatePicture( picture_t *, video_format_t * );
  71. static void SetOverlayTransparency( intf_thread_t *,
  72.                                     bool );
  73. static picture_t *LoadImage( intf_thread_t *, video_format_t *,
  74.                              char * );
  75. #if defined(FBOSD_BLENDING)
  76. static int BlendPicture( intf_thread_t *, video_format_t *,
  77.                          video_format_t *, picture_t *, picture_t * );
  78. #else
  79. static picture_t *ConvertImage( intf_thread_t *, picture_t *,
  80.                                 video_format_t *, video_format_t * );
  81. #endif
  82. static int RenderPicture( intf_thread_t *, int, int,
  83.                           picture_t *, picture_t * );
  84. static picture_t *RenderText( intf_thread_t *, const char *,
  85.                               text_style_t *, video_format_t * );
  86. #define DEVICE_TEXT N_("Framebuffer device")
  87. #define DEVICE_LONGTEXT N_( 
  88.     "Framebuffer device to use for rendering (usually /dev/fb0).")
  89. #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
  90. #define ASPECT_RATIO_LONGTEXT N_( 
  91.     "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
  92. #define FBOSD_IMAGE_TEXT N_("Image file")
  93. #define FBOSD_IMAGE_LONGTEXT N_( 
  94.     "Filename of image file to use on the overlay framebuffer." )
  95. #define ALPHA_TEXT N_("Transparency of the image")
  96. #define ALPHA_LONGTEXT N_( "Transparency value of the new image " 
  97.     "used in blending. By default it set to fully opaque (255). " 
  98.     "(from 0 for full transparency to 255 for full opacity)" )
  99. #define FBOSD_TEXT N_("Text")
  100. #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
  101. #define POSX_TEXT N_("X coordinate")
  102. #define POSX_LONGTEXT N_("X coordinate of the rendered image")
  103. #define POSY_TEXT N_("Y coordinate")
  104. #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
  105. #define POS_TEXT N_("Position")
  106. #define POS_LONGTEXT N_( 
  107.   "You can enforce the picture position on the overlay " 
  108.   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " 
  109.   "also use combinations of these values, e.g. 6=top-right).")
  110. #define OPACITY_TEXT N_("Opacity")
  111. #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " 
  112.     "overlayed text. 0 = transparent, 255 = totally opaque. " )
  113. #define SIZE_TEXT N_("Font size, pixels")
  114. #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " 
  115.     "font size)." )
  116. #define COLOR_TEXT N_("Color")
  117. #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "
  118.     "the video. This must be an hexadecimal (like HTML colors). The first two "
  119.     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"
  120.     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
  121. #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
  122. #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " 
  123.     "making the overlay completely transparent. All previously rendered " 
  124.     "images and text will be cleared from the cache." )
  125. #define RENDER_TEXT N_( "Render text or image" )
  126. #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " 
  127.     "buffer." )
  128. #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
  129. #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " 
  130.     "displayed on the overlay framebuffer." )
  131. static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
  132. static const char *const ppsz_pos_descriptions[] =
  133. { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
  134.   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
  135. static const int pi_color_values[] = {
  136.                0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
  137.                0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
  138.                0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
  139.                0x00000080, 0x000000FF, 0x0000FFFF};
  140. static const char *const ppsz_color_descriptions[] = {
  141.                N_("Default"), N_("Black"),
  142.                N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
  143.                N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
  144.                N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
  145.                N_("Aqua") };
  146. vlc_module_begin ()
  147.     set_shortname( "fbosd" )
  148.     set_category( CAT_INTERFACE )
  149.     set_subcategory( SUBCAT_INTERFACE_MAIN )
  150.     add_file( "fbosd-dev", "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
  151.               false )
  152.     add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
  153.                 ASPECT_RATIO_LONGTEXT, true )
  154.     add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
  155.                 FBOSD_IMAGE_LONGTEXT, true )
  156.     add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
  157.                 FBOSD_LONGTEXT, true )
  158.     add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
  159.                             ALPHA_LONGTEXT, true )
  160.     set_section( N_("Position"), NULL )
  161.     add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
  162.                  POSX_LONGTEXT, false )
  163.     add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
  164.                  POSY_LONGTEXT, false )
  165.     add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
  166.         change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
  167.     set_section( N_("Font"), NULL )
  168.     add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
  169.         OPACITY_TEXT, OPACITY_LONGTEXT, false )
  170.     add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
  171.                  false )
  172.         change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
  173.     add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
  174.                  false )
  175.     set_section( N_("Commands"), NULL )
  176.     add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
  177.     add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
  178.     add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
  179.     set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
  180.     set_capability( "interface", 10 )
  181.     set_callbacks( Create, Destroy )
  182. vlc_module_end ()
  183. /*****************************************************************************
  184.  * fbosd_render_t: render descriptor
  185.  *****************************************************************************/
  186. struct fbosd_render_t
  187. {
  188. #define FBOSD_RENDER_IMAGE 0
  189. #define FBOSD_RENDER_TEXT  1
  190.     int             i_type;
  191. #define FBOSD_STATE_FREE     0
  192. #define FBOSD_STATE_RESERVED 1
  193. #define FBOSD_STATE_RENDER   2
  194.     int             i_state;
  195.     /* Font style */
  196.     text_style_t    text_style;                              /* font control */
  197.     char            *psz_string;
  198.     /* Position */
  199.     bool            b_absolute;
  200.     int             i_x;
  201.     int             i_y;
  202.     int             i_pos;
  203.     int             i_alpha;                      /* transparency for images */
  204. };
  205. #define FBOSD_RENDER_MAX 10
  206. /*****************************************************************************
  207.  * intf_sys_t: interface framebuffer method descriptor
  208.  *****************************************************************************/
  209. struct intf_sys_t
  210. {
  211.     /* Framebuffer information */
  212.     int                         i_fd;                       /* device handle */
  213.     struct fb_var_screeninfo    var_info;        /* current mode information */
  214.     bool                  b_pan;     /* does device supports panning ? */
  215.     struct fb_cmap              fb_cmap;                /* original colormap */
  216.     uint16_t                    *p_palette;              /* original palette */
  217.     /* Overlay framebuffer format */
  218.     video_format_t  fmt_out;
  219.     picture_t       *p_overlay;
  220.     size_t          i_page_size;                                /* page size */
  221.     int             i_width;
  222.     int             i_height;
  223.     int             i_aspect;
  224.     int             i_bytes_per_pixel;
  225.     /* Image and Picture rendering */
  226.     image_handler_t *p_image;
  227. #if defined(FBOSD_BLENDING)
  228.     filter_t *p_blend;                              /* alpha blending module */
  229. #endif
  230.     filter_t *p_text;                                /* text renderer module */
  231.     /* Render */
  232.     struct fbosd_render_t render[FBOSD_RENDER_MAX];
  233.     /* Font style */
  234.     text_style_t    *p_style;                                /* font control */
  235.     /* Position */
  236.     bool      b_absolute;
  237.     int       i_x;
  238.     int       i_y;
  239.     int       i_pos;
  240.     int       i_alpha;                      /* transparency for images */
  241.     /* commands control */
  242.     bool      b_need_update;    /* update display with overlay buffer */
  243.     bool      b_clear;      /* clear overlay buffer make it tranparent */
  244.     bool      b_render;   /* render an image or text in overlay buffer */
  245. };
  246. /*****************************************************************************
  247.  * Create: allocates FB interface thread output method
  248.  *****************************************************************************/
  249. static int Create( vlc_object_t *p_this )
  250. {
  251.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  252.     intf_sys_t    *p_sys;
  253.     char          *psz_aspect;
  254.     char          *psz_tmp;
  255.     int i;
  256.     /* Allocate instance and initialize some members */
  257.     p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
  258.     if( !p_intf->p_sys )
  259.         return VLC_ENOMEM;
  260.     p_sys->p_style = malloc( sizeof( text_style_t ) );
  261.     if( !p_sys->p_style )
  262.     {
  263.         free( p_intf->p_sys );
  264.         return VLC_ENOMEM;
  265.     }
  266.     vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
  267.     p_intf->pf_run = Run;
  268.     p_sys->p_image = image_HandlerCreate( p_this );
  269.     if( !p_sys->p_image )
  270.     {
  271.         free( p_sys->p_style );
  272.         free( p_sys );
  273.         return VLC_ENOMEM;
  274.     }
  275.     p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
  276.     var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
  277.     p_sys->i_aspect = -1;
  278.     psz_aspect =
  279.             var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
  280.     if( psz_aspect )
  281.     {
  282.         char *psz_parser = strchr( psz_aspect, ':' );
  283.         if( psz_parser )
  284.         {
  285.             *psz_parser++ = '';
  286.             p_sys->i_aspect = ( atoi( psz_aspect )
  287.                               * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
  288.             p_sys->fmt_out.i_aspect = p_sys->i_aspect;
  289.         }
  290.         msg_Dbg( p_intf, "using aspect ratio %d:%d",
  291.                   atoi( psz_aspect ), atoi( psz_parser ) );
  292.         free( psz_aspect );
  293.     }
  294.     /* Use PAL by default */
  295.     p_sys->i_width  = p_sys->fmt_out.i_width  = 704;
  296.     p_sys->i_height = p_sys->fmt_out.i_height = 576;
  297.     psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
  298.     var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
  299.     if( psz_tmp && *psz_tmp )
  300.     {
  301.         p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
  302.         p_sys->render[0].i_state = FBOSD_STATE_RENDER;
  303.         p_sys->render[0].psz_string = strdup( psz_tmp );
  304.     }
  305.     free( psz_tmp );
  306.     psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
  307.     var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
  308.     if( psz_tmp && *psz_tmp )
  309.     {
  310.         p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
  311.         p_sys->render[1].i_state = FBOSD_STATE_RENDER;
  312.         p_sys->render[1].psz_string = strdup( psz_tmp );
  313.     }
  314.     free( psz_tmp );
  315.     p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
  316.     p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
  317.     p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
  318.     var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
  319.     var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
  320.     var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
  321.     p_sys->p_style->i_font_size =
  322.             var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
  323.     p_sys->p_style->i_font_color =
  324.             var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
  325.     p_sys->p_style->i_font_alpha = 255 -
  326.             var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
  327.     var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
  328.     var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
  329.     var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
  330.     for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  331.     {
  332.         vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
  333.                     sizeof( text_style_t ) );
  334.     }
  335.     p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
  336.     p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
  337.     p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
  338.     var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
  339.     var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
  340.     var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
  341.     /* Check if picture position was overridden */
  342.     p_sys->b_absolute = true;
  343.     if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
  344.     {
  345.         p_sys->b_absolute = false;
  346.         p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
  347.                         p_sys->i_y : p_sys->i_height;
  348.         p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
  349.                         p_sys->i_x : p_sys->i_width;
  350.     }
  351.     p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
  352.     p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
  353.     p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
  354.     p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
  355.     /* Initialize framebuffer */
  356.     if( OpenDisplay( p_intf ) )
  357.     {
  358.         Destroy( VLC_OBJECT(p_intf) );
  359.         return VLC_EGENERIC;
  360.     }
  361.     Init( p_intf );
  362. #if defined(FBOSD_BLENDING)
  363.     /* Load the blending module */
  364.     if( OpenBlending( p_intf ) )
  365.     {
  366.         msg_Err( p_intf, "Unable to load image blending module" );
  367.         Destroy( VLC_OBJECT(p_intf) );
  368.         return VLC_EGENERIC;
  369.     }
  370. #endif
  371.     /* Load text renderer module */
  372.     if( OpenTextRenderer( p_intf ) )
  373.     {
  374.         msg_Err( p_intf, "Unable to load text rendering module" );
  375.         Destroy( VLC_OBJECT(p_intf) );
  376.         return VLC_EGENERIC;
  377.     }
  378.     p_sys->b_render = true;
  379.     p_sys->b_need_update = true;
  380.     return VLC_SUCCESS;
  381. }
  382. /*****************************************************************************
  383.  * Destroy: destroy FB interface thread output method
  384.  *****************************************************************************
  385.  * Terminate an output method created by Create
  386.  *****************************************************************************/
  387. static void Destroy( vlc_object_t *p_this )
  388. {
  389.     intf_thread_t *p_intf = (intf_thread_t *)p_this;
  390.     intf_sys_t *p_sys = p_intf->p_sys;
  391.     int i;
  392.     p_sys->b_need_update = false;
  393.     p_sys->b_render = false;
  394.     p_sys->b_clear = false;
  395.     var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
  396.     var_Destroy( p_intf, "fbosd-alpha" );
  397.     var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
  398.     var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
  399.     var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
  400.     var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
  401.     var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
  402.     var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
  403.     var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
  404.     var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
  405.     var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
  406.     var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
  407.     var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
  408.     var_Destroy( p_intf, "fbosd-x" );
  409.     var_Destroy( p_intf, "fbosd-y" );
  410.     var_Destroy( p_intf, "fbosd-position" );
  411.     var_Destroy( p_intf, "fbosd-image" );
  412.     var_Destroy( p_intf, "fbosd-text" );
  413.     var_Destroy( p_intf, "fbosd-font-size" );
  414.     var_Destroy( p_intf, "fbosd-font-color" );
  415.     var_Destroy( p_intf, "fbosd-font-opacity" );
  416.     var_Destroy( p_intf, "fbosd-clear" );
  417.     var_Destroy( p_intf, "fbosd-render" );
  418.     var_Destroy( p_intf, "fbosd-display" );
  419.     var_Destroy( p_intf, "fbosd-aspect-ratio" );
  420.     CloseDisplay( p_intf );
  421.     for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  422.     {
  423.         free( p_sys->render[i].psz_string );
  424.         p_sys->render[i].i_state = FBOSD_STATE_FREE;
  425.     }
  426. #if defined(FBOSD_BLENDING)
  427.     if( p_sys->p_blend ) CloseBlending( p_intf );
  428. #endif
  429.     if( p_sys->p_text )  CloseTextRenderer( p_intf );
  430.     if( p_sys->p_image )
  431.         image_HandlerDelete( p_sys->p_image );
  432.     if( p_sys->p_overlay )
  433.         picture_Release( p_sys->p_overlay );
  434.     free( p_sys->p_style );
  435.     free( p_sys );
  436. }
  437. #if defined(FBOSD_BLENDING)
  438. static int OpenBlending( intf_thread_t *p_intf )
  439. {
  440.     if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
  441.     p_intf->p_sys->p_blend =
  442.             vlc_object_create( p_intf, sizeof(filter_t) );
  443.     vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
  444.     p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
  445.         p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
  446.     p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
  447.             p_intf->p_sys->fmt_out.i_aspect;
  448.     p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
  449.             p_intf->p_sys->fmt_out.i_chroma;
  450.     if( config_GetInt( p_intf, "freetype-yuvp" ) )
  451.         p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
  452.                 VLC_FOURCC('Y','U','V','P');
  453.     else
  454.         p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
  455.                 VLC_FOURCC('Y','U','V','A');
  456.     p_intf->p_sys->p_blend->p_module =
  457.         module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
  458.     if( !p_intf->p_sys->p_blend->p_module )
  459.         return VLC_EGENERIC;
  460.     return VLC_SUCCESS;
  461. }
  462. static void CloseBlending( intf_thread_t *p_intf )
  463. {
  464.     if( p_intf->p_sys->p_blend )
  465.     {
  466.         if( p_intf->p_sys->p_blend->p_module )
  467.             module_unneed( p_intf->p_sys->p_blend,
  468.                            p_intf->p_sys->p_blend->p_module );
  469.         vlc_object_detach( p_intf->p_sys->p_blend );
  470.         vlc_object_release( p_intf->p_sys->p_blend );
  471.     }
  472. }
  473. #endif
  474. static int OpenTextRenderer( intf_thread_t *p_intf )
  475. {
  476.     char *psz_modulename = NULL;
  477.     if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
  478.     p_intf->p_sys->p_text =
  479.             vlc_object_create( p_intf, sizeof(filter_t) );
  480.     vlc_object_attach( p_intf->p_sys->p_text, p_intf );
  481.     p_intf->p_sys->p_text->fmt_out.video.i_width =
  482.         p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
  483.         p_intf->p_sys->i_width;
  484.     p_intf->p_sys->p_text->fmt_out.video.i_height =
  485.         p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
  486.         p_intf->p_sys->i_height;
  487.     psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
  488.     if( psz_modulename && *psz_modulename )
  489.     {
  490.         p_intf->p_sys->p_text->p_module =
  491.             module_need( p_intf->p_sys->p_text, "text renderer",
  492.                             psz_modulename, true );
  493.     }
  494.     if( !p_intf->p_sys->p_text->p_module )
  495.     {
  496.         p_intf->p_sys->p_text->p_module =
  497.             module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
  498.     }
  499.     free( psz_modulename );
  500.     if( !p_intf->p_sys->p_text->p_module )
  501.         return VLC_EGENERIC;
  502.     return VLC_SUCCESS;
  503. }
  504. static void CloseTextRenderer( intf_thread_t *p_intf )
  505. {
  506.     if( p_intf->p_sys->p_text )
  507.     {
  508.         if( p_intf->p_sys->p_text->p_module )
  509.             module_unneed( p_intf->p_sys->p_text,
  510.                            p_intf->p_sys->p_text->p_module );
  511.         vlc_object_detach( p_intf->p_sys->p_text );
  512.         vlc_object_release( p_intf->p_sys->p_text );
  513.     }
  514. }
  515. /*****************************************************************************
  516.  * AllocatePicture:
  517.  * allocate a picture buffer for use with the overlay fb.
  518.  *****************************************************************************/
  519. static picture_t *AllocatePicture( video_format_t *p_fmt )
  520. {
  521.     picture_t *p_picture = picture_New( p_fmt->i_chroma,
  522.                                         p_fmt->i_width, p_fmt->i_height,
  523.                                         p_fmt->i_aspect );
  524.     if( !p_picture )
  525.         return NULL;
  526.     if( !p_fmt->p_palette &&
  527.         ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
  528.     {
  529.         p_fmt->p_palette = malloc( sizeof(video_palette_t) );
  530.         if( !p_fmt->p_palette )
  531.         {
  532.             picture_Release( p_picture );
  533.             return NULL;
  534.         }
  535.     }
  536.     else
  537.     {
  538.         p_fmt->p_palette = NULL;
  539.     }
  540.     return p_picture;
  541. }
  542. /*****************************************************************************
  543.  * DeAllocatePicture:
  544.  * Deallocate a picture buffer and free all associated memory.
  545.  *****************************************************************************/
  546. static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
  547. {
  548.     if( p_fmt )
  549.     {
  550.         free( p_fmt->p_palette );
  551.         p_fmt->p_palette = NULL;
  552.     }
  553.     if( p_pic )
  554.         picture_Release( p_pic );
  555. }
  556. /*****************************************************************************
  557.  * SetOverlayTransparency: Set the transparency for this overlay fb,
  558.  * - true is make transparent
  559.  * - false is make non tranparent
  560.  *****************************************************************************/
  561. static void SetOverlayTransparency( intf_thread_t *p_intf,
  562.                                     bool b_transparent )
  563. {
  564.     intf_sys_t *p_sys = p_intf->p_sys;
  565.     size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
  566.                         * p_sys->i_bytes_per_pixel;
  567.     size_t i_page_size = (p_sys->i_page_size > i_size) ?
  568.                             i_size : p_sys->i_page_size;
  569.     if( p_sys->p_overlay )
  570.     {
  571.         msg_Dbg( p_intf, "Make overlay %s",
  572.                  b_transparent ? "transparent" : "opaque" );
  573.         if( b_transparent )
  574.             memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
  575.         else
  576.             memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
  577.     }
  578. }
  579. #if defined(FBOSD_BLENDING)
  580. /*****************************************************************************
  581.  * BlendPicture: Blend two pictures together..
  582.  *****************************************************************************/
  583. static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
  584.                          video_format_t *p_fmt_dst, picture_t *p_pic_src,
  585.                          picture_t *p_pic_dst )
  586. {
  587.     intf_sys_t *p_sys = p_intf->p_sys;
  588.     if( p_sys->p_blend && p_sys->p_blend->p_module )
  589.     {
  590.         int i_x_offset = p_sys->i_x;
  591.         int i_y_offset = p_sys->i_y;
  592.         memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
  593.         /* Update the output picture size */
  594.         p_sys->p_blend->fmt_out.video.i_width =
  595.             p_sys->p_blend->fmt_out.video.i_visible_width =
  596.                 p_fmt_dst->i_width;
  597.         p_sys->p_blend->fmt_out.video.i_height =
  598.             p_sys->p_blend->fmt_out.video.i_visible_height =
  599.                 p_fmt_dst->i_height;
  600.         i_x_offset = __MAX( i_x_offset, 0 );
  601.         i_y_offset = __MAX( i_y_offset, 0 );
  602.         p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
  603.             p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
  604.             p_sys->i_alpha );
  605.         return VLC_SUCCESS;
  606.     }
  607.     return VLC_EGENERIC;
  608. }
  609. static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
  610. {
  611.     uint8_t *p_begin = NULL, *p_end = NULL;
  612.     uint8_t i_skip = 0;
  613.     if( *p_pic && ((*p_pic)->i_planes != 1) )
  614.     {
  615.         msg_Err( p_intf,
  616.                  "cannot invert alpha channel too many planes %d (only 1 supported)",
  617.                  (*p_pic)->i_planes );
  618.         return VLC_EGENERIC;
  619.     }
  620.     switch( fmt.i_chroma )
  621.     {
  622.         case VLC_FOURCC('R','V','2','4'):
  623.             p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
  624.             p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
  625.                       ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
  626.             i_skip = 3;
  627.             break;
  628.         case VLC_FOURCC('R','V','3','2'):
  629.             p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
  630.             p_end   = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
  631.                       ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
  632.             i_skip = 4;
  633.             break;
  634.         default:
  635.             msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
  636.                     (char *)&fmt.i_chroma );
  637.             return VLC_EGENERIC;
  638.     }
  639.     for( ; p_begin < p_end; p_begin += i_skip )
  640.     {
  641.         uint8_t i_opacity = 0;
  642.         if( *p_begin != 0xFF )
  643.             i_opacity = 255 - *p_begin;
  644.         *p_begin = i_opacity;
  645.     }
  646.     /* end of kludge */
  647.     return VLC_SUCCESS;
  648. }
  649. #endif
  650. /*****************************************************************************
  651.  * RenderPicture: Render the picture into the p_dest buffer.
  652.  * We don't take transparent pixels into account, so we don't have to blend
  653.  * the two images together.
  654.  *****************************************************************************/
  655. static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
  656.                           picture_t *p_src, picture_t *p_dest )
  657. {
  658.     int i;
  659.     VLC_UNUSED( p_intf );
  660.     if( !p_dest && !p_src ) return VLC_EGENERIC;
  661.     for( i = 0; i < p_src->i_planes ; i++ )
  662.     {
  663.         if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
  664.         {
  665.             /* There are margins, but with the same width : perfect ! */
  666.             vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
  667.                         p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
  668.         }
  669.         else
  670.         {
  671.             /* We need to proceed line by line */
  672.             uint8_t *p_in  = p_src->p[i].p_pixels;
  673.             uint8_t *p_out = p_dest->p[i].p_pixels;
  674.             int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
  675.             int i_x_clip, i_y_clip;
  676.             /* Check boundaries, clip the image if necessary */
  677.             i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
  678.             i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
  679.             i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
  680.             i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
  681. #if defined(FBOSD_DEBUG)
  682.             msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
  683.                      p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
  684.                      i_x_offset, i_y_offset, i_x, i_x_clip );
  685. #endif
  686.             if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
  687.                 ( i_x <= p_dest->p[i].i_visible_pitch ) )
  688.             {
  689.                 int i_line;
  690.                 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
  691.                 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
  692.                 {
  693.                     vlc_memcpy( p_out + i_x, p_in,
  694.                                 p_src->p[i].i_visible_pitch - i_x_clip );
  695.                     p_in += p_src->p[i].i_pitch;
  696.                     p_out += p_dest->p[i].i_pitch;
  697.                 }
  698.             }
  699.         }
  700.     }
  701.     return VLC_SUCCESS;
  702. }
  703. /*****************************************************************************
  704.  * RenderText - Render text to the desired picture format
  705.  *****************************************************************************/
  706. static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
  707.                               text_style_t *p_style, video_format_t *p_fmt )
  708. {
  709.     intf_sys_t *p_sys = p_intf->p_sys;
  710.     subpicture_region_t *p_region;
  711.     picture_t *p_dest = NULL;
  712.     if( !psz_string ) return p_dest;
  713.     if( p_sys->p_text && p_sys->p_text->p_module )
  714.     {
  715.         video_format_t fmt;
  716.         memset( &fmt, 0, sizeof(fmt) );
  717.         fmt.i_chroma = VLC_FOURCC('T','E','X','T');
  718.         fmt.i_aspect = 0;
  719.         fmt.i_width  = fmt.i_visible_width = 0;
  720.         fmt.i_height = fmt.i_visible_height = 0;
  721.         fmt.i_x_offset = 0;
  722.         fmt.i_y_offset = 0;
  723.         p_region = subpicture_region_New( &fmt );
  724.         if( !p_region )
  725.             return p_dest;
  726.         p_region->psz_text = strdup( psz_string );
  727.         if( !p_region->psz_text )
  728.         {
  729.             subpicture_region_Delete( p_region );
  730.             return NULL;
  731.         }
  732.         p_region->p_style = p_style;
  733.         p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
  734.         if( p_sys->p_text->pf_render_text )
  735.         {
  736.             video_format_t fmt_out;
  737.             memset( &fmt_out, 0, sizeof(video_format_t) );
  738.             p_sys->p_text->pf_render_text( p_sys->p_text,
  739.                                            p_region, p_region );
  740. #if defined(FBOSD_BLENDING)
  741.             fmt_out = p_region->fmt;
  742.             fmt_out.i_bits_per_pixel = 32;
  743.             vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
  744.             /* FIXME not needed to copy the picture anymore no ? */
  745.             p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
  746.             if( !p_dest )
  747.             {
  748.                 subpicture_region_Delete( p_region );
  749.                 return NULL;
  750.             }
  751.             picture_Copy( p_dest, p_region->p_picture );
  752. #else
  753.             fmt_out.i_chroma = p_fmt->i_chroma;
  754.             p_dest = ConvertImage( p_intf, p_region->p_picture,
  755.                                    &p_region->fmt, &fmt_out );
  756. #endif
  757.             subpicture_region_Delete( p_region );
  758.             return p_dest;
  759.         }
  760.         subpicture_region_Delete( p_region );
  761.     }
  762.     return p_dest;
  763. }
  764. /*****************************************************************************
  765.  * LoadImage: Load an image from file into a picture buffer.
  766.  *****************************************************************************/
  767. static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
  768.                              char *psz_file )
  769. {
  770.     picture_t  *p_pic = NULL;
  771.     if( psz_file && p_intf->p_sys->p_image )
  772.     {
  773.         video_format_t fmt_in, fmt_out;
  774.         memset( &fmt_in, 0, sizeof(fmt_in) );
  775.         memset( &fmt_out, 0, sizeof(fmt_out) );
  776.         fmt_out.i_chroma = p_fmt->i_chroma;
  777.         p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
  778.                                &fmt_in, &fmt_out );
  779.         msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
  780.                  fmt_out.i_width, fmt_out.i_height,
  781.                  (char *)&p_fmt->i_chroma );
  782.     }
  783.     return p_pic;
  784. }
  785. #if ! defined(FBOSD_BLENDING)
  786. /*****************************************************************************
  787.  * Convertmage: Convert image to another fourcc
  788.  *****************************************************************************/
  789. static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
  790.                          video_format_t *p_fmt_in, video_format_t *p_fmt_out )
  791. {
  792.     intf_sys_t *p_sys = p_intf->p_sys;
  793.     picture_t  *p_old = NULL;
  794.     if( p_sys->p_image )
  795.     {
  796.         p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
  797.         msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
  798.                  p_fmt_out->i_width, p_fmt_out->i_height,
  799.                  (char *)&p_fmt_out->i_chroma );
  800.     }
  801.     return p_old;
  802. }
  803. #endif
  804. /*****************************************************************************
  805.  * Init: initialize framebuffer video thread output method
  806.  *****************************************************************************/
  807. static int Init( intf_thread_t *p_intf )
  808. {
  809.     intf_sys_t *p_sys = p_intf->p_sys;
  810.     /* Initialize the output structure: RGB with square pixels, whatever
  811.      * the input format is, since it's the only format we know */
  812.     switch( p_sys->var_info.bits_per_pixel )
  813.     {
  814.     case 8: /* FIXME: set the palette */
  815.         p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
  816.     case 15:
  817.         p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
  818.     case 16:
  819.         p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
  820.     case 24:
  821.         p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
  822.     case 32:
  823.         p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
  824.     default:
  825.         msg_Err( p_intf, "unknown screen depth %i",
  826.                  p_sys->var_info.bits_per_pixel );
  827.         return VLC_EGENERIC;
  828.     }
  829.     p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
  830.     p_sys->fmt_out.i_width  = p_sys->i_width;
  831.     p_sys->fmt_out.i_height = p_sys->i_height;
  832.     /* Assume we have square pixels */
  833.     if( p_sys->i_aspect < 0 )
  834.     {
  835.         p_sys->fmt_out.i_aspect = ( p_sys->i_width
  836.                                   * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
  837.     }
  838.     else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
  839.     p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
  840.     /* Allocate overlay buffer */
  841.     p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
  842.     if( !p_sys->p_overlay ) return VLC_EGENERIC;
  843.     SetOverlayTransparency( p_intf, true );
  844.     /* We know the chroma, allocate a buffer which will be used
  845.      * to write to the overlay framebuffer */
  846.     p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
  847.     p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
  848.     p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
  849.     if( p_sys->var_info.xres_virtual )
  850.     {
  851.         p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
  852.                              * p_sys->i_bytes_per_pixel;
  853.     }
  854.     else
  855.     {
  856.         p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
  857.                              * p_sys->i_bytes_per_pixel;
  858.     }
  859.     p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
  860.                                  * p_sys->i_bytes_per_pixel;
  861.     p_sys->p_overlay->i_planes = 1;
  862.     return VLC_SUCCESS;
  863. }
  864. /*****************************************************************************
  865.  * End: terminate framebuffer interface
  866.  *****************************************************************************/
  867. static void End( intf_thread_t *p_intf )
  868. {
  869.     intf_sys_t *p_sys = p_intf->p_sys;
  870.     /* CleanUp */
  871.     SetOverlayTransparency( p_intf, false );
  872.     if( p_sys->p_overlay )
  873.     {
  874.         int ret;
  875.         ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
  876.                      p_sys->i_page_size );
  877.         if( ret < 0 )
  878.             msg_Err( p_intf, "unable to clear overlay" );
  879.     }
  880.     DeAllocatePicture( p_intf->p_sys->p_overlay,
  881.                        &p_intf->p_sys->fmt_out );
  882.     p_intf->p_sys->p_overlay = NULL;
  883. }
  884. /*****************************************************************************
  885.  * OpenDisplay: initialize framebuffer
  886.  *****************************************************************************/
  887. static int OpenDisplay( intf_thread_t *p_intf )
  888. {
  889.     intf_sys_t *p_sys = p_intf->p_sys;
  890.     char *psz_device;                             /* framebuffer device path */
  891.     struct fb_fix_screeninfo    fix_info;     /* framebuffer fix information */
  892.     /* Open framebuffer device */
  893.     if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
  894.     {
  895.         msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
  896.         return VLC_EGENERIC;
  897.     }
  898.     p_sys->i_fd = open( psz_device, O_RDWR );
  899.     if( p_sys->i_fd == -1 )
  900.     {
  901.         msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
  902.         free( psz_device );
  903.         return VLC_EGENERIC;
  904.     }
  905.     free( psz_device );
  906.     /* Get framebuffer device information */
  907.     if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
  908.     {
  909.         msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
  910.         close( p_sys->i_fd );
  911.         return VLC_EGENERIC;
  912.     }
  913.     /* Get some info on the framebuffer itself */
  914.     if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
  915.     {
  916.         p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
  917.         p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
  918.     }
  919.     /* FIXME: if the image is full-size, it gets cropped on the left
  920.      * because of the xres / xres_virtual slight difference */
  921.     msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
  922.              p_sys->var_info.xres, p_sys->var_info.yres,
  923.              p_sys->var_info.xres_virtual,
  924.              p_sys->var_info.yres_virtual );
  925.     p_sys->fmt_out.i_width = p_sys->i_width;
  926.     p_sys->fmt_out.i_height = p_sys->i_height;
  927.     p_sys->p_palette = NULL;
  928.     p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
  929.     switch( p_sys->var_info.bits_per_pixel )
  930.     {
  931.     case 8:
  932.         p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
  933.         if( !p_sys->p_palette )
  934.         {
  935.             close( p_sys->i_fd );
  936.             return VLC_ENOMEM;
  937.         }
  938.         p_sys->fb_cmap.start = 0;
  939.         p_sys->fb_cmap.len = 256;
  940.         p_sys->fb_cmap.red = p_sys->p_palette;
  941.         p_sys->fb_cmap.green  = p_sys->p_palette + 256 * sizeof( uint16_t );
  942.         p_sys->fb_cmap.blue   = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
  943.         p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
  944.         /* Save the colormap */
  945.         ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
  946.         p_sys->i_bytes_per_pixel = 1;
  947.         break;
  948.     case 15:
  949.     case 16:
  950.         p_sys->i_bytes_per_pixel = 2;
  951.         break;
  952.     case 24:
  953.         p_sys->i_bytes_per_pixel = 3;
  954.         break;
  955.     case 32:
  956.         p_sys->i_bytes_per_pixel = 4;
  957.         break;
  958.     default:
  959.         msg_Err( p_intf, "screen depth %d is not supported",
  960.                          p_sys->var_info.bits_per_pixel );
  961.         close( p_sys->i_fd );
  962.         return VLC_EGENERIC;
  963.     }
  964.     p_sys->i_page_size = p_sys->i_width * p_sys->i_height
  965.                          * p_sys->i_bytes_per_pixel;
  966.     msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
  967.              "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
  968.              fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
  969.     return VLC_SUCCESS;
  970. }
  971. /*****************************************************************************
  972.  * CloseDisplay: terminate FB interface thread
  973.  *****************************************************************************/
  974. static void CloseDisplay( intf_thread_t *p_intf )
  975. {
  976.     intf_sys_t *p_sys = p_intf->p_sys;
  977.     /* Restore palette */
  978.     if( p_sys->var_info.bits_per_pixel == 8 )
  979.     {
  980.         ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
  981.         free( p_sys->p_palette );
  982.         p_sys->p_palette = NULL;
  983.     }
  984.     /* Close fb */
  985.     close( p_sys->i_fd );
  986. }
  987. static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
  988. {
  989.     intf_sys_t *p_sys = p_intf->p_sys;
  990.     if( render->i_state != FBOSD_STATE_RENDER ) return;
  991.     if( !render->psz_string ) return;
  992.     if( render->i_type == FBOSD_RENDER_IMAGE )
  993.     {
  994.         picture_t *p_pic;
  995.         p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
  996.         if( p_pic )
  997.         {
  998.             RenderPicture( p_intf, render->i_x, render->i_y,
  999.                            p_pic, p_sys->p_overlay );
  1000.             picture_Release( p_pic );
  1001.         }
  1002.     }
  1003.     else if( render->i_type == FBOSD_RENDER_TEXT )
  1004.     {
  1005.         picture_t *p_text;
  1006. #if defined(FBOSD_BLENDING)
  1007.         video_format_t fmt_in;
  1008.         memset( &fmt_in, 0, sizeof(video_format_t) );
  1009.         p_text = RenderText( p_intf, render->psz_string, &render->text_style,
  1010.                              &fmt_in );
  1011.         if( p_text )
  1012.         {
  1013.             BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
  1014.                           p_text, p_sys->p_overlay );
  1015.             msg_Dbg( p_intf, "releasing picture" );
  1016.             DeAllocatePicture( p_text, &fmt_in );
  1017.         }
  1018. #else
  1019.         p_text = RenderText( p_intf, render->psz_string, &render->text_style,
  1020.                              &p_sys->fmt_out );
  1021.         if( p_text )
  1022.         {
  1023.             RenderPicture( p_intf, render->i_x, render->i_y,
  1024.                            p_text, p_sys->p_overlay );
  1025.             picture_Release( p_text );
  1026.         }
  1027. #endif
  1028.     }
  1029. }
  1030. static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
  1031. {
  1032.     intf_sys_t *p_sys = p_intf->p_sys;
  1033.     vlc_memcpy( &render->text_style, &default_text_style,
  1034.                 sizeof( text_style_t ) );
  1035.     free( render->psz_string );
  1036.     render->psz_string = NULL;
  1037.     render->i_x = p_sys->i_x;
  1038.     render->i_y = p_sys->i_y;
  1039.     render->i_pos = p_sys->i_pos;
  1040.     render->i_alpha = p_sys->i_alpha;
  1041.     render->b_absolute = p_sys->b_absolute;
  1042.     render->i_state = FBOSD_STATE_FREE;
  1043. }
  1044. static bool isRendererReady( intf_thread_t *p_intf )
  1045. {
  1046.     intf_sys_t *p_sys = p_intf->p_sys;
  1047.     int i;
  1048.     /* Check if there are more items to render */
  1049.     for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1050.     {
  1051.         if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
  1052.             return false;
  1053.     }
  1054.     return true;
  1055. }
  1056. /*****************************************************************************
  1057.  * Run: thread
  1058.  *****************************************************************************
  1059.  * This part of the interface is in a separate thread so that we can call
  1060.  * exec() from within it without annoying the rest of the program.
  1061.  *****************************************************************************/
  1062. static void Run( intf_thread_t *p_intf )
  1063. {
  1064.     intf_sys_t *p_sys = p_intf->p_sys;
  1065.     int canc = vlc_savecancel();
  1066.     while( vlc_object_alive( p_intf ) )
  1067.     {
  1068.         int i;
  1069.         /* Is there somthing to render? */
  1070.         for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1071.         {
  1072.             if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
  1073.             {
  1074.                 Render( p_intf, &p_sys->render[i] );
  1075.                 RenderClear( p_intf, &p_sys->render[i] );
  1076.             }
  1077.         }
  1078.         if( p_sys->b_clear )
  1079.         {
  1080.             SetOverlayTransparency( p_intf, true );
  1081.             var_SetString( p_intf, "fbosd-image", "" );
  1082.             var_SetString( p_intf, "fbosd-text", "" );
  1083.             p_sys->b_clear = false;
  1084.             p_sys->b_need_update = true;
  1085.         }
  1086.         if( p_sys->b_need_update && p_sys->p_overlay &&
  1087.             isRendererReady( p_intf ) )
  1088.         {
  1089.             int ret;
  1090. #if defined(FBOSD_BLENDING)
  1091.             /* Reverse alpha channel to work around FPGA bug */
  1092.             InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
  1093. #endif
  1094.             ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
  1095.                          p_sys->i_page_size );
  1096.             if( ret < 0 )
  1097.                 msg_Err( p_intf, "unable to write to overlay" );
  1098.             lseek( p_sys->i_fd, 0, SEEK_SET );
  1099.             /* clear the picture */
  1100.             memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
  1101.             p_sys->b_need_update = false;
  1102.         }
  1103.         msleep( INTF_IDLE_SLEEP );
  1104.     }
  1105.     End( p_intf );
  1106.     vlc_restorecancel( canc );
  1107. }
  1108. static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
  1109.                  vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1110. {
  1111.     intf_thread_t *p_intf = (intf_thread_t *) p_this;
  1112.     intf_sys_t *p_sys = p_intf->p_sys;
  1113.     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1114.     if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
  1115.     {
  1116.         p_sys->b_need_update = true;
  1117.     }
  1118.     else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
  1119.     {
  1120.         int i;
  1121.         /* Clear the entire render list */
  1122.         for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1123.         {
  1124.             RenderClear( p_intf, &p_sys->render[i] );
  1125.         }
  1126.         p_sys->b_clear = true;
  1127.     }
  1128.     else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
  1129.     {
  1130.         int i;
  1131.         /* Are we already busy with on slot ? */
  1132.         for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1133.         {
  1134.             if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
  1135.             {
  1136.                 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
  1137.                 break;
  1138.             }
  1139.         }
  1140.     }
  1141.     else
  1142.     {
  1143.         int i;
  1144.         /* Are we already busy with on slot ? */
  1145.         for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1146.         {
  1147.             if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
  1148.                 break;
  1149.         }
  1150.         /* No, then find first FREE slot */
  1151.         if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
  1152.         {
  1153.             for( i = 0; i < FBOSD_RENDER_MAX; i++ )
  1154.             {
  1155.                 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
  1156.                     break;
  1157.             }
  1158.             if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
  1159.             {
  1160.                 msg_Warn( p_this, "render space depleated" );
  1161.                 return VLC_SUCCESS;
  1162.             }
  1163.         }
  1164.         /* Found a free slot */
  1165.         p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
  1166.         if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
  1167.         {
  1168.             free( p_sys->render[i].psz_string );
  1169.             p_sys->render[i].psz_string = strdup( newval.psz_string );
  1170.             p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
  1171.         }
  1172.         else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
  1173.         {
  1174.             free( p_sys->render[i].psz_string );
  1175.             p_sys->render[i].psz_string = strdup( newval.psz_string );
  1176.             p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
  1177.         }
  1178.         else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
  1179.         {
  1180.             p_sys->render[i].b_absolute = false;
  1181.             p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
  1182.                                     newval.i_int : p_sys->i_width;
  1183.         }
  1184.         else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
  1185.         {
  1186.             p_sys->render[i].b_absolute = false;
  1187.             p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
  1188.                                     newval.i_int : p_sys->i_height;
  1189.         }
  1190.         else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
  1191.         {
  1192.             p_sys->render[i].b_absolute = true;
  1193.             p_sys->render[i].i_pos = newval.i_int;
  1194.         }
  1195.         else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
  1196.         {
  1197.             p_sys->render[i].text_style.i_font_size = newval.i_int;
  1198.         }
  1199.         else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
  1200.         {
  1201.             p_sys->render[i].text_style.i_font_color = newval.i_int;
  1202.         }
  1203.         else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
  1204.         {
  1205.             p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
  1206.         }
  1207.         else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
  1208.         {
  1209.             p_sys->render[i].i_alpha = newval.i_int;
  1210.         }
  1211.     }
  1212.     return VLC_SUCCESS;
  1213. }