1 /*****************************************************************************
2 * fbosd.c : framebuffer osd plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2007, the VideoLAN team
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 /*****************************************************************************
27 *****************************************************************************/
35 #include <stdlib.h> /* free() */
36 #include <string.h> /* strerror() */
37 #include <fcntl.h> /* open() */
38 #include <unistd.h> /* close() */
40 #include <sys/ioctl.h>
41 #include <sys/mman.h> /* mmap() */
45 #include <vlc_image.h>
46 #include <vlc_interface.h>
47 #include <vlc_input.h>
49 #include <vlc_filter.h>
51 #include <vlc_strings.h>
53 // #define FBOSD_BLENDING 1
55 /*****************************************************************************
57 *****************************************************************************/
58 static int Create ( vlc_object_t * );
59 static void Destroy ( vlc_object_t * );
60 static void Run ( intf_thread_t * );
62 static int Init ( intf_thread_t * );
63 static void End ( intf_thread_t * );
65 static int OpenDisplay ( intf_thread_t * );
66 static void CloseDisplay ( intf_thread_t * );
68 /* Load modules needed for rendering and blending */
70 static int OpenBlending ( intf_thread_t * );
71 static void CloseBlending ( intf_thread_t * );
73 static int OpenTextRenderer ( intf_thread_t * );
74 static void CloseTextRenderer( intf_thread_t * );
77 static int OpenScaling ( intf_thread_t * );
78 static int CloseScaling ( intf_thread_t * );
81 /* Manipulate the overlay buffer */
82 static int OverlayCallback( vlc_object_t *, char const *,
83 vlc_value_t, vlc_value_t, void * );
85 static picture_t *AllocatePicture( vlc_object_t *,
87 static void DeAllocatePicture( vlc_object_t *, picture_t *,
89 static void SetOverlayTransparency( intf_thread_t *,
91 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
95 static int BlendPicture( intf_thread_t *, video_format_t *,
96 video_format_t *, picture_t *, picture_t * );
98 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
99 video_format_t *, video_format_t * );
101 static int RenderPicture( intf_thread_t *, int, int,
102 picture_t *, picture_t * );
103 static picture_t *RenderText( intf_thread_t *, const char *,
104 text_style_t *, video_format_t * );
106 #define DEVICE_TEXT N_("Framebuffer device")
107 #define DEVICE_LONGTEXT N_( \
108 "Framebuffer device to use for rendering (usually /dev/fb0).")
110 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
111 #define ASPECT_RATIO_LONGTEXT N_( \
112 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
114 #define FBOSD_IMAGE_TEXT N_("Image file")
115 #define FBOSD_IMAGE_LONGTEXT N_( \
116 "Filename of image file to use on the overlay framebuffer." )
118 #define ALPHA_TEXT N_("Transparency of the image")
119 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
120 "used in blending. By default it set to fully opaque (255). " \
121 "(from 0 for full transparency to 255 for full opacity)" )
123 #define FBOSD_TEXT N_("Text")
124 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
126 #define POSX_TEXT N_("X coordinate")
127 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
129 #define POSY_TEXT N_("Y coordinate")
130 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
132 #define POS_TEXT N_("Position")
133 #define POS_LONGTEXT N_( \
134 "You can enforce the picture position on the overlay " \
135 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
136 "also use combinations of these values, e.g. 6=top-right).")
138 #define OPACITY_TEXT N_("Opacity")
139 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
140 "overlayed text. 0 = transparent, 255 = totally opaque. " )
142 #define SIZE_TEXT N_("Font size, pixels")
143 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
146 #define COLOR_TEXT N_("Color")
147 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
148 "the video. This must be an hexadecimal (like HTML colors). The first two "\
149 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
150 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
152 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
153 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
154 "making the overlay completely transparent. All previously rendered " \
155 "images and text will be cleared from the cache." )
157 #define RENDER_TEXT N_( "Render text or image" )
158 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
161 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
162 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
163 "displayed on the overlay framebuffer." )
165 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
166 static const char *ppsz_pos_descriptions[] =
167 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
168 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
170 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
171 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
172 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
173 0x00000080, 0x000000FF, 0x0000FFFF};
174 static const char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
175 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
176 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
177 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
181 set_shortname( "fbosd" );
182 set_category( CAT_INTERFACE );
183 set_subcategory( SUBCAT_INTERFACE_MAIN );
185 add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
187 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
188 ASPECT_RATIO_LONGTEXT, VLC_TRUE );
190 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
191 FBOSD_IMAGE_LONGTEXT, VLC_TRUE );
192 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
193 FBOSD_LONGTEXT, VLC_TRUE );
195 #ifdef FBOSD_BLENDING
196 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
197 ALPHA_LONGTEXT, VLC_TRUE );
201 set_section( N_("Position"), NULL );
202 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
203 POSX_LONGTEXT, VLC_FALSE );
204 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
205 POSY_LONGTEXT, VLC_FALSE );
206 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );
207 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
209 set_section( N_("Font"), NULL );
210 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
211 OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
212 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
214 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
215 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
218 set_section( N_("Commands"), NULL );
219 add_bool( "fbosd-clear", VLC_FALSE, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, VLC_TRUE );
220 add_bool( "fbosd-render", VLC_FALSE, NULL, RENDER_TEXT, RENDER_LONGTEXT, VLC_TRUE );
221 add_bool( "fbosd-display", VLC_FALSE, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
223 set_description( _("GNU/Linux osd/overlay framebuffer interface") );
224 set_capability( "interface", 10 );
225 set_callbacks( Create, Destroy );
228 /*****************************************************************************
229 * fbosd_render_t: render descriptor
230 *****************************************************************************/
231 struct fbosd_render_t
233 #define FBOSD_RENDER_IMAGE 0
234 #define FBOSD_RENDER_TEXT 1
237 #define FBOSD_STATE_FREE 0
238 #define FBOSD_STATE_RESERVED 1
239 #define FBOSD_STATE_RENDER 2
243 text_style_t text_style; /* font control */
247 vlc_bool_t b_absolute;
251 int i_alpha; /* transparency for images */
253 #define FBOSD_RENDER_MAX 10
255 /*****************************************************************************
256 * intf_sys_t: interface framebuffer method descriptor
257 *****************************************************************************/
260 /* Framebuffer information */
261 int i_fd; /* device handle */
262 struct fb_var_screeninfo var_info; /* current mode information */
263 vlc_bool_t b_pan; /* does device supports panning ? */
264 struct fb_cmap fb_cmap; /* original colormap */
265 uint16_t *p_palette; /* original palette */
267 /* Overlay framebuffer format */
268 video_format_t fmt_out;
269 picture_t *p_overlay;
270 size_t i_page_size; /* page size */
274 int i_bytes_per_pixel;
276 /* Image and Picture rendering */
277 image_handler_t *p_image;
278 #ifdef FBOSD_BLENDING
279 filter_t *p_blend; /* alpha blending module */
281 filter_t *p_text; /* text renderer module */
283 filter_t *p_scale; /* scaling module */
287 struct fbosd_render_t render[FBOSD_RENDER_MAX];
290 text_style_t *p_style; /* font control */
293 vlc_bool_t b_absolute;
298 int i_alpha; /* transparency for images */
300 /* commands control */
301 vlc_bool_t b_need_update; /* update display with \overlay buffer */
302 vlc_bool_t b_clear; /* clear overlay buffer make it tranparent */
303 vlc_bool_t b_render; /* render an image or text in overlay buffer */
306 /*****************************************************************************
307 * Create: allocates FB interface thread output method
308 *****************************************************************************/
309 static int Create( vlc_object_t *p_this )
311 intf_thread_t *p_intf = (intf_thread_t *)p_this;
318 /* Allocate instance and initialize some members */
319 p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
322 msg_Err( p_intf, "out of memory" );
325 memset( p_sys, 0, sizeof(intf_sys_t) );
327 p_sys->p_style = malloc( sizeof( text_style_t ) );
328 if( !p_sys->p_style )
330 free( p_intf->p_sys );
331 msg_Err( p_intf, "out of memory" );
334 p_intf->p_libvlc->pf_memcpy( p_sys->p_style, &default_text_style,
335 sizeof( text_style_t ) );
337 p_intf->pf_run = Run;
339 p_sys->p_image = image_HandlerCreate( p_this );
340 if( !p_sys->p_image )
342 free( p_intf->p_sys->p_style );
343 free( p_intf->p_sys );
344 msg_Err( p_intf, "out of memory" );
348 #ifdef FBOSD_BLENDING
349 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
350 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
352 p_sys->i_alpha = 255;
354 p_sys->i_aspect = -1;
356 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
359 char *psz_parser = strchr( psz_aspect, ':' );
363 *psz_parser++ = '\0';
364 p_sys->i_aspect = ( atoi( psz_aspect )
365 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
366 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
368 msg_Dbg( p_intf, "using aspect ratio %d:%d",
369 atoi( psz_aspect ), atoi( psz_parser ) );
375 /* Use PAL by default */
376 p_sys->i_width = p_sys->fmt_out.i_width = 704;
377 p_sys->i_height = p_sys->fmt_out.i_height = 576;
379 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
380 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
381 if( psz_tmp && *psz_tmp )
383 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
384 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
385 p_sys->render[0].psz_string = strdup( psz_tmp );
389 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
390 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
391 if( psz_tmp && *psz_tmp )
393 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
394 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
395 p_sys->render[1].psz_string = strdup( psz_tmp );
399 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
400 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
401 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
403 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
404 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
405 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
407 p_sys->p_style->i_font_size =
408 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
409 p_sys->p_style->i_font_color =
410 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
411 p_sys->p_style->i_font_alpha = 255 -
412 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
414 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
415 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
416 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
418 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
420 p_intf->p_libvlc->pf_memcpy( &p_sys->render[i].text_style,
422 sizeof( text_style_t ) );
425 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
426 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
427 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
429 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
430 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
431 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
433 /* Check if picture position was overridden */
434 p_sys->b_absolute = VLC_TRUE;
435 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
437 p_sys->b_absolute = VLC_FALSE;
438 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
439 p_sys->i_y : p_sys->i_height;
440 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
441 p_sys->i_x : p_sys->i_width;
444 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
445 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
446 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
447 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
449 /* Initialize framebuffer */
450 if( OpenDisplay( p_intf ) )
452 Destroy( VLC_OBJECT(p_intf) );
458 #ifdef FBOSD_BLENDING
459 /* Load the blending module */
460 if( OpenBlending( p_intf ) )
462 msg_Err( p_intf, "Unable to load image blending module" );
463 Destroy( VLC_OBJECT(p_intf) );
468 /* Load text renderer module */
469 if( OpenTextRenderer( p_intf ) )
471 msg_Err( p_intf, "Unable to load text rendering module" );
472 Destroy( VLC_OBJECT(p_intf) );
476 /* Load scaling module */
477 if( OpenScaling( p_intf ) )
479 msg_Err( p_intf, "Unable to load image scaling module" );
480 Destroy( VLC_OBJECT(p_intf) );
484 p_sys->b_render = VLC_TRUE;
485 p_sys->b_need_update = VLC_TRUE;
490 /*****************************************************************************
491 * Destroy: destroy FB interface thread output method
492 *****************************************************************************
493 * Terminate an output method created by Create
494 *****************************************************************************/
495 static void Destroy( vlc_object_t *p_this )
497 intf_thread_t *p_intf = (intf_thread_t *)p_this;
498 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
501 p_sys->b_need_update = VLC_FALSE;
502 p_sys->b_render = VLC_FALSE;
503 p_sys->b_clear = VLC_FALSE;
505 #ifdef FBOSD_BLENDING
506 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
507 var_Destroy( p_intf, "fbosd-alpha" );
510 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
511 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
512 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
513 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
514 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
515 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
516 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
517 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
518 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
519 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
520 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
522 var_Destroy( p_intf, "fbosd-x" );
523 var_Destroy( p_intf, "fbosd-y" );
524 var_Destroy( p_intf, "fbosd-position" );
525 var_Destroy( p_intf, "fbosd-image" );
526 var_Destroy( p_intf, "fbosd-text" );
527 var_Destroy( p_intf, "fbosd-font-size" );
528 var_Destroy( p_intf, "fbosd-font-color" );
529 var_Destroy( p_intf, "fbosd-font-opacity" );
530 var_Destroy( p_intf, "fbosd-clear" );
531 var_Destroy( p_intf, "fbosd-render" );
532 var_Destroy( p_intf, "fbosd-display" );
534 var_Destroy( p_intf, "fbosd-aspect-ratio" );
536 CloseDisplay( p_intf );
538 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
540 free( p_sys->render[i].psz_string );
541 p_sys->render[i].i_state = FBOSD_STATE_FREE;
544 #ifdef FBOSD_BLENDING
545 if( p_sys->p_blend ) CloseBlending( p_intf );
547 if( p_sys->p_text ) CloseTextRenderer( p_intf );
549 if( p_sys->p_scale ) CloseScaling( p_intf );
552 image_HandlerDelete( p_sys->p_image );
553 if( p_sys->p_overlay )
554 p_sys->p_overlay->pf_release( p_sys->p_overlay );
556 free( p_sys->p_style );
560 #ifdef FBOSD_BLENDING
561 static int OpenBlending( intf_thread_t *p_intf )
563 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
565 p_intf->p_sys->p_blend =
566 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
567 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
568 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
569 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
570 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
571 p_intf->p_sys->fmt_out.i_aspect;
572 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
573 p_intf->p_sys->fmt_out.i_chroma;
574 if( config_GetInt( p_intf, "freetype-yuvp" ) )
575 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
576 VLC_FOURCC('Y','U','V','P');
578 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
579 VLC_FOURCC('Y','U','V','A');
581 p_intf->p_sys->p_blend->p_module =
582 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
584 if( !p_intf->p_sys->p_blend->p_module )
590 static void CloseBlending( intf_thread_t *p_intf )
592 if( p_intf->p_sys->p_blend )
594 if( p_intf->p_sys->p_blend->p_module )
595 module_Unneed( p_intf->p_sys->p_blend,
596 p_intf->p_sys->p_blend->p_module );
598 vlc_object_detach( p_intf->p_sys->p_blend );
599 vlc_object_release( p_intf->p_sys->p_blend );
604 static int OpenTextRenderer( intf_thread_t *p_intf )
606 char *psz_modulename = NULL;
608 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
610 p_intf->p_sys->p_text =
611 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
612 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
614 p_intf->p_sys->p_text->fmt_out.video.i_width =
615 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
616 p_intf->p_sys->i_width;
617 p_intf->p_sys->p_text->fmt_out.video.i_height =
618 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
619 p_intf->p_sys->i_height;
621 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
622 if( psz_modulename && *psz_modulename )
624 p_intf->p_sys->p_text->p_module =
625 module_Need( p_intf->p_sys->p_text, "text renderer",
626 psz_modulename, VLC_TRUE );
628 if( !p_intf->p_sys->p_text->p_module )
630 p_intf->p_sys->p_text->p_module =
631 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
633 free( psz_modulename );
635 if( !p_intf->p_sys->p_text->p_module )
641 static void CloseTextRenderer( intf_thread_t *p_intf )
643 if( p_intf->p_sys->p_text )
645 if( p_intf->p_sys->p_text->p_module )
646 module_Unneed( p_intf->p_sys->p_text,
647 p_intf->p_sys->p_text->p_module );
649 vlc_object_detach( p_intf->p_sys->p_text );
650 vlc_object_release( p_intf->p_sys->p_text );
654 static int OpenScaling( intf_thread_t *p_intf )
656 if( p_intf->p_sys->p_scale ) return VLC_EGENERIC;
658 p_intf->p_sys->p_scale =
659 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
660 vlc_object_attach( p_intf->p_sys->p_scale, p_intf );
661 p_intf->p_sys->p_scale->fmt_out.video.i_chroma =
662 p_intf->p_sys->p_scale->fmt_in.video.i_chroma =
663 p_intf->p_sys->fmt_out.i_chroma;
665 /* XXX: We'll also be using it for YUVA and RGBA blending ... */
666 p_intf->p_sys->p_scale->fmt_in.video.i_width =
667 p_intf->p_sys->p_scale->fmt_in.video.i_height = 32;
668 p_intf->p_sys->p_scale->fmt_out.video.i_width =
669 p_intf->p_sys->p_scale->fmt_out.video.i_height = 16;
671 p_intf->p_sys->p_scale->p_module =
672 module_Need( p_intf->p_sys->p_scale, "video filter2", 0, 0 );
674 if( !p_intf->p_sys->p_scale->p_module )
680 static int CloseScaling( intf_thread_t *p_intf )
682 if( p_intf->p_sys->p_scale )
684 if( p_intf->p_sys->p_scale->p_module )
685 module_Unneed( p_intf->p_sys->p_scale,
686 p_intf->p_sys->p_scale->p_module );
688 vlc_object_detach( p_intf->p_sys->p_scale );
689 vlc_object_release( p_intf->p_sys->p_scale );
694 /*****************************************************************************
696 * allocate a picture buffer for use with the overlay fb.
697 *****************************************************************************/
698 static picture_t *AllocatePicture( vlc_object_t *p_this,
699 video_format_t *p_fmt )
701 picture_t *p_pic = malloc( sizeof( picture_t ) );
702 if( !p_pic ) return NULL;
704 if( !p_fmt->p_palette &&
705 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
707 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
708 if( !p_fmt->p_palette )
714 else p_fmt->p_palette = NULL;
716 p_pic->p_data_orig = NULL;
718 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
719 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
721 if( !p_pic->i_planes )
724 free( p_fmt->p_palette );
730 /*****************************************************************************
732 * Deallocate a picture buffer and free all associated memory.
733 *****************************************************************************/
734 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
735 video_format_t *p_fmt )
740 free( p_pic->p_data_orig );
741 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
745 free( p_fmt->p_palette );
746 p_fmt->p_palette = NULL;
751 /*****************************************************************************
752 * SetOverlayTransparency: Set the transparency for this overlay fb,
753 * - VLC_TRUE is make transparent
754 * - VLC_FALSE is make non tranparent
755 *****************************************************************************/
756 static void SetOverlayTransparency( intf_thread_t *p_intf,
757 vlc_bool_t b_transparent )
759 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
760 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
761 * p_sys->i_bytes_per_pixel;
762 size_t i_page_size = (p_sys->i_page_size > i_size) ?
763 i_size : p_sys->i_page_size;
765 if( p_sys->p_overlay )
767 msg_Dbg( p_intf, "Make overlay %s",
768 b_transparent ? "transparent" : "opaque" );
769 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
771 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
775 #ifdef FBOSD_BLENDING
776 /*****************************************************************************
777 * BlendPicture: Blend two pictures together..
778 *****************************************************************************/
779 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
780 video_format_t *p_fmt_dst, picture_t *p_pic_src,
781 picture_t *p_pic_dst )
783 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
784 if( p_sys->p_blend && p_sys->p_blend->p_module )
786 int i_x_offset = p_sys->i_x;
787 int i_y_offset = p_sys->i_y;
789 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
791 msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
792 p_pic_src, (char*)&p_fmt_src->i_chroma,
793 p_sys->p_blend->fmt_in.video.i_width, p_sys->p_blend->fmt_in.video.i_height,
794 p_fmt_src->i_bits_per_pixel,
796 p_pic_src->p[0].p_pixels, p_pic_src->p[1].p_pixels,
797 p_pic_src->p[2].p_pixels, p_pic_src->p[3].p_pixels );
798 msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
799 p_pic_dst, (char*)&p_fmt_dst->i_chroma,
800 p_fmt_dst->i_width, p_fmt_dst->i_height,
801 p_fmt_dst->i_bits_per_pixel,
803 p_pic_dst->p[0].p_pixels, p_pic_dst->p[1].p_pixels,
804 p_pic_dst->p[2].p_pixels, p_pic_dst->p[3].p_pixels );
806 /* Update the output picture size */
807 p_sys->p_blend->fmt_out.video.i_width =
808 p_sys->p_blend->fmt_out.video.i_visible_width =
810 p_sys->p_blend->fmt_out.video.i_height =
811 p_sys->p_blend->fmt_out.video.i_visible_height =
814 i_x_offset = __MAX( i_x_offset, 0 );
815 i_y_offset = __MAX( i_y_offset, 0 );
817 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
818 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
827 /*****************************************************************************
828 * RenderPicture: Render the picture into the p_dest buffer.
829 * We don't take transparent pixels into account, so we don't have to blend
830 * the two images together.
831 *****************************************************************************/
832 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
833 picture_t *p_src, picture_t *p_dest )
837 if( !p_dest && !p_src ) return VLC_EGENERIC;
839 for( i = 0; i < p_src->i_planes ; i++ )
841 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
843 /* There are margins, but with the same width : perfect ! */
844 p_intf->p_libvlc->pf_memcpy(
845 p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
846 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
850 /* We need to proceed line by line */
851 uint8_t *p_in = p_src->p[i].p_pixels;
852 uint8_t *p_out = p_dest->p[i].p_pixels;
854 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
855 int i_x_clip, i_y_clip;
857 /* Check boundaries, clip the image if necessary */
858 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
859 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
861 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
862 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
864 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
865 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
866 i_x_offset, i_y_offset, i_x, i_x_clip );
868 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
869 ( i_x <= p_dest->p[i].i_visible_pitch ) )
873 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
874 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
876 p_intf->p_libvlc->pf_memcpy( p_out + i_x, p_in,
877 p_src->p[i].i_visible_pitch - i_x_clip );
878 p_in += p_src->p[i].i_pitch;
879 p_out += p_dest->p[i].i_pitch;
887 /*****************************************************************************
888 * RenderText - Render text to the desired picture format
889 *****************************************************************************/
890 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
891 text_style_t *p_style, video_format_t *p_fmt )
893 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
894 subpicture_region_t *p_region;
895 picture_t *p_dest = NULL;
897 if( !psz_string ) return p_dest;
899 if( p_sys->p_text && p_sys->p_text->p_module )
901 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
905 memset( p_region, 0, sizeof(subpicture_region_t) );
907 p_region->psz_text = strdup( psz_string );
908 p_region->p_style = p_style;
910 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
911 p_region->fmt.i_aspect = 0;
912 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
913 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
914 p_region->fmt.i_x_offset = 0;
915 p_region->fmt.i_y_offset = 0;
917 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
919 if( p_sys->p_text->pf_render_text )
921 video_format_t fmt_out;
923 memset( &fmt_out, 0, sizeof(video_format_t) );
925 p_sys->p_text->pf_render_text( p_sys->p_text,
926 p_region, p_region );
928 #ifndef FBOSD_BLENDING
929 fmt_out.i_chroma = p_fmt->i_chroma;
930 p_dest = ConvertImage( p_intf, &p_region->picture,
931 &p_region->fmt, &fmt_out );
933 fmt_out = p_region->fmt;
934 fmt_out.i_bits_per_pixel = 32;
935 p_intf->p_libvlc->pf_memcpy( p_fmt, &fmt_out,
936 sizeof(video_format_t) );
938 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
941 if( p_region->picture.pf_release )
942 p_region->picture.pf_release( &p_region->picture );
943 free( p_region->psz_text );
947 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
949 if( p_region->picture.pf_release )
950 p_region->picture.pf_release( &p_region->picture );
951 free( p_region->psz_text );
955 free( p_region->psz_text );
961 /*****************************************************************************
962 * LoadImage: Load an image from file into a picture buffer.
963 *****************************************************************************/
964 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
967 picture_t *p_pic = NULL;
969 if( psz_file && p_intf->p_sys->p_image )
971 video_format_t fmt_in, fmt_out;
973 memset( &fmt_in, 0, sizeof(fmt_in) );
974 memset( &fmt_out, 0, sizeof(fmt_out) );
976 fmt_out.i_chroma = p_fmt->i_chroma;
977 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
980 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
981 fmt_out.i_width, fmt_out.i_height,
982 (char *)&p_fmt->i_chroma );
987 #ifndef FBOSD_BLENDING
988 /*****************************************************************************
989 * Convertmage: Convert image to another fourcc
990 *****************************************************************************/
991 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
992 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
994 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
995 picture_t *p_old = NULL;
999 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
1001 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
1002 p_fmt_out->i_width, p_fmt_out->i_height,
1003 (char *)&p_fmt_out->i_chroma );
1009 /*****************************************************************************
1010 * Init: initialize framebuffer video thread output method
1011 *****************************************************************************/
1012 static int Init( intf_thread_t *p_intf )
1014 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1016 /* Initialize the output structure: RGB with square pixels, whatever
1017 * the input format is, since it's the only format we know */
1018 switch( p_sys->var_info.bits_per_pixel )
1020 case 8: /* FIXME: set the palette */
1021 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
1023 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
1025 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
1027 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
1029 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
1031 msg_Err( p_intf, "unknown screen depth %i",
1032 p_sys->var_info.bits_per_pixel );
1033 return VLC_EGENERIC;
1036 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1037 p_sys->fmt_out.i_width = p_sys->i_width;
1038 p_sys->fmt_out.i_height = p_sys->i_height;
1040 /* Assume we have square pixels */
1041 if( p_sys->i_aspect < 0 )
1043 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1044 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1046 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1048 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1050 /* Allocate overlay buffer */
1051 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1053 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1055 SetOverlayTransparency( p_intf, VLC_TRUE );
1057 /* We know the chroma, allocate a buffer which will be used
1058 * to write to the overlay framebuffer */
1059 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1060 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1061 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1063 if( p_sys->var_info.xres_virtual )
1065 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1066 * p_sys->i_bytes_per_pixel;
1070 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1071 * p_sys->i_bytes_per_pixel;
1074 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1075 * p_sys->i_bytes_per_pixel;
1077 p_sys->p_overlay->i_planes = 1;
1082 /*****************************************************************************
1083 * End: terminate framebuffer interface
1084 *****************************************************************************/
1085 static void End( intf_thread_t *p_intf )
1087 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1090 SetOverlayTransparency( p_intf, VLC_FALSE );
1091 if( p_sys->p_overlay )
1094 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size );
1096 msg_Err( p_intf, "unable to clear overlay" );
1099 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1100 &p_intf->p_sys->fmt_out );
1101 p_intf->p_sys->p_overlay = NULL;
1104 /*****************************************************************************
1105 * OpenDisplay: initialize framebuffer
1106 *****************************************************************************/
1107 static int OpenDisplay( intf_thread_t *p_intf )
1109 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1110 char *psz_device; /* framebuffer device path */
1111 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1113 /* Open framebuffer device */
1114 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1116 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1117 return VLC_EGENERIC;
1120 p_sys->i_fd = open( psz_device, O_RDWR );
1121 if( p_sys->i_fd == -1 )
1123 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1125 return VLC_EGENERIC;
1129 /* Get framebuffer device information */
1130 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1132 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1133 close( p_sys->i_fd );
1134 return VLC_EGENERIC;
1137 /* Get some info on the framebuffer itself */
1138 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1140 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1141 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1144 /* FIXME: if the image is full-size, it gets cropped on the left
1145 * because of the xres / xres_virtual slight difference */
1146 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1147 p_sys->var_info.xres, p_sys->var_info.yres,
1148 p_sys->var_info.xres_virtual,
1149 p_sys->var_info.yres_virtual );
1151 p_sys->fmt_out.i_width = p_sys->i_width;
1152 p_sys->fmt_out.i_height = p_sys->i_height;
1154 p_sys->p_palette = NULL;
1155 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1157 switch( p_sys->var_info.bits_per_pixel )
1160 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1161 if( !p_sys->p_palette )
1163 msg_Err( p_intf, "out of memory" );
1164 close( p_sys->i_fd );
1167 p_sys->fb_cmap.start = 0;
1168 p_sys->fb_cmap.len = 256;
1169 p_sys->fb_cmap.red = p_sys->p_palette;
1170 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1171 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1172 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1174 /* Save the colormap */
1175 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1177 p_sys->i_bytes_per_pixel = 1;
1182 p_sys->i_bytes_per_pixel = 2;
1186 p_sys->i_bytes_per_pixel = 3;
1190 p_sys->i_bytes_per_pixel = 4;
1194 msg_Err( p_intf, "screen depth %d is not supported",
1195 p_sys->var_info.bits_per_pixel );
1197 close( p_sys->i_fd );
1198 return VLC_EGENERIC;
1201 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1202 * p_sys->i_bytes_per_pixel;
1204 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1205 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1206 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1210 /*****************************************************************************
1211 * CloseDisplay: terminate FB interface thread
1212 *****************************************************************************/
1213 static void CloseDisplay( intf_thread_t *p_intf )
1215 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1217 /* Restore palette */
1218 if( p_sys->var_info.bits_per_pixel == 8 )
1220 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1221 free( p_sys->p_palette );
1222 p_sys->p_palette = NULL;
1226 close( p_sys->i_fd );
1229 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1231 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1233 if( render->i_state != FBOSD_STATE_RENDER ) return;
1234 if( !render->psz_string ) return;
1236 if( render->i_type == FBOSD_RENDER_IMAGE )
1239 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1242 RenderPicture( p_intf, render->i_x, render->i_y,
1243 p_pic, p_sys->p_overlay );
1244 p_pic->pf_release( p_pic );
1247 else if( render->i_type == FBOSD_RENDER_TEXT )
1250 #ifdef FBOSD_BLENDING
1251 video_format_t fmt_in;
1252 memset( &fmt_in, 0, sizeof(video_format_t) );
1253 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1257 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1258 p_text, p_sys->p_overlay );
1259 msg_Dbg( p_intf, "releasing picture" );
1260 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1263 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1267 RenderPicture( p_intf, render->i_x, render->i_y,
1268 p_text, p_sys->p_overlay );
1269 p_text->pf_release( p_text );
1275 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1277 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1279 p_intf->p_libvlc->pf_memcpy( &render->text_style, &default_text_style,
1280 sizeof( text_style_t ) );
1281 free( render->psz_string );
1282 render->psz_string = NULL;
1284 render->i_x = p_sys->i_x;
1285 render->i_y = p_sys->i_y;
1286 render->i_pos = p_sys->i_pos;
1287 #ifdef FBOSD_BLENDING
1288 render->i_alpha = p_sys->i_alpha;
1290 render->b_absolute = p_sys->b_absolute;
1291 render->i_state = FBOSD_STATE_FREE;
1294 static vlc_bool_t isRendererReady( intf_thread_t *p_intf )
1296 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1299 /* Check if there are more items to render */
1300 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1302 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1308 /*****************************************************************************
1310 *****************************************************************************
1311 * This part of the interface is in a separate thread so that we can call
1312 * exec() from within it without annoying the rest of the program.
1313 *****************************************************************************/
1314 static void Run( intf_thread_t *p_intf )
1316 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1318 while( !intf_ShouldDie( p_intf ) )
1322 /* Is there somthing to render? */
1323 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1325 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1327 Render( p_intf, &p_sys->render[i] );
1328 RenderClear( p_intf, &p_sys->render[i] );
1332 if( p_sys->b_clear )
1334 SetOverlayTransparency( p_intf, VLC_TRUE );
1336 var_SetString( p_intf, "fbosd-image", "" );
1337 var_SetString( p_intf, "fbosd-text", "" );
1339 p_sys->b_clear = VLC_FALSE;
1340 p_sys->b_need_update = VLC_TRUE;
1343 if( p_sys->b_need_update && p_sys->p_overlay &&
1344 isRendererReady( p_intf ) )
1347 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1348 p_sys->i_page_size );
1350 msg_Err( p_intf, "unable to write to overlay" );
1351 lseek( p_sys->i_fd, 0, SEEK_SET );
1353 /* clear the picture */
1354 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1355 p_sys->b_need_update = VLC_FALSE;
1358 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1359 msleep( INTF_IDLE_SLEEP );
1367 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1368 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1370 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1371 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1372 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1374 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1376 p_sys->b_need_update = VLC_TRUE;
1378 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1381 /* Clear the entire render list */
1382 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1384 RenderClear( p_intf, &p_sys->render[i] );
1386 p_sys->b_clear = VLC_TRUE;
1388 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1391 /* Are we already busy with on slot ? */
1392 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1394 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1396 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1404 /* Are we already busy with on slot ? */
1405 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1407 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1410 /* No, then find first FREE slot */
1411 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1413 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1415 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1418 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1420 msg_Warn( p_this, "render space depleated" );
1424 /* Found a free slot */
1425 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1426 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1428 free( p_sys->render[i].psz_string );
1429 p_sys->render[i].psz_string = strdup( newval.psz_string );
1430 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1432 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1434 free( p_sys->render[i].psz_string );
1435 p_sys->render[i].psz_string = strdup( newval.psz_string );
1436 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1438 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1440 p_sys->render[i].b_absolute = VLC_FALSE;
1441 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1442 newval.i_int : p_sys->i_width;
1444 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1446 p_sys->render[i].b_absolute = VLC_FALSE;
1447 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1448 newval.i_int : p_sys->i_height;
1450 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1452 p_sys->render[i].b_absolute = VLC_TRUE;
1453 p_sys->render[i].i_pos = newval.i_int;
1455 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1457 p_sys->render[i].text_style.i_font_size = newval.i_int;
1459 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1461 p_sys->render[i].text_style.i_font_color = newval.i_int;
1463 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1465 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1467 #ifdef FBOSD_BLENDING
1468 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1470 p_sys->render[i].i_alpha = newval.i_int;