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>
56 /*****************************************************************************
58 *****************************************************************************/
59 static int Create ( vlc_object_t * );
60 static void Destroy ( vlc_object_t * );
61 static void Run ( intf_thread_t * );
63 static int Init ( intf_thread_t * );
64 static void End ( intf_thread_t * );
66 static int OpenDisplay ( intf_thread_t * );
67 static void CloseDisplay ( intf_thread_t * );
69 /* Load modules needed for rendering and blending */
70 #if defined(FBOSD_BLENDING)
71 static int OpenBlending ( intf_thread_t * );
72 static void CloseBlending ( intf_thread_t * );
74 static int OpenTextRenderer ( intf_thread_t * );
75 static void CloseTextRenderer( intf_thread_t * );
77 /* Manipulate the overlay buffer */
78 static int OverlayCallback( vlc_object_t *, char const *,
79 vlc_value_t, vlc_value_t, void * );
81 static picture_t *AllocatePicture( vlc_object_t *,
83 static void DeAllocatePicture( vlc_object_t *, picture_t *,
85 static void SetOverlayTransparency( intf_thread_t *,
87 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
90 #if defined(FBOSD_BLENDING)
91 static int BlendPicture( intf_thread_t *, video_format_t *,
92 video_format_t *, picture_t *, picture_t * );
94 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
95 video_format_t *, video_format_t * );
97 static int RenderPicture( intf_thread_t *, int, int,
98 picture_t *, picture_t * );
99 static picture_t *RenderText( intf_thread_t *, const char *,
100 text_style_t *, video_format_t * );
102 #define DEVICE_TEXT N_("Framebuffer device")
103 #define DEVICE_LONGTEXT N_( \
104 "Framebuffer device to use for rendering (usually /dev/fb0).")
106 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
107 #define ASPECT_RATIO_LONGTEXT N_( \
108 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
110 #define FBOSD_IMAGE_TEXT N_("Image file")
111 #define FBOSD_IMAGE_LONGTEXT N_( \
112 "Filename of image file to use on the overlay framebuffer." )
114 #define ALPHA_TEXT N_("Transparency of the image")
115 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
116 "used in blending. By default it set to fully opaque (255). " \
117 "(from 0 for full transparency to 255 for full opacity)" )
119 #define FBOSD_TEXT N_("Text")
120 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
122 #define POSX_TEXT N_("X coordinate")
123 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
125 #define POSY_TEXT N_("Y coordinate")
126 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
128 #define POS_TEXT N_("Position")
129 #define POS_LONGTEXT N_( \
130 "You can enforce the picture position on the overlay " \
131 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
132 "also use combinations of these values, e.g. 6=top-right).")
134 #define OPACITY_TEXT N_("Opacity")
135 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
136 "overlayed text. 0 = transparent, 255 = totally opaque. " )
138 #define SIZE_TEXT N_("Font size, pixels")
139 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
142 #define COLOR_TEXT N_("Color")
143 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
144 "the video. This must be an hexadecimal (like HTML colors). The first two "\
145 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
146 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
148 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
149 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
150 "making the overlay completely transparent. All previously rendered " \
151 "images and text will be cleared from the cache." )
153 #define RENDER_TEXT N_( "Render text or image" )
154 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
157 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
158 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
159 "displayed on the overlay framebuffer." )
161 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
162 static const char *ppsz_pos_descriptions[] =
163 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
164 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
166 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
167 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
168 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
169 0x00000080, 0x000000FF, 0x0000FFFF};
170 static const char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
171 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
172 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
173 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
177 set_shortname( "fbosd" );
178 set_category( CAT_INTERFACE );
179 set_subcategory( SUBCAT_INTERFACE_MAIN );
181 add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
183 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
184 ASPECT_RATIO_LONGTEXT, true );
186 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
187 FBOSD_IMAGE_LONGTEXT, true );
188 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
189 FBOSD_LONGTEXT, true );
191 #if defined(FBOSD_BLENDING)
192 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
193 ALPHA_LONGTEXT, true );
197 set_section( N_("Position"), NULL );
198 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
199 POSX_LONGTEXT, false );
200 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
201 POSY_LONGTEXT, false );
202 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true );
203 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
205 set_section( N_("Font"), NULL );
206 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
207 OPACITY_TEXT, OPACITY_LONGTEXT, false );
208 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
210 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
211 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
214 set_section( N_("Commands"), NULL );
215 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true );
216 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true );
217 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true );
219 set_description( _("GNU/Linux osd/overlay framebuffer interface") );
220 set_capability( "interface", 10 );
221 set_callbacks( Create, Destroy );
224 /*****************************************************************************
225 * fbosd_render_t: render descriptor
226 *****************************************************************************/
227 struct fbosd_render_t
229 #define FBOSD_RENDER_IMAGE 0
230 #define FBOSD_RENDER_TEXT 1
233 #define FBOSD_STATE_FREE 0
234 #define FBOSD_STATE_RESERVED 1
235 #define FBOSD_STATE_RENDER 2
239 text_style_t text_style; /* font control */
247 int i_alpha; /* transparency for images */
249 #define FBOSD_RENDER_MAX 10
251 /*****************************************************************************
252 * intf_sys_t: interface framebuffer method descriptor
253 *****************************************************************************/
256 /* Framebuffer information */
257 int i_fd; /* device handle */
258 struct fb_var_screeninfo var_info; /* current mode information */
259 bool b_pan; /* does device supports panning ? */
260 struct fb_cmap fb_cmap; /* original colormap */
261 uint16_t *p_palette; /* original palette */
263 /* Overlay framebuffer format */
264 video_format_t fmt_out;
265 picture_t *p_overlay;
266 size_t i_page_size; /* page size */
270 int i_bytes_per_pixel;
272 /* Image and Picture rendering */
273 image_handler_t *p_image;
274 #if defined(FBOSD_BLENDING)
275 filter_t *p_blend; /* alpha blending module */
277 filter_t *p_text; /* text renderer module */
280 struct fbosd_render_t render[FBOSD_RENDER_MAX];
283 text_style_t *p_style; /* font control */
291 int i_alpha; /* transparency for images */
293 /* commands control */
294 bool b_need_update; /* update display with \overlay buffer */
295 bool b_clear; /* clear overlay buffer make it tranparent */
296 bool b_render; /* render an image or text in overlay buffer */
299 /*****************************************************************************
300 * Create: allocates FB interface thread output method
301 *****************************************************************************/
302 static int Create( vlc_object_t *p_this )
304 intf_thread_t *p_intf = (intf_thread_t *)p_this;
310 /* Allocate instance and initialize some members */
311 p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
314 msg_Err( p_intf, "out of memory" );
317 memset( p_sys, 0, sizeof(intf_sys_t) );
319 p_sys->p_style = malloc( sizeof( text_style_t ) );
320 if( !p_sys->p_style )
322 free( p_intf->p_sys );
323 msg_Err( p_intf, "out of memory" );
326 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
328 p_intf->pf_run = Run;
330 p_sys->p_image = image_HandlerCreate( p_this );
331 if( !p_sys->p_image )
333 free( p_intf->p_sys->p_style );
334 free( p_intf->p_sys );
335 msg_Err( p_intf, "out of memory" );
339 #if defined(FBOSD_BLENDING)
340 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
341 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
343 p_sys->i_alpha = 255;
345 p_sys->i_aspect = -1;
347 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
350 char *psz_parser = strchr( psz_aspect, ':' );
354 *psz_parser++ = '\0';
355 p_sys->i_aspect = ( atoi( psz_aspect )
356 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
357 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
359 msg_Dbg( p_intf, "using aspect ratio %d:%d",
360 atoi( psz_aspect ), atoi( psz_parser ) );
366 /* Use PAL by default */
367 p_sys->i_width = p_sys->fmt_out.i_width = 704;
368 p_sys->i_height = p_sys->fmt_out.i_height = 576;
370 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
371 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
372 if( psz_tmp && *psz_tmp )
374 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
375 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
376 p_sys->render[0].psz_string = strdup( psz_tmp );
380 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
381 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
382 if( psz_tmp && *psz_tmp )
384 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
385 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
386 p_sys->render[1].psz_string = strdup( psz_tmp );
390 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
391 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
392 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
394 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
395 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
396 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
398 p_sys->p_style->i_font_size =
399 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
400 p_sys->p_style->i_font_color =
401 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
402 p_sys->p_style->i_font_alpha = 255 -
403 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
405 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
406 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
407 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
409 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
411 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
412 sizeof( text_style_t ) );
415 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
416 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
417 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
419 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
420 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
421 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
423 /* Check if picture position was overridden */
424 p_sys->b_absolute = true;
425 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
427 p_sys->b_absolute = false;
428 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
429 p_sys->i_y : p_sys->i_height;
430 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
431 p_sys->i_x : p_sys->i_width;
434 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
435 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
436 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
437 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
439 /* Initialize framebuffer */
440 if( OpenDisplay( p_intf ) )
442 Destroy( VLC_OBJECT(p_intf) );
448 #if defined(FBOSD_BLENDING)
449 /* Load the blending module */
450 if( OpenBlending( p_intf ) )
452 msg_Err( p_intf, "Unable to load image blending module" );
453 Destroy( VLC_OBJECT(p_intf) );
458 /* Load text renderer module */
459 if( OpenTextRenderer( p_intf ) )
461 msg_Err( p_intf, "Unable to load text rendering module" );
462 Destroy( VLC_OBJECT(p_intf) );
466 p_sys->b_render = true;
467 p_sys->b_need_update = true;
472 /*****************************************************************************
473 * Destroy: destroy FB interface thread output method
474 *****************************************************************************
475 * Terminate an output method created by Create
476 *****************************************************************************/
477 static void Destroy( vlc_object_t *p_this )
479 intf_thread_t *p_intf = (intf_thread_t *)p_this;
480 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
483 p_sys->b_need_update = false;
484 p_sys->b_render = false;
485 p_sys->b_clear = false;
487 #if defined(FBOSD_BLENDING)
488 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
489 var_Destroy( p_intf, "fbosd-alpha" );
492 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
493 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
494 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
495 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
496 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
497 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
498 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
499 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
500 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
501 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
502 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
504 var_Destroy( p_intf, "fbosd-x" );
505 var_Destroy( p_intf, "fbosd-y" );
506 var_Destroy( p_intf, "fbosd-position" );
507 var_Destroy( p_intf, "fbosd-image" );
508 var_Destroy( p_intf, "fbosd-text" );
509 var_Destroy( p_intf, "fbosd-font-size" );
510 var_Destroy( p_intf, "fbosd-font-color" );
511 var_Destroy( p_intf, "fbosd-font-opacity" );
512 var_Destroy( p_intf, "fbosd-clear" );
513 var_Destroy( p_intf, "fbosd-render" );
514 var_Destroy( p_intf, "fbosd-display" );
516 var_Destroy( p_intf, "fbosd-aspect-ratio" );
518 CloseDisplay( p_intf );
520 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
522 free( p_sys->render[i].psz_string );
523 p_sys->render[i].i_state = FBOSD_STATE_FREE;
526 #if defined(FBOSD_BLENDING)
527 if( p_sys->p_blend ) CloseBlending( p_intf );
529 if( p_sys->p_text ) CloseTextRenderer( p_intf );
532 image_HandlerDelete( p_sys->p_image );
533 if( p_sys->p_overlay )
534 p_sys->p_overlay->pf_release( p_sys->p_overlay );
536 free( p_sys->p_style );
540 #if defined(FBOSD_BLENDING)
541 static int OpenBlending( intf_thread_t *p_intf )
543 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
545 p_intf->p_sys->p_blend =
546 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
547 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
548 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
549 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
550 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
551 p_intf->p_sys->fmt_out.i_aspect;
552 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
553 p_intf->p_sys->fmt_out.i_chroma;
554 if( config_GetInt( p_intf, "freetype-yuvp" ) )
555 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
556 VLC_FOURCC('Y','U','V','P');
558 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
559 VLC_FOURCC('Y','U','V','A');
561 p_intf->p_sys->p_blend->p_module =
562 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
564 if( !p_intf->p_sys->p_blend->p_module )
570 static void CloseBlending( intf_thread_t *p_intf )
572 if( p_intf->p_sys->p_blend )
574 if( p_intf->p_sys->p_blend->p_module )
575 module_Unneed( p_intf->p_sys->p_blend,
576 p_intf->p_sys->p_blend->p_module );
578 vlc_object_detach( p_intf->p_sys->p_blend );
579 vlc_object_release( p_intf->p_sys->p_blend );
584 static int OpenTextRenderer( intf_thread_t *p_intf )
586 char *psz_modulename = NULL;
588 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
590 p_intf->p_sys->p_text =
591 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
592 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
594 p_intf->p_sys->p_text->fmt_out.video.i_width =
595 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
596 p_intf->p_sys->i_width;
597 p_intf->p_sys->p_text->fmt_out.video.i_height =
598 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
599 p_intf->p_sys->i_height;
601 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
602 if( psz_modulename && *psz_modulename )
604 p_intf->p_sys->p_text->p_module =
605 module_Need( p_intf->p_sys->p_text, "text renderer",
606 psz_modulename, true );
608 if( !p_intf->p_sys->p_text->p_module )
610 p_intf->p_sys->p_text->p_module =
611 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
613 free( psz_modulename );
615 if( !p_intf->p_sys->p_text->p_module )
621 static void CloseTextRenderer( intf_thread_t *p_intf )
623 if( p_intf->p_sys->p_text )
625 if( p_intf->p_sys->p_text->p_module )
626 module_Unneed( p_intf->p_sys->p_text,
627 p_intf->p_sys->p_text->p_module );
629 vlc_object_detach( p_intf->p_sys->p_text );
630 vlc_object_release( p_intf->p_sys->p_text );
634 /*****************************************************************************
636 * allocate a picture buffer for use with the overlay fb.
637 *****************************************************************************/
638 static picture_t *AllocatePicture( vlc_object_t *p_this,
639 video_format_t *p_fmt )
641 picture_t *p_pic = malloc( sizeof( picture_t ) );
642 if( !p_pic ) return NULL;
644 if( !p_fmt->p_palette &&
645 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
647 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
648 if( !p_fmt->p_palette )
654 else p_fmt->p_palette = NULL;
656 p_pic->p_data_orig = NULL;
658 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
659 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
661 if( !p_pic->i_planes )
664 free( p_fmt->p_palette );
670 /*****************************************************************************
672 * Deallocate a picture buffer and free all associated memory.
673 *****************************************************************************/
674 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
675 video_format_t *p_fmt )
680 free( p_pic->p_data_orig );
681 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
685 free( p_fmt->p_palette );
686 p_fmt->p_palette = NULL;
691 /*****************************************************************************
692 * SetOverlayTransparency: Set the transparency for this overlay fb,
693 * - true is make transparent
694 * - false is make non tranparent
695 *****************************************************************************/
696 static void SetOverlayTransparency( intf_thread_t *p_intf,
699 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
700 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
701 * p_sys->i_bytes_per_pixel;
702 size_t i_page_size = (p_sys->i_page_size > i_size) ?
703 i_size : p_sys->i_page_size;
705 if( p_sys->p_overlay )
707 msg_Dbg( p_intf, "Make overlay %s",
708 b_transparent ? "transparent" : "opaque" );
709 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
711 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
715 #if defined(FBOSD_BLENDING)
716 /*****************************************************************************
717 * BlendPicture: Blend two pictures together..
718 *****************************************************************************/
719 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
720 video_format_t *p_fmt_dst, picture_t *p_pic_src,
721 picture_t *p_pic_dst )
723 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
724 if( p_sys->p_blend && p_sys->p_blend->p_module )
726 int i_x_offset = p_sys->i_x;
727 int i_y_offset = p_sys->i_y;
729 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
731 /* Update the output picture size */
732 p_sys->p_blend->fmt_out.video.i_width =
733 p_sys->p_blend->fmt_out.video.i_visible_width =
735 p_sys->p_blend->fmt_out.video.i_height =
736 p_sys->p_blend->fmt_out.video.i_visible_height =
739 i_x_offset = __MAX( i_x_offset, 0 );
740 i_y_offset = __MAX( i_y_offset, 0 );
742 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
743 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
751 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
753 uint8_t *p_begin = NULL, *p_end = NULL;
756 if( *p_pic && ((*p_pic)->i_planes != 1) )
759 "cannot invert alpha channel too many planes %d (only 1 supported)",
760 (*p_pic)->i_planes );
764 switch( fmt.i_chroma )
766 case VLC_FOURCC('R','V','2','4'):
767 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
768 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
769 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
772 case VLC_FOURCC('R','V','3','2'):
773 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
774 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
775 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
779 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
780 (char *)&fmt.i_chroma );
784 for( ; p_begin < p_end; p_begin += i_skip )
788 if( i_opacity != 0xFF )
789 i_opacity = 255 - *p_begin;
790 *p_begin = i_opacity;
797 /*****************************************************************************
798 * RenderPicture: Render the picture into the p_dest buffer.
799 * We don't take transparent pixels into account, so we don't have to blend
800 * the two images together.
801 *****************************************************************************/
802 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
803 picture_t *p_src, picture_t *p_dest )
806 VLC_UNUSED( p_intf );
808 if( !p_dest && !p_src ) return VLC_EGENERIC;
810 for( i = 0; i < p_src->i_planes ; i++ )
812 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
814 /* There are margins, but with the same width : perfect ! */
815 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
816 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
820 /* We need to proceed line by line */
821 uint8_t *p_in = p_src->p[i].p_pixels;
822 uint8_t *p_out = p_dest->p[i].p_pixels;
824 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
825 int i_x_clip, i_y_clip;
827 /* Check boundaries, clip the image if necessary */
828 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
829 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
831 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
832 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
833 #if defined(FBOSD_DEBUG)
834 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
835 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
836 i_x_offset, i_y_offset, i_x, i_x_clip );
838 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
839 ( i_x <= p_dest->p[i].i_visible_pitch ) )
843 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
844 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
846 vlc_memcpy( p_out + i_x, p_in,
847 p_src->p[i].i_visible_pitch - i_x_clip );
848 p_in += p_src->p[i].i_pitch;
849 p_out += p_dest->p[i].i_pitch;
857 /*****************************************************************************
858 * RenderText - Render text to the desired picture format
859 *****************************************************************************/
860 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
861 text_style_t *p_style, video_format_t *p_fmt )
863 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
864 subpicture_region_t *p_region;
865 picture_t *p_dest = NULL;
867 if( !psz_string ) return p_dest;
869 if( p_sys->p_text && p_sys->p_text->p_module )
871 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
875 memset( p_region, 0, sizeof(subpicture_region_t) );
877 p_region->psz_text = strdup( psz_string );
878 p_region->p_style = p_style;
880 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
881 p_region->fmt.i_aspect = 0;
882 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
883 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
884 p_region->fmt.i_x_offset = 0;
885 p_region->fmt.i_y_offset = 0;
887 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
889 if( p_sys->p_text->pf_render_text )
891 video_format_t fmt_out;
893 memset( &fmt_out, 0, sizeof(video_format_t) );
895 p_sys->p_text->pf_render_text( p_sys->p_text,
896 p_region, p_region );
898 #if defined(FBOSD_BLENDING)
899 fmt_out = p_region->fmt;
900 fmt_out.i_bits_per_pixel = 32;
901 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
903 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
906 if( p_region->picture.pf_release )
907 p_region->picture.pf_release( &p_region->picture );
908 free( p_region->psz_text );
912 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
914 fmt_out.i_chroma = p_fmt->i_chroma;
915 p_dest = ConvertImage( p_intf, &p_region->picture,
916 &p_region->fmt, &fmt_out );
918 if( p_region->picture.pf_release )
919 p_region->picture.pf_release( &p_region->picture );
920 free( p_region->psz_text );
924 free( p_region->psz_text );
930 /*****************************************************************************
931 * LoadImage: Load an image from file into a picture buffer.
932 *****************************************************************************/
933 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
936 picture_t *p_pic = NULL;
938 if( psz_file && p_intf->p_sys->p_image )
940 video_format_t fmt_in, fmt_out;
942 memset( &fmt_in, 0, sizeof(fmt_in) );
943 memset( &fmt_out, 0, sizeof(fmt_out) );
945 fmt_out.i_chroma = p_fmt->i_chroma;
946 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
949 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
950 fmt_out.i_width, fmt_out.i_height,
951 (char *)&p_fmt->i_chroma );
956 #if ! defined(FBOSD_BLENDING)
957 /*****************************************************************************
958 * Convertmage: Convert image to another fourcc
959 *****************************************************************************/
960 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
961 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
963 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
964 picture_t *p_old = NULL;
968 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
970 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
971 p_fmt_out->i_width, p_fmt_out->i_height,
972 (char *)&p_fmt_out->i_chroma );
978 /*****************************************************************************
979 * Init: initialize framebuffer video thread output method
980 *****************************************************************************/
981 static int Init( intf_thread_t *p_intf )
983 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
985 /* Initialize the output structure: RGB with square pixels, whatever
986 * the input format is, since it's the only format we know */
987 switch( p_sys->var_info.bits_per_pixel )
989 case 8: /* FIXME: set the palette */
990 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
992 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
994 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
996 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
998 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
1000 msg_Err( p_intf, "unknown screen depth %i",
1001 p_sys->var_info.bits_per_pixel );
1002 return VLC_EGENERIC;
1005 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1006 p_sys->fmt_out.i_width = p_sys->i_width;
1007 p_sys->fmt_out.i_height = p_sys->i_height;
1009 /* Assume we have square pixels */
1010 if( p_sys->i_aspect < 0 )
1012 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1013 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1015 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1017 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1019 /* Allocate overlay buffer */
1020 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1022 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1024 SetOverlayTransparency( p_intf, true );
1026 /* We know the chroma, allocate a buffer which will be used
1027 * to write to the overlay framebuffer */
1028 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1029 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1030 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1032 if( p_sys->var_info.xres_virtual )
1034 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1035 * p_sys->i_bytes_per_pixel;
1039 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1040 * p_sys->i_bytes_per_pixel;
1043 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1044 * p_sys->i_bytes_per_pixel;
1046 p_sys->p_overlay->i_planes = 1;
1051 /*****************************************************************************
1052 * End: terminate framebuffer interface
1053 *****************************************************************************/
1054 static void End( intf_thread_t *p_intf )
1056 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1059 SetOverlayTransparency( p_intf, false );
1060 if( p_sys->p_overlay )
1063 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size );
1065 msg_Err( p_intf, "unable to clear overlay" );
1068 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1069 &p_intf->p_sys->fmt_out );
1070 p_intf->p_sys->p_overlay = NULL;
1073 /*****************************************************************************
1074 * OpenDisplay: initialize framebuffer
1075 *****************************************************************************/
1076 static int OpenDisplay( intf_thread_t *p_intf )
1078 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1079 char *psz_device; /* framebuffer device path */
1080 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1082 /* Open framebuffer device */
1083 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1085 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1086 return VLC_EGENERIC;
1089 p_sys->i_fd = open( psz_device, O_RDWR );
1090 if( p_sys->i_fd == -1 )
1092 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1094 return VLC_EGENERIC;
1098 /* Get framebuffer device information */
1099 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1101 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1102 close( p_sys->i_fd );
1103 return VLC_EGENERIC;
1106 /* Get some info on the framebuffer itself */
1107 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1109 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1110 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1113 /* FIXME: if the image is full-size, it gets cropped on the left
1114 * because of the xres / xres_virtual slight difference */
1115 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1116 p_sys->var_info.xres, p_sys->var_info.yres,
1117 p_sys->var_info.xres_virtual,
1118 p_sys->var_info.yres_virtual );
1120 p_sys->fmt_out.i_width = p_sys->i_width;
1121 p_sys->fmt_out.i_height = p_sys->i_height;
1123 p_sys->p_palette = NULL;
1124 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1126 switch( p_sys->var_info.bits_per_pixel )
1129 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1130 if( !p_sys->p_palette )
1132 close( p_sys->i_fd );
1135 p_sys->fb_cmap.start = 0;
1136 p_sys->fb_cmap.len = 256;
1137 p_sys->fb_cmap.red = p_sys->p_palette;
1138 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1139 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1140 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1142 /* Save the colormap */
1143 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1145 p_sys->i_bytes_per_pixel = 1;
1150 p_sys->i_bytes_per_pixel = 2;
1154 p_sys->i_bytes_per_pixel = 3;
1158 p_sys->i_bytes_per_pixel = 4;
1162 msg_Err( p_intf, "screen depth %d is not supported",
1163 p_sys->var_info.bits_per_pixel );
1165 close( p_sys->i_fd );
1166 return VLC_EGENERIC;
1169 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1170 * p_sys->i_bytes_per_pixel;
1172 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1173 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1174 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1178 /*****************************************************************************
1179 * CloseDisplay: terminate FB interface thread
1180 *****************************************************************************/
1181 static void CloseDisplay( intf_thread_t *p_intf )
1183 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1185 /* Restore palette */
1186 if( p_sys->var_info.bits_per_pixel == 8 )
1188 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1189 free( p_sys->p_palette );
1190 p_sys->p_palette = NULL;
1194 close( p_sys->i_fd );
1197 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1199 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1201 if( render->i_state != FBOSD_STATE_RENDER ) return;
1202 if( !render->psz_string ) return;
1204 if( render->i_type == FBOSD_RENDER_IMAGE )
1207 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1210 RenderPicture( p_intf, render->i_x, render->i_y,
1211 p_pic, p_sys->p_overlay );
1212 p_pic->pf_release( p_pic );
1215 else if( render->i_type == FBOSD_RENDER_TEXT )
1218 #if defined(FBOSD_BLENDING)
1219 video_format_t fmt_in;
1220 memset( &fmt_in, 0, sizeof(video_format_t) );
1221 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1225 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1226 p_text, p_sys->p_overlay );
1227 msg_Dbg( p_intf, "releasing picture" );
1228 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1231 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1235 RenderPicture( p_intf, render->i_x, render->i_y,
1236 p_text, p_sys->p_overlay );
1237 p_text->pf_release( p_text );
1243 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1245 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1247 vlc_memcpy( &render->text_style, &default_text_style,
1248 sizeof( text_style_t ) );
1249 free( render->psz_string );
1250 render->psz_string = NULL;
1252 render->i_x = p_sys->i_x;
1253 render->i_y = p_sys->i_y;
1254 render->i_pos = p_sys->i_pos;
1255 render->i_alpha = p_sys->i_alpha;
1256 render->b_absolute = p_sys->b_absolute;
1257 render->i_state = FBOSD_STATE_FREE;
1260 static bool isRendererReady( intf_thread_t *p_intf )
1262 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1265 /* Check if there are more items to render */
1266 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1268 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1274 /*****************************************************************************
1276 *****************************************************************************
1277 * This part of the interface is in a separate thread so that we can call
1278 * exec() from within it without annoying the rest of the program.
1279 *****************************************************************************/
1280 static void Run( intf_thread_t *p_intf )
1282 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1284 while( !intf_ShouldDie( p_intf ) )
1288 /* Is there somthing to render? */
1289 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1291 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1293 Render( p_intf, &p_sys->render[i] );
1294 RenderClear( p_intf, &p_sys->render[i] );
1298 if( p_sys->b_clear )
1300 SetOverlayTransparency( p_intf, true );
1302 var_SetString( p_intf, "fbosd-image", "" );
1303 var_SetString( p_intf, "fbosd-text", "" );
1305 p_sys->b_clear = false;
1306 p_sys->b_need_update = true;
1309 if( p_sys->b_need_update && p_sys->p_overlay &&
1310 isRendererReady( p_intf ) )
1313 #if defined(FBOSD_BLENDING)
1314 /* Reverse alpha channel to work around FPGA bug */
1315 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1317 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1318 p_sys->i_page_size );
1320 msg_Err( p_intf, "unable to write to overlay" );
1321 lseek( p_sys->i_fd, 0, SEEK_SET );
1323 /* clear the picture */
1324 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1325 p_sys->b_need_update = false;
1328 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1329 msleep( INTF_IDLE_SLEEP );
1337 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1338 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1340 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1341 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1342 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1344 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1346 p_sys->b_need_update = true;
1348 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1351 /* Clear the entire render list */
1352 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1354 RenderClear( p_intf, &p_sys->render[i] );
1356 p_sys->b_clear = true;
1358 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1361 /* Are we already busy with on slot ? */
1362 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1364 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1366 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1374 /* Are we already busy with on slot ? */
1375 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1377 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1380 /* No, then find first FREE slot */
1381 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1383 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1385 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1388 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1390 msg_Warn( p_this, "render space depleated" );
1394 /* Found a free slot */
1395 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1396 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1398 free( p_sys->render[i].psz_string );
1399 p_sys->render[i].psz_string = strdup( newval.psz_string );
1400 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1402 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1404 free( p_sys->render[i].psz_string );
1405 p_sys->render[i].psz_string = strdup( newval.psz_string );
1406 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1408 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1410 p_sys->render[i].b_absolute = false;
1411 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1412 newval.i_int : p_sys->i_width;
1414 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1416 p_sys->render[i].b_absolute = false;
1417 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1418 newval.i_int : p_sys->i_height;
1420 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1422 p_sys->render[i].b_absolute = true;
1423 p_sys->render[i].i_pos = newval.i_int;
1425 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1427 p_sys->render[i].text_style.i_font_size = newval.i_int;
1429 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1431 p_sys->render[i].text_style.i_font_color = newval.i_int;
1433 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1435 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1437 #if defined(FBOSD_BLENDING)
1438 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1440 p_sys->render[i].i_alpha = newval.i_int;