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 *****************************************************************************/
33 #include <vlc_plugin.h>
36 #include <stdlib.h> /* free() */
37 #include <string.h> /* strerror() */
38 #include <fcntl.h> /* open() */
39 #include <unistd.h> /* close() */
41 #include <sys/ioctl.h>
42 #include <sys/mman.h> /* mmap() */
46 #include <vlc_image.h>
47 #include <vlc_interface.h>
48 #include <vlc_input.h>
50 #include <vlc_filter.h>
52 #include <vlc_strings.h>
57 /*****************************************************************************
59 *****************************************************************************/
60 static int Create ( vlc_object_t * );
61 static void Destroy ( vlc_object_t * );
62 static void Run ( intf_thread_t * );
64 static int Init ( intf_thread_t * );
65 static void End ( intf_thread_t * );
67 static int OpenDisplay ( intf_thread_t * );
68 static void CloseDisplay ( intf_thread_t * );
70 /* Load modules needed for rendering and blending */
71 #if defined(FBOSD_BLENDING)
72 static int OpenBlending ( intf_thread_t * );
73 static void CloseBlending ( intf_thread_t * );
75 static int OpenTextRenderer ( intf_thread_t * );
76 static void CloseTextRenderer( intf_thread_t * );
78 /* Manipulate the overlay buffer */
79 static int OverlayCallback( vlc_object_t *, char const *,
80 vlc_value_t, vlc_value_t, void * );
82 static picture_t *AllocatePicture( vlc_object_t *,
84 static void DeAllocatePicture( vlc_object_t *, picture_t *,
86 static void SetOverlayTransparency( intf_thread_t *,
88 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
91 #if defined(FBOSD_BLENDING)
92 static int BlendPicture( intf_thread_t *, video_format_t *,
93 video_format_t *, picture_t *, picture_t * );
95 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
96 video_format_t *, video_format_t * );
98 static int RenderPicture( intf_thread_t *, int, int,
99 picture_t *, picture_t * );
100 static picture_t *RenderText( intf_thread_t *, const char *,
101 text_style_t *, video_format_t * );
103 #define DEVICE_TEXT N_("Framebuffer device")
104 #define DEVICE_LONGTEXT N_( \
105 "Framebuffer device to use for rendering (usually /dev/fb0).")
107 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
108 #define ASPECT_RATIO_LONGTEXT N_( \
109 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
111 #define FBOSD_IMAGE_TEXT N_("Image file")
112 #define FBOSD_IMAGE_LONGTEXT N_( \
113 "Filename of image file to use on the overlay framebuffer." )
115 #define ALPHA_TEXT N_("Transparency of the image")
116 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
117 "used in blending. By default it set to fully opaque (255). " \
118 "(from 0 for full transparency to 255 for full opacity)" )
120 #define FBOSD_TEXT N_("Text")
121 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
123 #define POSX_TEXT N_("X coordinate")
124 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
126 #define POSY_TEXT N_("Y coordinate")
127 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
129 #define POS_TEXT N_("Position")
130 #define POS_LONGTEXT N_( \
131 "You can enforce the picture position on the overlay " \
132 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
133 "also use combinations of these values, e.g. 6=top-right).")
135 #define OPACITY_TEXT N_("Opacity")
136 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
137 "overlayed text. 0 = transparent, 255 = totally opaque. " )
139 #define SIZE_TEXT N_("Font size, pixels")
140 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
143 #define COLOR_TEXT N_("Color")
144 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
145 "the video. This must be an hexadecimal (like HTML colors). The first two "\
146 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
147 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
149 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
150 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
151 "making the overlay completely transparent. All previously rendered " \
152 "images and text will be cleared from the cache." )
154 #define RENDER_TEXT N_( "Render text or image" )
155 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
158 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
159 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
160 "displayed on the overlay framebuffer." )
162 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
163 static const char *ppsz_pos_descriptions[] =
164 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
165 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
167 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
168 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
169 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
170 0x00000080, 0x000000FF, 0x0000FFFF};
171 static const char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
172 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
173 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
174 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
178 set_shortname( "fbosd" );
179 set_category( CAT_INTERFACE );
180 set_subcategory( SUBCAT_INTERFACE_MAIN );
182 add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
184 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
185 ASPECT_RATIO_LONGTEXT, true );
187 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
188 FBOSD_IMAGE_LONGTEXT, true );
189 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
190 FBOSD_LONGTEXT, true );
192 #if defined(FBOSD_BLENDING)
193 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
194 ALPHA_LONGTEXT, true );
198 set_section( N_("Position"), NULL );
199 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
200 POSX_LONGTEXT, false );
201 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
202 POSY_LONGTEXT, false );
203 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true );
204 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
206 set_section( N_("Font"), NULL );
207 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
208 OPACITY_TEXT, OPACITY_LONGTEXT, false );
209 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
211 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
212 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
215 set_section( N_("Commands"), NULL );
216 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true );
217 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true );
218 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true );
220 set_description( _("GNU/Linux osd/overlay framebuffer interface") );
221 set_capability( "interface", 10 );
222 set_callbacks( Create, Destroy );
225 /*****************************************************************************
226 * fbosd_render_t: render descriptor
227 *****************************************************************************/
228 struct fbosd_render_t
230 #define FBOSD_RENDER_IMAGE 0
231 #define FBOSD_RENDER_TEXT 1
234 #define FBOSD_STATE_FREE 0
235 #define FBOSD_STATE_RESERVED 1
236 #define FBOSD_STATE_RENDER 2
240 text_style_t text_style; /* font control */
248 int i_alpha; /* transparency for images */
250 #define FBOSD_RENDER_MAX 10
252 /*****************************************************************************
253 * intf_sys_t: interface framebuffer method descriptor
254 *****************************************************************************/
257 /* Framebuffer information */
258 int i_fd; /* device handle */
259 struct fb_var_screeninfo var_info; /* current mode information */
260 bool b_pan; /* does device supports panning ? */
261 struct fb_cmap fb_cmap; /* original colormap */
262 uint16_t *p_palette; /* original palette */
264 /* Overlay framebuffer format */
265 video_format_t fmt_out;
266 picture_t *p_overlay;
267 size_t i_page_size; /* page size */
271 int i_bytes_per_pixel;
273 /* Image and Picture rendering */
274 image_handler_t *p_image;
275 #if defined(FBOSD_BLENDING)
276 filter_t *p_blend; /* alpha blending module */
278 filter_t *p_text; /* text renderer module */
281 struct fbosd_render_t render[FBOSD_RENDER_MAX];
284 text_style_t *p_style; /* font control */
292 int i_alpha; /* transparency for images */
294 /* commands control */
295 bool b_need_update; /* update display with \overlay buffer */
296 bool b_clear; /* clear overlay buffer make it tranparent */
297 bool b_render; /* render an image or text in overlay buffer */
300 /*****************************************************************************
301 * Create: allocates FB interface thread output method
302 *****************************************************************************/
303 static int Create( vlc_object_t *p_this )
305 intf_thread_t *p_intf = (intf_thread_t *)p_this;
311 /* Allocate instance and initialize some members */
312 p_intf->p_sys = p_sys = malloc( sizeof( intf_sys_t ) );
315 msg_Err( p_intf, "out of memory" );
318 memset( p_sys, 0, sizeof(intf_sys_t) );
320 p_sys->p_style = malloc( sizeof( text_style_t ) );
321 if( !p_sys->p_style )
323 free( p_intf->p_sys );
324 msg_Err( p_intf, "out of memory" );
327 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
329 p_intf->pf_run = Run;
331 p_sys->p_image = image_HandlerCreate( p_this );
332 if( !p_sys->p_image )
334 free( p_intf->p_sys->p_style );
335 free( p_intf->p_sys );
336 msg_Err( p_intf, "out of memory" );
340 #if defined(FBOSD_BLENDING)
341 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
342 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
344 p_sys->i_alpha = 255;
346 p_sys->i_aspect = -1;
348 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
351 char *psz_parser = strchr( psz_aspect, ':' );
355 *psz_parser++ = '\0';
356 p_sys->i_aspect = ( atoi( psz_aspect )
357 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
358 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
360 msg_Dbg( p_intf, "using aspect ratio %d:%d",
361 atoi( psz_aspect ), atoi( psz_parser ) );
367 /* Use PAL by default */
368 p_sys->i_width = p_sys->fmt_out.i_width = 704;
369 p_sys->i_height = p_sys->fmt_out.i_height = 576;
371 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
372 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
373 if( psz_tmp && *psz_tmp )
375 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
376 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
377 p_sys->render[0].psz_string = strdup( psz_tmp );
381 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
382 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
383 if( psz_tmp && *psz_tmp )
385 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
386 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
387 p_sys->render[1].psz_string = strdup( psz_tmp );
391 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
392 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
393 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
395 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
396 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
397 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
399 p_sys->p_style->i_font_size =
400 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
401 p_sys->p_style->i_font_color =
402 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
403 p_sys->p_style->i_font_alpha = 255 -
404 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
406 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
407 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
408 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
410 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
412 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
413 sizeof( text_style_t ) );
416 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
417 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
418 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
420 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
421 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
422 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
424 /* Check if picture position was overridden */
425 p_sys->b_absolute = true;
426 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
428 p_sys->b_absolute = false;
429 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
430 p_sys->i_y : p_sys->i_height;
431 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
432 p_sys->i_x : p_sys->i_width;
435 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
436 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
437 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
438 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
440 /* Initialize framebuffer */
441 if( OpenDisplay( p_intf ) )
443 Destroy( VLC_OBJECT(p_intf) );
449 #if defined(FBOSD_BLENDING)
450 /* Load the blending module */
451 if( OpenBlending( p_intf ) )
453 msg_Err( p_intf, "Unable to load image blending module" );
454 Destroy( VLC_OBJECT(p_intf) );
459 /* Load text renderer module */
460 if( OpenTextRenderer( p_intf ) )
462 msg_Err( p_intf, "Unable to load text rendering module" );
463 Destroy( VLC_OBJECT(p_intf) );
467 p_sys->b_render = true;
468 p_sys->b_need_update = true;
473 /*****************************************************************************
474 * Destroy: destroy FB interface thread output method
475 *****************************************************************************
476 * Terminate an output method created by Create
477 *****************************************************************************/
478 static void Destroy( vlc_object_t *p_this )
480 intf_thread_t *p_intf = (intf_thread_t *)p_this;
481 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
484 p_sys->b_need_update = false;
485 p_sys->b_render = false;
486 p_sys->b_clear = false;
488 #if defined(FBOSD_BLENDING)
489 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
490 var_Destroy( p_intf, "fbosd-alpha" );
493 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
494 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
495 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
496 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
497 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
498 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
499 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
500 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
501 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
502 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
503 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
505 var_Destroy( p_intf, "fbosd-x" );
506 var_Destroy( p_intf, "fbosd-y" );
507 var_Destroy( p_intf, "fbosd-position" );
508 var_Destroy( p_intf, "fbosd-image" );
509 var_Destroy( p_intf, "fbosd-text" );
510 var_Destroy( p_intf, "fbosd-font-size" );
511 var_Destroy( p_intf, "fbosd-font-color" );
512 var_Destroy( p_intf, "fbosd-font-opacity" );
513 var_Destroy( p_intf, "fbosd-clear" );
514 var_Destroy( p_intf, "fbosd-render" );
515 var_Destroy( p_intf, "fbosd-display" );
517 var_Destroy( p_intf, "fbosd-aspect-ratio" );
519 CloseDisplay( p_intf );
521 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
523 free( p_sys->render[i].psz_string );
524 p_sys->render[i].i_state = FBOSD_STATE_FREE;
527 #if defined(FBOSD_BLENDING)
528 if( p_sys->p_blend ) CloseBlending( p_intf );
530 if( p_sys->p_text ) CloseTextRenderer( p_intf );
533 image_HandlerDelete( p_sys->p_image );
534 if( p_sys->p_overlay )
535 p_sys->p_overlay->pf_release( p_sys->p_overlay );
537 free( p_sys->p_style );
541 #if defined(FBOSD_BLENDING)
542 static int OpenBlending( intf_thread_t *p_intf )
544 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
546 p_intf->p_sys->p_blend =
547 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
548 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
549 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
550 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
551 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
552 p_intf->p_sys->fmt_out.i_aspect;
553 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
554 p_intf->p_sys->fmt_out.i_chroma;
555 if( config_GetInt( p_intf, "freetype-yuvp" ) )
556 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
557 VLC_FOURCC('Y','U','V','P');
559 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
560 VLC_FOURCC('Y','U','V','A');
562 p_intf->p_sys->p_blend->p_module =
563 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
565 if( !p_intf->p_sys->p_blend->p_module )
571 static void CloseBlending( intf_thread_t *p_intf )
573 if( p_intf->p_sys->p_blend )
575 if( p_intf->p_sys->p_blend->p_module )
576 module_Unneed( p_intf->p_sys->p_blend,
577 p_intf->p_sys->p_blend->p_module );
579 vlc_object_detach( p_intf->p_sys->p_blend );
580 vlc_object_release( p_intf->p_sys->p_blend );
585 static int OpenTextRenderer( intf_thread_t *p_intf )
587 char *psz_modulename = NULL;
589 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
591 p_intf->p_sys->p_text =
592 vlc_object_create( p_intf, VLC_OBJECT_FILTER );
593 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
595 p_intf->p_sys->p_text->fmt_out.video.i_width =
596 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
597 p_intf->p_sys->i_width;
598 p_intf->p_sys->p_text->fmt_out.video.i_height =
599 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
600 p_intf->p_sys->i_height;
602 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
603 if( psz_modulename && *psz_modulename )
605 p_intf->p_sys->p_text->p_module =
606 module_Need( p_intf->p_sys->p_text, "text renderer",
607 psz_modulename, true );
609 if( !p_intf->p_sys->p_text->p_module )
611 p_intf->p_sys->p_text->p_module =
612 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
614 free( psz_modulename );
616 if( !p_intf->p_sys->p_text->p_module )
622 static void CloseTextRenderer( intf_thread_t *p_intf )
624 if( p_intf->p_sys->p_text )
626 if( p_intf->p_sys->p_text->p_module )
627 module_Unneed( p_intf->p_sys->p_text,
628 p_intf->p_sys->p_text->p_module );
630 vlc_object_detach( p_intf->p_sys->p_text );
631 vlc_object_release( p_intf->p_sys->p_text );
635 /*****************************************************************************
637 * allocate a picture buffer for use with the overlay fb.
638 *****************************************************************************/
639 static picture_t *AllocatePicture( vlc_object_t *p_this,
640 video_format_t *p_fmt )
642 picture_t *p_pic = malloc( sizeof( picture_t ) );
643 if( !p_pic ) return NULL;
645 if( !p_fmt->p_palette &&
646 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
648 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
649 if( !p_fmt->p_palette )
655 else p_fmt->p_palette = NULL;
657 p_pic->p_data_orig = NULL;
659 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
660 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
662 if( !p_pic->i_planes )
665 free( p_fmt->p_palette );
671 /*****************************************************************************
673 * Deallocate a picture buffer and free all associated memory.
674 *****************************************************************************/
675 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
676 video_format_t *p_fmt )
681 free( p_pic->p_data_orig );
682 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
686 free( p_fmt->p_palette );
687 p_fmt->p_palette = NULL;
692 /*****************************************************************************
693 * SetOverlayTransparency: Set the transparency for this overlay fb,
694 * - true is make transparent
695 * - false is make non tranparent
696 *****************************************************************************/
697 static void SetOverlayTransparency( intf_thread_t *p_intf,
700 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
701 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
702 * p_sys->i_bytes_per_pixel;
703 size_t i_page_size = (p_sys->i_page_size > i_size) ?
704 i_size : p_sys->i_page_size;
706 if( p_sys->p_overlay )
708 msg_Dbg( p_intf, "Make overlay %s",
709 b_transparent ? "transparent" : "opaque" );
710 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
712 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
716 #if defined(FBOSD_BLENDING)
717 /*****************************************************************************
718 * BlendPicture: Blend two pictures together..
719 *****************************************************************************/
720 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
721 video_format_t *p_fmt_dst, picture_t *p_pic_src,
722 picture_t *p_pic_dst )
724 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
725 if( p_sys->p_blend && p_sys->p_blend->p_module )
727 int i_x_offset = p_sys->i_x;
728 int i_y_offset = p_sys->i_y;
730 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
732 /* Update the output picture size */
733 p_sys->p_blend->fmt_out.video.i_width =
734 p_sys->p_blend->fmt_out.video.i_visible_width =
736 p_sys->p_blend->fmt_out.video.i_height =
737 p_sys->p_blend->fmt_out.video.i_visible_height =
740 i_x_offset = __MAX( i_x_offset, 0 );
741 i_y_offset = __MAX( i_y_offset, 0 );
743 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
744 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
752 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
754 uint8_t *p_begin = NULL, *p_end = NULL;
757 if( *p_pic && ((*p_pic)->i_planes != 1) )
760 "cannot invert alpha channel too many planes %d (only 1 supported)",
761 (*p_pic)->i_planes );
765 switch( fmt.i_chroma )
767 case VLC_FOURCC('R','V','2','4'):
768 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
769 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
770 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
773 case VLC_FOURCC('R','V','3','2'):
774 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
775 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
776 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
780 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
781 (char *)&fmt.i_chroma );
785 for( ; p_begin < p_end; p_begin += i_skip )
789 if( i_opacity != 0xFF )
790 i_opacity = 255 - *p_begin;
791 *p_begin = i_opacity;
798 /*****************************************************************************
799 * RenderPicture: Render the picture into the p_dest buffer.
800 * We don't take transparent pixels into account, so we don't have to blend
801 * the two images together.
802 *****************************************************************************/
803 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
804 picture_t *p_src, picture_t *p_dest )
807 VLC_UNUSED( p_intf );
809 if( !p_dest && !p_src ) return VLC_EGENERIC;
811 for( i = 0; i < p_src->i_planes ; i++ )
813 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
815 /* There are margins, but with the same width : perfect ! */
816 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
817 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
821 /* We need to proceed line by line */
822 uint8_t *p_in = p_src->p[i].p_pixels;
823 uint8_t *p_out = p_dest->p[i].p_pixels;
825 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
826 int i_x_clip, i_y_clip;
828 /* Check boundaries, clip the image if necessary */
829 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
830 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
832 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
833 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
834 #if defined(FBOSD_DEBUG)
835 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
836 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
837 i_x_offset, i_y_offset, i_x, i_x_clip );
839 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
840 ( i_x <= p_dest->p[i].i_visible_pitch ) )
844 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
845 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
847 vlc_memcpy( p_out + i_x, p_in,
848 p_src->p[i].i_visible_pitch - i_x_clip );
849 p_in += p_src->p[i].i_pitch;
850 p_out += p_dest->p[i].i_pitch;
858 /*****************************************************************************
859 * RenderText - Render text to the desired picture format
860 *****************************************************************************/
861 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
862 text_style_t *p_style, video_format_t *p_fmt )
864 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
865 subpicture_region_t *p_region;
866 picture_t *p_dest = NULL;
868 if( !psz_string ) return p_dest;
870 if( p_sys->p_text && p_sys->p_text->p_module )
872 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
876 memset( p_region, 0, sizeof(subpicture_region_t) );
878 p_region->psz_text = strdup( psz_string );
879 p_region->p_style = p_style;
881 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
882 p_region->fmt.i_aspect = 0;
883 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
884 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
885 p_region->fmt.i_x_offset = 0;
886 p_region->fmt.i_y_offset = 0;
888 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
890 if( p_sys->p_text->pf_render_text )
892 video_format_t fmt_out;
894 memset( &fmt_out, 0, sizeof(video_format_t) );
896 p_sys->p_text->pf_render_text( p_sys->p_text,
897 p_region, p_region );
899 #if defined(FBOSD_BLENDING)
900 fmt_out = p_region->fmt;
901 fmt_out.i_bits_per_pixel = 32;
902 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
904 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
907 if( p_region->picture.pf_release )
908 p_region->picture.pf_release( &p_region->picture );
909 free( p_region->psz_text );
913 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
915 fmt_out.i_chroma = p_fmt->i_chroma;
916 p_dest = ConvertImage( p_intf, &p_region->picture,
917 &p_region->fmt, &fmt_out );
919 if( p_region->picture.pf_release )
920 p_region->picture.pf_release( &p_region->picture );
921 free( p_region->psz_text );
925 free( p_region->psz_text );
931 /*****************************************************************************
932 * LoadImage: Load an image from file into a picture buffer.
933 *****************************************************************************/
934 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
937 picture_t *p_pic = NULL;
939 if( psz_file && p_intf->p_sys->p_image )
941 video_format_t fmt_in, fmt_out;
943 memset( &fmt_in, 0, sizeof(fmt_in) );
944 memset( &fmt_out, 0, sizeof(fmt_out) );
946 fmt_out.i_chroma = p_fmt->i_chroma;
947 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
950 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
951 fmt_out.i_width, fmt_out.i_height,
952 (char *)&p_fmt->i_chroma );
957 #if ! defined(FBOSD_BLENDING)
958 /*****************************************************************************
959 * Convertmage: Convert image to another fourcc
960 *****************************************************************************/
961 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
962 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
964 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
965 picture_t *p_old = NULL;
969 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
971 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
972 p_fmt_out->i_width, p_fmt_out->i_height,
973 (char *)&p_fmt_out->i_chroma );
979 /*****************************************************************************
980 * Init: initialize framebuffer video thread output method
981 *****************************************************************************/
982 static int Init( intf_thread_t *p_intf )
984 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
986 /* Initialize the output structure: RGB with square pixels, whatever
987 * the input format is, since it's the only format we know */
988 switch( p_sys->var_info.bits_per_pixel )
990 case 8: /* FIXME: set the palette */
991 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
993 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
995 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
997 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
999 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
1001 msg_Err( p_intf, "unknown screen depth %i",
1002 p_sys->var_info.bits_per_pixel );
1003 return VLC_EGENERIC;
1006 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1007 p_sys->fmt_out.i_width = p_sys->i_width;
1008 p_sys->fmt_out.i_height = p_sys->i_height;
1010 /* Assume we have square pixels */
1011 if( p_sys->i_aspect < 0 )
1013 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1014 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1016 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1018 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1020 /* Allocate overlay buffer */
1021 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1023 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1025 SetOverlayTransparency( p_intf, true );
1027 /* We know the chroma, allocate a buffer which will be used
1028 * to write to the overlay framebuffer */
1029 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1030 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1031 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1033 if( p_sys->var_info.xres_virtual )
1035 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1036 * p_sys->i_bytes_per_pixel;
1040 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1041 * p_sys->i_bytes_per_pixel;
1044 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1045 * p_sys->i_bytes_per_pixel;
1047 p_sys->p_overlay->i_planes = 1;
1052 /*****************************************************************************
1053 * End: terminate framebuffer interface
1054 *****************************************************************************/
1055 static void End( intf_thread_t *p_intf )
1057 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1060 SetOverlayTransparency( p_intf, false );
1061 if( p_sys->p_overlay )
1064 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels, p_sys->i_page_size );
1066 msg_Err( p_intf, "unable to clear overlay" );
1069 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1070 &p_intf->p_sys->fmt_out );
1071 p_intf->p_sys->p_overlay = NULL;
1074 /*****************************************************************************
1075 * OpenDisplay: initialize framebuffer
1076 *****************************************************************************/
1077 static int OpenDisplay( intf_thread_t *p_intf )
1079 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1080 char *psz_device; /* framebuffer device path */
1081 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1083 /* Open framebuffer device */
1084 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1086 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1087 return VLC_EGENERIC;
1090 p_sys->i_fd = open( psz_device, O_RDWR );
1091 if( p_sys->i_fd == -1 )
1093 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1095 return VLC_EGENERIC;
1099 /* Get framebuffer device information */
1100 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1102 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1103 close( p_sys->i_fd );
1104 return VLC_EGENERIC;
1107 /* Get some info on the framebuffer itself */
1108 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1110 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1111 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1114 /* FIXME: if the image is full-size, it gets cropped on the left
1115 * because of the xres / xres_virtual slight difference */
1116 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1117 p_sys->var_info.xres, p_sys->var_info.yres,
1118 p_sys->var_info.xres_virtual,
1119 p_sys->var_info.yres_virtual );
1121 p_sys->fmt_out.i_width = p_sys->i_width;
1122 p_sys->fmt_out.i_height = p_sys->i_height;
1124 p_sys->p_palette = NULL;
1125 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1127 switch( p_sys->var_info.bits_per_pixel )
1130 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1131 if( !p_sys->p_palette )
1133 close( p_sys->i_fd );
1136 p_sys->fb_cmap.start = 0;
1137 p_sys->fb_cmap.len = 256;
1138 p_sys->fb_cmap.red = p_sys->p_palette;
1139 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1140 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1141 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1143 /* Save the colormap */
1144 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1146 p_sys->i_bytes_per_pixel = 1;
1151 p_sys->i_bytes_per_pixel = 2;
1155 p_sys->i_bytes_per_pixel = 3;
1159 p_sys->i_bytes_per_pixel = 4;
1163 msg_Err( p_intf, "screen depth %d is not supported",
1164 p_sys->var_info.bits_per_pixel );
1166 close( p_sys->i_fd );
1167 return VLC_EGENERIC;
1170 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1171 * p_sys->i_bytes_per_pixel;
1173 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1174 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1175 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1179 /*****************************************************************************
1180 * CloseDisplay: terminate FB interface thread
1181 *****************************************************************************/
1182 static void CloseDisplay( intf_thread_t *p_intf )
1184 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1186 /* Restore palette */
1187 if( p_sys->var_info.bits_per_pixel == 8 )
1189 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1190 free( p_sys->p_palette );
1191 p_sys->p_palette = NULL;
1195 close( p_sys->i_fd );
1198 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1200 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1202 if( render->i_state != FBOSD_STATE_RENDER ) return;
1203 if( !render->psz_string ) return;
1205 if( render->i_type == FBOSD_RENDER_IMAGE )
1208 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1211 RenderPicture( p_intf, render->i_x, render->i_y,
1212 p_pic, p_sys->p_overlay );
1213 p_pic->pf_release( p_pic );
1216 else if( render->i_type == FBOSD_RENDER_TEXT )
1219 #if defined(FBOSD_BLENDING)
1220 video_format_t fmt_in;
1221 memset( &fmt_in, 0, sizeof(video_format_t) );
1222 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1226 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1227 p_text, p_sys->p_overlay );
1228 msg_Dbg( p_intf, "releasing picture" );
1229 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1232 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1236 RenderPicture( p_intf, render->i_x, render->i_y,
1237 p_text, p_sys->p_overlay );
1238 p_text->pf_release( p_text );
1244 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1246 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1248 vlc_memcpy( &render->text_style, &default_text_style,
1249 sizeof( text_style_t ) );
1250 free( render->psz_string );
1251 render->psz_string = NULL;
1253 render->i_x = p_sys->i_x;
1254 render->i_y = p_sys->i_y;
1255 render->i_pos = p_sys->i_pos;
1256 render->i_alpha = p_sys->i_alpha;
1257 render->b_absolute = p_sys->b_absolute;
1258 render->i_state = FBOSD_STATE_FREE;
1261 static bool isRendererReady( intf_thread_t *p_intf )
1263 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1266 /* Check if there are more items to render */
1267 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1269 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1275 /*****************************************************************************
1277 *****************************************************************************
1278 * This part of the interface is in a separate thread so that we can call
1279 * exec() from within it without annoying the rest of the program.
1280 *****************************************************************************/
1281 static void Run( intf_thread_t *p_intf )
1283 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1285 while( !intf_ShouldDie( p_intf ) )
1289 /* Is there somthing to render? */
1290 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1292 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1294 Render( p_intf, &p_sys->render[i] );
1295 RenderClear( p_intf, &p_sys->render[i] );
1299 if( p_sys->b_clear )
1301 SetOverlayTransparency( p_intf, true );
1303 var_SetString( p_intf, "fbosd-image", "" );
1304 var_SetString( p_intf, "fbosd-text", "" );
1306 p_sys->b_clear = false;
1307 p_sys->b_need_update = true;
1310 if( p_sys->b_need_update && p_sys->p_overlay &&
1311 isRendererReady( p_intf ) )
1314 #if defined(FBOSD_BLENDING)
1315 /* Reverse alpha channel to work around FPGA bug */
1316 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1318 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1319 p_sys->i_page_size );
1321 msg_Err( p_intf, "unable to write to overlay" );
1322 lseek( p_sys->i_fd, 0, SEEK_SET );
1324 /* clear the picture */
1325 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1326 p_sys->b_need_update = false;
1329 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1330 msleep( INTF_IDLE_SLEEP );
1338 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1339 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1341 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1342 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1343 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1345 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1347 p_sys->b_need_update = true;
1349 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1352 /* Clear the entire render list */
1353 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1355 RenderClear( p_intf, &p_sys->render[i] );
1357 p_sys->b_clear = true;
1359 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1362 /* Are we already busy with on slot ? */
1363 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1365 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1367 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1375 /* Are we already busy with on slot ? */
1376 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1378 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1381 /* No, then find first FREE slot */
1382 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1384 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1386 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1389 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1391 msg_Warn( p_this, "render space depleated" );
1395 /* Found a free slot */
1396 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1397 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1399 free( p_sys->render[i].psz_string );
1400 p_sys->render[i].psz_string = strdup( newval.psz_string );
1401 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1403 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1405 free( p_sys->render[i].psz_string );
1406 p_sys->render[i].psz_string = strdup( newval.psz_string );
1407 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1409 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1411 p_sys->render[i].b_absolute = false;
1412 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1413 newval.i_int : p_sys->i_width;
1415 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1417 p_sys->render[i].b_absolute = false;
1418 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1419 newval.i_int : p_sys->i_height;
1421 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1423 p_sys->render[i].b_absolute = true;
1424 p_sys->render[i].i_pos = newval.i_int;
1426 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1428 p_sys->render[i].text_style.i_font_size = newval.i_int;
1430 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1432 p_sys->render[i].text_style.i_font_color = newval.i_int;
1434 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1436 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1438 #if defined(FBOSD_BLENDING)
1439 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1441 p_sys->render[i].i_alpha = newval.i_int;