fix indentation.
[vlc/vlc-skelet.git] / modules / gui / fbosd.c
blob8e63a9ed9be3bd0db191907b66c9ab1912ccc602
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/vlc.h>
33 #include <vlc_plugin.h>
35 #include <errno.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( vlc_object_t *,
83 video_format_t * );
84 static void DeAllocatePicture( vlc_object_t *, picture_t *,
85 video_format_t * );
86 static void SetOverlayTransparency( intf_thread_t *,
87 bool );
88 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
89 char * );
91 #if defined(FBOSD_BLENDING)
92 static int BlendPicture( intf_thread_t *, video_format_t *,
93 video_format_t *, picture_t *, picture_t * );
94 #else
95 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
96 video_format_t *, video_format_t * );
97 #endif
98 static int RenderPicture( intf_thread_t *, int, int,
99 picture_t *, picture_t * );
100 static picture_t *RenderText( intf_thread_t *, const char *,
101 text_style_t *, video_format_t * );
103 #define DEVICE_TEXT N_("Framebuffer device")
104 #define DEVICE_LONGTEXT N_( \
105 "Framebuffer device to use for rendering (usually /dev/fb0).")
107 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
108 #define ASPECT_RATIO_LONGTEXT N_( \
109 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
111 #define FBOSD_IMAGE_TEXT N_("Image file")
112 #define FBOSD_IMAGE_LONGTEXT N_( \
113 "Filename of image file to use on the overlay framebuffer." )
115 #define ALPHA_TEXT N_("Transparency of the image")
116 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
117 "used in blending. By default it set to fully opaque (255). " \
118 "(from 0 for full transparency to 255 for full opacity)" )
120 #define FBOSD_TEXT N_("Text")
121 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
123 #define POSX_TEXT N_("X coordinate")
124 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
126 #define POSY_TEXT N_("Y coordinate")
127 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
129 #define POS_TEXT N_("Position")
130 #define POS_LONGTEXT N_( \
131 "You can enforce the picture position on the overlay " \
132 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
133 "also use combinations of these values, e.g. 6=top-right).")
135 #define OPACITY_TEXT N_("Opacity")
136 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
137 "overlayed text. 0 = transparent, 255 = totally opaque. " )
139 #define SIZE_TEXT N_("Font size, pixels")
140 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
141 "font size)." )
143 #define COLOR_TEXT N_("Color")
144 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
145 "the video. This must be an hexadecimal (like HTML colors). The first two "\
146 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
147 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
149 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
150 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
151 "making the overlay completely transparent. All previously rendered " \
152 "images and text will be cleared from the cache." )
154 #define RENDER_TEXT N_( "Render text or image" )
155 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
156 "buffer." )
158 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
159 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
160 "displayed on the overlay framebuffer." )
162 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
163 static const char *ppsz_pos_descriptions[] =
164 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
165 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
167 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
168 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
169 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
170 0x00000080, 0x000000FF, 0x0000FFFF};
171 static const char *ppsz_color_descriptions[] = { 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/fb1", 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, 0 );
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, 0 );
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( _("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 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 = malloc( sizeof( intf_sys_t ) );
310 if( !p_intf->p_sys )
311 return VLC_ENOMEM;
312 memset( p_sys, 0, sizeof(intf_sys_t) );
314 p_sys->p_style = malloc( sizeof( text_style_t ) );
315 if( !p_sys->p_style )
317 free( p_intf->p_sys );
318 return VLC_ENOMEM;
320 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
322 p_intf->pf_run = Run;
324 p_sys->p_image = image_HandlerCreate( p_this );
325 if( !p_sys->p_image )
327 free( p_intf->p_sys->p_style );
328 free( p_intf->p_sys );
329 return VLC_ENOMEM;
332 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
333 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
335 p_sys->i_aspect = -1;
336 psz_aspect =
337 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
338 if( psz_aspect )
340 char *psz_parser = strchr( psz_aspect, ':' );
342 if( psz_parser )
344 *psz_parser++ = '\0';
345 p_sys->i_aspect = ( atoi( psz_aspect )
346 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
347 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
349 msg_Dbg( p_intf, "using aspect ratio %d:%d",
350 atoi( psz_aspect ), atoi( psz_parser ) );
352 free( psz_aspect );
353 psz_aspect = NULL;
356 /* Use PAL by default */
357 p_sys->i_width = p_sys->fmt_out.i_width = 704;
358 p_sys->i_height = p_sys->fmt_out.i_height = 576;
360 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
361 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
362 if( psz_tmp && *psz_tmp )
364 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
365 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
366 p_sys->render[0].psz_string = strdup( psz_tmp );
368 free( psz_tmp );
370 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
371 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
372 if( psz_tmp && *psz_tmp )
374 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
375 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
376 p_sys->render[1].psz_string = strdup( psz_tmp );
378 free( psz_tmp );
380 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
381 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
382 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
384 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
385 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
386 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
388 p_sys->p_style->i_font_size =
389 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
390 p_sys->p_style->i_font_color =
391 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
392 p_sys->p_style->i_font_alpha = 255 -
393 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
395 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
396 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
397 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
399 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
401 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
402 sizeof( text_style_t ) );
405 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
406 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
407 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
409 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
410 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
411 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
413 /* Check if picture position was overridden */
414 p_sys->b_absolute = true;
415 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
417 p_sys->b_absolute = false;
418 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
419 p_sys->i_y : p_sys->i_height;
420 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
421 p_sys->i_x : p_sys->i_width;
424 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
425 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
426 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
427 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
429 /* Initialize framebuffer */
430 if( OpenDisplay( p_intf ) )
432 Destroy( VLC_OBJECT(p_intf) );
433 return VLC_EGENERIC;
436 Init( p_intf );
438 #if defined(FBOSD_BLENDING)
439 /* Load the blending module */
440 if( OpenBlending( p_intf ) )
442 msg_Err( p_intf, "Unable to load image blending module" );
443 Destroy( VLC_OBJECT(p_intf) );
444 return VLC_EGENERIC;
446 #endif
448 /* Load text renderer module */
449 if( OpenTextRenderer( p_intf ) )
451 msg_Err( p_intf, "Unable to load text rendering module" );
452 Destroy( VLC_OBJECT(p_intf) );
453 return VLC_EGENERIC;
456 p_sys->b_render = true;
457 p_sys->b_need_update = true;
459 return VLC_SUCCESS;
462 /*****************************************************************************
463 * Destroy: destroy FB interface thread output method
464 *****************************************************************************
465 * Terminate an output method created by Create
466 *****************************************************************************/
467 static void Destroy( vlc_object_t *p_this )
469 intf_thread_t *p_intf = (intf_thread_t *)p_this;
470 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
471 int i;
473 p_sys->b_need_update = false;
474 p_sys->b_render = false;
475 p_sys->b_clear = false;
477 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
478 var_Destroy( p_intf, "fbosd-alpha" );
480 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
481 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
482 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
487 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
488 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
489 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
490 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
492 var_Destroy( p_intf, "fbosd-x" );
493 var_Destroy( p_intf, "fbosd-y" );
494 var_Destroy( p_intf, "fbosd-position" );
495 var_Destroy( p_intf, "fbosd-image" );
496 var_Destroy( p_intf, "fbosd-text" );
497 var_Destroy( p_intf, "fbosd-font-size" );
498 var_Destroy( p_intf, "fbosd-font-color" );
499 var_Destroy( p_intf, "fbosd-font-opacity" );
500 var_Destroy( p_intf, "fbosd-clear" );
501 var_Destroy( p_intf, "fbosd-render" );
502 var_Destroy( p_intf, "fbosd-display" );
504 var_Destroy( p_intf, "fbosd-aspect-ratio" );
506 CloseDisplay( p_intf );
508 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
510 free( p_sys->render[i].psz_string );
511 p_sys->render[i].i_state = FBOSD_STATE_FREE;
514 #if defined(FBOSD_BLENDING)
515 if( p_sys->p_blend ) CloseBlending( p_intf );
516 #endif
517 if( p_sys->p_text ) CloseTextRenderer( p_intf );
519 if( p_sys->p_image )
520 image_HandlerDelete( p_sys->p_image );
521 if( p_sys->p_overlay )
522 p_sys->p_overlay->pf_release( p_sys->p_overlay );
524 free( p_sys->p_style );
525 free( p_sys );
528 #if defined(FBOSD_BLENDING)
529 static int OpenBlending( intf_thread_t *p_intf )
531 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
533 p_intf->p_sys->p_blend =
534 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
535 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
536 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
537 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
538 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
539 p_intf->p_sys->fmt_out.i_aspect;
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_FOURCC('Y','U','V','P');
545 else
546 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
547 VLC_FOURCC('Y','U','V','A');
549 p_intf->p_sys->p_blend->p_module =
550 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
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, VLC_OBJECT_FILTER );
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", 0, 0 );
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( vlc_object_t *p_this,
627 video_format_t *p_fmt )
629 picture_t *p_pic = malloc( sizeof( picture_t ) );
630 if( !p_pic ) return NULL;
632 if( !p_fmt->p_palette &&
633 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
635 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
636 if( !p_fmt->p_palette )
638 free( p_pic );
639 return NULL;
642 else p_fmt->p_palette = NULL;
644 p_pic->p_data_orig = NULL;
646 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
647 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
649 if( !p_pic->i_planes )
651 free( p_pic );
652 free( p_fmt->p_palette );
653 return NULL;
655 return p_pic;
658 /*****************************************************************************
659 * DeAllocatePicture:
660 * Deallocate a picture buffer and free all associated memory.
661 *****************************************************************************/
662 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
663 video_format_t *p_fmt )
665 VLC_UNUSED(p_this);
666 if( p_pic )
668 free( p_pic->p_data_orig );
669 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
670 else free( p_pic );
672 if( p_fmt )
674 free( p_fmt->p_palette );
675 p_fmt->p_palette = NULL;
677 p_pic = NULL;
680 /*****************************************************************************
681 * SetOverlayTransparency: Set the transparency for this overlay fb,
682 * - true is make transparent
683 * - false is make non tranparent
684 *****************************************************************************/
685 static void SetOverlayTransparency( intf_thread_t *p_intf,
686 bool b_transparent )
688 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
689 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
690 * p_sys->i_bytes_per_pixel;
691 size_t i_page_size = (p_sys->i_page_size > i_size) ?
692 i_size : p_sys->i_page_size;
694 if( p_sys->p_overlay )
696 msg_Dbg( p_intf, "Make overlay %s",
697 b_transparent ? "transparent" : "opaque" );
698 if( b_transparent )
699 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
700 else
701 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
705 #if defined(FBOSD_BLENDING)
706 /*****************************************************************************
707 * BlendPicture: Blend two pictures together..
708 *****************************************************************************/
709 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
710 video_format_t *p_fmt_dst, picture_t *p_pic_src,
711 picture_t *p_pic_dst )
713 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
714 if( p_sys->p_blend && p_sys->p_blend->p_module )
716 int i_x_offset = p_sys->i_x;
717 int i_y_offset = p_sys->i_y;
719 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
721 /* Update the output picture size */
722 p_sys->p_blend->fmt_out.video.i_width =
723 p_sys->p_blend->fmt_out.video.i_visible_width =
724 p_fmt_dst->i_width;
725 p_sys->p_blend->fmt_out.video.i_height =
726 p_sys->p_blend->fmt_out.video.i_visible_height =
727 p_fmt_dst->i_height;
729 i_x_offset = __MAX( i_x_offset, 0 );
730 i_y_offset = __MAX( i_y_offset, 0 );
732 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
733 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
734 p_sys->i_alpha );
736 return VLC_SUCCESS;
738 return VLC_EGENERIC;
741 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
743 uint8_t *p_begin = NULL, *p_end = NULL;
744 uint8_t i_skip = 0;
746 if( *p_pic && ((*p_pic)->i_planes != 1) )
748 msg_Err( p_intf,
749 "cannot invert alpha channel too many planes %d (only 1 supported)",
750 (*p_pic)->i_planes );
751 return VLC_EGENERIC;
754 switch( fmt.i_chroma )
756 case VLC_FOURCC('R','V','2','4'):
757 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
758 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
759 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
760 i_skip = 3;
761 break;
762 case VLC_FOURCC('R','V','3','2'):
763 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
764 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
765 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
766 i_skip = 4;
767 break;
768 default:
769 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
770 (char *)&fmt.i_chroma );
771 return VLC_EGENERIC;
774 for( ; p_begin < p_end; p_begin += i_skip )
776 uint8_t i_opacity = 0;
778 if( *p_begin != 0xFF )
779 i_opacity = 255 - *p_begin;
780 *p_begin = i_opacity;
782 /* end of kludge */
783 return VLC_SUCCESS;
785 #endif
787 /*****************************************************************************
788 * RenderPicture: Render the picture into the p_dest buffer.
789 * We don't take transparent pixels into account, so we don't have to blend
790 * the two images together.
791 *****************************************************************************/
792 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
793 picture_t *p_src, picture_t *p_dest )
795 int i;
796 VLC_UNUSED( p_intf );
798 if( !p_dest && !p_src ) return VLC_EGENERIC;
800 for( i = 0; i < p_src->i_planes ; i++ )
802 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
804 /* There are margins, but with the same width : perfect ! */
805 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
806 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
808 else
810 /* We need to proceed line by line */
811 uint8_t *p_in = p_src->p[i].p_pixels;
812 uint8_t *p_out = p_dest->p[i].p_pixels;
814 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
815 int i_x_clip, i_y_clip;
817 /* Check boundaries, clip the image if necessary */
818 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
819 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
821 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
822 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
823 #if defined(FBOSD_DEBUG)
824 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
825 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
826 i_x_offset, i_y_offset, i_x, i_x_clip );
827 #endif
828 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
829 ( i_x <= p_dest->p[i].i_visible_pitch ) )
831 int i_line;
833 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
834 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
836 vlc_memcpy( p_out + i_x, p_in,
837 p_src->p[i].i_visible_pitch - i_x_clip );
838 p_in += p_src->p[i].i_pitch;
839 p_out += p_dest->p[i].i_pitch;
844 return VLC_SUCCESS;
847 /*****************************************************************************
848 * RenderText - Render text to the desired picture format
849 *****************************************************************************/
850 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
851 text_style_t *p_style, video_format_t *p_fmt )
853 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
854 subpicture_region_t *p_region;
855 picture_t *p_dest = NULL;
857 if( !psz_string ) return p_dest;
859 if( p_sys->p_text && p_sys->p_text->p_module )
861 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
862 if( !p_region )
863 return p_dest;
865 memset( p_region, 0, sizeof(subpicture_region_t) );
867 p_region->psz_text = strdup( psz_string );
868 if( !p_region->psz_text )
870 free( p_region );
871 return NULL;
873 p_region->p_style = p_style;
875 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
876 p_region->fmt.i_aspect = 0;
877 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
878 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
879 p_region->fmt.i_x_offset = 0;
880 p_region->fmt.i_y_offset = 0;
882 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
884 if( p_sys->p_text->pf_render_text )
886 video_format_t fmt_out;
888 memset( &fmt_out, 0, sizeof(video_format_t) );
890 p_sys->p_text->pf_render_text( p_sys->p_text,
891 p_region, p_region );
893 #if defined(FBOSD_BLENDING)
894 fmt_out = p_region->fmt;
895 fmt_out.i_bits_per_pixel = 32;
896 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
898 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
899 if( !p_dest )
901 if( p_region->picture.pf_release )
902 p_region->picture.pf_release( &p_region->picture );
903 free( p_region->psz_text );
904 free( p_region );
905 return NULL;
907 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
908 #else
909 fmt_out.i_chroma = p_fmt->i_chroma;
910 p_dest = ConvertImage( p_intf, &p_region->picture,
911 &p_region->fmt, &fmt_out );
912 #endif
913 if( p_region->picture.pf_release )
914 p_region->picture.pf_release( &p_region->picture );
915 free( p_region->psz_text );
916 free( p_region );
917 return p_dest;
919 free( p_region->psz_text );
920 free( p_region );
922 return p_dest;
925 /*****************************************************************************
926 * LoadImage: Load an image from file into a picture buffer.
927 *****************************************************************************/
928 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
929 char *psz_file )
931 picture_t *p_pic = NULL;
933 if( psz_file && p_intf->p_sys->p_image )
935 video_format_t fmt_in, fmt_out;
937 memset( &fmt_in, 0, sizeof(fmt_in) );
938 memset( &fmt_out, 0, sizeof(fmt_out) );
940 fmt_out.i_chroma = p_fmt->i_chroma;
941 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
942 &fmt_in, &fmt_out );
944 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
945 fmt_out.i_width, fmt_out.i_height,
946 (char *)&p_fmt->i_chroma );
948 return p_pic;
951 #if ! defined(FBOSD_BLENDING)
952 /*****************************************************************************
953 * Convertmage: Convert image to another fourcc
954 *****************************************************************************/
955 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
956 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
958 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
959 picture_t *p_old = NULL;
961 if( p_sys->p_image )
963 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
965 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
966 p_fmt_out->i_width, p_fmt_out->i_height,
967 (char *)&p_fmt_out->i_chroma );
969 return p_old;
971 #endif
973 /*****************************************************************************
974 * Init: initialize framebuffer video thread output method
975 *****************************************************************************/
976 static int Init( intf_thread_t *p_intf )
978 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
980 /* Initialize the output structure: RGB with square pixels, whatever
981 * the input format is, since it's the only format we know */
982 switch( p_sys->var_info.bits_per_pixel )
984 case 8: /* FIXME: set the palette */
985 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
986 case 15:
987 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
988 case 16:
989 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
990 case 24:
991 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
992 case 32:
993 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
994 default:
995 msg_Err( p_intf, "unknown screen depth %i",
996 p_sys->var_info.bits_per_pixel );
997 return VLC_EGENERIC;
1000 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1001 p_sys->fmt_out.i_width = p_sys->i_width;
1002 p_sys->fmt_out.i_height = p_sys->i_height;
1004 /* Assume we have square pixels */
1005 if( p_sys->i_aspect < 0 )
1007 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1008 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1010 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1012 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1014 /* Allocate overlay buffer */
1015 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1016 &p_sys->fmt_out );
1017 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1019 SetOverlayTransparency( p_intf, true );
1021 /* We know the chroma, allocate a buffer which will be used
1022 * to write to the overlay framebuffer */
1023 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1024 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1025 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1027 if( p_sys->var_info.xres_virtual )
1029 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1030 * p_sys->i_bytes_per_pixel;
1032 else
1034 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1035 * p_sys->i_bytes_per_pixel;
1038 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1039 * p_sys->i_bytes_per_pixel;
1041 p_sys->p_overlay->i_planes = 1;
1043 return VLC_SUCCESS;
1046 /*****************************************************************************
1047 * End: terminate framebuffer interface
1048 *****************************************************************************/
1049 static void End( intf_thread_t *p_intf )
1051 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1053 /* CleanUp */
1054 SetOverlayTransparency( p_intf, false );
1055 if( p_sys->p_overlay )
1057 int ret;
1058 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1059 p_sys->i_page_size );
1060 if( ret < 0 )
1061 msg_Err( p_intf, "unable to clear overlay" );
1064 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1065 &p_intf->p_sys->fmt_out );
1066 p_intf->p_sys->p_overlay = NULL;
1069 /*****************************************************************************
1070 * OpenDisplay: initialize framebuffer
1071 *****************************************************************************/
1072 static int OpenDisplay( intf_thread_t *p_intf )
1074 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1075 char *psz_device; /* framebuffer device path */
1076 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1078 /* Open framebuffer device */
1079 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1081 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1082 return VLC_EGENERIC;
1085 p_sys->i_fd = open( psz_device, O_RDWR );
1086 if( p_sys->i_fd == -1 )
1088 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1089 free( psz_device );
1090 return VLC_EGENERIC;
1092 free( psz_device );
1094 /* Get framebuffer device information */
1095 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1097 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1098 close( p_sys->i_fd );
1099 return VLC_EGENERIC;
1102 /* Get some info on the framebuffer itself */
1103 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1105 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1106 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1109 /* FIXME: if the image is full-size, it gets cropped on the left
1110 * because of the xres / xres_virtual slight difference */
1111 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1112 p_sys->var_info.xres, p_sys->var_info.yres,
1113 p_sys->var_info.xres_virtual,
1114 p_sys->var_info.yres_virtual );
1116 p_sys->fmt_out.i_width = p_sys->i_width;
1117 p_sys->fmt_out.i_height = p_sys->i_height;
1119 p_sys->p_palette = NULL;
1120 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1122 switch( p_sys->var_info.bits_per_pixel )
1124 case 8:
1125 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1126 if( !p_sys->p_palette )
1128 close( p_sys->i_fd );
1129 return VLC_ENOMEM;
1131 p_sys->fb_cmap.start = 0;
1132 p_sys->fb_cmap.len = 256;
1133 p_sys->fb_cmap.red = p_sys->p_palette;
1134 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1135 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1136 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1138 /* Save the colormap */
1139 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1141 p_sys->i_bytes_per_pixel = 1;
1142 break;
1144 case 15:
1145 case 16:
1146 p_sys->i_bytes_per_pixel = 2;
1147 break;
1149 case 24:
1150 p_sys->i_bytes_per_pixel = 3;
1151 break;
1153 case 32:
1154 p_sys->i_bytes_per_pixel = 4;
1155 break;
1157 default:
1158 msg_Err( p_intf, "screen depth %d is not supported",
1159 p_sys->var_info.bits_per_pixel );
1161 close( p_sys->i_fd );
1162 return VLC_EGENERIC;
1165 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1166 * p_sys->i_bytes_per_pixel;
1168 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1169 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1170 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1171 return VLC_SUCCESS;
1174 /*****************************************************************************
1175 * CloseDisplay: terminate FB interface thread
1176 *****************************************************************************/
1177 static void CloseDisplay( intf_thread_t *p_intf )
1179 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1181 /* Restore palette */
1182 if( p_sys->var_info.bits_per_pixel == 8 )
1184 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1185 free( p_sys->p_palette );
1186 p_sys->p_palette = NULL;
1189 /* Close fb */
1190 close( p_sys->i_fd );
1193 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1195 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1197 if( render->i_state != FBOSD_STATE_RENDER ) return;
1198 if( !render->psz_string ) return;
1200 if( render->i_type == FBOSD_RENDER_IMAGE )
1202 picture_t *p_pic;
1203 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1204 if( p_pic )
1206 RenderPicture( p_intf, render->i_x, render->i_y,
1207 p_pic, p_sys->p_overlay );
1208 p_pic->pf_release( p_pic );
1211 else if( render->i_type == FBOSD_RENDER_TEXT )
1213 picture_t *p_text;
1214 #if defined(FBOSD_BLENDING)
1215 video_format_t fmt_in;
1216 memset( &fmt_in, 0, sizeof(video_format_t) );
1217 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1218 &fmt_in );
1219 if( p_text )
1221 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1222 p_text, p_sys->p_overlay );
1223 msg_Dbg( p_intf, "releasing picture" );
1224 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1226 #else
1227 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1228 &p_sys->fmt_out );
1229 if( p_text )
1231 RenderPicture( p_intf, render->i_x, render->i_y,
1232 p_text, p_sys->p_overlay );
1233 p_text->pf_release( p_text );
1235 #endif
1239 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1241 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1243 vlc_memcpy( &render->text_style, &default_text_style,
1244 sizeof( text_style_t ) );
1245 free( render->psz_string );
1246 render->psz_string = NULL;
1248 render->i_x = p_sys->i_x;
1249 render->i_y = p_sys->i_y;
1250 render->i_pos = p_sys->i_pos;
1251 render->i_alpha = p_sys->i_alpha;
1252 render->b_absolute = p_sys->b_absolute;
1253 render->i_state = FBOSD_STATE_FREE;
1256 static bool isRendererReady( intf_thread_t *p_intf )
1258 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1259 int i;
1261 /* Check if there are more items to render */
1262 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1264 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1265 return false;
1267 return true;
1270 /*****************************************************************************
1271 * Run: thread
1272 *****************************************************************************
1273 * This part of the interface is in a separate thread so that we can call
1274 * exec() from within it without annoying the rest of the program.
1275 *****************************************************************************/
1276 static void Run( intf_thread_t *p_intf )
1278 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1280 while( !intf_ShouldDie( p_intf ) )
1282 int i;
1284 /* Is there somthing to render? */
1285 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1287 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1289 Render( p_intf, &p_sys->render[i] );
1290 RenderClear( p_intf, &p_sys->render[i] );
1294 if( p_sys->b_clear )
1296 SetOverlayTransparency( p_intf, true );
1298 var_SetString( p_intf, "fbosd-image", "" );
1299 var_SetString( p_intf, "fbosd-text", "" );
1301 p_sys->b_clear = false;
1302 p_sys->b_need_update = true;
1305 if( p_sys->b_need_update && p_sys->p_overlay &&
1306 isRendererReady( p_intf ) )
1308 int ret;
1309 #if defined(FBOSD_BLENDING)
1310 /* Reverse alpha channel to work around FPGA bug */
1311 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1312 #endif
1313 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1314 p_sys->i_page_size );
1315 if( ret < 0 )
1316 msg_Err( p_intf, "unable to write to overlay" );
1317 lseek( p_sys->i_fd, 0, SEEK_SET );
1319 /* clear the picture */
1320 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1321 p_sys->b_need_update = false;
1324 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1325 msleep( INTF_IDLE_SLEEP );
1326 else
1327 msleep( 500 );
1330 End( p_intf );
1333 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1334 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1336 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1337 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1338 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1340 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1342 p_sys->b_need_update = true;
1344 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1346 int i;
1347 /* Clear the entire render list */
1348 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1350 RenderClear( p_intf, &p_sys->render[i] );
1352 p_sys->b_clear = true;
1354 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1356 int i;
1357 /* Are we already busy with on slot ? */
1358 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1360 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1362 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1363 break;
1367 else
1369 int i;
1370 /* Are we already busy with on slot ? */
1371 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1373 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1374 break;
1376 /* No, then find first FREE slot */
1377 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1379 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1381 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1382 break;
1384 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1386 msg_Warn( p_this, "render space depleated" );
1387 return VLC_SUCCESS;
1390 /* Found a free slot */
1391 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1392 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1394 free( p_sys->render[i].psz_string );
1395 p_sys->render[i].psz_string = strdup( newval.psz_string );
1396 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1398 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1400 free( p_sys->render[i].psz_string );
1401 p_sys->render[i].psz_string = strdup( newval.psz_string );
1402 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1404 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1406 p_sys->render[i].b_absolute = false;
1407 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1408 newval.i_int : p_sys->i_width;
1410 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1412 p_sys->render[i].b_absolute = false;
1413 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1414 newval.i_int : p_sys->i_height;
1416 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1418 p_sys->render[i].b_absolute = true;
1419 p_sys->render[i].i_pos = newval.i_int;
1421 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1423 p_sys->render[i].text_style.i_font_size = newval.i_int;
1425 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1427 p_sys->render[i].text_style.i_font_color = newval.i_int;
1429 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1431 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1433 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1435 p_sys->render[i].i_alpha = newval.i_int;
1438 return VLC_SUCCESS;