add_integer: remove callback parameter
[vlc/asuraparaju-public.git] / modules / gui / fbosd.c
blob86400d720d1dd5e39303e3dccfbf4a537518556f
1 /*****************************************************************************
2 * fbosd.c : framebuffer osd plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2007-2008, the VideoLAN team
5 * $Id$
7 * Authors: Jean-Paul Saman
8 * Copied from modules/video_output/fb.c by Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_fs.h>
35 #include <vlc_modules.h>
37 #include <stdlib.h> /* free() */
38 #include <string.h> /* strerror() */
39 #include <fcntl.h> /* open() */
40 #include <unistd.h> /* close() */
42 #include <sys/ioctl.h>
43 #include <sys/mman.h> /* mmap() */
45 #include <linux/fb.h>
47 #include <vlc_image.h>
48 #include <vlc_interface.h>
49 #include <vlc_input.h>
50 #include <vlc_vout.h>
51 #include <vlc_filter.h>
52 #include <vlc_osd.h>
53 #include <vlc_strings.h>
55 #undef FBOSD_BLENDING
56 #undef FBOSD_DEBUG
58 /*****************************************************************************
59 * Local prototypes
60 *****************************************************************************/
61 static int Create ( vlc_object_t * );
62 static void Destroy ( vlc_object_t * );
63 static void Run ( intf_thread_t * );
65 static int Init ( intf_thread_t * );
66 static void End ( intf_thread_t * );
68 static int OpenDisplay ( intf_thread_t * );
69 static void CloseDisplay ( intf_thread_t * );
71 /* Load modules needed for rendering and blending */
72 #if defined(FBOSD_BLENDING)
73 static int OpenBlending ( intf_thread_t * );
74 static void CloseBlending ( intf_thread_t * );
75 #endif
76 static int OpenTextRenderer ( intf_thread_t * );
77 static void CloseTextRenderer( intf_thread_t * );
79 /* Manipulate the overlay buffer */
80 static int OverlayCallback( vlc_object_t *, char const *,
81 vlc_value_t, vlc_value_t, void * );
83 static picture_t *AllocatePicture( video_format_t * );
84 static void DeAllocatePicture( picture_t *, video_format_t * );
85 static void SetOverlayTransparency( intf_thread_t *,
86 bool );
87 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
88 char * );
90 #if defined(FBOSD_BLENDING)
91 static int BlendPicture( intf_thread_t *, video_format_t *,
92 video_format_t *, picture_t *, picture_t * );
93 #else
94 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
95 video_format_t *, video_format_t * );
96 #endif
97 static int RenderPicture( intf_thread_t *, int, int,
98 picture_t *, picture_t * );
99 static picture_t *RenderText( intf_thread_t *, const char *,
100 text_style_t *, video_format_t * );
102 #define DEVICE_TEXT N_("Framebuffer device")
103 #define DEVICE_LONGTEXT N_( \
104 "Framebuffer device to use for rendering (usually /dev/fb0).")
106 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
107 #define ASPECT_RATIO_LONGTEXT N_( \
108 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
110 #define FBOSD_IMAGE_TEXT N_("Image file")
111 #define FBOSD_IMAGE_LONGTEXT N_( \
112 "Filename of image file to use on the overlay framebuffer." )
114 #define ALPHA_TEXT N_("Transparency of the image")
115 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
116 "used in blending. By default it set to fully opaque (255). " \
117 "(from 0 for full transparency to 255 for full opacity)" )
119 #define FBOSD_TEXT N_("Text")
120 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
122 #define POSX_TEXT N_("X coordinate")
123 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
125 #define POSY_TEXT N_("Y coordinate")
126 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
128 #define POS_TEXT N_("Position")
129 #define POS_LONGTEXT N_( \
130 "You can enforce the picture position on the overlay " \
131 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
132 "also use combinations of these values, e.g. 6=top-right).")
134 #define OPACITY_TEXT N_("Opacity")
135 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
136 "overlayed text. 0 = transparent, 255 = totally opaque. " )
138 #define SIZE_TEXT N_("Font size, pixels")
139 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
140 "font size)." )
142 #define COLOR_TEXT N_("Color")
143 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
144 "the video. This must be an hexadecimal (like HTML colors). The first two "\
145 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
146 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
148 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
149 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
150 "making the overlay completely transparent. All previously rendered " \
151 "images and text will be cleared from the cache." )
153 #define RENDER_TEXT N_( "Render text or image" )
154 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
155 "buffer." )
157 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
158 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
159 "displayed on the overlay framebuffer." )
161 static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
162 static const char *const ppsz_pos_descriptions[] =
163 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
164 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
166 static const int pi_color_values[] = {
167 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
168 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
169 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
170 0x00000080, 0x000000FF, 0x0000FFFF};
171 static const char *const ppsz_color_descriptions[] = {
172 N_("Default"), N_("Black"),
173 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
174 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
175 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
176 N_("Aqua") };
178 vlc_module_begin ()
179 set_shortname( "fbosd" )
180 set_category( CAT_INTERFACE )
181 set_subcategory( SUBCAT_INTERFACE_MAIN )
183 add_loadfile( "fbosd-dev", "/dev/fb0", DEVICE_TEXT, DEVICE_LONGTEXT,
184 false )
185 add_string( "fbosd-aspect-ratio", "", ASPECT_RATIO_TEXT,
186 ASPECT_RATIO_LONGTEXT, true )
188 add_string( "fbosd-image", NULL, FBOSD_IMAGE_TEXT,
189 FBOSD_IMAGE_LONGTEXT, true )
190 add_string( "fbosd-text", NULL, FBOSD_TEXT,
191 FBOSD_LONGTEXT, true )
193 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
194 ALPHA_LONGTEXT, true )
196 set_section( N_("Position"), NULL )
197 add_integer( "fbosd-x", 0, POSX_TEXT,
198 POSX_LONGTEXT, false )
199 add_integer( "fbosd-y", 0, POSY_TEXT,
200 POSY_LONGTEXT, false )
201 add_integer( "fbosd-position", 8, POS_TEXT, POS_LONGTEXT, true )
202 change_integer_list( pi_pos_values, ppsz_pos_descriptions );
204 set_section( N_("Font"), NULL )
205 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
206 OPACITY_TEXT, OPACITY_LONGTEXT, false )
207 add_integer( "fbosd-font-color", 0x00FFFFFF, COLOR_TEXT, COLOR_LONGTEXT,
208 false )
209 change_integer_list( pi_color_values, ppsz_color_descriptions );
210 add_integer( "fbosd-font-size", -1, SIZE_TEXT, SIZE_LONGTEXT,
211 false )
213 set_section( N_("Commands"), NULL )
214 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
215 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
216 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
218 set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
219 set_capability( "interface", 10 )
220 set_callbacks( Create, Destroy )
221 vlc_module_end ()
223 /*****************************************************************************
224 * fbosd_render_t: render descriptor
225 *****************************************************************************/
226 struct fbosd_render_t
228 #define FBOSD_RENDER_IMAGE 0
229 #define FBOSD_RENDER_TEXT 1
230 int i_type;
232 #define FBOSD_STATE_FREE 0
233 #define FBOSD_STATE_RESERVED 1
234 #define FBOSD_STATE_RENDER 2
235 int i_state;
237 /* Font style */
238 text_style_t* p_text_style; /* font control */
239 char *psz_string;
241 /* Position */
242 bool b_absolute;
243 int i_x;
244 int i_y;
245 int i_pos;
246 int i_alpha; /* transparency for images */
248 #define FBOSD_RENDER_MAX 10
250 /*****************************************************************************
251 * intf_sys_t: interface framebuffer method descriptor
252 *****************************************************************************/
253 struct intf_sys_t
255 /* Framebuffer information */
256 int i_fd; /* device handle */
257 struct fb_var_screeninfo var_info; /* current mode information */
258 bool b_pan; /* does device supports panning ? */
259 struct fb_cmap fb_cmap; /* original colormap */
260 uint16_t *p_palette; /* original palette */
262 /* Overlay framebuffer format */
263 video_format_t fmt_out;
264 picture_t *p_overlay;
265 size_t i_page_size; /* page size */
266 int i_width;
267 int i_height;
268 int i_aspect;
269 int i_bytes_per_pixel;
271 /* Image and Picture rendering */
272 image_handler_t *p_image;
273 #if defined(FBOSD_BLENDING)
274 filter_t *p_blend; /* alpha blending module */
275 #endif
276 filter_t *p_text; /* text renderer module */
278 /* Render */
279 struct fbosd_render_t render[FBOSD_RENDER_MAX];
281 /* Font style */
282 text_style_t *p_style; /* font control */
284 /* Position */
285 bool b_absolute;
286 int i_x;
287 int i_y;
288 int i_pos;
290 int i_alpha; /* transparency for images */
292 /* commands control */
293 bool b_need_update; /* update display with \overlay buffer */
294 bool b_clear; /* clear overlay buffer make it tranparent */
295 bool b_render; /* render an image or text in overlay buffer */
298 /*****************************************************************************
299 * Create: allocates FB interface thread output method
300 *****************************************************************************/
301 static int Create( vlc_object_t *p_this )
303 intf_thread_t *p_intf = (intf_thread_t *)p_this;
304 intf_sys_t *p_sys;
305 char *psz_aspect;
306 char *psz_tmp;
307 int i;
309 /* Allocate instance and initialize some members */
310 p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
311 if( !p_intf->p_sys )
312 return VLC_ENOMEM;
314 p_sys->p_style = text_style_New();
315 if( !p_sys->p_style )
317 free( p_intf->p_sys );
318 return VLC_ENOMEM;
321 p_intf->pf_run = Run;
323 p_sys->p_image = image_HandlerCreate( p_this );
324 if( !p_sys->p_image )
326 text_style_Delete( p_sys->p_style );
327 free( p_sys );
328 return VLC_ENOMEM;
331 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
332 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
334 /* Use PAL by default */
335 p_sys->i_width = p_sys->fmt_out.i_width = 704;
336 p_sys->i_height = p_sys->fmt_out.i_height = 576;
338 p_sys->i_aspect = -1;
339 psz_aspect =
340 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
341 if( psz_aspect )
343 char *psz_parser = strchr( psz_aspect, ':' );
345 if( psz_parser )
347 *psz_parser++ = '\0';
348 p_sys->i_aspect = ( atoi( psz_aspect )
349 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
350 p_sys->fmt_out.i_sar_num = p_sys->i_aspect * p_sys->i_height;
351 p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
353 msg_Dbg( p_intf, "using aspect ratio %d:%d",
354 atoi( psz_aspect ), atoi( psz_parser ) );
356 free( psz_aspect );
359 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
360 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
361 if( psz_tmp && *psz_tmp )
363 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
364 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
365 p_sys->render[0].psz_string = strdup( psz_tmp );
367 free( psz_tmp );
369 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
370 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
371 if( psz_tmp && *psz_tmp )
373 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
374 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
375 p_sys->render[1].psz_string = strdup( psz_tmp );
377 free( psz_tmp );
379 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
380 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
381 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
383 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
384 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
385 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
387 p_sys->p_style->i_font_size =
388 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
389 p_sys->p_style->i_font_color =
390 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
391 p_sys->p_style->i_font_alpha = 255 -
392 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
394 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
395 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
396 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
398 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
399 p_sys->render[i].p_text_style = text_style_New();
401 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
402 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
403 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
405 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
406 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
407 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
409 /* Check if picture position was overridden */
410 p_sys->b_absolute = true;
411 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
413 p_sys->b_absolute = false;
414 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
415 p_sys->i_y : p_sys->i_height;
416 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
417 p_sys->i_x : p_sys->i_width;
420 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
421 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
422 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
423 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
425 /* Initialize framebuffer */
426 if( OpenDisplay( p_intf ) )
428 Destroy( VLC_OBJECT(p_intf) );
429 return VLC_EGENERIC;
432 Init( p_intf );
434 #if defined(FBOSD_BLENDING)
435 /* Load the blending module */
436 if( OpenBlending( p_intf ) )
438 msg_Err( p_intf, "Unable to load image blending module" );
439 Destroy( VLC_OBJECT(p_intf) );
440 return VLC_EGENERIC;
442 #endif
444 /* Load text renderer module */
445 if( OpenTextRenderer( p_intf ) )
447 msg_Err( p_intf, "Unable to load text rendering module" );
448 Destroy( VLC_OBJECT(p_intf) );
449 return VLC_EGENERIC;
452 p_sys->b_render = true;
453 p_sys->b_need_update = true;
455 return VLC_SUCCESS;
458 /*****************************************************************************
459 * Destroy: destroy FB interface thread output method
460 *****************************************************************************
461 * Terminate an output method created by Create
462 *****************************************************************************/
463 static void Destroy( vlc_object_t *p_this )
465 intf_thread_t *p_intf = (intf_thread_t *)p_this;
466 intf_sys_t *p_sys = p_intf->p_sys;
467 int i;
470 p_sys->b_need_update = false;
471 p_sys->b_render = false;
472 p_sys->b_clear = false;
474 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
475 var_Destroy( p_intf, "fbosd-alpha" );
477 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
478 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
479 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
480 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
481 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
482 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
487 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
489 var_Destroy( p_intf, "fbosd-x" );
490 var_Destroy( p_intf, "fbosd-y" );
491 var_Destroy( p_intf, "fbosd-position" );
492 var_Destroy( p_intf, "fbosd-image" );
493 var_Destroy( p_intf, "fbosd-text" );
494 var_Destroy( p_intf, "fbosd-font-size" );
495 var_Destroy( p_intf, "fbosd-font-color" );
496 var_Destroy( p_intf, "fbosd-font-opacity" );
497 var_Destroy( p_intf, "fbosd-clear" );
498 var_Destroy( p_intf, "fbosd-render" );
499 var_Destroy( p_intf, "fbosd-display" );
501 var_Destroy( p_intf, "fbosd-aspect-ratio" );
503 CloseDisplay( p_intf );
505 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
507 free( p_sys->render[i].psz_string );
508 p_sys->render[i].i_state = FBOSD_STATE_FREE;
509 text_style_Delete( p_sys->render[i].p_text_style );
512 #if defined(FBOSD_BLENDING)
513 if( p_sys->p_blend ) CloseBlending( p_intf );
514 #endif
515 if( p_sys->p_text ) CloseTextRenderer( p_intf );
517 if( p_sys->p_image )
518 image_HandlerDelete( p_sys->p_image );
519 if( p_sys->p_overlay )
520 picture_Release( p_sys->p_overlay );
522 text_style_Delete( p_sys->p_style );
523 free( p_sys );
526 #if defined(FBOSD_BLENDING)
527 static int OpenBlending( intf_thread_t *p_intf )
529 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
531 p_intf->p_sys->p_blend =
532 vlc_object_create( p_intf, sizeof(filter_t) );
533 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
534 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
535 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
536 p_intf->p_sys->p_blend->fmt_out.video.i_sar_num =
537 p_intf->p_sys->fmt_out.i_sar_num;
538 p_intf->p_sys->p_blend->fmt_out.video.i_sar_den =
539 p_intf->p_sys->fmt_out.i_sar_den;
540 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
541 p_intf->p_sys->fmt_out.i_chroma;
542 if( var_InheritBool( p_intf, "freetype-yuvp" ) )
543 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
544 VLC_CODEC_YUVP;
545 else
546 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
547 VLC_CODEC_YUVA;
549 p_intf->p_sys->p_blend->p_module =
550 module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
552 if( !p_intf->p_sys->p_blend->p_module )
553 return VLC_EGENERIC;
555 return VLC_SUCCESS;
558 static void CloseBlending( intf_thread_t *p_intf )
560 if( p_intf->p_sys->p_blend )
562 if( p_intf->p_sys->p_blend->p_module )
563 module_unneed( p_intf->p_sys->p_blend,
564 p_intf->p_sys->p_blend->p_module );
566 vlc_object_release( p_intf->p_sys->p_blend );
569 #endif
571 static int OpenTextRenderer( intf_thread_t *p_intf )
573 char *psz_modulename = NULL;
575 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
577 p_intf->p_sys->p_text =
578 vlc_object_create( p_intf, sizeof(filter_t) );
579 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
581 p_intf->p_sys->p_text->fmt_out.video.i_width =
582 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
583 p_intf->p_sys->i_width;
584 p_intf->p_sys->p_text->fmt_out.video.i_height =
585 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
586 p_intf->p_sys->i_height;
588 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
589 if( psz_modulename && *psz_modulename )
591 p_intf->p_sys->p_text->p_module =
592 module_need( p_intf->p_sys->p_text, "text renderer",
593 psz_modulename, true );
595 if( !p_intf->p_sys->p_text->p_module )
597 p_intf->p_sys->p_text->p_module =
598 module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
600 free( psz_modulename );
602 if( !p_intf->p_sys->p_text->p_module )
603 return VLC_EGENERIC;
605 return VLC_SUCCESS;
608 static void CloseTextRenderer( intf_thread_t *p_intf )
610 if( p_intf->p_sys->p_text )
612 if( p_intf->p_sys->p_text->p_module )
613 module_unneed( p_intf->p_sys->p_text,
614 p_intf->p_sys->p_text->p_module );
616 vlc_object_release( p_intf->p_sys->p_text );
620 /*****************************************************************************
621 * AllocatePicture:
622 * allocate a picture buffer for use with the overlay fb.
623 *****************************************************************************/
624 static picture_t *AllocatePicture( video_format_t *p_fmt )
626 picture_t *p_picture = picture_NewFromFormat( p_fmt );
627 if( !p_picture )
628 return NULL;
630 if( !p_fmt->p_palette &&
631 ( p_fmt->i_chroma == VLC_CODEC_YUVP ) )
633 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
634 if( !p_fmt->p_palette )
636 picture_Release( p_picture );
637 return NULL;
640 else
642 p_fmt->p_palette = NULL;
645 return p_picture;
648 /*****************************************************************************
649 * DeAllocatePicture:
650 * Deallocate a picture buffer and free all associated memory.
651 *****************************************************************************/
652 static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
654 if( p_fmt )
656 free( p_fmt->p_palette );
657 p_fmt->p_palette = NULL;
660 if( p_pic )
661 picture_Release( p_pic );
664 /*****************************************************************************
665 * SetOverlayTransparency: Set the transparency for this overlay fb,
666 * - true is make transparent
667 * - false is make non tranparent
668 *****************************************************************************/
669 static void SetOverlayTransparency( intf_thread_t *p_intf,
670 bool b_transparent )
672 intf_sys_t *p_sys = p_intf->p_sys;
673 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
674 * p_sys->i_bytes_per_pixel;
675 size_t i_page_size = (p_sys->i_page_size > i_size) ?
676 i_size : p_sys->i_page_size;
678 if( p_sys->p_overlay )
680 msg_Dbg( p_intf, "Make overlay %s",
681 b_transparent ? "transparent" : "opaque" );
682 if( b_transparent )
683 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
684 else
685 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
689 #if defined(FBOSD_BLENDING)
690 /*****************************************************************************
691 * BlendPicture: Blend two pictures together..
692 *****************************************************************************/
693 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
694 video_format_t *p_fmt_dst, picture_t *p_pic_src,
695 picture_t *p_pic_dst )
697 intf_sys_t *p_sys = p_intf->p_sys;
698 if( p_sys->p_blend && p_sys->p_blend->p_module )
700 int i_x_offset = p_sys->i_x;
701 int i_y_offset = p_sys->i_y;
703 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
705 /* Update the output picture size */
706 p_sys->p_blend->fmt_out.video.i_width =
707 p_sys->p_blend->fmt_out.video.i_visible_width =
708 p_fmt_dst->i_width;
709 p_sys->p_blend->fmt_out.video.i_height =
710 p_sys->p_blend->fmt_out.video.i_visible_height =
711 p_fmt_dst->i_height;
713 i_x_offset = __MAX( i_x_offset, 0 );
714 i_y_offset = __MAX( i_y_offset, 0 );
716 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
717 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
718 p_sys->i_alpha );
720 return VLC_SUCCESS;
722 return VLC_EGENERIC;
725 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
727 uint8_t *p_begin = NULL, *p_end = NULL;
728 uint8_t i_skip = 0;
730 if( *p_pic && ((*p_pic)->i_planes != 1) )
732 msg_Err( p_intf,
733 "cannot invert alpha channel too many planes %d (only 1 supported)",
734 (*p_pic)->i_planes );
735 return VLC_EGENERIC;
738 switch( fmt.i_chroma )
740 case VLC_CODEC_RGB24:
741 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
742 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
743 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
744 i_skip = 3;
745 break;
746 case VLC_CODEC_RGB32:
747 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
748 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
749 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
750 i_skip = 4;
751 break;
752 default:
753 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
754 (char *)&fmt.i_chroma );
755 return VLC_EGENERIC;
758 for( ; p_begin < p_end; p_begin += i_skip )
760 uint8_t i_opacity = 0;
762 if( *p_begin != 0xFF )
763 i_opacity = 255 - *p_begin;
764 *p_begin = i_opacity;
766 /* end of kludge */
767 return VLC_SUCCESS;
769 #endif
771 /*****************************************************************************
772 * RenderPicture: Render the picture into the p_dest buffer.
773 * We don't take transparent pixels into account, so we don't have to blend
774 * the two images together.
775 *****************************************************************************/
776 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
777 picture_t *p_src, picture_t *p_dest )
779 int i;
780 VLC_UNUSED( p_intf );
782 if( !p_dest && !p_src ) return VLC_EGENERIC;
784 for( i = 0; i < p_src->i_planes ; i++ )
786 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
788 /* There are margins, but with the same width : perfect ! */
789 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
790 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
792 else
794 /* We need to proceed line by line */
795 uint8_t *p_in = p_src->p[i].p_pixels;
796 uint8_t *p_out = p_dest->p[i].p_pixels;
798 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
799 int i_x_clip, i_y_clip;
801 /* Check boundaries, clip the image if necessary */
802 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
803 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
805 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
806 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
807 #if defined(FBOSD_DEBUG)
808 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
809 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
810 i_x_offset, i_y_offset, i_x, i_x_clip );
811 #endif
812 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
813 ( i_x <= p_dest->p[i].i_visible_pitch ) )
815 int i_line;
817 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
818 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
820 vlc_memcpy( p_out + i_x, p_in,
821 p_src->p[i].i_visible_pitch - i_x_clip );
822 p_in += p_src->p[i].i_pitch;
823 p_out += p_dest->p[i].i_pitch;
828 return VLC_SUCCESS;
831 /*****************************************************************************
832 * RenderText - Render text to the desired picture format
833 *****************************************************************************/
834 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
835 text_style_t *p_style, video_format_t *p_fmt )
837 intf_sys_t *p_sys = p_intf->p_sys;
838 subpicture_region_t *p_region;
839 picture_t *p_dest = NULL;
841 if( !psz_string ) return p_dest;
843 if( p_sys->p_text && p_sys->p_text->p_module )
845 video_format_t fmt;
847 memset( &fmt, 0, sizeof(fmt) );
848 fmt.i_chroma = VLC_CODEC_TEXT;
849 fmt.i_width = fmt.i_visible_width = 0;
850 fmt.i_height = fmt.i_visible_height = 0;
851 fmt.i_x_offset = 0;
852 fmt.i_y_offset = 0;
854 p_region = subpicture_region_New( &fmt );
855 if( !p_region )
856 return p_dest;
858 p_region->psz_text = strdup( psz_string );
859 if( !p_region->psz_text )
861 subpicture_region_Delete( p_region );
862 return NULL;
864 p_region->p_style = text_style_Duplicate( p_style );
865 p_region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
867 if( p_sys->p_text->pf_render_text )
869 video_format_t fmt_out;
871 memset( &fmt_out, 0, sizeof(video_format_t) );
873 p_sys->p_text->pf_render_text( p_sys->p_text,
874 p_region, p_region );
876 #if defined(FBOSD_BLENDING)
877 fmt_out = p_region->fmt;
878 fmt_out.i_bits_per_pixel = 32;
879 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
881 /* FIXME not needed to copy the picture anymore no ? */
882 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
883 if( !p_dest )
885 subpicture_region_Delete( p_region );
886 return NULL;
888 picture_Copy( p_dest, p_region->p_picture );
889 #else
890 fmt_out.i_chroma = p_fmt->i_chroma;
891 p_dest = ConvertImage( p_intf, p_region->p_picture,
892 &p_region->fmt, &fmt_out );
893 #endif
894 subpicture_region_Delete( p_region );
895 return p_dest;
897 subpicture_region_Delete( p_region );
899 return p_dest;
902 /*****************************************************************************
903 * LoadImage: Load an image from file into a picture buffer.
904 *****************************************************************************/
905 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
906 char *psz_file )
908 picture_t *p_pic = NULL;
910 if( psz_file && p_intf->p_sys->p_image )
912 video_format_t fmt_in, fmt_out;
914 memset( &fmt_in, 0, sizeof(fmt_in) );
915 memset( &fmt_out, 0, sizeof(fmt_out) );
917 fmt_out.i_chroma = p_fmt->i_chroma;
918 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
919 &fmt_in, &fmt_out );
921 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
922 fmt_out.i_width, fmt_out.i_height,
923 (char *)&p_fmt->i_chroma );
925 return p_pic;
928 #if ! defined(FBOSD_BLENDING)
929 /*****************************************************************************
930 * Convertmage: Convert image to another fourcc
931 *****************************************************************************/
932 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
933 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
935 intf_sys_t *p_sys = p_intf->p_sys;
936 picture_t *p_old = NULL;
938 if( p_sys->p_image )
940 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
942 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
943 p_fmt_out->i_width, p_fmt_out->i_height,
944 (char *)&p_fmt_out->i_chroma );
946 return p_old;
948 #endif
950 /*****************************************************************************
951 * Init: initialize framebuffer video thread output method
952 *****************************************************************************/
953 static int Init( intf_thread_t *p_intf )
955 intf_sys_t *p_sys = p_intf->p_sys;
957 /* Initialize the output structure: RGB with square pixels, whatever
958 * the input format is, since it's the only format we know */
959 switch( p_sys->var_info.bits_per_pixel )
961 case 8: /* FIXME: set the palette */
962 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB8; break;
963 case 15:
964 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB15; break;
965 case 16:
966 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB16; break;
967 case 24:
968 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB24; break;
969 case 32:
970 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB32; break;
971 default:
972 msg_Err( p_intf, "unknown screen depth %i",
973 p_sys->var_info.bits_per_pixel );
974 return VLC_EGENERIC;
977 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
978 p_sys->fmt_out.i_width = p_sys->i_width;
979 p_sys->fmt_out.i_height = p_sys->i_height;
981 /* Assume we have square pixels */
982 if( p_sys->i_aspect < 0 )
984 p_sys->fmt_out.i_sar_num = 1;
985 p_sys->fmt_out.i_sar_den = 1;
987 else
989 p_sys->fmt_out.i_sar_num = p_sys->i_aspect * p_sys->i_height;
990 p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
993 /* Allocate overlay buffer */
994 p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
995 if( !p_sys->p_overlay ) return VLC_EGENERIC;
997 SetOverlayTransparency( p_intf, true );
999 /* We know the chroma, allocate a buffer which will be used
1000 * to write to the overlay framebuffer */
1001 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1002 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1003 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1005 if( p_sys->var_info.xres_virtual )
1007 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1008 * p_sys->i_bytes_per_pixel;
1010 else
1012 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1013 * p_sys->i_bytes_per_pixel;
1016 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1017 * p_sys->i_bytes_per_pixel;
1019 p_sys->p_overlay->i_planes = 1;
1021 return VLC_SUCCESS;
1024 /*****************************************************************************
1025 * End: terminate framebuffer interface
1026 *****************************************************************************/
1027 static void End( intf_thread_t *p_intf )
1029 intf_sys_t *p_sys = p_intf->p_sys;
1031 /* CleanUp */
1032 SetOverlayTransparency( p_intf, false );
1033 if( p_sys->p_overlay )
1035 int ret;
1036 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1037 p_sys->i_page_size );
1038 if( ret < 0 )
1039 msg_Err( p_intf, "unable to clear overlay" );
1042 DeAllocatePicture( p_intf->p_sys->p_overlay,
1043 &p_intf->p_sys->fmt_out );
1044 p_intf->p_sys->p_overlay = NULL;
1047 /*****************************************************************************
1048 * OpenDisplay: initialize framebuffer
1049 *****************************************************************************/
1050 static int OpenDisplay( intf_thread_t *p_intf )
1052 intf_sys_t *p_sys = p_intf->p_sys;
1053 char *psz_device; /* framebuffer device path */
1054 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1056 /* Open framebuffer device */
1057 if( !(psz_device = var_InheritString( p_intf, "fbosd-dev" )) )
1059 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1060 return VLC_EGENERIC;
1063 p_sys->i_fd = vlc_open( psz_device, O_RDWR );
1064 if( p_sys->i_fd == -1 )
1066 msg_Err( p_intf, "cannot open %s (%m)", psz_device );
1067 free( psz_device );
1068 return VLC_EGENERIC;
1070 free( psz_device );
1072 /* Get framebuffer device information */
1073 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1075 msg_Err( p_intf, "cannot get fb info (%m)" );
1076 close( p_sys->i_fd );
1077 return VLC_EGENERIC;
1080 /* Get some info on the framebuffer itself */
1081 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1083 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1084 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1087 /* FIXME: if the image is full-size, it gets cropped on the left
1088 * because of the xres / xres_virtual slight difference */
1089 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1090 p_sys->var_info.xres, p_sys->var_info.yres,
1091 p_sys->var_info.xres_virtual,
1092 p_sys->var_info.yres_virtual );
1094 p_sys->fmt_out.i_width = p_sys->i_width;
1095 p_sys->fmt_out.i_height = p_sys->i_height;
1097 p_sys->p_palette = NULL;
1098 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1100 switch( p_sys->var_info.bits_per_pixel )
1102 case 8:
1103 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1104 if( !p_sys->p_palette )
1106 close( p_sys->i_fd );
1107 return VLC_ENOMEM;
1109 p_sys->fb_cmap.start = 0;
1110 p_sys->fb_cmap.len = 256;
1111 p_sys->fb_cmap.red = p_sys->p_palette;
1112 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1113 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1114 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1116 /* Save the colormap */
1117 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1119 p_sys->i_bytes_per_pixel = 1;
1120 break;
1122 case 15:
1123 case 16:
1124 p_sys->i_bytes_per_pixel = 2;
1125 break;
1127 case 24:
1128 p_sys->i_bytes_per_pixel = 3;
1129 break;
1131 case 32:
1132 p_sys->i_bytes_per_pixel = 4;
1133 break;
1135 default:
1136 msg_Err( p_intf, "screen depth %d is not supported",
1137 p_sys->var_info.bits_per_pixel );
1139 close( p_sys->i_fd );
1140 return VLC_EGENERIC;
1143 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1144 * p_sys->i_bytes_per_pixel;
1146 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1147 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1148 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1149 return VLC_SUCCESS;
1152 /*****************************************************************************
1153 * CloseDisplay: terminate FB interface thread
1154 *****************************************************************************/
1155 static void CloseDisplay( intf_thread_t *p_intf )
1157 intf_sys_t *p_sys = p_intf->p_sys;
1159 /* Restore palette */
1160 if( p_sys->var_info.bits_per_pixel == 8 )
1162 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1163 free( p_sys->p_palette );
1164 p_sys->p_palette = NULL;
1167 /* Close fb */
1168 close( p_sys->i_fd );
1171 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1173 intf_sys_t *p_sys = p_intf->p_sys;
1175 if( render->i_state != FBOSD_STATE_RENDER ) return;
1176 if( !render->psz_string ) return;
1178 if( render->i_type == FBOSD_RENDER_IMAGE )
1180 picture_t *p_pic;
1181 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1182 if( p_pic )
1184 RenderPicture( p_intf, render->i_x, render->i_y,
1185 p_pic, p_sys->p_overlay );
1186 picture_Release( p_pic );
1189 else if( render->i_type == FBOSD_RENDER_TEXT )
1191 picture_t *p_text;
1192 #if defined(FBOSD_BLENDING)
1193 video_format_t fmt_in;
1194 memset( &fmt_in, 0, sizeof(video_format_t) );
1195 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1196 &fmt_in );
1197 if( p_text )
1199 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1200 p_text, p_sys->p_overlay );
1201 msg_Dbg( p_intf, "releasing picture" );
1202 DeAllocatePicture( p_text, &fmt_in );
1204 #else
1205 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1206 &p_sys->fmt_out );
1207 if( p_text )
1209 RenderPicture( p_intf, render->i_x, render->i_y,
1210 p_text, p_sys->p_overlay );
1211 picture_Release( p_text );
1213 #endif
1217 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1219 intf_sys_t *p_sys = p_intf->p_sys;
1221 text_style_Delete( render->p_text_style );
1222 render->p_text_style = text_style_New();
1223 free( render->psz_string );
1224 render->psz_string = NULL;
1226 render->i_x = p_sys->i_x;
1227 render->i_y = p_sys->i_y;
1228 render->i_pos = p_sys->i_pos;
1229 render->i_alpha = p_sys->i_alpha;
1230 render->b_absolute = p_sys->b_absolute;
1231 render->i_state = FBOSD_STATE_FREE;
1234 static bool isRendererReady( intf_thread_t *p_intf )
1236 intf_sys_t *p_sys = p_intf->p_sys;
1237 int i;
1239 /* Check if there are more items to render */
1240 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1242 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1243 return false;
1245 return true;
1248 /*****************************************************************************
1249 * Run: thread
1250 *****************************************************************************
1251 * This part of the interface is in a separate thread so that we can call
1252 * exec() from within it without annoying the rest of the program.
1253 *****************************************************************************/
1254 static void Run( intf_thread_t *p_intf )
1256 intf_sys_t *p_sys = p_intf->p_sys;
1257 int canc = vlc_savecancel();
1259 while( vlc_object_alive( p_intf ) )
1261 int i;
1263 /* Is there somthing to render? */
1264 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1266 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1268 Render( p_intf, &p_sys->render[i] );
1269 RenderClear( p_intf, &p_sys->render[i] );
1273 if( p_sys->b_clear )
1275 SetOverlayTransparency( p_intf, true );
1277 var_SetString( p_intf, "fbosd-image", "" );
1278 var_SetString( p_intf, "fbosd-text", "" );
1280 p_sys->b_clear = false;
1281 p_sys->b_need_update = true;
1284 if( p_sys->b_need_update && p_sys->p_overlay &&
1285 isRendererReady( p_intf ) )
1287 int ret;
1288 #if defined(FBOSD_BLENDING)
1289 /* Reverse alpha channel to work around FPGA bug */
1290 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1291 #endif
1292 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1293 p_sys->i_page_size );
1294 if( ret < 0 )
1295 msg_Err( p_intf, "unable to write to overlay" );
1296 lseek( p_sys->i_fd, 0, SEEK_SET );
1298 /* clear the picture */
1299 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1300 p_sys->b_need_update = false;
1303 msleep( INTF_IDLE_SLEEP );
1306 End( p_intf );
1307 vlc_restorecancel( canc );
1310 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1311 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1313 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1314 intf_sys_t *p_sys = p_intf->p_sys;
1315 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1317 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1319 p_sys->b_need_update = true;
1321 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1323 int i;
1324 /* Clear the entire render list */
1325 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1327 RenderClear( p_intf, &p_sys->render[i] );
1329 p_sys->b_clear = true;
1331 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1333 int i;
1334 /* Are we already busy with on slot ? */
1335 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1337 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1339 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1340 break;
1344 else
1346 int i;
1347 /* Are we already busy with on slot ? */
1348 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1350 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1351 break;
1353 /* No, then find first FREE slot */
1354 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1356 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1358 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1359 break;
1361 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1363 msg_Warn( p_this, "render space depleated" );
1364 return VLC_SUCCESS;
1367 /* Found a free slot */
1368 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1369 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1371 free( p_sys->render[i].psz_string );
1372 p_sys->render[i].psz_string = strdup( newval.psz_string );
1373 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1375 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1377 free( p_sys->render[i].psz_string );
1378 p_sys->render[i].psz_string = strdup( newval.psz_string );
1379 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1381 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1383 p_sys->render[i].b_absolute = false;
1384 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1385 newval.i_int : p_sys->i_width;
1387 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1389 p_sys->render[i].b_absolute = false;
1390 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1391 newval.i_int : p_sys->i_height;
1393 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1395 p_sys->render[i].b_absolute = true;
1396 p_sys->render[i].i_pos = newval.i_int;
1398 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1400 p_sys->render[i].p_text_style->i_font_size = newval.i_int;
1402 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1404 p_sys->render[i].p_text_style->i_font_color = newval.i_int;
1406 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1408 p_sys->render[i].p_text_style->i_font_alpha = 255 - newval.i_int;
1410 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1412 p_sys->render[i].i_alpha = newval.i_int;
1415 return VLC_SUCCESS;