skins2(Linux): check if _NET_WM_PID is supported
[vlc/asuraparaju-public.git] / modules / gui / fbosd.c
blobe55941e32f324178438f9700d2300529882e83a3
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>
36 #include <stdlib.h> /* free() */
37 #include <string.h> /* strerror() */
38 #include <fcntl.h> /* open() */
39 #include <unistd.h> /* close() */
41 #include <sys/ioctl.h>
42 #include <sys/mman.h> /* mmap() */
44 #include <linux/fb.h>
46 #include <vlc_image.h>
47 #include <vlc_interface.h>
48 #include <vlc_input.h>
49 #include <vlc_vout.h>
50 #include <vlc_filter.h>
51 #include <vlc_osd.h>
52 #include <vlc_strings.h>
54 #undef FBOSD_BLENDING
55 #undef FBOSD_DEBUG
57 /*****************************************************************************
58 * Local prototypes
59 *****************************************************************************/
60 static int Create ( vlc_object_t * );
61 static void Destroy ( vlc_object_t * );
62 static void Run ( intf_thread_t * );
64 static int Init ( intf_thread_t * );
65 static void End ( intf_thread_t * );
67 static int OpenDisplay ( intf_thread_t * );
68 static void CloseDisplay ( intf_thread_t * );
70 /* Load modules needed for rendering and blending */
71 #if defined(FBOSD_BLENDING)
72 static int OpenBlending ( intf_thread_t * );
73 static void CloseBlending ( intf_thread_t * );
74 #endif
75 static int OpenTextRenderer ( intf_thread_t * );
76 static void CloseTextRenderer( intf_thread_t * );
78 /* Manipulate the overlay buffer */
79 static int OverlayCallback( vlc_object_t *, char const *,
80 vlc_value_t, vlc_value_t, void * );
82 static picture_t *AllocatePicture( video_format_t * );
83 static void DeAllocatePicture( picture_t *, video_format_t * );
84 static void SetOverlayTransparency( intf_thread_t *,
85 bool );
86 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
87 char * );
89 #if defined(FBOSD_BLENDING)
90 static int BlendPicture( intf_thread_t *, video_format_t *,
91 video_format_t *, picture_t *, picture_t * );
92 #else
93 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
94 video_format_t *, video_format_t * );
95 #endif
96 static int RenderPicture( intf_thread_t *, int, int,
97 picture_t *, picture_t * );
98 static picture_t *RenderText( intf_thread_t *, const char *,
99 text_style_t *, video_format_t * );
101 #define DEVICE_TEXT N_("Framebuffer device")
102 #define DEVICE_LONGTEXT N_( \
103 "Framebuffer device to use for rendering (usually /dev/fb0).")
105 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
106 #define ASPECT_RATIO_LONGTEXT N_( \
107 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
109 #define FBOSD_IMAGE_TEXT N_("Image file")
110 #define FBOSD_IMAGE_LONGTEXT N_( \
111 "Filename of image file to use on the overlay framebuffer." )
113 #define ALPHA_TEXT N_("Transparency of the image")
114 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
115 "used in blending. By default it set to fully opaque (255). " \
116 "(from 0 for full transparency to 255 for full opacity)" )
118 #define FBOSD_TEXT N_("Text")
119 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
121 #define POSX_TEXT N_("X coordinate")
122 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
124 #define POSY_TEXT N_("Y coordinate")
125 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
127 #define POS_TEXT N_("Position")
128 #define POS_LONGTEXT N_( \
129 "You can enforce the picture position on the overlay " \
130 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
131 "also use combinations of these values, e.g. 6=top-right).")
133 #define OPACITY_TEXT N_("Opacity")
134 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
135 "overlayed text. 0 = transparent, 255 = totally opaque. " )
137 #define SIZE_TEXT N_("Font size, pixels")
138 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
139 "font size)." )
141 #define COLOR_TEXT N_("Color")
142 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
143 "the video. This must be an hexadecimal (like HTML colors). The first two "\
144 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
145 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
147 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
148 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
149 "making the overlay completely transparent. All previously rendered " \
150 "images and text will be cleared from the cache." )
152 #define RENDER_TEXT N_( "Render text or image" )
153 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
154 "buffer." )
156 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
157 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
158 "displayed on the overlay framebuffer." )
160 static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
161 static const char *const ppsz_pos_descriptions[] =
162 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
163 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
165 static const int pi_color_values[] = {
166 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
167 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
168 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
169 0x00000080, 0x000000FF, 0x0000FFFF};
170 static const char *const ppsz_color_descriptions[] = {
171 N_("Default"), N_("Black"),
172 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
173 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
174 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
175 N_("Aqua") };
177 vlc_module_begin ()
178 set_shortname( "fbosd" )
179 set_category( CAT_INTERFACE )
180 set_subcategory( SUBCAT_INTERFACE_MAIN )
182 add_file( "fbosd-dev", "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
183 false )
184 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
185 ASPECT_RATIO_LONGTEXT, true )
187 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
188 FBOSD_IMAGE_LONGTEXT, true )
189 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
190 FBOSD_LONGTEXT, true )
192 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
193 ALPHA_LONGTEXT, true )
195 set_section( N_("Position"), NULL )
196 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
197 POSX_LONGTEXT, false )
198 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
199 POSY_LONGTEXT, false )
200 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
201 change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
203 set_section( N_("Font"), NULL )
204 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
205 OPACITY_TEXT, OPACITY_LONGTEXT, false )
206 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
207 false )
208 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
209 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
210 false )
212 set_section( N_("Commands"), NULL )
213 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
214 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
215 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
217 set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
218 set_capability( "interface", 10 )
219 set_callbacks( Create, Destroy )
220 vlc_module_end ()
222 /*****************************************************************************
223 * fbosd_render_t: render descriptor
224 *****************************************************************************/
225 struct fbosd_render_t
227 #define FBOSD_RENDER_IMAGE 0
228 #define FBOSD_RENDER_TEXT 1
229 int i_type;
231 #define FBOSD_STATE_FREE 0
232 #define FBOSD_STATE_RESERVED 1
233 #define FBOSD_STATE_RENDER 2
234 int i_state;
236 /* Font style */
237 text_style_t* p_text_style; /* font control */
238 char *psz_string;
240 /* Position */
241 bool b_absolute;
242 int i_x;
243 int i_y;
244 int i_pos;
245 int i_alpha; /* transparency for images */
247 #define FBOSD_RENDER_MAX 10
249 /*****************************************************************************
250 * intf_sys_t: interface framebuffer method descriptor
251 *****************************************************************************/
252 struct intf_sys_t
254 /* Framebuffer information */
255 int i_fd; /* device handle */
256 struct fb_var_screeninfo var_info; /* current mode information */
257 bool b_pan; /* does device supports panning ? */
258 struct fb_cmap fb_cmap; /* original colormap */
259 uint16_t *p_palette; /* original palette */
261 /* Overlay framebuffer format */
262 video_format_t fmt_out;
263 picture_t *p_overlay;
264 size_t i_page_size; /* page size */
265 int i_width;
266 int i_height;
267 int i_aspect;
268 int i_bytes_per_pixel;
270 /* Image and Picture rendering */
271 image_handler_t *p_image;
272 #if defined(FBOSD_BLENDING)
273 filter_t *p_blend; /* alpha blending module */
274 #endif
275 filter_t *p_text; /* text renderer module */
277 /* Render */
278 struct fbosd_render_t render[FBOSD_RENDER_MAX];
280 /* Font style */
281 text_style_t *p_style; /* font control */
283 /* Position */
284 bool b_absolute;
285 int i_x;
286 int i_y;
287 int i_pos;
289 int i_alpha; /* transparency for images */
291 /* commands control */
292 bool b_need_update; /* update display with \overlay buffer */
293 bool b_clear; /* clear overlay buffer make it tranparent */
294 bool b_render; /* render an image or text in overlay buffer */
297 /*****************************************************************************
298 * Create: allocates FB interface thread output method
299 *****************************************************************************/
300 static int Create( vlc_object_t *p_this )
302 intf_thread_t *p_intf = (intf_thread_t *)p_this;
303 intf_sys_t *p_sys;
304 char *psz_aspect;
305 char *psz_tmp;
306 int i;
308 /* Allocate instance and initialize some members */
309 p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
310 if( !p_intf->p_sys )
311 return VLC_ENOMEM;
313 p_sys->p_style = text_style_New();
314 if( !p_sys->p_style )
316 free( p_intf->p_sys );
317 return VLC_ENOMEM;
320 p_intf->pf_run = Run;
322 p_sys->p_image = image_HandlerCreate( p_this );
323 if( !p_sys->p_image )
325 text_style_Delete( p_sys->p_style );
326 free( p_sys );
327 return VLC_ENOMEM;
330 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
331 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
333 /* Use PAL by default */
334 p_sys->i_width = p_sys->fmt_out.i_width = 704;
335 p_sys->i_height = p_sys->fmt_out.i_height = 576;
337 p_sys->i_aspect = -1;
338 psz_aspect =
339 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
340 if( psz_aspect )
342 char *psz_parser = strchr( psz_aspect, ':' );
344 if( psz_parser )
346 *psz_parser++ = '\0';
347 p_sys->i_aspect = ( atoi( psz_aspect )
348 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
349 p_sys->fmt_out.i_sar_num = p_sys->i_aspect * p_sys->i_height;
350 p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
352 msg_Dbg( p_intf, "using aspect ratio %d:%d",
353 atoi( psz_aspect ), atoi( psz_parser ) );
355 free( psz_aspect );
358 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
359 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
360 if( psz_tmp && *psz_tmp )
362 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
363 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
364 p_sys->render[0].psz_string = strdup( psz_tmp );
366 free( psz_tmp );
368 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
369 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
370 if( psz_tmp && *psz_tmp )
372 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
373 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
374 p_sys->render[1].psz_string = strdup( psz_tmp );
376 free( psz_tmp );
378 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
379 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
380 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
382 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
383 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
384 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
386 p_sys->p_style->i_font_size =
387 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
388 p_sys->p_style->i_font_color =
389 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
390 p_sys->p_style->i_font_alpha = 255 -
391 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
393 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
394 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
395 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
397 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
398 p_sys->render[i].p_text_style = text_style_New();
400 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
401 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
402 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
404 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
405 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
406 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
408 /* Check if picture position was overridden */
409 p_sys->b_absolute = true;
410 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
412 p_sys->b_absolute = false;
413 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
414 p_sys->i_y : p_sys->i_height;
415 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
416 p_sys->i_x : p_sys->i_width;
419 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
420 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
421 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
422 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
424 /* Initialize framebuffer */
425 if( OpenDisplay( p_intf ) )
427 Destroy( VLC_OBJECT(p_intf) );
428 return VLC_EGENERIC;
431 Init( p_intf );
433 #if defined(FBOSD_BLENDING)
434 /* Load the blending module */
435 if( OpenBlending( p_intf ) )
437 msg_Err( p_intf, "Unable to load image blending module" );
438 Destroy( VLC_OBJECT(p_intf) );
439 return VLC_EGENERIC;
441 #endif
443 /* Load text renderer module */
444 if( OpenTextRenderer( p_intf ) )
446 msg_Err( p_intf, "Unable to load text rendering module" );
447 Destroy( VLC_OBJECT(p_intf) );
448 return VLC_EGENERIC;
451 p_sys->b_render = true;
452 p_sys->b_need_update = true;
454 return VLC_SUCCESS;
457 /*****************************************************************************
458 * Destroy: destroy FB interface thread output method
459 *****************************************************************************
460 * Terminate an output method created by Create
461 *****************************************************************************/
462 static void Destroy( vlc_object_t *p_this )
464 intf_thread_t *p_intf = (intf_thread_t *)p_this;
465 intf_sys_t *p_sys = p_intf->p_sys;
466 int i;
469 p_sys->b_need_update = false;
470 p_sys->b_render = false;
471 p_sys->b_clear = false;
473 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
474 var_Destroy( p_intf, "fbosd-alpha" );
476 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
477 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
478 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
479 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
480 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
481 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
482 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
488 var_Destroy( p_intf, "fbosd-x" );
489 var_Destroy( p_intf, "fbosd-y" );
490 var_Destroy( p_intf, "fbosd-position" );
491 var_Destroy( p_intf, "fbosd-image" );
492 var_Destroy( p_intf, "fbosd-text" );
493 var_Destroy( p_intf, "fbosd-font-size" );
494 var_Destroy( p_intf, "fbosd-font-color" );
495 var_Destroy( p_intf, "fbosd-font-opacity" );
496 var_Destroy( p_intf, "fbosd-clear" );
497 var_Destroy( p_intf, "fbosd-render" );
498 var_Destroy( p_intf, "fbosd-display" );
500 var_Destroy( p_intf, "fbosd-aspect-ratio" );
502 CloseDisplay( p_intf );
504 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
506 free( p_sys->render[i].psz_string );
507 p_sys->render[i].i_state = FBOSD_STATE_FREE;
508 text_style_Delete( p_sys->render[i].p_text_style );
511 #if defined(FBOSD_BLENDING)
512 if( p_sys->p_blend ) CloseBlending( p_intf );
513 #endif
514 if( p_sys->p_text ) CloseTextRenderer( p_intf );
516 if( p_sys->p_image )
517 image_HandlerDelete( p_sys->p_image );
518 if( p_sys->p_overlay )
519 picture_Release( p_sys->p_overlay );
521 text_style_Delete( p_sys->p_style );
522 free( p_sys );
525 #if defined(FBOSD_BLENDING)
526 static int OpenBlending( intf_thread_t *p_intf )
528 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
530 p_intf->p_sys->p_blend =
531 vlc_object_create( p_intf, sizeof(filter_t) );
532 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
533 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
534 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
535 p_intf->p_sys->p_blend->fmt_out.video.i_sar_num =
536 p_intf->p_sys->fmt_out.i_sar_num;
537 p_intf->p_sys->p_blend->fmt_out.video.i_sar_den =
538 p_intf->p_sys->fmt_out.i_sar_den;
539 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
540 p_intf->p_sys->fmt_out.i_chroma;
541 if( var_InheritBool( p_intf, "freetype-yuvp" ) )
542 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
543 VLC_CODEC_YUVP;
544 else
545 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
546 VLC_CODEC_YUVA;
548 p_intf->p_sys->p_blend->p_module =
549 module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
551 if( !p_intf->p_sys->p_blend->p_module )
552 return VLC_EGENERIC;
554 return VLC_SUCCESS;
557 static void CloseBlending( intf_thread_t *p_intf )
559 if( p_intf->p_sys->p_blend )
561 if( p_intf->p_sys->p_blend->p_module )
562 module_unneed( p_intf->p_sys->p_blend,
563 p_intf->p_sys->p_blend->p_module );
565 vlc_object_release( p_intf->p_sys->p_blend );
568 #endif
570 static int OpenTextRenderer( intf_thread_t *p_intf )
572 char *psz_modulename = NULL;
574 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
576 p_intf->p_sys->p_text =
577 vlc_object_create( p_intf, sizeof(filter_t) );
578 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
580 p_intf->p_sys->p_text->fmt_out.video.i_width =
581 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
582 p_intf->p_sys->i_width;
583 p_intf->p_sys->p_text->fmt_out.video.i_height =
584 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
585 p_intf->p_sys->i_height;
587 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
588 if( psz_modulename && *psz_modulename )
590 p_intf->p_sys->p_text->p_module =
591 module_need( p_intf->p_sys->p_text, "text renderer",
592 psz_modulename, true );
594 if( !p_intf->p_sys->p_text->p_module )
596 p_intf->p_sys->p_text->p_module =
597 module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
599 free( psz_modulename );
601 if( !p_intf->p_sys->p_text->p_module )
602 return VLC_EGENERIC;
604 return VLC_SUCCESS;
607 static void CloseTextRenderer( intf_thread_t *p_intf )
609 if( p_intf->p_sys->p_text )
611 if( p_intf->p_sys->p_text->p_module )
612 module_unneed( p_intf->p_sys->p_text,
613 p_intf->p_sys->p_text->p_module );
615 vlc_object_release( p_intf->p_sys->p_text );
619 /*****************************************************************************
620 * AllocatePicture:
621 * allocate a picture buffer for use with the overlay fb.
622 *****************************************************************************/
623 static picture_t *AllocatePicture( video_format_t *p_fmt )
625 picture_t *p_picture = picture_NewFromFormat( p_fmt );
626 if( !p_picture )
627 return NULL;
629 if( !p_fmt->p_palette &&
630 ( p_fmt->i_chroma == VLC_CODEC_YUVP ) )
632 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
633 if( !p_fmt->p_palette )
635 picture_Release( p_picture );
636 return NULL;
639 else
641 p_fmt->p_palette = NULL;
644 return p_picture;
647 /*****************************************************************************
648 * DeAllocatePicture:
649 * Deallocate a picture buffer and free all associated memory.
650 *****************************************************************************/
651 static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
653 if( p_fmt )
655 free( p_fmt->p_palette );
656 p_fmt->p_palette = NULL;
659 if( p_pic )
660 picture_Release( p_pic );
663 /*****************************************************************************
664 * SetOverlayTransparency: Set the transparency for this overlay fb,
665 * - true is make transparent
666 * - false is make non tranparent
667 *****************************************************************************/
668 static void SetOverlayTransparency( intf_thread_t *p_intf,
669 bool b_transparent )
671 intf_sys_t *p_sys = p_intf->p_sys;
672 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
673 * p_sys->i_bytes_per_pixel;
674 size_t i_page_size = (p_sys->i_page_size > i_size) ?
675 i_size : p_sys->i_page_size;
677 if( p_sys->p_overlay )
679 msg_Dbg( p_intf, "Make overlay %s",
680 b_transparent ? "transparent" : "opaque" );
681 if( b_transparent )
682 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
683 else
684 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
688 #if defined(FBOSD_BLENDING)
689 /*****************************************************************************
690 * BlendPicture: Blend two pictures together..
691 *****************************************************************************/
692 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
693 video_format_t *p_fmt_dst, picture_t *p_pic_src,
694 picture_t *p_pic_dst )
696 intf_sys_t *p_sys = p_intf->p_sys;
697 if( p_sys->p_blend && p_sys->p_blend->p_module )
699 int i_x_offset = p_sys->i_x;
700 int i_y_offset = p_sys->i_y;
702 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
704 /* Update the output picture size */
705 p_sys->p_blend->fmt_out.video.i_width =
706 p_sys->p_blend->fmt_out.video.i_visible_width =
707 p_fmt_dst->i_width;
708 p_sys->p_blend->fmt_out.video.i_height =
709 p_sys->p_blend->fmt_out.video.i_visible_height =
710 p_fmt_dst->i_height;
712 i_x_offset = __MAX( i_x_offset, 0 );
713 i_y_offset = __MAX( i_y_offset, 0 );
715 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
716 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
717 p_sys->i_alpha );
719 return VLC_SUCCESS;
721 return VLC_EGENERIC;
724 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
726 uint8_t *p_begin = NULL, *p_end = NULL;
727 uint8_t i_skip = 0;
729 if( *p_pic && ((*p_pic)->i_planes != 1) )
731 msg_Err( p_intf,
732 "cannot invert alpha channel too many planes %d (only 1 supported)",
733 (*p_pic)->i_planes );
734 return VLC_EGENERIC;
737 switch( fmt.i_chroma )
739 case VLC_CODEC_RGB24:
740 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
741 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
742 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
743 i_skip = 3;
744 break;
745 case VLC_CODEC_RGB32:
746 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
747 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
748 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
749 i_skip = 4;
750 break;
751 default:
752 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
753 (char *)&fmt.i_chroma );
754 return VLC_EGENERIC;
757 for( ; p_begin < p_end; p_begin += i_skip )
759 uint8_t i_opacity = 0;
761 if( *p_begin != 0xFF )
762 i_opacity = 255 - *p_begin;
763 *p_begin = i_opacity;
765 /* end of kludge */
766 return VLC_SUCCESS;
768 #endif
770 /*****************************************************************************
771 * RenderPicture: Render the picture into the p_dest buffer.
772 * We don't take transparent pixels into account, so we don't have to blend
773 * the two images together.
774 *****************************************************************************/
775 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
776 picture_t *p_src, picture_t *p_dest )
778 int i;
779 VLC_UNUSED( p_intf );
781 if( !p_dest && !p_src ) return VLC_EGENERIC;
783 for( i = 0; i < p_src->i_planes ; i++ )
785 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
787 /* There are margins, but with the same width : perfect ! */
788 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
789 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
791 else
793 /* We need to proceed line by line */
794 uint8_t *p_in = p_src->p[i].p_pixels;
795 uint8_t *p_out = p_dest->p[i].p_pixels;
797 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
798 int i_x_clip, i_y_clip;
800 /* Check boundaries, clip the image if necessary */
801 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
802 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
804 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
805 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
806 #if defined(FBOSD_DEBUG)
807 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
808 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
809 i_x_offset, i_y_offset, i_x, i_x_clip );
810 #endif
811 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
812 ( i_x <= p_dest->p[i].i_visible_pitch ) )
814 int i_line;
816 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
817 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
819 vlc_memcpy( p_out + i_x, p_in,
820 p_src->p[i].i_visible_pitch - i_x_clip );
821 p_in += p_src->p[i].i_pitch;
822 p_out += p_dest->p[i].i_pitch;
827 return VLC_SUCCESS;
830 /*****************************************************************************
831 * RenderText - Render text to the desired picture format
832 *****************************************************************************/
833 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
834 text_style_t *p_style, video_format_t *p_fmt )
836 intf_sys_t *p_sys = p_intf->p_sys;
837 subpicture_region_t *p_region;
838 picture_t *p_dest = NULL;
840 if( !psz_string ) return p_dest;
842 if( p_sys->p_text && p_sys->p_text->p_module )
844 video_format_t fmt;
846 memset( &fmt, 0, sizeof(fmt) );
847 fmt.i_chroma = VLC_CODEC_TEXT;
848 fmt.i_width = fmt.i_visible_width = 0;
849 fmt.i_height = fmt.i_visible_height = 0;
850 fmt.i_x_offset = 0;
851 fmt.i_y_offset = 0;
853 p_region = subpicture_region_New( &fmt );
854 if( !p_region )
855 return p_dest;
857 p_region->psz_text = strdup( psz_string );
858 if( !p_region->psz_text )
860 subpicture_region_Delete( p_region );
861 return NULL;
863 p_region->p_style = text_style_Duplicate( p_style );
864 p_region->i_align = SUBPICTURE_ALIGN_LEFT | SUBPICTURE_ALIGN_TOP;
866 if( p_sys->p_text->pf_render_text )
868 video_format_t fmt_out;
870 memset( &fmt_out, 0, sizeof(video_format_t) );
872 p_sys->p_text->pf_render_text( p_sys->p_text,
873 p_region, p_region );
875 #if defined(FBOSD_BLENDING)
876 fmt_out = p_region->fmt;
877 fmt_out.i_bits_per_pixel = 32;
878 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
880 /* FIXME not needed to copy the picture anymore no ? */
881 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
882 if( !p_dest )
884 subpicture_region_Delete( p_region );
885 return NULL;
887 picture_Copy( p_dest, p_region->p_picture );
888 #else
889 fmt_out.i_chroma = p_fmt->i_chroma;
890 p_dest = ConvertImage( p_intf, p_region->p_picture,
891 &p_region->fmt, &fmt_out );
892 #endif
893 subpicture_region_Delete( p_region );
894 return p_dest;
896 subpicture_region_Delete( p_region );
898 return p_dest;
901 /*****************************************************************************
902 * LoadImage: Load an image from file into a picture buffer.
903 *****************************************************************************/
904 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
905 char *psz_file )
907 picture_t *p_pic = NULL;
909 if( psz_file && p_intf->p_sys->p_image )
911 video_format_t fmt_in, fmt_out;
913 memset( &fmt_in, 0, sizeof(fmt_in) );
914 memset( &fmt_out, 0, sizeof(fmt_out) );
916 fmt_out.i_chroma = p_fmt->i_chroma;
917 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
918 &fmt_in, &fmt_out );
920 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
921 fmt_out.i_width, fmt_out.i_height,
922 (char *)&p_fmt->i_chroma );
924 return p_pic;
927 #if ! defined(FBOSD_BLENDING)
928 /*****************************************************************************
929 * Convertmage: Convert image to another fourcc
930 *****************************************************************************/
931 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
932 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
934 intf_sys_t *p_sys = p_intf->p_sys;
935 picture_t *p_old = NULL;
937 if( p_sys->p_image )
939 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
941 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
942 p_fmt_out->i_width, p_fmt_out->i_height,
943 (char *)&p_fmt_out->i_chroma );
945 return p_old;
947 #endif
949 /*****************************************************************************
950 * Init: initialize framebuffer video thread output method
951 *****************************************************************************/
952 static int Init( intf_thread_t *p_intf )
954 intf_sys_t *p_sys = p_intf->p_sys;
956 /* Initialize the output structure: RGB with square pixels, whatever
957 * the input format is, since it's the only format we know */
958 switch( p_sys->var_info.bits_per_pixel )
960 case 8: /* FIXME: set the palette */
961 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB8; break;
962 case 15:
963 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB15; break;
964 case 16:
965 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB16; break;
966 case 24:
967 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB24; break;
968 case 32:
969 p_sys->fmt_out.i_chroma = VLC_CODEC_RGB32; break;
970 default:
971 msg_Err( p_intf, "unknown screen depth %i",
972 p_sys->var_info.bits_per_pixel );
973 return VLC_EGENERIC;
976 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
977 p_sys->fmt_out.i_width = p_sys->i_width;
978 p_sys->fmt_out.i_height = p_sys->i_height;
980 /* Assume we have square pixels */
981 if( p_sys->i_aspect < 0 )
983 p_sys->fmt_out.i_sar_num = 1;
984 p_sys->fmt_out.i_sar_den = 1;
986 else
988 p_sys->fmt_out.i_sar_num = p_sys->i_aspect * p_sys->i_height;
989 p_sys->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR * p_sys->i_width;
992 /* Allocate overlay buffer */
993 p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
994 if( !p_sys->p_overlay ) return VLC_EGENERIC;
996 SetOverlayTransparency( p_intf, true );
998 /* We know the chroma, allocate a buffer which will be used
999 * to write to the overlay framebuffer */
1000 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1001 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1002 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1004 if( p_sys->var_info.xres_virtual )
1006 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1007 * p_sys->i_bytes_per_pixel;
1009 else
1011 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1012 * p_sys->i_bytes_per_pixel;
1015 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1016 * p_sys->i_bytes_per_pixel;
1018 p_sys->p_overlay->i_planes = 1;
1020 return VLC_SUCCESS;
1023 /*****************************************************************************
1024 * End: terminate framebuffer interface
1025 *****************************************************************************/
1026 static void End( intf_thread_t *p_intf )
1028 intf_sys_t *p_sys = p_intf->p_sys;
1030 /* CleanUp */
1031 SetOverlayTransparency( p_intf, false );
1032 if( p_sys->p_overlay )
1034 int ret;
1035 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1036 p_sys->i_page_size );
1037 if( ret < 0 )
1038 msg_Err( p_intf, "unable to clear overlay" );
1041 DeAllocatePicture( p_intf->p_sys->p_overlay,
1042 &p_intf->p_sys->fmt_out );
1043 p_intf->p_sys->p_overlay = NULL;
1046 /*****************************************************************************
1047 * OpenDisplay: initialize framebuffer
1048 *****************************************************************************/
1049 static int OpenDisplay( intf_thread_t *p_intf )
1051 intf_sys_t *p_sys = p_intf->p_sys;
1052 char *psz_device; /* framebuffer device path */
1053 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1055 /* Open framebuffer device */
1056 if( !(psz_device = var_InheritString( p_intf, "fbosd-dev" )) )
1058 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1059 return VLC_EGENERIC;
1062 p_sys->i_fd = vlc_open( psz_device, O_RDWR );
1063 if( p_sys->i_fd == -1 )
1065 msg_Err( p_intf, "cannot open %s (%m)", psz_device );
1066 free( psz_device );
1067 return VLC_EGENERIC;
1069 free( psz_device );
1071 /* Get framebuffer device information */
1072 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1074 msg_Err( p_intf, "cannot get fb info (%m)" );
1075 close( p_sys->i_fd );
1076 return VLC_EGENERIC;
1079 /* Get some info on the framebuffer itself */
1080 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1082 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1083 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1086 /* FIXME: if the image is full-size, it gets cropped on the left
1087 * because of the xres / xres_virtual slight difference */
1088 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1089 p_sys->var_info.xres, p_sys->var_info.yres,
1090 p_sys->var_info.xres_virtual,
1091 p_sys->var_info.yres_virtual );
1093 p_sys->fmt_out.i_width = p_sys->i_width;
1094 p_sys->fmt_out.i_height = p_sys->i_height;
1096 p_sys->p_palette = NULL;
1097 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1099 switch( p_sys->var_info.bits_per_pixel )
1101 case 8:
1102 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1103 if( !p_sys->p_palette )
1105 close( p_sys->i_fd );
1106 return VLC_ENOMEM;
1108 p_sys->fb_cmap.start = 0;
1109 p_sys->fb_cmap.len = 256;
1110 p_sys->fb_cmap.red = p_sys->p_palette;
1111 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1112 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1113 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1115 /* Save the colormap */
1116 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1118 p_sys->i_bytes_per_pixel = 1;
1119 break;
1121 case 15:
1122 case 16:
1123 p_sys->i_bytes_per_pixel = 2;
1124 break;
1126 case 24:
1127 p_sys->i_bytes_per_pixel = 3;
1128 break;
1130 case 32:
1131 p_sys->i_bytes_per_pixel = 4;
1132 break;
1134 default:
1135 msg_Err( p_intf, "screen depth %d is not supported",
1136 p_sys->var_info.bits_per_pixel );
1138 close( p_sys->i_fd );
1139 return VLC_EGENERIC;
1142 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1143 * p_sys->i_bytes_per_pixel;
1145 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1146 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1147 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1148 return VLC_SUCCESS;
1151 /*****************************************************************************
1152 * CloseDisplay: terminate FB interface thread
1153 *****************************************************************************/
1154 static void CloseDisplay( intf_thread_t *p_intf )
1156 intf_sys_t *p_sys = p_intf->p_sys;
1158 /* Restore palette */
1159 if( p_sys->var_info.bits_per_pixel == 8 )
1161 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1162 free( p_sys->p_palette );
1163 p_sys->p_palette = NULL;
1166 /* Close fb */
1167 close( p_sys->i_fd );
1170 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1172 intf_sys_t *p_sys = p_intf->p_sys;
1174 if( render->i_state != FBOSD_STATE_RENDER ) return;
1175 if( !render->psz_string ) return;
1177 if( render->i_type == FBOSD_RENDER_IMAGE )
1179 picture_t *p_pic;
1180 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1181 if( p_pic )
1183 RenderPicture( p_intf, render->i_x, render->i_y,
1184 p_pic, p_sys->p_overlay );
1185 picture_Release( p_pic );
1188 else if( render->i_type == FBOSD_RENDER_TEXT )
1190 picture_t *p_text;
1191 #if defined(FBOSD_BLENDING)
1192 video_format_t fmt_in;
1193 memset( &fmt_in, 0, sizeof(video_format_t) );
1194 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1195 &fmt_in );
1196 if( p_text )
1198 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1199 p_text, p_sys->p_overlay );
1200 msg_Dbg( p_intf, "releasing picture" );
1201 DeAllocatePicture( p_text, &fmt_in );
1203 #else
1204 p_text = RenderText( p_intf, render->psz_string, render->p_text_style,
1205 &p_sys->fmt_out );
1206 if( p_text )
1208 RenderPicture( p_intf, render->i_x, render->i_y,
1209 p_text, p_sys->p_overlay );
1210 picture_Release( p_text );
1212 #endif
1216 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1218 intf_sys_t *p_sys = p_intf->p_sys;
1220 text_style_Delete( render->p_text_style );
1221 render->p_text_style = text_style_New();
1222 free( render->psz_string );
1223 render->psz_string = NULL;
1225 render->i_x = p_sys->i_x;
1226 render->i_y = p_sys->i_y;
1227 render->i_pos = p_sys->i_pos;
1228 render->i_alpha = p_sys->i_alpha;
1229 render->b_absolute = p_sys->b_absolute;
1230 render->i_state = FBOSD_STATE_FREE;
1233 static bool isRendererReady( intf_thread_t *p_intf )
1235 intf_sys_t *p_sys = p_intf->p_sys;
1236 int i;
1238 /* Check if there are more items to render */
1239 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1241 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1242 return false;
1244 return true;
1247 /*****************************************************************************
1248 * Run: thread
1249 *****************************************************************************
1250 * This part of the interface is in a separate thread so that we can call
1251 * exec() from within it without annoying the rest of the program.
1252 *****************************************************************************/
1253 static void Run( intf_thread_t *p_intf )
1255 intf_sys_t *p_sys = p_intf->p_sys;
1256 int canc = vlc_savecancel();
1258 while( vlc_object_alive( p_intf ) )
1260 int i;
1262 /* Is there somthing to render? */
1263 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1265 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1267 Render( p_intf, &p_sys->render[i] );
1268 RenderClear( p_intf, &p_sys->render[i] );
1272 if( p_sys->b_clear )
1274 SetOverlayTransparency( p_intf, true );
1276 var_SetString( p_intf, "fbosd-image", "" );
1277 var_SetString( p_intf, "fbosd-text", "" );
1279 p_sys->b_clear = false;
1280 p_sys->b_need_update = true;
1283 if( p_sys->b_need_update && p_sys->p_overlay &&
1284 isRendererReady( p_intf ) )
1286 int ret;
1287 #if defined(FBOSD_BLENDING)
1288 /* Reverse alpha channel to work around FPGA bug */
1289 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1290 #endif
1291 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1292 p_sys->i_page_size );
1293 if( ret < 0 )
1294 msg_Err( p_intf, "unable to write to overlay" );
1295 lseek( p_sys->i_fd, 0, SEEK_SET );
1297 /* clear the picture */
1298 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1299 p_sys->b_need_update = false;
1302 msleep( INTF_IDLE_SLEEP );
1305 End( p_intf );
1306 vlc_restorecancel( canc );
1309 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1310 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1312 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1313 intf_sys_t *p_sys = p_intf->p_sys;
1314 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1316 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1318 p_sys->b_need_update = true;
1320 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1322 int i;
1323 /* Clear the entire render list */
1324 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1326 RenderClear( p_intf, &p_sys->render[i] );
1328 p_sys->b_clear = true;
1330 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1332 int i;
1333 /* Are we already busy with on slot ? */
1334 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1336 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1338 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1339 break;
1343 else
1345 int i;
1346 /* Are we already busy with on slot ? */
1347 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1349 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1350 break;
1352 /* No, then find first FREE slot */
1353 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1355 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1357 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1358 break;
1360 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1362 msg_Warn( p_this, "render space depleated" );
1363 return VLC_SUCCESS;
1366 /* Found a free slot */
1367 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1368 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1370 free( p_sys->render[i].psz_string );
1371 p_sys->render[i].psz_string = strdup( newval.psz_string );
1372 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1374 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1376 free( p_sys->render[i].psz_string );
1377 p_sys->render[i].psz_string = strdup( newval.psz_string );
1378 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1380 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1382 p_sys->render[i].b_absolute = false;
1383 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1384 newval.i_int : p_sys->i_width;
1386 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1388 p_sys->render[i].b_absolute = false;
1389 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1390 newval.i_int : p_sys->i_height;
1392 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1394 p_sys->render[i].b_absolute = true;
1395 p_sys->render[i].i_pos = newval.i_int;
1397 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1399 p_sys->render[i].p_text_style->i_font_size = newval.i_int;
1401 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1403 p_sys->render[i].p_text_style->i_font_color = newval.i_int;
1405 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1407 p_sys->render[i].p_text_style->i_font_alpha = 255 - newval.i_int;
1409 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1411 p_sys->render[i].i_alpha = newval.i_int;
1414 return VLC_SUCCESS;