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( video_format_t * );
83 static void DeAllocatePicture( picture_t *, video_format_t * );
84 static void SetOverlayTransparency( intf_thread_t *,
86 static picture_t *LoadImage( intf_thread_t *, video_format_t *,
89 #if defined(FBOSD_BLENDING)
90 static int BlendPicture( intf_thread_t *, video_format_t *,
91 video_format_t *, picture_t *, picture_t * );
93 static picture_t *ConvertImage( intf_thread_t *, picture_t *,
94 video_format_t *, video_format_t * );
96 static int RenderPicture( intf_thread_t *, int, int,
97 picture_t *, picture_t * );
98 static picture_t *RenderText( intf_thread_t *, const char *,
99 text_style_t *, video_format_t * );
101 #define DEVICE_TEXT N_("Framebuffer device")
102 #define DEVICE_LONGTEXT N_( \
103 "Framebuffer device to use for rendering (usually /dev/fb0).")
105 #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
106 #define ASPECT_RATIO_LONGTEXT N_( \
107 "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
109 #define FBOSD_IMAGE_TEXT N_("Image file")
110 #define FBOSD_IMAGE_LONGTEXT N_( \
111 "Filename of image file to use on the overlay framebuffer." )
113 #define ALPHA_TEXT N_("Transparency of the image")
114 #define ALPHA_LONGTEXT N_( "Transparency value of the new image " \
115 "used in blending. By default it set to fully opaque (255). " \
116 "(from 0 for full transparency to 255 for full opacity)" )
118 #define FBOSD_TEXT N_("Text")
119 #define FBOSD_LONGTEXT N_( "Text to display on the overlay framebuffer." )
121 #define POSX_TEXT N_("X coordinate")
122 #define POSX_LONGTEXT N_("X coordinate of the rendered image")
124 #define POSY_TEXT N_("Y coordinate")
125 #define POSY_LONGTEXT N_("Y coordinate of the rendered image")
127 #define POS_TEXT N_("Position")
128 #define POS_LONGTEXT N_( \
129 "You can enforce the picture position on the overlay " \
130 "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
131 "also use combinations of these values, e.g. 6=top-right).")
133 #define OPACITY_TEXT N_("Opacity")
134 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
135 "overlayed text. 0 = transparent, 255 = totally opaque. " )
137 #define SIZE_TEXT N_("Font size, pixels")
138 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
141 #define COLOR_TEXT N_("Color")
142 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
143 "the video. This must be an hexadecimal (like HTML colors). The first two "\
144 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
145 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
147 #define CLEAR_TEXT N_( "Clear overlay framebuffer" )
148 #define CLEAR_LONGTEXT N_( "The displayed overlay images is cleared by " \
149 "making the overlay completely transparent. All previously rendered " \
150 "images and text will be cleared from the cache." )
152 #define RENDER_TEXT N_( "Render text or image" )
153 #define RENDER_LONGTEXT N_( "Render the image or text in current overlay " \
156 #define DISPLAY_TEXT N_( "Display on overlay framebuffer" )
157 #define DISPLAY_LONGTEXT N_( "All rendered images and text will be " \
158 "displayed on the overlay framebuffer." )
160 static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
161 static const char *const ppsz_pos_descriptions[] =
162 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
163 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
165 static const int pi_color_values[] = {
166 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
167 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
168 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
169 0x00000080, 0x000000FF, 0x0000FFFF};
170 static const char *const ppsz_color_descriptions[] = {
171 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/fb0", 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 add_integer_with_range( "fbosd-alpha", 255, 0, 255, NULL, ALPHA_TEXT,
193 ALPHA_LONGTEXT, true )
195 set_section( N_("Position"), NULL )
196 add_integer( "fbosd-x", 0, NULL, POSX_TEXT,
197 POSX_LONGTEXT, false )
198 add_integer( "fbosd-y", 0, NULL, POSY_TEXT,
199 POSY_LONGTEXT, false )
200 add_integer( "fbosd-position", 8, NULL, POS_TEXT, POS_LONGTEXT, true )
201 change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL );
203 set_section( N_("Font"), NULL )
204 add_integer_with_range( "fbosd-font-opacity", 255, 0, 255, NULL,
205 OPACITY_TEXT, OPACITY_LONGTEXT, false )
206 add_integer( "fbosd-font-color", 0x00FFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
208 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
209 add_integer( "fbosd-font-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT,
212 set_section( N_("Commands"), NULL )
213 add_bool( "fbosd-clear", false, NULL, CLEAR_TEXT, CLEAR_LONGTEXT, true )
214 add_bool( "fbosd-render", false, NULL, RENDER_TEXT, RENDER_LONGTEXT, true )
215 add_bool( "fbosd-display", false, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
217 set_description( N_("GNU/Linux osd/overlay framebuffer interface") )
218 set_capability( "interface", 10 )
219 set_callbacks( Create, Destroy )
222 /*****************************************************************************
223 * fbosd_render_t: render descriptor
224 *****************************************************************************/
225 struct fbosd_render_t
227 #define FBOSD_RENDER_IMAGE 0
228 #define FBOSD_RENDER_TEXT 1
231 #define FBOSD_STATE_FREE 0
232 #define FBOSD_STATE_RESERVED 1
233 #define FBOSD_STATE_RENDER 2
237 text_style_t text_style; /* font control */
245 int i_alpha; /* transparency for images */
247 #define FBOSD_RENDER_MAX 10
249 /*****************************************************************************
250 * intf_sys_t: interface framebuffer method descriptor
251 *****************************************************************************/
254 /* Framebuffer information */
255 int i_fd; /* device handle */
256 struct fb_var_screeninfo var_info; /* current mode information */
257 bool b_pan; /* does device supports panning ? */
258 struct fb_cmap fb_cmap; /* original colormap */
259 uint16_t *p_palette; /* original palette */
261 /* Overlay framebuffer format */
262 video_format_t fmt_out;
263 picture_t *p_overlay;
264 size_t i_page_size; /* page size */
268 int i_bytes_per_pixel;
270 /* Image and Picture rendering */
271 image_handler_t *p_image;
272 #if defined(FBOSD_BLENDING)
273 filter_t *p_blend; /* alpha blending module */
275 filter_t *p_text; /* text renderer module */
278 struct fbosd_render_t render[FBOSD_RENDER_MAX];
281 text_style_t *p_style; /* font control */
289 int i_alpha; /* transparency for images */
291 /* commands control */
292 bool b_need_update; /* update display with \overlay buffer */
293 bool b_clear; /* clear overlay buffer make it tranparent */
294 bool b_render; /* render an image or text in overlay buffer */
297 /*****************************************************************************
298 * Create: allocates FB interface thread output method
299 *****************************************************************************/
300 static int Create( vlc_object_t *p_this )
302 intf_thread_t *p_intf = (intf_thread_t *)p_this;
308 /* Allocate instance and initialize some members */
309 p_intf->p_sys = p_sys = calloc( 1, sizeof( intf_sys_t ) );
313 p_sys->p_style = text_style_New();
314 if( !p_sys->p_style )
316 free( p_intf->p_sys );
320 p_intf->pf_run = Run;
322 p_sys->p_image = image_HandlerCreate( p_this );
323 if( !p_sys->p_image )
325 text_style_Delete( p_sys->p_style );
330 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
331 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
333 p_sys->i_aspect = -1;
335 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
338 char *psz_parser = strchr( psz_aspect, ':' );
342 *psz_parser++ = '\0';
343 p_sys->i_aspect = ( atoi( psz_aspect )
344 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
345 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
347 msg_Dbg( p_intf, "using aspect ratio %d:%d",
348 atoi( psz_aspect ), atoi( psz_parser ) );
353 /* Use PAL by default */
354 p_sys->i_width = p_sys->fmt_out.i_width = 704;
355 p_sys->i_height = p_sys->fmt_out.i_height = 576;
357 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
358 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
359 if( psz_tmp && *psz_tmp )
361 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
362 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
363 p_sys->render[0].psz_string = strdup( psz_tmp );
367 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
368 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
369 if( psz_tmp && *psz_tmp )
371 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
372 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
373 p_sys->render[1].psz_string = strdup( psz_tmp );
377 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
378 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
379 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
381 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
382 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
383 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
385 p_sys->p_style->i_font_size =
386 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
387 p_sys->p_style->i_font_color =
388 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
389 p_sys->p_style->i_font_alpha = 255 -
390 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
392 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
393 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
394 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
396 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
398 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
399 sizeof( text_style_t ) );
402 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
403 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
404 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
406 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
407 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
408 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
410 /* Check if picture position was overridden */
411 p_sys->b_absolute = true;
412 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
414 p_sys->b_absolute = false;
415 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
416 p_sys->i_y : p_sys->i_height;
417 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
418 p_sys->i_x : p_sys->i_width;
421 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
422 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
423 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
424 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
426 /* Initialize framebuffer */
427 if( OpenDisplay( p_intf ) )
429 Destroy( VLC_OBJECT(p_intf) );
435 #if defined(FBOSD_BLENDING)
436 /* Load the blending module */
437 if( OpenBlending( p_intf ) )
439 msg_Err( p_intf, "Unable to load image blending module" );
440 Destroy( VLC_OBJECT(p_intf) );
445 /* Load text renderer module */
446 if( OpenTextRenderer( p_intf ) )
448 msg_Err( p_intf, "Unable to load text rendering module" );
449 Destroy( VLC_OBJECT(p_intf) );
453 p_sys->b_render = true;
454 p_sys->b_need_update = true;
459 /*****************************************************************************
460 * Destroy: destroy FB interface thread output method
461 *****************************************************************************
462 * Terminate an output method created by Create
463 *****************************************************************************/
464 static void Destroy( vlc_object_t *p_this )
466 intf_thread_t *p_intf = (intf_thread_t *)p_this;
467 intf_sys_t *p_sys = p_intf->p_sys;
471 p_sys->b_need_update = false;
472 p_sys->b_render = false;
473 p_sys->b_clear = false;
475 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
476 var_Destroy( p_intf, "fbosd-alpha" );
478 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
479 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
480 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
481 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
482 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
487 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
488 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
490 var_Destroy( p_intf, "fbosd-x" );
491 var_Destroy( p_intf, "fbosd-y" );
492 var_Destroy( p_intf, "fbosd-position" );
493 var_Destroy( p_intf, "fbosd-image" );
494 var_Destroy( p_intf, "fbosd-text" );
495 var_Destroy( p_intf, "fbosd-font-size" );
496 var_Destroy( p_intf, "fbosd-font-color" );
497 var_Destroy( p_intf, "fbosd-font-opacity" );
498 var_Destroy( p_intf, "fbosd-clear" );
499 var_Destroy( p_intf, "fbosd-render" );
500 var_Destroy( p_intf, "fbosd-display" );
502 var_Destroy( p_intf, "fbosd-aspect-ratio" );
504 CloseDisplay( p_intf );
506 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
508 free( p_sys->render[i].psz_string );
509 p_sys->render[i].i_state = FBOSD_STATE_FREE;
512 #if defined(FBOSD_BLENDING)
513 if( p_sys->p_blend ) CloseBlending( p_intf );
515 if( p_sys->p_text ) CloseTextRenderer( p_intf );
518 image_HandlerDelete( p_sys->p_image );
519 if( p_sys->p_overlay )
520 picture_Release( p_sys->p_overlay );
522 text_style_Delete( p_sys->p_style );
526 #if defined(FBOSD_BLENDING)
527 static int OpenBlending( intf_thread_t *p_intf )
529 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
531 p_intf->p_sys->p_blend =
532 vlc_object_create( p_intf, sizeof(filter_t) );
533 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
534 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
535 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
536 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
537 p_intf->p_sys->fmt_out.i_aspect;
538 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
539 p_intf->p_sys->fmt_out.i_chroma;
540 if( config_GetInt( p_intf, "freetype-yuvp" ) )
541 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
542 VLC_FOURCC('Y','U','V','P');
544 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
545 VLC_FOURCC('Y','U','V','A');
547 p_intf->p_sys->p_blend->p_module =
548 module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
550 if( !p_intf->p_sys->p_blend->p_module )
556 static void CloseBlending( intf_thread_t *p_intf )
558 if( p_intf->p_sys->p_blend )
560 if( p_intf->p_sys->p_blend->p_module )
561 module_unneed( p_intf->p_sys->p_blend,
562 p_intf->p_sys->p_blend->p_module );
564 vlc_object_detach( p_intf->p_sys->p_blend );
565 vlc_object_release( p_intf->p_sys->p_blend );
570 static int OpenTextRenderer( intf_thread_t *p_intf )
572 char *psz_modulename = NULL;
574 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
576 p_intf->p_sys->p_text =
577 vlc_object_create( p_intf, sizeof(filter_t) );
578 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
580 p_intf->p_sys->p_text->fmt_out.video.i_width =
581 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
582 p_intf->p_sys->i_width;
583 p_intf->p_sys->p_text->fmt_out.video.i_height =
584 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
585 p_intf->p_sys->i_height;
587 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
588 if( psz_modulename && *psz_modulename )
590 p_intf->p_sys->p_text->p_module =
591 module_need( p_intf->p_sys->p_text, "text renderer",
592 psz_modulename, true );
594 if( !p_intf->p_sys->p_text->p_module )
596 p_intf->p_sys->p_text->p_module =
597 module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
599 free( psz_modulename );
601 if( !p_intf->p_sys->p_text->p_module )
607 static void CloseTextRenderer( intf_thread_t *p_intf )
609 if( p_intf->p_sys->p_text )
611 if( p_intf->p_sys->p_text->p_module )
612 module_unneed( p_intf->p_sys->p_text,
613 p_intf->p_sys->p_text->p_module );
615 vlc_object_detach( p_intf->p_sys->p_text );
616 vlc_object_release( p_intf->p_sys->p_text );
620 /*****************************************************************************
622 * allocate a picture buffer for use with the overlay fb.
623 *****************************************************************************/
624 static picture_t *AllocatePicture( video_format_t *p_fmt )
626 picture_t *p_picture = picture_New( p_fmt->i_chroma,
627 p_fmt->i_width, p_fmt->i_height,
632 if( !p_fmt->p_palette &&
633 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
635 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
636 if( !p_fmt->p_palette )
638 picture_Release( p_picture );
644 p_fmt->p_palette = NULL;
650 /*****************************************************************************
652 * Deallocate a picture buffer and free all associated memory.
653 *****************************************************************************/
654 static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
658 free( p_fmt->p_palette );
659 p_fmt->p_palette = NULL;
663 picture_Release( p_pic );
666 /*****************************************************************************
667 * SetOverlayTransparency: Set the transparency for this overlay fb,
668 * - true is make transparent
669 * - false is make non tranparent
670 *****************************************************************************/
671 static void SetOverlayTransparency( intf_thread_t *p_intf,
674 intf_sys_t *p_sys = p_intf->p_sys;
675 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
676 * p_sys->i_bytes_per_pixel;
677 size_t i_page_size = (p_sys->i_page_size > i_size) ?
678 i_size : p_sys->i_page_size;
680 if( p_sys->p_overlay )
682 msg_Dbg( p_intf, "Make overlay %s",
683 b_transparent ? "transparent" : "opaque" );
685 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
687 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
691 #if defined(FBOSD_BLENDING)
692 /*****************************************************************************
693 * BlendPicture: Blend two pictures together..
694 *****************************************************************************/
695 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
696 video_format_t *p_fmt_dst, picture_t *p_pic_src,
697 picture_t *p_pic_dst )
699 intf_sys_t *p_sys = p_intf->p_sys;
700 if( p_sys->p_blend && p_sys->p_blend->p_module )
702 int i_x_offset = p_sys->i_x;
703 int i_y_offset = p_sys->i_y;
705 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
707 /* Update the output picture size */
708 p_sys->p_blend->fmt_out.video.i_width =
709 p_sys->p_blend->fmt_out.video.i_visible_width =
711 p_sys->p_blend->fmt_out.video.i_height =
712 p_sys->p_blend->fmt_out.video.i_visible_height =
715 i_x_offset = __MAX( i_x_offset, 0 );
716 i_y_offset = __MAX( i_y_offset, 0 );
718 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
719 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
727 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
729 uint8_t *p_begin = NULL, *p_end = NULL;
732 if( *p_pic && ((*p_pic)->i_planes != 1) )
735 "cannot invert alpha channel too many planes %d (only 1 supported)",
736 (*p_pic)->i_planes );
740 switch( fmt.i_chroma )
742 case VLC_FOURCC('R','V','2','4'):
743 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
744 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
745 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
748 case VLC_FOURCC('R','V','3','2'):
749 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
750 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
751 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
755 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
756 (char *)&fmt.i_chroma );
760 for( ; p_begin < p_end; p_begin += i_skip )
762 uint8_t i_opacity = 0;
764 if( *p_begin != 0xFF )
765 i_opacity = 255 - *p_begin;
766 *p_begin = i_opacity;
773 /*****************************************************************************
774 * RenderPicture: Render the picture into the p_dest buffer.
775 * We don't take transparent pixels into account, so we don't have to blend
776 * the two images together.
777 *****************************************************************************/
778 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
779 picture_t *p_src, picture_t *p_dest )
782 VLC_UNUSED( p_intf );
784 if( !p_dest && !p_src ) return VLC_EGENERIC;
786 for( i = 0; i < p_src->i_planes ; i++ )
788 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
790 /* There are margins, but with the same width : perfect ! */
791 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
792 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
796 /* We need to proceed line by line */
797 uint8_t *p_in = p_src->p[i].p_pixels;
798 uint8_t *p_out = p_dest->p[i].p_pixels;
800 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
801 int i_x_clip, i_y_clip;
803 /* Check boundaries, clip the image if necessary */
804 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
805 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
807 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
808 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
809 #if defined(FBOSD_DEBUG)
810 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
811 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
812 i_x_offset, i_y_offset, i_x, i_x_clip );
814 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
815 ( i_x <= p_dest->p[i].i_visible_pitch ) )
819 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
820 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
822 vlc_memcpy( p_out + i_x, p_in,
823 p_src->p[i].i_visible_pitch - i_x_clip );
824 p_in += p_src->p[i].i_pitch;
825 p_out += p_dest->p[i].i_pitch;
833 /*****************************************************************************
834 * RenderText - Render text to the desired picture format
835 *****************************************************************************/
836 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
837 text_style_t *p_style, video_format_t *p_fmt )
839 intf_sys_t *p_sys = p_intf->p_sys;
840 subpicture_region_t *p_region;
841 picture_t *p_dest = NULL;
843 if( !psz_string ) return p_dest;
845 if( p_sys->p_text && p_sys->p_text->p_module )
849 memset( &fmt, 0, sizeof(fmt) );
850 fmt.i_chroma = VLC_FOURCC('T','E','X','T');
852 fmt.i_width = fmt.i_visible_width = 0;
853 fmt.i_height = fmt.i_visible_height = 0;
857 p_region = subpicture_region_New( &fmt );
861 p_region->psz_text = strdup( psz_string );
862 if( !p_region->psz_text )
864 subpicture_region_Delete( p_region );
867 p_region->p_style = text_style_Duplicate( p_style );
868 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
870 if( p_sys->p_text->pf_render_text )
872 video_format_t fmt_out;
874 memset( &fmt_out, 0, sizeof(video_format_t) );
876 p_sys->p_text->pf_render_text( p_sys->p_text,
877 p_region, p_region );
879 #if defined(FBOSD_BLENDING)
880 fmt_out = p_region->fmt;
881 fmt_out.i_bits_per_pixel = 32;
882 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
884 /* FIXME not needed to copy the picture anymore no ? */
885 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
888 subpicture_region_Delete( p_region );
891 picture_Copy( p_dest, p_region->p_picture );
893 fmt_out.i_chroma = p_fmt->i_chroma;
894 p_dest = ConvertImage( p_intf, p_region->p_picture,
895 &p_region->fmt, &fmt_out );
897 subpicture_region_Delete( p_region );
900 subpicture_region_Delete( p_region );
905 /*****************************************************************************
906 * LoadImage: Load an image from file into a picture buffer.
907 *****************************************************************************/
908 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
911 picture_t *p_pic = NULL;
913 if( psz_file && p_intf->p_sys->p_image )
915 video_format_t fmt_in, fmt_out;
917 memset( &fmt_in, 0, sizeof(fmt_in) );
918 memset( &fmt_out, 0, sizeof(fmt_out) );
920 fmt_out.i_chroma = p_fmt->i_chroma;
921 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
924 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
925 fmt_out.i_width, fmt_out.i_height,
926 (char *)&p_fmt->i_chroma );
931 #if ! defined(FBOSD_BLENDING)
932 /*****************************************************************************
933 * Convertmage: Convert image to another fourcc
934 *****************************************************************************/
935 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
936 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
938 intf_sys_t *p_sys = p_intf->p_sys;
939 picture_t *p_old = NULL;
943 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
945 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
946 p_fmt_out->i_width, p_fmt_out->i_height,
947 (char *)&p_fmt_out->i_chroma );
953 /*****************************************************************************
954 * Init: initialize framebuffer video thread output method
955 *****************************************************************************/
956 static int Init( intf_thread_t *p_intf )
958 intf_sys_t *p_sys = p_intf->p_sys;
960 /* Initialize the output structure: RGB with square pixels, whatever
961 * the input format is, since it's the only format we know */
962 switch( p_sys->var_info.bits_per_pixel )
964 case 8: /* FIXME: set the palette */
965 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
967 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
969 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
971 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
973 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
975 msg_Err( p_intf, "unknown screen depth %i",
976 p_sys->var_info.bits_per_pixel );
980 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
981 p_sys->fmt_out.i_width = p_sys->i_width;
982 p_sys->fmt_out.i_height = p_sys->i_height;
984 /* Assume we have square pixels */
985 if( p_sys->i_aspect < 0 )
987 p_sys->fmt_out.i_aspect = ( p_sys->i_width
988 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
990 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
992 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
994 /* Allocate overlay buffer */
995 p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
996 if( !p_sys->p_overlay ) return VLC_EGENERIC;
998 SetOverlayTransparency( p_intf, true );
1000 /* We know the chroma, allocate a buffer which will be used
1001 * to write to the overlay framebuffer */
1002 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1003 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1004 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1006 if( p_sys->var_info.xres_virtual )
1008 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1009 * p_sys->i_bytes_per_pixel;
1013 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1014 * p_sys->i_bytes_per_pixel;
1017 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1018 * p_sys->i_bytes_per_pixel;
1020 p_sys->p_overlay->i_planes = 1;
1025 /*****************************************************************************
1026 * End: terminate framebuffer interface
1027 *****************************************************************************/
1028 static void End( intf_thread_t *p_intf )
1030 intf_sys_t *p_sys = p_intf->p_sys;
1033 SetOverlayTransparency( p_intf, false );
1034 if( p_sys->p_overlay )
1037 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1038 p_sys->i_page_size );
1040 msg_Err( p_intf, "unable to clear overlay" );
1043 DeAllocatePicture( p_intf->p_sys->p_overlay,
1044 &p_intf->p_sys->fmt_out );
1045 p_intf->p_sys->p_overlay = NULL;
1048 /*****************************************************************************
1049 * OpenDisplay: initialize framebuffer
1050 *****************************************************************************/
1051 static int OpenDisplay( intf_thread_t *p_intf )
1053 intf_sys_t *p_sys = p_intf->p_sys;
1054 char *psz_device; /* framebuffer device path */
1055 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1057 /* Open framebuffer device */
1058 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1060 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1061 return VLC_EGENERIC;
1064 p_sys->i_fd = open( psz_device, O_RDWR );
1065 if( p_sys->i_fd == -1 )
1067 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1069 return VLC_EGENERIC;
1073 /* Get framebuffer device information */
1074 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1076 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1077 close( p_sys->i_fd );
1078 return VLC_EGENERIC;
1081 /* Get some info on the framebuffer itself */
1082 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1084 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1085 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1088 /* FIXME: if the image is full-size, it gets cropped on the left
1089 * because of the xres / xres_virtual slight difference */
1090 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1091 p_sys->var_info.xres, p_sys->var_info.yres,
1092 p_sys->var_info.xres_virtual,
1093 p_sys->var_info.yres_virtual );
1095 p_sys->fmt_out.i_width = p_sys->i_width;
1096 p_sys->fmt_out.i_height = p_sys->i_height;
1098 p_sys->p_palette = NULL;
1099 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1101 switch( p_sys->var_info.bits_per_pixel )
1104 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1105 if( !p_sys->p_palette )
1107 close( p_sys->i_fd );
1110 p_sys->fb_cmap.start = 0;
1111 p_sys->fb_cmap.len = 256;
1112 p_sys->fb_cmap.red = p_sys->p_palette;
1113 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1114 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1115 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1117 /* Save the colormap */
1118 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1120 p_sys->i_bytes_per_pixel = 1;
1125 p_sys->i_bytes_per_pixel = 2;
1129 p_sys->i_bytes_per_pixel = 3;
1133 p_sys->i_bytes_per_pixel = 4;
1137 msg_Err( p_intf, "screen depth %d is not supported",
1138 p_sys->var_info.bits_per_pixel );
1140 close( p_sys->i_fd );
1141 return VLC_EGENERIC;
1144 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1145 * p_sys->i_bytes_per_pixel;
1147 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1148 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1149 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1153 /*****************************************************************************
1154 * CloseDisplay: terminate FB interface thread
1155 *****************************************************************************/
1156 static void CloseDisplay( intf_thread_t *p_intf )
1158 intf_sys_t *p_sys = p_intf->p_sys;
1160 /* Restore palette */
1161 if( p_sys->var_info.bits_per_pixel == 8 )
1163 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1164 free( p_sys->p_palette );
1165 p_sys->p_palette = NULL;
1169 close( p_sys->i_fd );
1172 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1174 intf_sys_t *p_sys = p_intf->p_sys;
1176 if( render->i_state != FBOSD_STATE_RENDER ) return;
1177 if( !render->psz_string ) return;
1179 if( render->i_type == FBOSD_RENDER_IMAGE )
1182 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1185 RenderPicture( p_intf, render->i_x, render->i_y,
1186 p_pic, p_sys->p_overlay );
1187 picture_Release( p_pic );
1190 else if( render->i_type == FBOSD_RENDER_TEXT )
1193 #if defined(FBOSD_BLENDING)
1194 video_format_t fmt_in;
1195 memset( &fmt_in, 0, sizeof(video_format_t) );
1196 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1200 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1201 p_text, p_sys->p_overlay );
1202 msg_Dbg( p_intf, "releasing picture" );
1203 DeAllocatePicture( p_text, &fmt_in );
1206 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1210 RenderPicture( p_intf, render->i_x, render->i_y,
1211 p_text, p_sys->p_overlay );
1212 picture_Release( p_text );
1218 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1220 intf_sys_t *p_sys = p_intf->p_sys;
1222 vlc_memcpy( &render->text_style, &default_text_style,
1223 sizeof( text_style_t ) );
1224 free( render->psz_string );
1225 render->psz_string = NULL;
1227 render->i_x = p_sys->i_x;
1228 render->i_y = p_sys->i_y;
1229 render->i_pos = p_sys->i_pos;
1230 render->i_alpha = p_sys->i_alpha;
1231 render->b_absolute = p_sys->b_absolute;
1232 render->i_state = FBOSD_STATE_FREE;
1235 static bool isRendererReady( intf_thread_t *p_intf )
1237 intf_sys_t *p_sys = p_intf->p_sys;
1240 /* Check if there are more items to render */
1241 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1243 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1249 /*****************************************************************************
1251 *****************************************************************************
1252 * This part of the interface is in a separate thread so that we can call
1253 * exec() from within it without annoying the rest of the program.
1254 *****************************************************************************/
1255 static void Run( intf_thread_t *p_intf )
1257 intf_sys_t *p_sys = p_intf->p_sys;
1258 int canc = vlc_savecancel();
1260 while( vlc_object_alive( p_intf ) )
1264 /* Is there somthing to render? */
1265 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1267 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1269 Render( p_intf, &p_sys->render[i] );
1270 RenderClear( p_intf, &p_sys->render[i] );
1274 if( p_sys->b_clear )
1276 SetOverlayTransparency( p_intf, true );
1278 var_SetString( p_intf, "fbosd-image", "" );
1279 var_SetString( p_intf, "fbosd-text", "" );
1281 p_sys->b_clear = false;
1282 p_sys->b_need_update = true;
1285 if( p_sys->b_need_update && p_sys->p_overlay &&
1286 isRendererReady( p_intf ) )
1289 #if defined(FBOSD_BLENDING)
1290 /* Reverse alpha channel to work around FPGA bug */
1291 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1293 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1294 p_sys->i_page_size );
1296 msg_Err( p_intf, "unable to write to overlay" );
1297 lseek( p_sys->i_fd, 0, SEEK_SET );
1299 /* clear the picture */
1300 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1301 p_sys->b_need_update = false;
1304 msleep( INTF_IDLE_SLEEP );
1308 vlc_restorecancel( canc );
1311 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1312 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1314 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1315 intf_sys_t *p_sys = p_intf->p_sys;
1316 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1318 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1320 p_sys->b_need_update = true;
1322 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1325 /* Clear the entire render list */
1326 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1328 RenderClear( p_intf, &p_sys->render[i] );
1330 p_sys->b_clear = true;
1332 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1335 /* Are we already busy with on slot ? */
1336 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1338 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1340 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1348 /* Are we already busy with on slot ? */
1349 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1351 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1354 /* No, then find first FREE slot */
1355 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1357 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1359 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1362 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1364 msg_Warn( p_this, "render space depleated" );
1368 /* Found a free slot */
1369 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1370 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1372 free( p_sys->render[i].psz_string );
1373 p_sys->render[i].psz_string = strdup( newval.psz_string );
1374 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1376 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1378 free( p_sys->render[i].psz_string );
1379 p_sys->render[i].psz_string = strdup( newval.psz_string );
1380 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1382 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1384 p_sys->render[i].b_absolute = false;
1385 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1386 newval.i_int : p_sys->i_width;
1388 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1390 p_sys->render[i].b_absolute = false;
1391 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1392 newval.i_int : p_sys->i_height;
1394 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1396 p_sys->render[i].b_absolute = true;
1397 p_sys->render[i].i_pos = newval.i_int;
1399 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1401 p_sys->render[i].text_style.i_font_size = newval.i_int;
1403 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1405 p_sys->render[i].text_style.i_font_color = newval.i_int;
1407 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1409 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1411 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1413 p_sys->render[i].i_alpha = newval.i_int;