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