Remove silly "out of memory" messages.
[vlc/vlc-skelet.git] / modules / gui / fbosd.c
blob2b4d5c99a6fc3b9d807b18ea8d3b1d47ac633003
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 #if defined(FBOSD_BLENDING)
193 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
194 ALPHA_LONGTEXT, true );
196 #endif
198 set_section( N_("Position"), NULL );
199 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
200 POSX_LONGTEXT, false );
201 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
202 POSY_LONGTEXT, false );
203 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true );
204 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
206 set_section( N_("Font"), NULL );
207 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
208 OPACITY_TEXT, OPACITY_LONGTEXT, false );
209 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
210 false );
211 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
212 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
213 false );
215 set_section( N_("Commands"), NULL );
216 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true );
217 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true );
218 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true );
220 set_description( _("GNU/Linux osd/overlay framebuffer interface") );
221 set_capability( "interface", 10 );
222 set_callbacks( Create, Destroy );
223 vlc_module_end();
225 /*****************************************************************************
226 * fbosd_render_t: render descriptor
227 *****************************************************************************/
228 struct fbosd_render_t
230 #define FBOSD_RENDER_IMAGE 0
231 #define FBOSD_RENDER_TEXT 1
232 int i_type;
234 #define FBOSD_STATE_FREE 0
235 #define FBOSD_STATE_RESERVED 1
236 #define FBOSD_STATE_RENDER 2
237 int i_state;
239 /* Font style */
240 text_style_t text_style; /* font control */
241 char *psz_string;
243 /* Position */
244 bool b_absolute;
245 int i_x;
246 int i_y;
247 int i_pos;
248 int i_alpha; /* transparency for images */
250 #define FBOSD_RENDER_MAX 10
252 /*****************************************************************************
253 * intf_sys_t: interface framebuffer method descriptor
254 *****************************************************************************/
255 struct intf_sys_t
257 /* Framebuffer information */
258 int i_fd; /* device handle */
259 struct fb_var_screeninfo var_info; /* current mode information */
260 bool b_pan; /* does device supports panning ? */
261 struct fb_cmap fb_cmap; /* original colormap */
262 uint16_t *p_palette; /* original palette */
264 /* Overlay framebuffer format */
265 video_format_t fmt_out;
266 picture_t *p_overlay;
267 size_t i_page_size; /* page size */
268 int i_width;
269 int i_height;
270 int i_aspect;
271 int i_bytes_per_pixel;
273 /* Image and Picture rendering */
274 image_handler_t *p_image;
275 #if defined(FBOSD_BLENDING)
276 filter_t *p_blend; /* alpha blending module */
277 #endif
278 filter_t *p_text; /* text renderer module */
280 /* Render */
281 struct fbosd_render_t render[FBOSD_RENDER_MAX];
283 /* Font style */
284 text_style_t *p_style; /* font control */
286 /* Position */
287 bool b_absolute;
288 int i_x;
289 int i_y;
290 int i_pos;
292 int i_alpha; /* transparency for images */
294 /* commands control */
295 bool b_need_update; /* update display with \overlay buffer */
296 bool b_clear; /* clear overlay buffer make it tranparent */
297 bool b_render; /* render an image or text in overlay buffer */
300 /*****************************************************************************
301 * Create: allocates FB interface thread output method
302 *****************************************************************************/
303 static int Create( vlc_object_t *p_this )
305 intf_thread_t *p_intf = (intf_thread_t *)p_this;
306 intf_sys_t *p_sys;
307 char *psz_aspect;
308 char *psz_tmp;
309 int i;
311 /* Allocate instance and initialize some members */
312 p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
313 if( !p_intf->p_sys )
314 return VLC_ENOMEM;
315 memset( p_sys, 0, sizeof(intf_sys_t) );
317 p_sys->p_style = malloc( sizeof( text_style_t ) );
318 if( !p_sys->p_style )
320 free( p_intf->p_sys );
321 return VLC_ENOMEM;
323 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
325 p_intf->pf_run = Run;
327 p_sys->p_image = image_HandlerCreate( p_this );
328 if( !p_sys->p_image )
330 free( p_intf->p_sys->p_style );
331 free( p_intf->p_sys );
332 return VLC_ENOMEM;
335 #if defined(FBOSD_BLENDING)
336 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
337 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
338 #else
339 p_sys->i_alpha = 255;
340 #endif
341 p_sys->i_aspect = -1;
342 psz_aspect =
343 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
344 if( psz_aspect )
346 char *psz_parser = strchr( psz_aspect, ':' );
348 if( psz_parser )
350 *psz_parser++ = '\0';
351 p_sys->i_aspect = ( atoi( psz_aspect )
352 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
353 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
355 msg_Dbg( p_intf, "using aspect ratio %d:%d",
356 atoi( psz_aspect ), atoi( psz_parser ) );
358 free( psz_aspect );
359 psz_aspect = NULL;
362 /* Use PAL by default */
363 p_sys->i_width = p_sys->fmt_out.i_width = 704;
364 p_sys->i_height = p_sys->fmt_out.i_height = 576;
366 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
367 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
368 if( psz_tmp && *psz_tmp )
370 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
371 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
372 p_sys->render[0].psz_string = strdup( psz_tmp );
374 free( psz_tmp );
376 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
377 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
378 if( psz_tmp && *psz_tmp )
380 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
381 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
382 p_sys->render[1].psz_string = strdup( psz_tmp );
384 free( psz_tmp );
386 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
387 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
388 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
390 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
391 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
392 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
394 p_sys->p_style->i_font_size =
395 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
396 p_sys->p_style->i_font_color =
397 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
398 p_sys->p_style->i_font_alpha = 255 -
399 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
401 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
402 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
403 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
405 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
407 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
408 sizeof( text_style_t ) );
411 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
412 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
413 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
415 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
416 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
417 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
419 /* Check if picture position was overridden */
420 p_sys->b_absolute = true;
421 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
423 p_sys->b_absolute = false;
424 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
425 p_sys->i_y : p_sys->i_height;
426 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
427 p_sys->i_x : p_sys->i_width;
430 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
431 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
432 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
433 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
435 /* Initialize framebuffer */
436 if( OpenDisplay( p_intf ) )
438 Destroy( VLC_OBJECT(p_intf) );
439 return VLC_EGENERIC;
442 Init( p_intf );
444 #if defined(FBOSD_BLENDING)
445 /* Load the blending module */
446 if( OpenBlending( p_intf ) )
448 msg_Err( p_intf, "Unable to load image blending module" );
449 Destroy( VLC_OBJECT(p_intf) );
450 return VLC_EGENERIC;
452 #endif
454 /* Load text renderer module */
455 if( OpenTextRenderer( p_intf ) )
457 msg_Err( p_intf, "Unable to load text rendering module" );
458 Destroy( VLC_OBJECT(p_intf) );
459 return VLC_EGENERIC;
462 p_sys->b_render = true;
463 p_sys->b_need_update = true;
465 return VLC_SUCCESS;
468 /*****************************************************************************
469 * Destroy: destroy FB interface thread output method
470 *****************************************************************************
471 * Terminate an output method created by Create
472 *****************************************************************************/
473 static void Destroy( vlc_object_t *p_this )
475 intf_thread_t *p_intf = (intf_thread_t *)p_this;
476 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
477 int i;
479 p_sys->b_need_update = false;
480 p_sys->b_render = false;
481 p_sys->b_clear = false;
483 #if defined(FBOSD_BLENDING)
484 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
485 var_Destroy( p_intf, "fbosd-alpha" );
486 #endif
488 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
489 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
490 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
491 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
492 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
493 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
494 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
495 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
496 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
497 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
498 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
500 var_Destroy( p_intf, "fbosd-x" );
501 var_Destroy( p_intf, "fbosd-y" );
502 var_Destroy( p_intf, "fbosd-position" );
503 var_Destroy( p_intf, "fbosd-image" );
504 var_Destroy( p_intf, "fbosd-text" );
505 var_Destroy( p_intf, "fbosd-font-size" );
506 var_Destroy( p_intf, "fbosd-font-color" );
507 var_Destroy( p_intf, "fbosd-font-opacity" );
508 var_Destroy( p_intf, "fbosd-clear" );
509 var_Destroy( p_intf, "fbosd-render" );
510 var_Destroy( p_intf, "fbosd-display" );
512 var_Destroy( p_intf, "fbosd-aspect-ratio" );
514 CloseDisplay( p_intf );
516 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
518 free( p_sys->render[i].psz_string );
519 p_sys->render[i].i_state = FBOSD_STATE_FREE;
522 #if defined(FBOSD_BLENDING)
523 if( p_sys->p_blend ) CloseBlending( p_intf );
524 #endif
525 if( p_sys->p_text ) CloseTextRenderer( p_intf );
527 if( p_sys->p_image )
528 image_HandlerDelete( p_sys->p_image );
529 if( p_sys->p_overlay )
530 p_sys->p_overlay->pf_release( p_sys->p_overlay );
532 free( p_sys->p_style );
533 free( p_sys );
536 #if defined(FBOSD_BLENDING)
537 static int OpenBlending( intf_thread_t *p_intf )
539 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
541 p_intf->p_sys->p_blend =
542 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
543 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
544 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
545 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
546 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
547 p_intf->p_sys->fmt_out.i_aspect;
548 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
549 p_intf->p_sys->fmt_out.i_chroma;
550 if( config_GetInt( p_intf, "freetype-yuvp" ) )
551 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
552 VLC_FOURCC('Y','U','V','P');
553 else
554 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
555 VLC_FOURCC('Y','U','V','A');
557 p_intf->p_sys->p_blend->p_module =
558 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
560 if( !p_intf->p_sys->p_blend->p_module )
561 return VLC_EGENERIC;
563 return VLC_SUCCESS;
566 static void CloseBlending( intf_thread_t *p_intf )
568 if( p_intf->p_sys->p_blend )
570 if( p_intf->p_sys->p_blend->p_module )
571 module_Unneed( p_intf->p_sys->p_blend,
572 p_intf->p_sys->p_blend->p_module );
574 vlc_object_detach( p_intf->p_sys->p_blend );
575 vlc_object_release( p_intf->p_sys->p_blend );
578 #endif
580 static int OpenTextRenderer( intf_thread_t *p_intf )
582 char *psz_modulename = NULL;
584 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
586 p_intf->p_sys->p_text =
587 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
588 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
590 p_intf->p_sys->p_text->fmt_out.video.i_width =
591 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
592 p_intf->p_sys->i_width;
593 p_intf->p_sys->p_text->fmt_out.video.i_height =
594 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
595 p_intf->p_sys->i_height;
597 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
598 if( psz_modulename && *psz_modulename )
600 p_intf->p_sys->p_text->p_module =
601 module_Need( p_intf->p_sys->p_text, "text renderer",
602 psz_modulename, true );
604 if( !p_intf->p_sys->p_text->p_module )
606 p_intf->p_sys->p_text->p_module =
607 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
609 free( psz_modulename );
611 if( !p_intf->p_sys->p_text->p_module )
612 return VLC_EGENERIC;
614 return VLC_SUCCESS;
617 static void CloseTextRenderer( intf_thread_t *p_intf )
619 if( p_intf->p_sys->p_text )
621 if( p_intf->p_sys->p_text->p_module )
622 module_Unneed( p_intf->p_sys->p_text,
623 p_intf->p_sys->p_text->p_module );
625 vlc_object_detach( p_intf->p_sys->p_text );
626 vlc_object_release( p_intf->p_sys->p_text );
630 /*****************************************************************************
631 * AllocatePicture:
632 * allocate a picture buffer for use with the overlay fb.
633 *****************************************************************************/
634 static picture_t *AllocatePicture( vlc_object_t *p_this,
635 video_format_t *p_fmt )
637 picture_t *p_pic = malloc( sizeof( picture_t ) );
638 if( !p_pic ) return NULL;
640 if( !p_fmt->p_palette &&
641 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
643 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
644 if( !p_fmt->p_palette )
646 free( p_pic );
647 return NULL;
650 else p_fmt->p_palette = NULL;
652 p_pic->p_data_orig = NULL;
654 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
655 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
657 if( !p_pic->i_planes )
659 free( p_pic );
660 free( p_fmt->p_palette );
661 return NULL;
663 return p_pic;
666 /*****************************************************************************
667 * DeAllocatePicture:
668 * Deallocate a picture buffer and free all associated memory.
669 *****************************************************************************/
670 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
671 video_format_t *p_fmt )
673 VLC_UNUSED(p_this);
674 if( p_pic )
676 free( p_pic->p_data_orig );
677 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
679 if( p_fmt )
681 free( p_fmt->p_palette );
682 p_fmt->p_palette = NULL;
684 p_pic = NULL;
687 /*****************************************************************************
688 * SetOverlayTransparency: Set the transparency for this overlay fb,
689 * - true is make transparent
690 * - false is make non tranparent
691 *****************************************************************************/
692 static void SetOverlayTransparency( intf_thread_t *p_intf,
693 bool b_transparent )
695 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
696 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
697 * p_sys->i_bytes_per_pixel;
698 size_t i_page_size = (p_sys->i_page_size > i_size) ?
699 i_size : p_sys->i_page_size;
701 if( p_sys->p_overlay )
703 msg_Dbg( p_intf, "Make overlay %s",
704 b_transparent ? "transparent" : "opaque" );
705 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
706 if( b_transparent )
707 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
711 #if defined(FBOSD_BLENDING)
712 /*****************************************************************************
713 * BlendPicture: Blend two pictures together..
714 *****************************************************************************/
715 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
716 video_format_t *p_fmt_dst, picture_t *p_pic_src,
717 picture_t *p_pic_dst )
719 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
720 if( p_sys->p_blend && p_sys->p_blend->p_module )
722 int i_x_offset = p_sys->i_x;
723 int i_y_offset = p_sys->i_y;
725 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
727 /* Update the output picture size */
728 p_sys->p_blend->fmt_out.video.i_width =
729 p_sys->p_blend->fmt_out.video.i_visible_width =
730 p_fmt_dst->i_width;
731 p_sys->p_blend->fmt_out.video.i_height =
732 p_sys->p_blend->fmt_out.video.i_visible_height =
733 p_fmt_dst->i_height;
735 i_x_offset = __MAX( i_x_offset, 0 );
736 i_y_offset = __MAX( i_y_offset, 0 );
738 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
739 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
740 p_sys->i_alpha );
742 return VLC_SUCCESS;
744 return VLC_EGENERIC;
747 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
749 uint8_t *p_begin = NULL, *p_end = NULL;
750 uint8_t i_skip = 0;
752 if( *p_pic && ((*p_pic)->i_planes != 1) )
754 msg_Err( p_intf,
755 "cannot invert alpha channel too many planes %d (only 1 supported)",
756 (*p_pic)->i_planes );
757 return VLC_EGENERIC;
760 switch( fmt.i_chroma )
762 case VLC_FOURCC('R','V','2','4'):
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 = 3;
767 break;
768 case VLC_FOURCC('R','V','3','2'):
769 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
770 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
771 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
772 i_skip = 4;
773 break;
774 default:
775 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
776 (char *)&fmt.i_chroma );
777 return VLC_EGENERIC;
780 for( ; p_begin < p_end; p_begin += i_skip )
782 uint8_t i_opacity;
784 if( i_opacity != 0xFF )
785 i_opacity = 255 - *p_begin;
786 *p_begin = i_opacity;
788 /* end of kludge */
789 return VLC_SUCCESS;
791 #endif
793 /*****************************************************************************
794 * RenderPicture: Render the picture into the p_dest buffer.
795 * We don't take transparent pixels into account, so we don't have to blend
796 * the two images together.
797 *****************************************************************************/
798 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
799 picture_t *p_src, picture_t *p_dest )
801 int i;
802 VLC_UNUSED( p_intf );
804 if( !p_dest && !p_src ) return VLC_EGENERIC;
806 for( i = 0; i < p_src->i_planes ; i++ )
808 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
810 /* There are margins, but with the same width : perfect ! */
811 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
812 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
814 else
816 /* We need to proceed line by line */
817 uint8_t *p_in = p_src->p[i].p_pixels;
818 uint8_t *p_out = p_dest->p[i].p_pixels;
820 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
821 int i_x_clip, i_y_clip;
823 /* Check boundaries, clip the image if necessary */
824 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
825 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
827 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
828 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
829 #if defined(FBOSD_DEBUG)
830 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
831 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
832 i_x_offset, i_y_offset, i_x, i_x_clip );
833 #endif
834 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
835 ( i_x <= p_dest->p[i].i_visible_pitch ) )
837 int i_line;
839 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
840 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
842 vlc_memcpy( p_out + i_x, p_in,
843 p_src->p[i].i_visible_pitch - i_x_clip );
844 p_in += p_src->p[i].i_pitch;
845 p_out += p_dest->p[i].i_pitch;
850 return VLC_SUCCESS;
853 /*****************************************************************************
854 * RenderText - Render text to the desired picture format
855 *****************************************************************************/
856 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
857 text_style_t *p_style, video_format_t *p_fmt )
859 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
860 subpicture_region_t *p_region;
861 picture_t *p_dest = NULL;
863 if( !psz_string ) return p_dest;
865 if( p_sys->p_text && p_sys->p_text->p_module )
867 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
868 if( !p_region )
869 return p_dest;
871 memset( p_region, 0, sizeof(subpicture_region_t) );
873 p_region->psz_text = strdup( psz_string );
874 p_region->p_style = p_style;
876 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
877 p_region->fmt.i_aspect = 0;
878 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
879 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
880 p_region->fmt.i_x_offset = 0;
881 p_region->fmt.i_y_offset = 0;
883 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
885 if( p_sys->p_text->pf_render_text )
887 video_format_t fmt_out;
889 memset( &fmt_out, 0, sizeof(video_format_t) );
891 p_sys->p_text->pf_render_text( p_sys->p_text,
892 p_region, p_region );
894 #if defined(FBOSD_BLENDING)
895 fmt_out = p_region->fmt;
896 fmt_out.i_bits_per_pixel = 32;
897 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
899 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
900 if( !p_dest )
902 if( p_region->picture.pf_release )
903 p_region->picture.pf_release( &p_region->picture );
904 free( p_region->psz_text );
905 free( p_region );
906 return NULL;
908 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
909 #else
910 fmt_out.i_chroma = p_fmt->i_chroma;
911 p_dest = ConvertImage( p_intf, &p_region->picture,
912 &p_region->fmt, &fmt_out );
913 #endif
914 if( p_region->picture.pf_release )
915 p_region->picture.pf_release( &p_region->picture );
916 free( p_region->psz_text );
917 free( p_region );
918 return p_dest;
920 free( p_region->psz_text );
921 free( p_region );
923 return p_dest;
926 /*****************************************************************************
927 * LoadImage: Load an image from file into a picture buffer.
928 *****************************************************************************/
929 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
930 char *psz_file )
932 picture_t *p_pic = NULL;
934 if( psz_file && p_intf->p_sys->p_image )
936 video_format_t fmt_in, fmt_out;
938 memset( &fmt_in, 0, sizeof(fmt_in) );
939 memset( &fmt_out, 0, sizeof(fmt_out) );
941 fmt_out.i_chroma = p_fmt->i_chroma;
942 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
943 &fmt_in, &fmt_out );
945 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
946 fmt_out.i_width, fmt_out.i_height,
947 (char *)&p_fmt->i_chroma );
949 return p_pic;
952 #if ! defined(FBOSD_BLENDING)
953 /*****************************************************************************
954 * Convertmage: Convert image to another fourcc
955 *****************************************************************************/
956 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
957 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
959 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
960 picture_t *p_old = NULL;
962 if( p_sys->p_image )
964 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
966 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
967 p_fmt_out->i_width, p_fmt_out->i_height,
968 (char *)&p_fmt_out->i_chroma );
970 return p_old;
972 #endif
974 /*****************************************************************************
975 * Init: initialize framebuffer video thread output method
976 *****************************************************************************/
977 static int Init( intf_thread_t *p_intf )
979 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
981 /* Initialize the output structure: RGB with square pixels, whatever
982 * the input format is, since it's the only format we know */
983 switch( p_sys->var_info.bits_per_pixel )
985 case 8: /* FIXME: set the palette */
986 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
987 case 15:
988 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
989 case 16:
990 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
991 case 24:
992 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
993 case 32:
994 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
995 default:
996 msg_Err( p_intf, "unknown screen depth %i",
997 p_sys->var_info.bits_per_pixel );
998 return VLC_EGENERIC;
1001 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1002 p_sys->fmt_out.i_width = p_sys->i_width;
1003 p_sys->fmt_out.i_height = p_sys->i_height;
1005 /* Assume we have square pixels */
1006 if( p_sys->i_aspect < 0 )
1008 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1009 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1011 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1013 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1015 /* Allocate overlay buffer */
1016 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1017 &p_sys->fmt_out );
1018 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1020 SetOverlayTransparency( p_intf, true );
1022 /* We know the chroma, allocate a buffer which will be used
1023 * to write to the overlay framebuffer */
1024 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1025 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1026 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1028 if( p_sys->var_info.xres_virtual )
1030 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1031 * p_sys->i_bytes_per_pixel;
1033 else
1035 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1036 * p_sys->i_bytes_per_pixel;
1039 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1040 * p_sys->i_bytes_per_pixel;
1042 p_sys->p_overlay->i_planes = 1;
1044 return VLC_SUCCESS;
1047 /*****************************************************************************
1048 * End: terminate framebuffer interface
1049 *****************************************************************************/
1050 static void End( intf_thread_t *p_intf )
1052 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1054 /* CleanUp */
1055 SetOverlayTransparency( p_intf, false );
1056 if( p_sys->p_overlay )
1058 int ret;
1059 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, 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: rc 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 #if defined(FBOSD_BLENDING)
1434 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1436 p_sys->render[i].i_alpha = newval.i_int;
1438 #endif
1440 return VLC_SUCCESS;