1 /*****************************************************************************
2 * fbosd.c : framebuffer osd plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2007-2008, 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
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 */
69 #if defined(FBOSD_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 *,
94 #if defined(FBOSD_BLENDING)
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, true );
190 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
191 FBOSD_IMAGE_LONGTEXT, true );
192 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
193 FBOSD_LONGTEXT, true );
195 #if defined(FBOSD_BLENDING)
196 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
197 ALPHA_LONGTEXT, true );
201 set_section( N_("Position"), NULL );
202 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
203 POSX_LONGTEXT, false );
204 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
205 POSY_LONGTEXT, false );
206 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, 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, 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", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true );
220 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true );
221 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, 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 */
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 bool 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 #if defined(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 */
298 int i_alpha; /* transparency for images */
300 /* commands control */
301 bool b_need_update; /* update display with \overlay buffer */
302 bool b_clear; /* clear overlay buffer make it tranparent */
303 bool 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 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
336 p_intf->pf_run = Run;
338 p_sys->p_image = image_HandlerCreate( p_this );
339 if( !p_sys->p_image )
341 free( p_intf->p_sys->p_style );
342 free( p_intf->p_sys );
343 msg_Err( p_intf, "out of memory" );
347 #if defined(FBOSD_BLENDING)
348 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
349 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
351 p_sys->i_alpha = 255;
353 p_sys->i_aspect = -1;
355 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
358 char *psz_parser = strchr( psz_aspect, ':' );
362 *psz_parser++ = '\0';
363 p_sys->i_aspect = ( atoi( psz_aspect )
364 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
365 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
367 msg_Dbg( p_intf, "using aspect ratio %d:%d",
368 atoi( psz_aspect ), atoi( psz_parser ) );
374 /* Use PAL by default */
375 p_sys->i_width = p_sys->fmt_out.i_width = 704;
376 p_sys->i_height = p_sys->fmt_out.i_height = 576;
378 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
379 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
380 if( psz_tmp && *psz_tmp )
382 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
383 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
384 p_sys->render[0].psz_string = strdup( psz_tmp );
388 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
389 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
390 if( psz_tmp && *psz_tmp )
392 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
393 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
394 p_sys->render[1].psz_string = strdup( psz_tmp );
398 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
399 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
400 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
402 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
403 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
404 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
406 p_sys->p_style->i_font_size =
407 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
408 p_sys->p_style->i_font_color =
409 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
410 p_sys->p_style->i_font_alpha = 255 -
411 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
413 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
414 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
415 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
417 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
419 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
420 sizeof( text_style_t ) );
423 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
424 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
425 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
427 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
428 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
429 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
431 /* Check if picture position was overridden */
432 p_sys->b_absolute = true;
433 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
435 p_sys->b_absolute = false;
436 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
437 p_sys->i_y : p_sys->i_height;
438 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
439 p_sys->i_x : p_sys->i_width;
442 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
443 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
444 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
445 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
447 /* Initialize framebuffer */
448 if( OpenDisplay( p_intf ) )
450 Destroy( VLC_OBJECT(p_intf) );
456 #if defined(FBOSD_BLENDING)
457 /* Load the blending module */
458 if( OpenBlending( p_intf ) )
460 msg_Err( p_intf, "Unable to load image blending module" );
461 Destroy( VLC_OBJECT(p_intf) );
466 /* Load text renderer module */
467 if( OpenTextRenderer( p_intf ) )
469 msg_Err( p_intf, "Unable to load text rendering module" );
470 Destroy( VLC_OBJECT(p_intf) );
474 /* Load scaling module */
475 if( OpenScaling( p_intf ) )
477 msg_Err( p_intf, "Unable to load image scaling module" );
478 Destroy( VLC_OBJECT(p_intf) );
482 p_sys->b_render = true;
483 p_sys->b_need_update = true;
488 /*****************************************************************************
489 * Destroy: destroy FB interface thread output method
490 *****************************************************************************
491 * Terminate an output method created by Create
492 *****************************************************************************/
493 static void Destroy( vlc_object_t *p_this )
495 intf_thread_t *p_intf = (intf_thread_t *)p_this;
496 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
499 p_sys->b_need_update = false;
500 p_sys->b_render = false;
501 p_sys->b_clear = false;
503 #if defined(FBOSD_BLENDING)
504 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
505 var_Destroy( p_intf, "fbosd-alpha" );
508 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
509 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
510 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
511 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
512 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
513 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
514 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
515 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
516 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
517 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
518 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
520 var_Destroy( p_intf, "fbosd-x" );
521 var_Destroy( p_intf, "fbosd-y" );
522 var_Destroy( p_intf, "fbosd-position" );
523 var_Destroy( p_intf, "fbosd-image" );
524 var_Destroy( p_intf, "fbosd-text" );
525 var_Destroy( p_intf, "fbosd-font-size" );
526 var_Destroy( p_intf, "fbosd-font-color" );
527 var_Destroy( p_intf, "fbosd-font-opacity" );
528 var_Destroy( p_intf, "fbosd-clear" );
529 var_Destroy( p_intf, "fbosd-render" );
530 var_Destroy( p_intf, "fbosd-display" );
532 var_Destroy( p_intf, "fbosd-aspect-ratio" );
534 CloseDisplay( p_intf );
536 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
538 free( p_sys->render[i].psz_string );
539 p_sys->render[i].i_state = FBOSD_STATE_FREE;
542 #if defined(FBOSD_BLENDING)
543 if( p_sys->p_blend ) CloseBlending( p_intf );
545 if( p_sys->p_text ) CloseTextRenderer( p_intf );
547 if( p_sys->p_scale ) CloseScaling( p_intf );
550 image_HandlerDelete( p_sys->p_image );
551 if( p_sys->p_overlay )
552 p_sys->p_overlay->pf_release( p_sys->p_overlay );
554 free( p_sys->p_style );
558 #if defined(FBOSD_BLENDING)
559 static int OpenBlending( intf_thread_t *p_intf )
561 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
563 p_intf->p_sys->p_blend =
564 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
565 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
566 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
567 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
568 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
569 p_intf->p_sys->fmt_out.i_aspect;
570 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
571 p_intf->p_sys->fmt_out.i_chroma;
572 if( config_GetInt( p_intf, "freetype-yuvp" ) )
573 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
574 VLC_FOURCC('Y','U','V','P');
576 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
577 VLC_FOURCC('Y','U','V','A');
579 p_intf->p_sys->p_blend->p_module =
580 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
582 if( !p_intf->p_sys->p_blend->p_module )
588 static void CloseBlending( intf_thread_t *p_intf )
590 if( p_intf->p_sys->p_blend )
592 if( p_intf->p_sys->p_blend->p_module )
593 module_Unneed( p_intf->p_sys->p_blend,
594 p_intf->p_sys->p_blend->p_module );
596 vlc_object_detach( p_intf->p_sys->p_blend );
597 vlc_object_release( p_intf->p_sys->p_blend );
602 static int OpenTextRenderer( intf_thread_t *p_intf )
604 char *psz_modulename = NULL;
606 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
608 p_intf->p_sys->p_text =
609 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
610 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
612 p_intf->p_sys->p_text->fmt_out.video.i_width =
613 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
614 p_intf->p_sys->i_width;
615 p_intf->p_sys->p_text->fmt_out.video.i_height =
616 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
617 p_intf->p_sys->i_height;
619 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
620 if( psz_modulename && *psz_modulename )
622 p_intf->p_sys->p_text->p_module =
623 module_Need( p_intf->p_sys->p_text, "text renderer",
624 psz_modulename, true );
626 if( !p_intf->p_sys->p_text->p_module )
628 p_intf->p_sys->p_text->p_module =
629 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
631 free( psz_modulename );
633 if( !p_intf->p_sys->p_text->p_module )
639 static void CloseTextRenderer( intf_thread_t *p_intf )
641 if( p_intf->p_sys->p_text )
643 if( p_intf->p_sys->p_text->p_module )
644 module_Unneed( p_intf->p_sys->p_text,
645 p_intf->p_sys->p_text->p_module );
647 vlc_object_detach( p_intf->p_sys->p_text );
648 vlc_object_release( p_intf->p_sys->p_text );
652 static int OpenScaling( intf_thread_t *p_intf )
654 if( p_intf->p_sys->p_scale ) return VLC_EGENERIC;
656 p_intf->p_sys->p_scale =
657 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
658 vlc_object_attach( p_intf->p_sys->p_scale, p_intf );
659 p_intf->p_sys->p_scale->fmt_out.video.i_chroma =
660 p_intf->p_sys->p_scale->fmt_in.video.i_chroma =
661 p_intf->p_sys->fmt_out.i_chroma;
663 /* XXX: We'll also be using it for YUVA and RGBA blending ... */
664 p_intf->p_sys->p_scale->fmt_in.video.i_width =
665 p_intf->p_sys->p_scale->fmt_in.video.i_height = 32;
666 p_intf->p_sys->p_scale->fmt_out.video.i_width =
667 p_intf->p_sys->p_scale->fmt_out.video.i_height = 16;
669 p_intf->p_sys->p_scale->p_module =
670 module_Need( p_intf->p_sys->p_scale, "video filter2", 0, 0 );
672 if( !p_intf->p_sys->p_scale->p_module )
678 static int CloseScaling( intf_thread_t *p_intf )
680 if( p_intf->p_sys->p_scale )
682 if( p_intf->p_sys->p_scale->p_module )
683 module_Unneed( p_intf->p_sys->p_scale,
684 p_intf->p_sys->p_scale->p_module );
686 vlc_object_detach( p_intf->p_sys->p_scale );
687 vlc_object_release( p_intf->p_sys->p_scale );
692 /*****************************************************************************
694 * allocate a picture buffer for use with the overlay fb.
695 *****************************************************************************/
696 static picture_t *AllocatePicture( vlc_object_t *p_this,
697 video_format_t *p_fmt )
699 picture_t *p_pic = malloc( sizeof( picture_t ) );
700 if( !p_pic ) return NULL;
702 if( !p_fmt->p_palette &&
703 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
705 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
706 if( !p_fmt->p_palette )
712 else p_fmt->p_palette = NULL;
714 p_pic->p_data_orig = NULL;
716 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
717 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
719 if( !p_pic->i_planes )
722 free( p_fmt->p_palette );
728 /*****************************************************************************
730 * Deallocate a picture buffer and free all associated memory.
731 *****************************************************************************/
732 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
733 video_format_t *p_fmt )
738 free( p_pic->p_data_orig );
739 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
743 free( p_fmt->p_palette );
744 p_fmt->p_palette = NULL;
749 /*****************************************************************************
750 * SetOverlayTransparency: Set the transparency for this overlay fb,
751 * - true is make transparent
752 * - false is make non tranparent
753 *****************************************************************************/
754 static void SetOverlayTransparency( intf_thread_t *p_intf,
757 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
758 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
759 * p_sys->i_bytes_per_pixel;
760 size_t i_page_size = (p_sys->i_page_size > i_size) ?
761 i_size : p_sys->i_page_size;
763 if( p_sys->p_overlay )
765 msg_Dbg( p_intf, "Make overlay %s",
766 b_transparent ? "transparent" : "opaque" );
767 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
769 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
773 #if defined(FBOSD_BLENDING)
774 /*****************************************************************************
775 * BlendPicture: Blend two pictures together..
776 *****************************************************************************/
777 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
778 video_format_t *p_fmt_dst, picture_t *p_pic_src,
779 picture_t *p_pic_dst )
781 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
782 if( p_sys->p_blend && p_sys->p_blend->p_module )
784 int i_x_offset = p_sys->i_x;
785 int i_y_offset = p_sys->i_y;
787 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
789 msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
790 p_pic_src, (char*)&p_fmt_src->i_chroma,
791 p_sys->p_blend->fmt_in.video.i_width, p_sys->p_blend->fmt_in.video.i_height,
792 p_fmt_src->i_bits_per_pixel,
794 p_pic_src->p[0].p_pixels, p_pic_src->p[1].p_pixels,
795 p_pic_src->p[2].p_pixels, p_pic_src->p[3].p_pixels );
796 msg_Dbg( p_intf, "Blending pictures %p %4.4s (%dx%d) %d bits %d planes: 0=%p 1=%p 2=%p 3=%p",
797 p_pic_dst, (char*)&p_fmt_dst->i_chroma,
798 p_fmt_dst->i_width, p_fmt_dst->i_height,
799 p_fmt_dst->i_bits_per_pixel,
801 p_pic_dst->p[0].p_pixels, p_pic_dst->p[1].p_pixels,
802 p_pic_dst->p[2].p_pixels, p_pic_dst->p[3].p_pixels );
804 /* Update the output picture size */
805 p_sys->p_blend->fmt_out.video.i_width =
806 p_sys->p_blend->fmt_out.video.i_visible_width =
808 p_sys->p_blend->fmt_out.video.i_height =
809 p_sys->p_blend->fmt_out.video.i_visible_height =
812 i_x_offset = __MAX( i_x_offset, 0 );
813 i_y_offset = __MAX( i_y_offset, 0 );
815 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
816 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
825 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
827 uint8_t *p_begin = NULL, *p_end = NULL;
830 if( *p_pic && ((*p_pic)->i_planes != 1) )
833 "cannot invert alpha channel too many planes %d (only 1 supported)",
834 (*p_pic)->i_planes );
838 switch( fmt.i_chroma )
840 case VLC_FOURCC('R','V','2','4'):
841 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
842 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
843 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
846 case VLC_FOURCC('R','V','3','2'):
847 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
848 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
849 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
853 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
854 (char *)&fmt.i_chroma );
858 for( ; p_begin < p_end; p_begin += i_skip )
862 if( i_opacity != 0xFF )
863 i_opacity = 255 - *p_begin;
864 *p_begin = i_opacity;
870 /*****************************************************************************
871 * RenderPicture: Render the picture into the p_dest buffer.
872 * We don't take transparent pixels into account, so we don't have to blend
873 * the two images together.
874 *****************************************************************************/
875 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
876 picture_t *p_src, picture_t *p_dest )
880 if( !p_dest && !p_src ) return VLC_EGENERIC;
882 for( i = 0; i < p_src->i_planes ; i++ )
884 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
886 /* There are margins, but with the same width : perfect ! */
887 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
888 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
892 /* We need to proceed line by line */
893 uint8_t *p_in = p_src->p[i].p_pixels;
894 uint8_t *p_out = p_dest->p[i].p_pixels;
896 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
897 int i_x_clip, i_y_clip;
899 /* Check boundaries, clip the image if necessary */
900 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
901 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
903 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
904 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
906 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
907 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
908 i_x_offset, i_y_offset, i_x, i_x_clip );
910 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
911 ( i_x <= p_dest->p[i].i_visible_pitch ) )
915 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
916 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
918 vlc_memcpy( p_out + i_x, p_in,
919 p_src->p[i].i_visible_pitch - i_x_clip );
920 p_in += p_src->p[i].i_pitch;
921 p_out += p_dest->p[i].i_pitch;
929 /*****************************************************************************
930 * RenderText - Render text to the desired picture format
931 *****************************************************************************/
932 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
933 text_style_t *p_style, video_format_t *p_fmt )
935 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
936 subpicture_region_t *p_region;
937 picture_t *p_dest = NULL;
939 if( !psz_string ) return p_dest;
941 if( p_sys->p_text && p_sys->p_text->p_module )
943 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
947 memset( p_region, 0, sizeof(subpicture_region_t) );
949 p_region->psz_text = strdup( psz_string );
950 p_region->p_style = p_style;
952 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
953 p_region->fmt.i_aspect = 0;
954 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
955 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
956 p_region->fmt.i_x_offset = 0;
957 p_region->fmt.i_y_offset = 0;
959 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
961 if( p_sys->p_text->pf_render_text )
963 video_format_t fmt_out;
965 memset( &fmt_out, 0, sizeof(video_format_t) );
967 p_sys->p_text->pf_render_text( p_sys->p_text,
968 p_region, p_region );
970 #if defined(FBOSD_BLENDING)
971 fmt_out = p_region->fmt;
972 fmt_out.i_bits_per_pixel = 32;
973 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
975 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
978 if( p_region->picture.pf_release )
979 p_region->picture.pf_release( &p_region->picture );
980 free( p_region->psz_text );
984 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
986 fmt_out.i_chroma = p_fmt->i_chroma;
987 p_dest = ConvertImage( p_intf, &p_region->picture,
988 &p_region->fmt, &fmt_out );
990 if( p_region->picture.pf_release )
991 p_region->picture.pf_release( &p_region->picture );
992 free( p_region->psz_text );
996 free( p_region->psz_text );
1002 /*****************************************************************************
1003 * LoadImage: Load an image from file into a picture buffer.
1004 *****************************************************************************/
1005 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
1008 picture_t *p_pic = NULL;
1010 if( psz_file && p_intf->p_sys->p_image )
1012 video_format_t fmt_in, fmt_out;
1014 memset( &fmt_in, 0, sizeof(fmt_in) );
1015 memset( &fmt_out, 0, sizeof(fmt_out) );
1017 fmt_out.i_chroma = p_fmt->i_chroma;
1018 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
1019 &fmt_in, &fmt_out );
1021 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
1022 fmt_out.i_width, fmt_out.i_height,
1023 (char *)&p_fmt->i_chroma );
1028 #if ! defined(FBOSD_BLENDING)
1029 /*****************************************************************************
1030 * Convertmage: Convert image to another fourcc
1031 *****************************************************************************/
1032 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
1033 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
1035 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1036 picture_t *p_old = NULL;
1038 if( p_sys->p_image )
1040 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
1042 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
1043 p_fmt_out->i_width, p_fmt_out->i_height,
1044 (char *)&p_fmt_out->i_chroma );
1050 /*****************************************************************************
1051 * Init: initialize framebuffer video thread output method
1052 *****************************************************************************/
1053 static int Init( intf_thread_t *p_intf )
1055 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1057 /* Initialize the output structure: RGB with square pixels, whatever
1058 * the input format is, since it's the only format we know */
1059 switch( p_sys->var_info.bits_per_pixel )
1061 case 8: /* FIXME: set the palette */
1062 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
1064 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
1066 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
1068 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
1070 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
1072 msg_Err( p_intf, "unknown screen depth %i",
1073 p_sys->var_info.bits_per_pixel );
1074 return VLC_EGENERIC;
1077 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1078 p_sys->fmt_out.i_width = p_sys->i_width;
1079 p_sys->fmt_out.i_height = p_sys->i_height;
1081 /* Assume we have square pixels */
1082 if( p_sys->i_aspect < 0 )
1084 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1085 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1087 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1089 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1091 /* Allocate overlay buffer */
1092 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1094 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1096 SetOverlayTransparency( p_intf, true );
1098 /* We know the chroma, allocate a buffer which will be used
1099 * to write to the overlay framebuffer */
1100 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1101 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1102 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1104 if( p_sys->var_info.xres_virtual )
1106 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1107 * p_sys->i_bytes_per_pixel;
1111 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1112 * p_sys->i_bytes_per_pixel;
1115 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1116 * p_sys->i_bytes_per_pixel;
1118 p_sys->p_overlay->i_planes = 1;
1123 /*****************************************************************************
1124 * End: terminate framebuffer interface
1125 *****************************************************************************/
1126 static void End( intf_thread_t *p_intf )
1128 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1131 SetOverlayTransparency( p_intf, false );
1132 if( p_sys->p_overlay )
1135 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size );
1137 msg_Err( p_intf, "unable to clear overlay" );
1140 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1141 &p_intf->p_sys->fmt_out );
1142 p_intf->p_sys->p_overlay = NULL;
1145 /*****************************************************************************
1146 * OpenDisplay: initialize framebuffer
1147 *****************************************************************************/
1148 static int OpenDisplay( intf_thread_t *p_intf )
1150 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1151 char *psz_device; /* framebuffer device path */
1152 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1154 /* Open framebuffer device */
1155 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1157 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1158 return VLC_EGENERIC;
1161 p_sys->i_fd = open( psz_device, O_RDWR );
1162 if( p_sys->i_fd == -1 )
1164 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1166 return VLC_EGENERIC;
1170 /* Get framebuffer device information */
1171 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1173 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1174 close( p_sys->i_fd );
1175 return VLC_EGENERIC;
1178 /* Get some info on the framebuffer itself */
1179 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1181 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1182 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1185 /* FIXME: if the image is full-size, it gets cropped on the left
1186 * because of the xres / xres_virtual slight difference */
1187 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1188 p_sys->var_info.xres, p_sys->var_info.yres,
1189 p_sys->var_info.xres_virtual,
1190 p_sys->var_info.yres_virtual );
1192 p_sys->fmt_out.i_width = p_sys->i_width;
1193 p_sys->fmt_out.i_height = p_sys->i_height;
1195 p_sys->p_palette = NULL;
1196 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1198 switch( p_sys->var_info.bits_per_pixel )
1201 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1202 if( !p_sys->p_palette )
1204 msg_Err( p_intf, "out of memory" );
1205 close( p_sys->i_fd );
1208 p_sys->fb_cmap.start = 0;
1209 p_sys->fb_cmap.len = 256;
1210 p_sys->fb_cmap.red = p_sys->p_palette;
1211 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1212 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1213 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1215 /* Save the colormap */
1216 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1218 p_sys->i_bytes_per_pixel = 1;
1223 p_sys->i_bytes_per_pixel = 2;
1227 p_sys->i_bytes_per_pixel = 3;
1231 p_sys->i_bytes_per_pixel = 4;
1235 msg_Err( p_intf, "screen depth %d is not supported",
1236 p_sys->var_info.bits_per_pixel );
1238 close( p_sys->i_fd );
1239 return VLC_EGENERIC;
1242 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1243 * p_sys->i_bytes_per_pixel;
1245 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1246 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1247 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1251 /*****************************************************************************
1252 * CloseDisplay: terminate FB interface thread
1253 *****************************************************************************/
1254 static void CloseDisplay( intf_thread_t *p_intf )
1256 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1258 /* Restore palette */
1259 if( p_sys->var_info.bits_per_pixel == 8 )
1261 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1262 free( p_sys->p_palette );
1263 p_sys->p_palette = NULL;
1267 close( p_sys->i_fd );
1270 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1272 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1274 if( render->i_state != FBOSD_STATE_RENDER ) return;
1275 if( !render->psz_string ) return;
1277 if( render->i_type == FBOSD_RENDER_IMAGE )
1280 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1283 RenderPicture( p_intf, render->i_x, render->i_y,
1284 p_pic, p_sys->p_overlay );
1285 p_pic->pf_release( p_pic );
1288 else if( render->i_type == FBOSD_RENDER_TEXT )
1291 #if defined(FBOSD_BLENDING)
1292 video_format_t fmt_in;
1293 memset( &fmt_in, 0, sizeof(video_format_t) );
1294 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1298 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1299 p_text, p_sys->p_overlay );
1300 msg_Dbg( p_intf, "releasing picture" );
1301 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1304 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1308 RenderPicture( p_intf, render->i_x, render->i_y,
1309 p_text, p_sys->p_overlay );
1310 p_text->pf_release( p_text );
1316 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1318 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1320 vlc_memcpy( &render->text_style, &default_text_style,
1321 sizeof( text_style_t ) );
1322 free( render->psz_string );
1323 render->psz_string = NULL;
1325 render->i_x = p_sys->i_x;
1326 render->i_y = p_sys->i_y;
1327 render->i_pos = p_sys->i_pos;
1328 render->i_alpha = p_sys->i_alpha;
1329 render->b_absolute = p_sys->b_absolute;
1330 render->i_state = FBOSD_STATE_FREE;
1333 static bool isRendererReady( intf_thread_t *p_intf )
1335 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1338 /* Check if there are more items to render */
1339 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1341 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1347 /*****************************************************************************
1349 *****************************************************************************
1350 * This part of the interface is in a separate thread so that we can call
1351 * exec() from within it without annoying the rest of the program.
1352 *****************************************************************************/
1353 static void Run( intf_thread_t *p_intf )
1355 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1357 while( !intf_ShouldDie( p_intf ) )
1361 /* Is there somthing to render? */
1362 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1364 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1366 Render( p_intf, &p_sys->render[i] );
1367 RenderClear( p_intf, &p_sys->render[i] );
1371 if( p_sys->b_clear )
1373 SetOverlayTransparency( p_intf, true );
1375 var_SetString( p_intf, "fbosd-image", "" );
1376 var_SetString( p_intf, "fbosd-text", "" );
1378 p_sys->b_clear = false;
1379 p_sys->b_need_update = true;
1382 if( p_sys->b_need_update && p_sys->p_overlay &&
1383 isRendererReady( p_intf ) )
1386 #if defined(FBOSD_BLENDING)
1387 /* Reverse alpha channel to work around FPGA bug */
1388 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1390 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1391 p_sys->i_page_size );
1393 msg_Err( p_intf, "unable to write to overlay" );
1394 lseek( p_sys->i_fd, 0, SEEK_SET );
1396 /* clear the picture */
1397 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1398 p_sys->b_need_update = false;
1401 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1402 msleep( INTF_IDLE_SLEEP );
1410 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1411 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1413 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1414 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1415 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1417 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1419 p_sys->b_need_update = true;
1421 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1424 /* Clear the entire render list */
1425 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1427 RenderClear( p_intf, &p_sys->render[i] );
1429 p_sys->b_clear = true;
1431 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1434 /* Are we already busy with on slot ? */
1435 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1437 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1439 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1447 /* Are we already busy with on slot ? */
1448 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1450 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1453 /* No, then find first FREE slot */
1454 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1456 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1458 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1461 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1463 msg_Warn( p_this, "render space depleated" );
1467 /* Found a free slot */
1468 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1469 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1471 free( p_sys->render[i].psz_string );
1472 p_sys->render[i].psz_string = strdup( newval.psz_string );
1473 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1475 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1477 free( p_sys->render[i].psz_string );
1478 p_sys->render[i].psz_string = strdup( newval.psz_string );
1479 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1481 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1483 p_sys->render[i].b_absolute = false;
1484 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1485 newval.i_int : p_sys->i_width;
1487 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1489 p_sys->render[i].b_absolute = false;
1490 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1491 newval.i_int : p_sys->i_height;
1493 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1495 p_sys->render[i].b_absolute = true;
1496 p_sys->render[i].i_pos = newval.i_int;
1498 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1500 p_sys->render[i].text_style.i_font_size = newval.i_int;
1502 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1504 p_sys->render[i].text_style.i_font_color = newval.i_int;
1506 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1508 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1510 #if defined(FBOSD_BLENDING)
1511 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1513 p_sys->render[i].i_alpha = newval.i_int;