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 *****************************************************************************/
32 #include <vlc_common.h>
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 const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
163 static const char *const 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 const int pi_color_values[] = {
168 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
169 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
170 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
171 0x00000080, 0x000000FF, 0x0000FFFF};
172 static const char *const ppsz_color_descriptions[] = {
173 N_("Default"), N_("Black"),
174 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
175 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
176 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
180 set_shortname( "fbosd" );
181 set_category( CAT_INTERFACE );
182 set_subcategory( SUBCAT_INTERFACE_MAIN );
184 add_file( "fbosd-dev", "/dev/fb1", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
186 add_string( "fbosd-aspect-ratio", "", NULL, ASPECT_RATIO_TEXT,
187 ASPECT_RATIO_LONGTEXT, true );
189 add_string( "fbosd-image", NULL, NULL, FBOSD_IMAGE_TEXT,
190 FBOSD_IMAGE_LONGTEXT, true );
191 add_string( "fbosd-text", NULL, NULL, FBOSD_TEXT,
192 FBOSD_LONGTEXT, true );
194 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
195 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( N_("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 memset( p_sys, 0, sizeof(intf_sys_t) );
316 p_sys->p_style = malloc( sizeof( text_style_t ) );
317 if( !p_sys->p_style )
319 free( p_intf->p_sys );
322 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
324 p_intf->pf_run = Run;
326 p_sys->p_image = image_HandlerCreate( p_this );
327 if( !p_sys->p_image )
329 free( p_intf->p_sys->p_style );
330 free( p_intf->p_sys );
334 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
335 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
337 p_sys->i_aspect = -1;
339 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
342 char *psz_parser = strchr( psz_aspect, ':' );
346 *psz_parser++ = '\0';
347 p_sys->i_aspect = ( atoi( psz_aspect )
348 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
349 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
351 msg_Dbg( p_intf, "using aspect ratio %d:%d",
352 atoi( psz_aspect ), atoi( psz_parser ) );
358 /* Use PAL by default */
359 p_sys->i_width = p_sys->fmt_out.i_width = 704;
360 p_sys->i_height = p_sys->fmt_out.i_height = 576;
362 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
363 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
364 if( psz_tmp && *psz_tmp )
366 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
367 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
368 p_sys->render[0].psz_string = strdup( psz_tmp );
372 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
373 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
374 if( psz_tmp && *psz_tmp )
376 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
377 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
378 p_sys->render[1].psz_string = strdup( psz_tmp );
382 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
383 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
384 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
386 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
387 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
388 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
390 p_sys->p_style->i_font_size =
391 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
392 p_sys->p_style->i_font_color =
393 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
394 p_sys->p_style->i_font_alpha = 255 -
395 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
397 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
398 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
399 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
401 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
403 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
404 sizeof( text_style_t ) );
407 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
408 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
409 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
411 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
412 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
413 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
415 /* Check if picture position was overridden */
416 p_sys->b_absolute = true;
417 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
419 p_sys->b_absolute = false;
420 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
421 p_sys->i_y : p_sys->i_height;
422 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
423 p_sys->i_x : p_sys->i_width;
426 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
427 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
428 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
429 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
431 /* Initialize framebuffer */
432 if( OpenDisplay( p_intf ) )
434 Destroy( VLC_OBJECT(p_intf) );
440 #if defined(FBOSD_BLENDING)
441 /* Load the blending module */
442 if( OpenBlending( p_intf ) )
444 msg_Err( p_intf, "Unable to load image blending module" );
445 Destroy( VLC_OBJECT(p_intf) );
450 /* Load text renderer module */
451 if( OpenTextRenderer( p_intf ) )
453 msg_Err( p_intf, "Unable to load text rendering module" );
454 Destroy( VLC_OBJECT(p_intf) );
458 p_sys->b_render = true;
459 p_sys->b_need_update = true;
464 /*****************************************************************************
465 * Destroy: destroy FB interface thread output method
466 *****************************************************************************
467 * Terminate an output method created by Create
468 *****************************************************************************/
469 static void Destroy( vlc_object_t *p_this )
471 intf_thread_t *p_intf = (intf_thread_t *)p_this;
472 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
475 p_sys->b_need_update = false;
476 p_sys->b_render = false;
477 p_sys->b_clear = false;
479 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
480 var_Destroy( p_intf, "fbosd-alpha" );
482 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
487 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
488 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
489 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
490 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
491 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
492 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
494 var_Destroy( p_intf, "fbosd-x" );
495 var_Destroy( p_intf, "fbosd-y" );
496 var_Destroy( p_intf, "fbosd-position" );
497 var_Destroy( p_intf, "fbosd-image" );
498 var_Destroy( p_intf, "fbosd-text" );
499 var_Destroy( p_intf, "fbosd-font-size" );
500 var_Destroy( p_intf, "fbosd-font-color" );
501 var_Destroy( p_intf, "fbosd-font-opacity" );
502 var_Destroy( p_intf, "fbosd-clear" );
503 var_Destroy( p_intf, "fbosd-render" );
504 var_Destroy( p_intf, "fbosd-display" );
506 var_Destroy( p_intf, "fbosd-aspect-ratio" );
508 CloseDisplay( p_intf );
510 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
512 free( p_sys->render[i].psz_string );
513 p_sys->render[i].i_state = FBOSD_STATE_FREE;
516 #if defined(FBOSD_BLENDING)
517 if( p_sys->p_blend ) CloseBlending( p_intf );
519 if( p_sys->p_text ) CloseTextRenderer( p_intf );
522 image_HandlerDelete( p_sys->p_image );
523 if( p_sys->p_overlay )
524 p_sys->p_overlay->pf_release( p_sys->p_overlay );
526 free( p_sys->p_style );
530 #if defined(FBOSD_BLENDING)
531 static int OpenBlending( intf_thread_t *p_intf )
533 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
535 p_intf->p_sys->p_blend =
536 vlc_object_create( p_intf, sizeof(filter_t) );
537 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
538 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
539 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
540 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
541 p_intf->p_sys->fmt_out.i_aspect;
542 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
543 p_intf->p_sys->fmt_out.i_chroma;
544 if( config_GetInt( p_intf, "freetype-yuvp" ) )
545 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
546 VLC_FOURCC('Y','U','V','P');
548 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
549 VLC_FOURCC('Y','U','V','A');
551 p_intf->p_sys->p_blend->p_module =
552 module_Need( p_intf->p_sys->p_blend, "video blending", 0, 0 );
554 if( !p_intf->p_sys->p_blend->p_module )
560 static void CloseBlending( intf_thread_t *p_intf )
562 if( p_intf->p_sys->p_blend )
564 if( p_intf->p_sys->p_blend->p_module )
565 module_Unneed( p_intf->p_sys->p_blend,
566 p_intf->p_sys->p_blend->p_module );
568 vlc_object_detach( p_intf->p_sys->p_blend );
569 vlc_object_release( p_intf->p_sys->p_blend );
574 static int OpenTextRenderer( intf_thread_t *p_intf )
576 char *psz_modulename = NULL;
578 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
580 p_intf->p_sys->p_text =
581 vlc_object_create( p_intf, sizeof(filter_t) );
582 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
584 p_intf->p_sys->p_text->fmt_out.video.i_width =
585 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
586 p_intf->p_sys->i_width;
587 p_intf->p_sys->p_text->fmt_out.video.i_height =
588 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
589 p_intf->p_sys->i_height;
591 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
592 if( psz_modulename && *psz_modulename )
594 p_intf->p_sys->p_text->p_module =
595 module_Need( p_intf->p_sys->p_text, "text renderer",
596 psz_modulename, true );
598 if( !p_intf->p_sys->p_text->p_module )
600 p_intf->p_sys->p_text->p_module =
601 module_Need( p_intf->p_sys->p_text, "text renderer", 0, 0 );
603 free( psz_modulename );
605 if( !p_intf->p_sys->p_text->p_module )
611 static void CloseTextRenderer( intf_thread_t *p_intf )
613 if( p_intf->p_sys->p_text )
615 if( p_intf->p_sys->p_text->p_module )
616 module_Unneed( p_intf->p_sys->p_text,
617 p_intf->p_sys->p_text->p_module );
619 vlc_object_detach( p_intf->p_sys->p_text );
620 vlc_object_release( p_intf->p_sys->p_text );
624 /*****************************************************************************
626 * allocate a picture buffer for use with the overlay fb.
627 *****************************************************************************/
628 static picture_t *AllocatePicture( vlc_object_t *p_this,
629 video_format_t *p_fmt )
631 picture_t *p_pic = malloc( sizeof( picture_t ) );
632 if( !p_pic ) return NULL;
634 if( !p_fmt->p_palette &&
635 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
637 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
638 if( !p_fmt->p_palette )
644 else p_fmt->p_palette = NULL;
646 p_pic->p_data_orig = NULL;
648 vout_AllocatePicture( p_this, p_pic, p_fmt->i_chroma,
649 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
651 if( !p_pic->i_planes )
654 free( p_fmt->p_palette );
660 /*****************************************************************************
662 * Deallocate a picture buffer and free all associated memory.
663 *****************************************************************************/
664 static void DeAllocatePicture( vlc_object_t *p_this, picture_t *p_pic,
665 video_format_t *p_fmt )
670 free( p_pic->p_data_orig );
671 if( p_pic->pf_release ) p_pic->pf_release( p_pic );
676 free( p_fmt->p_palette );
677 p_fmt->p_palette = NULL;
682 /*****************************************************************************
683 * SetOverlayTransparency: Set the transparency for this overlay fb,
684 * - true is make transparent
685 * - false is make non tranparent
686 *****************************************************************************/
687 static void SetOverlayTransparency( intf_thread_t *p_intf,
690 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
691 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
692 * p_sys->i_bytes_per_pixel;
693 size_t i_page_size = (p_sys->i_page_size > i_size) ?
694 i_size : p_sys->i_page_size;
696 if( p_sys->p_overlay )
698 msg_Dbg( p_intf, "Make overlay %s",
699 b_transparent ? "transparent" : "opaque" );
701 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
703 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
707 #if defined(FBOSD_BLENDING)
708 /*****************************************************************************
709 * BlendPicture: Blend two pictures together..
710 *****************************************************************************/
711 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
712 video_format_t *p_fmt_dst, picture_t *p_pic_src,
713 picture_t *p_pic_dst )
715 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
716 if( p_sys->p_blend && p_sys->p_blend->p_module )
718 int i_x_offset = p_sys->i_x;
719 int i_y_offset = p_sys->i_y;
721 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
723 /* Update the output picture size */
724 p_sys->p_blend->fmt_out.video.i_width =
725 p_sys->p_blend->fmt_out.video.i_visible_width =
727 p_sys->p_blend->fmt_out.video.i_height =
728 p_sys->p_blend->fmt_out.video.i_visible_height =
731 i_x_offset = __MAX( i_x_offset, 0 );
732 i_y_offset = __MAX( i_y_offset, 0 );
734 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
735 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
743 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
745 uint8_t *p_begin = NULL, *p_end = NULL;
748 if( *p_pic && ((*p_pic)->i_planes != 1) )
751 "cannot invert alpha channel too many planes %d (only 1 supported)",
752 (*p_pic)->i_planes );
756 switch( fmt.i_chroma )
758 case VLC_FOURCC('R','V','2','4'):
759 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
760 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
761 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
764 case VLC_FOURCC('R','V','3','2'):
765 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
766 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
767 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
771 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
772 (char *)&fmt.i_chroma );
776 for( ; p_begin < p_end; p_begin += i_skip )
778 uint8_t i_opacity = 0;
780 if( *p_begin != 0xFF )
781 i_opacity = 255 - *p_begin;
782 *p_begin = i_opacity;
789 /*****************************************************************************
790 * RenderPicture: Render the picture into the p_dest buffer.
791 * We don't take transparent pixels into account, so we don't have to blend
792 * the two images together.
793 *****************************************************************************/
794 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
795 picture_t *p_src, picture_t *p_dest )
798 VLC_UNUSED( p_intf );
800 if( !p_dest && !p_src ) return VLC_EGENERIC;
802 for( i = 0; i < p_src->i_planes ; i++ )
804 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
806 /* There are margins, but with the same width : perfect ! */
807 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
808 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
812 /* We need to proceed line by line */
813 uint8_t *p_in = p_src->p[i].p_pixels;
814 uint8_t *p_out = p_dest->p[i].p_pixels;
816 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
817 int i_x_clip, i_y_clip;
819 /* Check boundaries, clip the image if necessary */
820 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
821 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
823 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
824 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
825 #if defined(FBOSD_DEBUG)
826 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
827 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
828 i_x_offset, i_y_offset, i_x, i_x_clip );
830 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
831 ( i_x <= p_dest->p[i].i_visible_pitch ) )
835 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
836 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
838 vlc_memcpy( p_out + i_x, p_in,
839 p_src->p[i].i_visible_pitch - i_x_clip );
840 p_in += p_src->p[i].i_pitch;
841 p_out += p_dest->p[i].i_pitch;
849 /*****************************************************************************
850 * RenderText - Render text to the desired picture format
851 *****************************************************************************/
852 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
853 text_style_t *p_style, video_format_t *p_fmt )
855 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
856 subpicture_region_t *p_region;
857 picture_t *p_dest = NULL;
859 if( !psz_string ) return p_dest;
861 if( p_sys->p_text && p_sys->p_text->p_module )
863 p_region = (subpicture_region_t *) malloc( sizeof(subpicture_region_t) );
867 memset( p_region, 0, sizeof(subpicture_region_t) );
869 p_region->psz_text = strdup( psz_string );
870 if( !p_region->psz_text )
875 p_region->p_style = p_style;
877 p_region->fmt.i_chroma = VLC_FOURCC('T','E','X','T');
878 p_region->fmt.i_aspect = 0;
879 p_region->fmt.i_width = p_region->fmt.i_visible_width = 0;
880 p_region->fmt.i_height = p_region->fmt.i_visible_height = 0;
881 p_region->fmt.i_x_offset = 0;
882 p_region->fmt.i_y_offset = 0;
884 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
886 if( p_sys->p_text->pf_render_text )
888 video_format_t fmt_out;
890 memset( &fmt_out, 0, sizeof(video_format_t) );
892 p_sys->p_text->pf_render_text( p_sys->p_text,
893 p_region, p_region );
895 #if defined(FBOSD_BLENDING)
896 fmt_out = p_region->fmt;
897 fmt_out.i_bits_per_pixel = 32;
898 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
900 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
903 if( p_region->picture.pf_release )
904 p_region->picture.pf_release( &p_region->picture );
905 free( p_region->psz_text );
909 vout_CopyPicture( VLC_OBJECT(p_intf), p_dest, &p_region->picture );
911 fmt_out.i_chroma = p_fmt->i_chroma;
912 p_dest = ConvertImage( p_intf, &p_region->picture,
913 &p_region->fmt, &fmt_out );
915 if( p_region->picture.pf_release )
916 p_region->picture.pf_release( &p_region->picture );
917 free( p_region->psz_text );
921 free( p_region->psz_text );
927 /*****************************************************************************
928 * LoadImage: Load an image from file into a picture buffer.
929 *****************************************************************************/
930 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
933 picture_t *p_pic = NULL;
935 if( psz_file && p_intf->p_sys->p_image )
937 video_format_t fmt_in, fmt_out;
939 memset( &fmt_in, 0, sizeof(fmt_in) );
940 memset( &fmt_out, 0, sizeof(fmt_out) );
942 fmt_out.i_chroma = p_fmt->i_chroma;
943 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
946 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
947 fmt_out.i_width, fmt_out.i_height,
948 (char *)&p_fmt->i_chroma );
953 #if ! defined(FBOSD_BLENDING)
954 /*****************************************************************************
955 * Convertmage: Convert image to another fourcc
956 *****************************************************************************/
957 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
958 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
960 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
961 picture_t *p_old = NULL;
965 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
967 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
968 p_fmt_out->i_width, p_fmt_out->i_height,
969 (char *)&p_fmt_out->i_chroma );
975 /*****************************************************************************
976 * Init: initialize framebuffer video thread output method
977 *****************************************************************************/
978 static int Init( intf_thread_t *p_intf )
980 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
982 /* Initialize the output structure: RGB with square pixels, whatever
983 * the input format is, since it's the only format we know */
984 switch( p_sys->var_info.bits_per_pixel )
986 case 8: /* FIXME: set the palette */
987 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
989 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
991 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
993 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
995 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
997 msg_Err( p_intf, "unknown screen depth %i",
998 p_sys->var_info.bits_per_pixel );
1002 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
1003 p_sys->fmt_out.i_width = p_sys->i_width;
1004 p_sys->fmt_out.i_height = p_sys->i_height;
1006 /* Assume we have square pixels */
1007 if( p_sys->i_aspect < 0 )
1009 p_sys->fmt_out.i_aspect = ( p_sys->i_width
1010 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
1012 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
1014 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
1016 /* Allocate overlay buffer */
1017 p_sys->p_overlay = AllocatePicture( VLC_OBJECT(p_intf),
1019 if( !p_sys->p_overlay ) return VLC_EGENERIC;
1021 SetOverlayTransparency( p_intf, true );
1023 /* We know the chroma, allocate a buffer which will be used
1024 * to write to the overlay framebuffer */
1025 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1026 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1027 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1029 if( p_sys->var_info.xres_virtual )
1031 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1032 * p_sys->i_bytes_per_pixel;
1036 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1037 * p_sys->i_bytes_per_pixel;
1040 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1041 * p_sys->i_bytes_per_pixel;
1043 p_sys->p_overlay->i_planes = 1;
1048 /*****************************************************************************
1049 * End: terminate framebuffer interface
1050 *****************************************************************************/
1051 static void End( intf_thread_t *p_intf )
1053 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1056 SetOverlayTransparency( p_intf, false );
1057 if( p_sys->p_overlay )
1060 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1061 p_sys->i_page_size );
1063 msg_Err( p_intf, "unable to clear overlay" );
1066 DeAllocatePicture( VLC_OBJECT(p_intf), p_intf->p_sys->p_overlay,
1067 &p_intf->p_sys->fmt_out );
1068 p_intf->p_sys->p_overlay = NULL;
1071 /*****************************************************************************
1072 * OpenDisplay: initialize framebuffer
1073 *****************************************************************************/
1074 static int OpenDisplay( intf_thread_t *p_intf )
1076 intf_sys_t *p_sys = (intf_sys_t *) p_intf->p_sys;
1077 char *psz_device; /* framebuffer device path */
1078 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1080 /* Open framebuffer device */
1081 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1083 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1084 return VLC_EGENERIC;
1087 p_sys->i_fd = open( psz_device, O_RDWR );
1088 if( p_sys->i_fd == -1 )
1090 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1092 return VLC_EGENERIC;
1096 /* Get framebuffer device information */
1097 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1099 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1100 close( p_sys->i_fd );
1101 return VLC_EGENERIC;
1104 /* Get some info on the framebuffer itself */
1105 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1107 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1108 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1111 /* FIXME: if the image is full-size, it gets cropped on the left
1112 * because of the xres / xres_virtual slight difference */
1113 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1114 p_sys->var_info.xres, p_sys->var_info.yres,
1115 p_sys->var_info.xres_virtual,
1116 p_sys->var_info.yres_virtual );
1118 p_sys->fmt_out.i_width = p_sys->i_width;
1119 p_sys->fmt_out.i_height = p_sys->i_height;
1121 p_sys->p_palette = NULL;
1122 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1124 switch( p_sys->var_info.bits_per_pixel )
1127 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1128 if( !p_sys->p_palette )
1130 close( p_sys->i_fd );
1133 p_sys->fb_cmap.start = 0;
1134 p_sys->fb_cmap.len = 256;
1135 p_sys->fb_cmap.red = p_sys->p_palette;
1136 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1137 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1138 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1140 /* Save the colormap */
1141 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1143 p_sys->i_bytes_per_pixel = 1;
1148 p_sys->i_bytes_per_pixel = 2;
1152 p_sys->i_bytes_per_pixel = 3;
1156 p_sys->i_bytes_per_pixel = 4;
1160 msg_Err( p_intf, "screen depth %d is not supported",
1161 p_sys->var_info.bits_per_pixel );
1163 close( p_sys->i_fd );
1164 return VLC_EGENERIC;
1167 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1168 * p_sys->i_bytes_per_pixel;
1170 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1171 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1172 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1176 /*****************************************************************************
1177 * CloseDisplay: terminate FB interface thread
1178 *****************************************************************************/
1179 static void CloseDisplay( intf_thread_t *p_intf )
1181 intf_sys_t *p_sys = (intf_sys_t *) p_intf;
1183 /* Restore palette */
1184 if( p_sys->var_info.bits_per_pixel == 8 )
1186 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1187 free( p_sys->p_palette );
1188 p_sys->p_palette = NULL;
1192 close( p_sys->i_fd );
1195 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1197 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1199 if( render->i_state != FBOSD_STATE_RENDER ) return;
1200 if( !render->psz_string ) return;
1202 if( render->i_type == FBOSD_RENDER_IMAGE )
1205 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1208 RenderPicture( p_intf, render->i_x, render->i_y,
1209 p_pic, p_sys->p_overlay );
1210 p_pic->pf_release( p_pic );
1213 else if( render->i_type == FBOSD_RENDER_TEXT )
1216 #if defined(FBOSD_BLENDING)
1217 video_format_t fmt_in;
1218 memset( &fmt_in, 0, sizeof(video_format_t) );
1219 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1223 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1224 p_text, p_sys->p_overlay );
1225 msg_Dbg( p_intf, "releasing picture" );
1226 DeAllocatePicture( VLC_OBJECT( p_intf ), p_text, &fmt_in );
1229 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1233 RenderPicture( p_intf, render->i_x, render->i_y,
1234 p_text, p_sys->p_overlay );
1235 p_text->pf_release( p_text );
1241 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1243 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1245 vlc_memcpy( &render->text_style, &default_text_style,
1246 sizeof( text_style_t ) );
1247 free( render->psz_string );
1248 render->psz_string = NULL;
1250 render->i_x = p_sys->i_x;
1251 render->i_y = p_sys->i_y;
1252 render->i_pos = p_sys->i_pos;
1253 render->i_alpha = p_sys->i_alpha;
1254 render->b_absolute = p_sys->b_absolute;
1255 render->i_state = FBOSD_STATE_FREE;
1258 static bool isRendererReady( intf_thread_t *p_intf )
1260 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1263 /* Check if there are more items to render */
1264 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1266 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1272 /*****************************************************************************
1274 *****************************************************************************
1275 * This part of the interface is in a separate thread so that we can call
1276 * exec() from within it without annoying the rest of the program.
1277 *****************************************************************************/
1278 static void Run( intf_thread_t *p_intf )
1280 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1282 while( !intf_ShouldDie( p_intf ) )
1286 /* Is there somthing to render? */
1287 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1289 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1291 Render( p_intf, &p_sys->render[i] );
1292 RenderClear( p_intf, &p_sys->render[i] );
1296 if( p_sys->b_clear )
1298 SetOverlayTransparency( p_intf, true );
1300 var_SetString( p_intf, "fbosd-image", "" );
1301 var_SetString( p_intf, "fbosd-text", "" );
1303 p_sys->b_clear = false;
1304 p_sys->b_need_update = true;
1307 if( p_sys->b_need_update && p_sys->p_overlay &&
1308 isRendererReady( p_intf ) )
1311 #if defined(FBOSD_BLENDING)
1312 /* Reverse alpha channel to work around FPGA bug */
1313 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1315 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1316 p_sys->i_page_size );
1318 msg_Err( p_intf, "unable to write to overlay" );
1319 lseek( p_sys->i_fd, 0, SEEK_SET );
1321 /* clear the picture */
1322 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1323 p_sys->b_need_update = false;
1326 if( vlc_CPU() & CPU_CAPABILITY_FPU )
1327 msleep( INTF_IDLE_SLEEP );
1335 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1336 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1338 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1339 intf_sys_t *p_sys = (intf_sys_t*) p_intf->p_sys;
1340 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1342 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1344 p_sys->b_need_update = true;
1346 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1349 /* Clear the entire render list */
1350 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1352 RenderClear( p_intf, &p_sys->render[i] );
1354 p_sys->b_clear = true;
1356 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1359 /* Are we already busy with on slot ? */
1360 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1362 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1364 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1372 /* Are we already busy with on slot ? */
1373 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1375 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1378 /* No, then find first FREE slot */
1379 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1381 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1383 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1386 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1388 msg_Warn( p_this, "render space depleated" );
1392 /* Found a free slot */
1393 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1394 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1396 free( p_sys->render[i].psz_string );
1397 p_sys->render[i].psz_string = strdup( newval.psz_string );
1398 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1400 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1402 free( p_sys->render[i].psz_string );
1403 p_sys->render[i].psz_string = strdup( newval.psz_string );
1404 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1406 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1408 p_sys->render[i].b_absolute = false;
1409 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1410 newval.i_int : p_sys->i_width;
1412 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1414 p_sys->render[i].b_absolute = false;
1415 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1416 newval.i_int : p_sys->i_height;
1418 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1420 p_sys->render[i].b_absolute = true;
1421 p_sys->render[i].i_pos = newval.i_int;
1423 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1425 p_sys->render[i].text_style.i_font_size = newval.i_int;
1427 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1429 p_sys->render[i].text_style.i_font_color = newval.i_int;
1431 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1433 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1435 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1437 p_sys->render[i].i_alpha = newval.i_int;