POTFiles update with removal/addition of files
[vlc/solaris.git] / modules / gui / fbosd.c
blob8aa5a17435925f8765a72847c901f2bb2b38ad7d
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_charset.h>
36 #include <errno.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_file( "fbosd-dev", "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
184 false )
185 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
186 ASPECT_RATIO_LONGTEXT, true )
188 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
189 FBOSD_IMAGE_LONGTEXT, true )
190 add_string( "fbosd-text", NULL, 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, NULL, POSX_TEXT,
198 POSX_LONGTEXT, false )
199 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
200 POSY_LONGTEXT, false )
201 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
202 change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
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, NULL, COLOR_TEXT, COLOR_LONGTEXT,
208 false )
209 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
210 add_integer( "fbosd-font-size", -1, NULL, 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( config_GetInt( 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_detach( p_intf->p_sys->p_blend );
567 vlc_object_release( p_intf->p_sys->p_blend );
570 #endif
572 static int OpenTextRenderer( intf_thread_t *p_intf )
574 char *psz_modulename = NULL;
576 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
578 p_intf->p_sys->p_text =
579 vlc_object_create( p_intf, sizeof(filter_t) );
580 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
582 p_intf->p_sys->p_text->fmt_out.video.i_width =
583 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
584 p_intf->p_sys->i_width;
585 p_intf->p_sys->p_text->fmt_out.video.i_height =
586 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
587 p_intf->p_sys->i_height;
589 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
590 if( psz_modulename && *psz_modulename )
592 p_intf->p_sys->p_text->p_module =
593 module_need( p_intf->p_sys->p_text, "text renderer",
594 psz_modulename, true );
596 if( !p_intf->p_sys->p_text->p_module )
598 p_intf->p_sys->p_text->p_module =
599 module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
601 free( psz_modulename );
603 if( !p_intf->p_sys->p_text->p_module )
604 return VLC_EGENERIC;
606 return VLC_SUCCESS;
609 static void CloseTextRenderer( intf_thread_t *p_intf )
611 if( p_intf->p_sys->p_text )
613 if( p_intf->p_sys->p_text->p_module )
614 module_unneed( p_intf->p_sys->p_text,
615 p_intf->p_sys->p_text->p_module );
617 vlc_object_detach( p_intf->p_sys->p_text );
618 vlc_object_release( p_intf->p_sys->p_text );
622 /*****************************************************************************
623 * AllocatePicture:
624 * allocate a picture buffer for use with the overlay fb.
625 *****************************************************************************/
626 static picture_t *AllocatePicture( video_format_t *p_fmt )
628 picture_t *p_picture = picture_NewFromFormat( p_fmt );
629 if( !p_picture )
630 return NULL;
632 if( !p_fmt->p_palette &&
633 ( p_fmt->i_chroma == VLC_CODEC_YUVP ) )
635 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
636 if( !p_fmt->p_palette )
638 picture_Release( p_picture );
639 return NULL;
642 else
644 p_fmt->p_palette = NULL;
647 return p_picture;
650 /*****************************************************************************
651 * DeAllocatePicture:
652 * Deallocate a picture buffer and free all associated memory.
653 *****************************************************************************/
654 static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
656 if( p_fmt )
658 free( p_fmt->p_palette );
659 p_fmt->p_palette = NULL;
662 if( p_pic )
663 picture_Release( p_pic );
666 /*****************************************************************************
667 * SetOverlayTransparency: Set the transparency for this overlay fb,
668 * - true is make transparent
669 * - false is make non tranparent
670 *****************************************************************************/
671 static void SetOverlayTransparency( intf_thread_t *p_intf,
672 bool b_transparent )
674 intf_sys_t *p_sys = p_intf->p_sys;
675 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
676 * p_sys->i_bytes_per_pixel;
677 size_t i_page_size = (p_sys->i_page_size > i_size) ?
678 i_size : p_sys->i_page_size;
680 if( p_sys->p_overlay )
682 msg_Dbg( p_intf, "Make overlay %s",
683 b_transparent ? "transparent" : "opaque" );
684 if( b_transparent )
685 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
686 else
687 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
691 #if defined(FBOSD_BLENDING)
692 /*****************************************************************************
693 * BlendPicture: Blend two pictures together..
694 *****************************************************************************/
695 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
696 video_format_t *p_fmt_dst, picture_t *p_pic_src,
697 picture_t *p_pic_dst )
699 intf_sys_t *p_sys = p_intf->p_sys;
700 if( p_sys->p_blend && p_sys->p_blend->p_module )
702 int i_x_offset = p_sys->i_x;
703 int i_y_offset = p_sys->i_y;
705 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
707 /* Update the output picture size */
708 p_sys->p_blend->fmt_out.video.i_width =
709 p_sys->p_blend->fmt_out.video.i_visible_width =
710 p_fmt_dst->i_width;
711 p_sys->p_blend->fmt_out.video.i_height =
712 p_sys->p_blend->fmt_out.video.i_visible_height =
713 p_fmt_dst->i_height;
715 i_x_offset = __MAX( i_x_offset, 0 );
716 i_y_offset = __MAX( i_y_offset, 0 );
718 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
719 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
720 p_sys->i_alpha );
722 return VLC_SUCCESS;
724 return VLC_EGENERIC;
727 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
729 uint8_t *p_begin = NULL, *p_end = NULL;
730 uint8_t i_skip = 0;
732 if( *p_pic && ((*p_pic)->i_planes != 1) )
734 msg_Err( p_intf,
735 "cannot invert alpha channel too many planes %d (only 1 supported)",
736 (*p_pic)->i_planes );
737 return VLC_EGENERIC;
740 switch( fmt.i_chroma )
742 case VLC_CODEC_RGB24:
743 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
744 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
745 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
746 i_skip = 3;
747 break;
748 case VLC_CODEC_RGB32:
749 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
750 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
751 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
752 i_skip = 4;
753 break;
754 default:
755 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
756 (char *)&fmt.i_chroma );
757 return VLC_EGENERIC;
760 for( ; p_begin < p_end; p_begin += i_skip )
762 uint8_t i_opacity = 0;
764 if( *p_begin != 0xFF )
765 i_opacity = 255 - *p_begin;
766 *p_begin = i_opacity;
768 /* end of kludge */
769 return VLC_SUCCESS;
771 #endif
773 /*****************************************************************************
774 * RenderPicture: Render the picture into the p_dest buffer.
775 * We don't take transparent pixels into account, so we don't have to blend
776 * the two images together.
777 *****************************************************************************/
778 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
779 picture_t *p_src, picture_t *p_dest )
781 int i;
782 VLC_UNUSED( p_intf );
784 if( !p_dest && !p_src ) return VLC_EGENERIC;
786 for( i = 0; i < p_src->i_planes ; i++ )
788 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
790 /* There are margins, but with the same width : perfect ! */
791 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
792 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
794 else
796 /* We need to proceed line by line */
797 uint8_t *p_in = p_src->p[i].p_pixels;
798 uint8_t *p_out = p_dest->p[i].p_pixels;
800 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
801 int i_x_clip, i_y_clip;
803 /* Check boundaries, clip the image if necessary */
804 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
805 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
807 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
808 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
809 #if defined(FBOSD_DEBUG)
810 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
811 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
812 i_x_offset, i_y_offset, i_x, i_x_clip );
813 #endif
814 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
815 ( i_x <= p_dest->p[i].i_visible_pitch ) )
817 int i_line;
819 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
820 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
822 vlc_memcpy( p_out + i_x, p_in,
823 p_src->p[i].i_visible_pitch - i_x_clip );
824 p_in += p_src->p[i].i_pitch;
825 p_out += p_dest->p[i].i_pitch;
830 return VLC_SUCCESS;
833 /*****************************************************************************
834 * RenderText - Render text to the desired picture format
835 *****************************************************************************/
836 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
837 text_style_t *p_style, video_format_t *p_fmt )
839 intf_sys_t *p_sys = p_intf->p_sys;
840 subpicture_region_t *p_region;
841 picture_t *p_dest = NULL;
843 if( !psz_string ) return p_dest;
845 if( p_sys->p_text && p_sys->p_text->p_module )
847 video_format_t fmt;
849 memset( &fmt, 0, sizeof(fmt) );
850 fmt.i_chroma = VLC_CODEC_TEXT;
851 fmt.i_width = fmt.i_visible_width = 0;
852 fmt.i_height = fmt.i_visible_height = 0;
853 fmt.i_x_offset = 0;
854 fmt.i_y_offset = 0;
856 p_region = subpicture_region_New( &fmt );
857 if( !p_region )
858 return p_dest;
860 p_region->psz_text = strdup( psz_string );
861 if( !p_region->psz_text )
863 subpicture_region_Delete( p_region );
864 return NULL;
866 p_region->p_style = text_style_Duplicate( p_style );
867 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
869 if( p_sys->p_text->pf_render_text )
871 video_format_t fmt_out;
873 memset( &fmt_out, 0, sizeof(video_format_t) );
875 p_sys->p_text->pf_render_text( p_sys->p_text,
876 p_region, p_region );
878 #if defined(FBOSD_BLENDING)
879 fmt_out = p_region->fmt;
880 fmt_out.i_bits_per_pixel = 32;
881 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
883 /* FIXME not needed to copy the picture anymore no ? */
884 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
885 if( !p_dest )
887 subpicture_region_Delete( p_region );
888 return NULL;
890 picture_Copy( p_dest, p_region->p_picture );
891 #else
892 fmt_out.i_chroma = p_fmt->i_chroma;
893 p_dest = ConvertImage( p_intf, p_region->p_picture,
894 &p_region->fmt, &fmt_out );
895 #endif
896 subpicture_region_Delete( p_region );
897 return p_dest;
899 subpicture_region_Delete( p_region );
901 return p_dest;
904 /*****************************************************************************
905 * LoadImage: Load an image from file into a picture buffer.
906 *****************************************************************************/
907 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
908 char *psz_file )
910 picture_t *p_pic = NULL;
912 if( psz_file && p_intf->p_sys->p_image )
914 video_format_t fmt_in, fmt_out;
916 memset( &fmt_in, 0, sizeof(fmt_in) );
917 memset( &fmt_out, 0, sizeof(fmt_out) );
919 fmt_out.i_chroma = p_fmt->i_chroma;
920 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
921 &fmt_in, &fmt_out );
923 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
924 fmt_out.i_width, fmt_out.i_height,
925 (char *)&p_fmt->i_chroma );
927 return p_pic;
930 #if ! defined(FBOSD_BLENDING)
931 /*****************************************************************************
932 * Convertmage: Convert image to another fourcc
933 *****************************************************************************/
934 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
935 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
937 intf_sys_t *p_sys = p_intf->p_sys;
938 picture_t *p_old = NULL;
940 if( p_sys->p_image )
942 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
944 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
945 p_fmt_out->i_width, p_fmt_out->i_height,
946 (char *)&p_fmt_out->i_chroma );
948 return p_old;
950 #endif
952 /*****************************************************************************
953 * Init: initialize framebuffer video thread output method
954 *****************************************************************************/
955 static int Init( intf_thread_t *p_intf )
957 intf_sys_t *p_sys = p_intf->p_sys;
959 /* Initialize the output structure: RGB with square pixels, whatever
960 * the input format is, since it's the only format we know */
961 switch( p_sys->var_info.bits_per_pixel )
963 case 8: /* FIXME: set the palette */
964 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB8; break;
965 case 15:
966 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB15; break;
967 case 16:
968 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB16; break;
969 case 24:
970 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB24; break;
971 case 32:
972 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB32; break;
973 default:
974 msg_Err( p_intf, "unknown screen depth %i",
975 p_sys->var_info.bits_per_pixel );
976 return VLC_EGENERIC;
979 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
980 p_sys->fmt_out.i_width = p_sys->i_width;
981 p_sys->fmt_out.i_height = p_sys->i_height;
983 /* Assume we have square pixels */
984 if( p_sys->i_aspect < 0 )
986 p_sys->fmt_out.i_sar_num = 1;
987 p_sys->fmt_out.i_sar_den = 1;
989 else
991 p_sys->fmt_out.i_sar_num = p_sys->i_aspect * p_sys->i_height;
992 p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
995 /* Allocate overlay buffer */
996 p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
997 if( !p_sys->p_overlay ) return VLC_EGENERIC;
999 SetOverlayTransparency( p_intf, true );
1001 /* We know the chroma, allocate a buffer which will be used
1002 * to write to the overlay framebuffer */
1003 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1004 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1005 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1007 if( p_sys->var_info.xres_virtual )
1009 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1010 * p_sys->i_bytes_per_pixel;
1012 else
1014 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1015 * p_sys->i_bytes_per_pixel;
1018 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1019 * p_sys->i_bytes_per_pixel;
1021 p_sys->p_overlay->i_planes = 1;
1023 return VLC_SUCCESS;
1026 /*****************************************************************************
1027 * End: terminate framebuffer interface
1028 *****************************************************************************/
1029 static void End( intf_thread_t *p_intf )
1031 intf_sys_t *p_sys = p_intf->p_sys;
1033 /* CleanUp */
1034 SetOverlayTransparency( p_intf, false );
1035 if( p_sys->p_overlay )
1037 int ret;
1038 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1039 p_sys->i_page_size );
1040 if( ret < 0 )
1041 msg_Err( p_intf, "unable to clear overlay" );
1044 DeAllocatePicture( p_intf->p_sys->p_overlay,
1045 &p_intf->p_sys->fmt_out );
1046 p_intf->p_sys->p_overlay = NULL;
1049 /*****************************************************************************
1050 * OpenDisplay: initialize framebuffer
1051 *****************************************************************************/
1052 static int OpenDisplay( intf_thread_t *p_intf )
1054 intf_sys_t *p_sys = p_intf->p_sys;
1055 char *psz_device; /* framebuffer device path */
1056 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1058 /* Open framebuffer device */
1059 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1061 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1062 return VLC_EGENERIC;
1065 p_sys->i_fd = utf8_open( psz_device, O_RDWR );
1066 if( p_sys->i_fd == -1 )
1068 msg_Err( p_intf, "cannot open %s (%m)", psz_device );
1069 free( psz_device );
1070 return VLC_EGENERIC;
1072 free( psz_device );
1074 /* Get framebuffer device information */
1075 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1077 msg_Err( p_intf, "cannot get fb info (%m)" );
1078 close( p_sys->i_fd );
1079 return VLC_EGENERIC;
1082 /* Get some info on the framebuffer itself */
1083 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1085 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1086 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1089 /* FIXME: if the image is full-size, it gets cropped on the left
1090 * because of the xres / xres_virtual slight difference */
1091 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1092 p_sys->var_info.xres, p_sys->var_info.yres,
1093 p_sys->var_info.xres_virtual,
1094 p_sys->var_info.yres_virtual );
1096 p_sys->fmt_out.i_width = p_sys->i_width;
1097 p_sys->fmt_out.i_height = p_sys->i_height;
1099 p_sys->p_palette = NULL;
1100 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1102 switch( p_sys->var_info.bits_per_pixel )
1104 case 8:
1105 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1106 if( !p_sys->p_palette )
1108 close( p_sys->i_fd );
1109 return VLC_ENOMEM;
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 );
1118 /* Save the colormap */
1119 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1121 p_sys->i_bytes_per_pixel = 1;
1122 break;
1124 case 15:
1125 case 16:
1126 p_sys->i_bytes_per_pixel = 2;
1127 break;
1129 case 24:
1130 p_sys->i_bytes_per_pixel = 3;
1131 break;
1133 case 32:
1134 p_sys->i_bytes_per_pixel = 4;
1135 break;
1137 default:
1138 msg_Err( p_intf, "screen depth %d is not supported",
1139 p_sys->var_info.bits_per_pixel );
1141 close( p_sys->i_fd );
1142 return VLC_EGENERIC;
1145 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1146 * p_sys->i_bytes_per_pixel;
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;
1154 /*****************************************************************************
1155 * CloseDisplay: terminate FB interface thread
1156 *****************************************************************************/
1157 static void CloseDisplay( intf_thread_t *p_intf )
1159 intf_sys_t *p_sys = p_intf->p_sys;
1161 /* Restore palette */
1162 if( p_sys->var_info.bits_per_pixel == 8 )
1164 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1165 free( p_sys->p_palette );
1166 p_sys->p_palette = NULL;
1169 /* Close fb */
1170 close( p_sys->i_fd );
1173 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1175 intf_sys_t *p_sys = p_intf->p_sys;
1177 if( render->i_state != FBOSD_STATE_RENDER ) return;
1178 if( !render->psz_string ) return;
1180 if( render->i_type == FBOSD_RENDER_IMAGE )
1182 picture_t *p_pic;
1183 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1184 if( p_pic )
1186 RenderPicture( p_intf, render->i_x, render->i_y,
1187 p_pic, p_sys->p_overlay );
1188 picture_Release( p_pic );
1191 else if( render->i_type == FBOSD_RENDER_TEXT )
1193 picture_t *p_text;
1194 #if defined(FBOSD_BLENDING)
1195 video_format_t fmt_in;
1196 memset( &fmt_in, 0, sizeof(video_format_t) );
1197 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1198 &fmt_in );
1199 if( p_text )
1201 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1202 p_text, p_sys->p_overlay );
1203 msg_Dbg( p_intf, "releasing picture" );
1204 DeAllocatePicture( p_text, &fmt_in );
1206 #else
1207 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1208 &p_sys->fmt_out );
1209 if( p_text )
1211 RenderPicture( p_intf, render->i_x, render->i_y,
1212 p_text, p_sys->p_overlay );
1213 picture_Release( p_text );
1215 #endif
1219 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1221 intf_sys_t *p_sys = p_intf->p_sys;
1223 text_style_Delete( render->p_text_style );
1224 render->p_text_style = text_style_New();
1225 free( render->psz_string );
1226 render->psz_string = NULL;
1228 render->i_x = p_sys->i_x;
1229 render->i_y = p_sys->i_y;
1230 render->i_pos = p_sys->i_pos;
1231 render->i_alpha = p_sys->i_alpha;
1232 render->b_absolute = p_sys->b_absolute;
1233 render->i_state = FBOSD_STATE_FREE;
1236 static bool isRendererReady( intf_thread_t *p_intf )
1238 intf_sys_t *p_sys = p_intf->p_sys;
1239 int i;
1241 /* Check if there are more items to render */
1242 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1244 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1245 return false;
1247 return true;
1250 /*****************************************************************************
1251 * Run: thread
1252 *****************************************************************************
1253 * This part of the interface is in a separate thread so that we can call
1254 * exec() from within it without annoying the rest of the program.
1255 *****************************************************************************/
1256 static void Run( intf_thread_t *p_intf )
1258 intf_sys_t *p_sys = p_intf->p_sys;
1259 int canc = vlc_savecancel();
1261 while( vlc_object_alive( p_intf ) )
1263 int i;
1265 /* Is there somthing to render? */
1266 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1268 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1270 Render( p_intf, &p_sys->render[i] );
1271 RenderClear( p_intf, &p_sys->render[i] );
1275 if( p_sys->b_clear )
1277 SetOverlayTransparency( p_intf, true );
1279 var_SetString( p_intf, "fbosd-image", "" );
1280 var_SetString( p_intf, "fbosd-text", "" );
1282 p_sys->b_clear = false;
1283 p_sys->b_need_update = true;
1286 if( p_sys->b_need_update && p_sys->p_overlay &&
1287 isRendererReady( p_intf ) )
1289 int ret;
1290 #if defined(FBOSD_BLENDING)
1291 /* Reverse alpha channel to work around FPGA bug */
1292 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1293 #endif
1294 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1295 p_sys->i_page_size );
1296 if( ret < 0 )
1297 msg_Err( p_intf, "unable to write to overlay" );
1298 lseek( p_sys->i_fd, 0, SEEK_SET );
1300 /* clear the picture */
1301 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1302 p_sys->b_need_update = false;
1305 msleep( INTF_IDLE_SLEEP );
1308 End( p_intf );
1309 vlc_restorecancel( canc );
1312 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1313 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1315 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1316 intf_sys_t *p_sys = p_intf->p_sys;
1317 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1319 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1321 p_sys->b_need_update = true;
1323 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1325 int i;
1326 /* Clear the entire render list */
1327 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1329 RenderClear( p_intf, &p_sys->render[i] );
1331 p_sys->b_clear = true;
1333 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1335 int i;
1336 /* Are we already busy with on slot ? */
1337 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1339 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1341 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1342 break;
1346 else
1348 int i;
1349 /* Are we already busy with on slot ? */
1350 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1352 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1353 break;
1355 /* No, then find first FREE slot */
1356 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1358 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1360 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1361 break;
1363 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1365 msg_Warn( p_this, "render space depleated" );
1366 return VLC_SUCCESS;
1369 /* Found a free slot */
1370 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1371 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1373 free( p_sys->render[i].psz_string );
1374 p_sys->render[i].psz_string = strdup( newval.psz_string );
1375 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1377 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1379 free( p_sys->render[i].psz_string );
1380 p_sys->render[i].psz_string = strdup( newval.psz_string );
1381 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1383 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1385 p_sys->render[i].b_absolute = false;
1386 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1387 newval.i_int : p_sys->i_width;
1389 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1391 p_sys->render[i].b_absolute = false;
1392 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1393 newval.i_int : p_sys->i_height;
1395 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1397 p_sys->render[i].b_absolute = true;
1398 p_sys->render[i].i_pos = newval.i_int;
1400 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1402 p_sys->render[i].p_text_style->i_font_size = newval.i_int;
1404 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1406 p_sys->render[i].p_text_style->i_font_color = newval.i_int;
1408 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1410 p_sys->render[i].p_text_style->i_font_alpha = 255 - newval.i_int;
1412 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1414 p_sys->render[i].i_alpha = newval.i_int;
1417 return VLC_SUCCESS;