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 = malloc( sizeof( text_style_t ) );
314 if( !p_sys->p_style )
316 free( p_intf->p_sys );
319 vlc_memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ) );
321 p_intf->pf_run = Run;
323 p_sys->p_image = image_HandlerCreate( p_this );
324 if( !p_sys->p_image )
326 free( p_sys->p_style );
331 p_sys->i_alpha = var_CreateGetIntegerCommand( p_intf, "fbosd-alpha" );
332 var_AddCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
334 p_sys->i_aspect = -1;
336 var_CreateGetNonEmptyString( p_intf, "fbosd-aspect-ratio" );
339 char *psz_parser = strchr( psz_aspect, ':' );
343 *psz_parser++ = '\0';
344 p_sys->i_aspect = ( atoi( psz_aspect )
345 * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
346 p_sys->fmt_out.i_aspect = p_sys->i_aspect;
348 msg_Dbg( p_intf, "using aspect ratio %d:%d",
349 atoi( psz_aspect ), atoi( psz_parser ) );
354 /* Use PAL by default */
355 p_sys->i_width = p_sys->fmt_out.i_width = 704;
356 p_sys->i_height = p_sys->fmt_out.i_height = 576;
358 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-image" );
359 var_AddCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
360 if( psz_tmp && *psz_tmp )
362 p_sys->render[0].i_type = FBOSD_RENDER_IMAGE;
363 p_sys->render[0].i_state = FBOSD_STATE_RENDER;
364 p_sys->render[0].psz_string = strdup( psz_tmp );
368 psz_tmp = var_CreateGetNonEmptyStringCommand( p_intf, "fbosd-text" );
369 var_AddCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
370 if( psz_tmp && *psz_tmp )
372 p_sys->render[1].i_type = FBOSD_RENDER_TEXT;
373 p_sys->render[1].i_state = FBOSD_STATE_RENDER;
374 p_sys->render[1].psz_string = strdup( psz_tmp );
378 p_sys->i_pos = var_CreateGetIntegerCommand( p_intf, "fbosd-position" );
379 p_sys->i_x = var_CreateGetIntegerCommand( p_intf, "fbosd-x" );
380 p_sys->i_y = var_CreateGetIntegerCommand( p_intf, "fbosd-y" );
382 var_AddCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
383 var_AddCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
384 var_AddCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
386 p_sys->p_style->i_font_size =
387 var_CreateGetIntegerCommand( p_intf, "fbosd-font-size" );
388 p_sys->p_style->i_font_color =
389 var_CreateGetIntegerCommand( p_intf, "fbosd-font-color" );
390 p_sys->p_style->i_font_alpha = 255 -
391 var_CreateGetIntegerCommand( p_intf, "fbosd-font-opacity" );
393 var_AddCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
394 var_AddCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
395 var_AddCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
397 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
399 vlc_memcpy( &p_sys->render[i].text_style, &default_text_style,
400 sizeof( text_style_t ) );
403 p_sys->b_clear = var_CreateGetBoolCommand( p_intf, "fbosd-clear" );
404 p_sys->b_render = var_CreateGetBoolCommand( p_intf, "fbosd-render" );
405 p_sys->b_need_update = var_CreateGetBoolCommand( p_intf, "fbosd-display" );
407 var_AddCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
408 var_AddCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
409 var_AddCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
411 /* Check if picture position was overridden */
412 p_sys->b_absolute = true;
413 if( ( p_sys->i_x >= 0 ) && ( p_sys->i_y >= 0 ) )
415 p_sys->b_absolute = false;
416 p_sys->i_y = (p_sys->i_y < p_sys->i_height) ?
417 p_sys->i_y : p_sys->i_height;
418 p_sys->i_x = (p_sys->i_x < p_sys->i_width) ?
419 p_sys->i_x : p_sys->i_width;
422 p_sys->render[0].i_x = p_sys->render[1].i_x = p_sys->i_x;
423 p_sys->render[0].i_y = p_sys->render[1].i_y = p_sys->i_y;
424 p_sys->render[0].i_pos = p_sys->render[1].i_pos = p_sys->i_pos;
425 p_sys->render[0].i_alpha = p_sys->render[1].i_alpha = p_sys->i_alpha;
427 /* Initialize framebuffer */
428 if( OpenDisplay( p_intf ) )
430 Destroy( VLC_OBJECT(p_intf) );
436 #if defined(FBOSD_BLENDING)
437 /* Load the blending module */
438 if( OpenBlending( p_intf ) )
440 msg_Err( p_intf, "Unable to load image blending module" );
441 Destroy( VLC_OBJECT(p_intf) );
446 /* Load text renderer module */
447 if( OpenTextRenderer( p_intf ) )
449 msg_Err( p_intf, "Unable to load text rendering module" );
450 Destroy( VLC_OBJECT(p_intf) );
454 p_sys->b_render = true;
455 p_sys->b_need_update = true;
460 /*****************************************************************************
461 * Destroy: destroy FB interface thread output method
462 *****************************************************************************
463 * Terminate an output method created by Create
464 *****************************************************************************/
465 static void Destroy( vlc_object_t *p_this )
467 intf_thread_t *p_intf = (intf_thread_t *)p_this;
468 intf_sys_t *p_sys = p_intf->p_sys;
472 p_sys->b_need_update = false;
473 p_sys->b_render = false;
474 p_sys->b_clear = false;
476 var_DelCallback( p_intf, "fbosd-alpha", OverlayCallback, NULL );
477 var_Destroy( p_intf, "fbosd-alpha" );
479 var_DelCallback( p_intf, "fbosd-x", OverlayCallback, NULL );
480 var_DelCallback( p_intf, "fbosd-y", OverlayCallback, NULL );
481 var_DelCallback( p_intf, "fbosd-position", OverlayCallback, NULL );
482 var_DelCallback( p_intf, "fbosd-image", OverlayCallback, NULL );
483 var_DelCallback( p_intf, "fbosd-text", OverlayCallback, NULL );
484 var_DelCallback( p_intf, "fbosd-font-size", OverlayCallback, NULL );
485 var_DelCallback( p_intf, "fbosd-font-color", OverlayCallback, NULL );
486 var_DelCallback( p_intf, "fbosd-font-opacity", OverlayCallback, NULL );
487 var_DelCallback( p_intf, "fbosd-clear", OverlayCallback, NULL );
488 var_DelCallback( p_intf, "fbosd-render", OverlayCallback, NULL );
489 var_DelCallback( p_intf, "fbosd-display", OverlayCallback, NULL );
491 var_Destroy( p_intf, "fbosd-x" );
492 var_Destroy( p_intf, "fbosd-y" );
493 var_Destroy( p_intf, "fbosd-position" );
494 var_Destroy( p_intf, "fbosd-image" );
495 var_Destroy( p_intf, "fbosd-text" );
496 var_Destroy( p_intf, "fbosd-font-size" );
497 var_Destroy( p_intf, "fbosd-font-color" );
498 var_Destroy( p_intf, "fbosd-font-opacity" );
499 var_Destroy( p_intf, "fbosd-clear" );
500 var_Destroy( p_intf, "fbosd-render" );
501 var_Destroy( p_intf, "fbosd-display" );
503 var_Destroy( p_intf, "fbosd-aspect-ratio" );
505 CloseDisplay( p_intf );
507 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
509 free( p_sys->render[i].psz_string );
510 p_sys->render[i].i_state = FBOSD_STATE_FREE;
513 #if defined(FBOSD_BLENDING)
514 if( p_sys->p_blend ) CloseBlending( p_intf );
516 if( p_sys->p_text ) CloseTextRenderer( p_intf );
519 image_HandlerDelete( p_sys->p_image );
520 if( p_sys->p_overlay )
521 picture_Release( p_sys->p_overlay );
523 free( p_sys->p_style );
527 #if defined(FBOSD_BLENDING)
528 static int OpenBlending( intf_thread_t *p_intf )
530 if( p_intf->p_sys->p_blend ) return VLC_EGENERIC;
532 p_intf->p_sys->p_blend =
533 vlc_object_create( p_intf, sizeof(filter_t) );
534 vlc_object_attach( p_intf->p_sys->p_blend, p_intf );
535 p_intf->p_sys->p_blend->fmt_out.video.i_x_offset =
536 p_intf->p_sys->p_blend->fmt_out.video.i_y_offset = 0;
537 p_intf->p_sys->p_blend->fmt_out.video.i_aspect =
538 p_intf->p_sys->fmt_out.i_aspect;
539 p_intf->p_sys->p_blend->fmt_out.video.i_chroma =
540 p_intf->p_sys->fmt_out.i_chroma;
541 if( config_GetInt( p_intf, "freetype-yuvp" ) )
542 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
543 VLC_FOURCC('Y','U','V','P');
545 p_intf->p_sys->p_blend->fmt_in.video.i_chroma =
546 VLC_FOURCC('Y','U','V','A');
548 p_intf->p_sys->p_blend->p_module =
549 module_need( p_intf->p_sys->p_blend, "video blending", NULL, false );
551 if( !p_intf->p_sys->p_blend->p_module )
557 static void CloseBlending( intf_thread_t *p_intf )
559 if( p_intf->p_sys->p_blend )
561 if( p_intf->p_sys->p_blend->p_module )
562 module_unneed( p_intf->p_sys->p_blend,
563 p_intf->p_sys->p_blend->p_module );
565 vlc_object_detach( p_intf->p_sys->p_blend );
566 vlc_object_release( p_intf->p_sys->p_blend );
571 static int OpenTextRenderer( intf_thread_t *p_intf )
573 char *psz_modulename = NULL;
575 if( p_intf->p_sys->p_text ) return VLC_EGENERIC;
577 p_intf->p_sys->p_text =
578 vlc_object_create( p_intf, sizeof(filter_t) );
579 vlc_object_attach( p_intf->p_sys->p_text, p_intf );
581 p_intf->p_sys->p_text->fmt_out.video.i_width =
582 p_intf->p_sys->p_text->fmt_out.video.i_visible_width =
583 p_intf->p_sys->i_width;
584 p_intf->p_sys->p_text->fmt_out.video.i_height =
585 p_intf->p_sys->p_text->fmt_out.video.i_visible_height =
586 p_intf->p_sys->i_height;
588 psz_modulename = var_CreateGetString( p_intf, "text-renderer" );
589 if( psz_modulename && *psz_modulename )
591 p_intf->p_sys->p_text->p_module =
592 module_need( p_intf->p_sys->p_text, "text renderer",
593 psz_modulename, true );
595 if( !p_intf->p_sys->p_text->p_module )
597 p_intf->p_sys->p_text->p_module =
598 module_need( p_intf->p_sys->p_text, "text renderer", NULL, false );
600 free( psz_modulename );
602 if( !p_intf->p_sys->p_text->p_module )
608 static void CloseTextRenderer( intf_thread_t *p_intf )
610 if( p_intf->p_sys->p_text )
612 if( p_intf->p_sys->p_text->p_module )
613 module_unneed( p_intf->p_sys->p_text,
614 p_intf->p_sys->p_text->p_module );
616 vlc_object_detach( p_intf->p_sys->p_text );
617 vlc_object_release( p_intf->p_sys->p_text );
621 /*****************************************************************************
623 * allocate a picture buffer for use with the overlay fb.
624 *****************************************************************************/
625 static picture_t *AllocatePicture( video_format_t *p_fmt )
627 picture_t *p_picture = picture_New( p_fmt->i_chroma,
628 p_fmt->i_width, p_fmt->i_height,
633 if( !p_fmt->p_palette &&
634 ( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') ) )
636 p_fmt->p_palette = malloc( sizeof(video_palette_t) );
637 if( !p_fmt->p_palette )
639 picture_Release( p_picture );
645 p_fmt->p_palette = NULL;
651 /*****************************************************************************
653 * Deallocate a picture buffer and free all associated memory.
654 *****************************************************************************/
655 static void DeAllocatePicture( picture_t *p_pic, video_format_t *p_fmt )
659 free( p_fmt->p_palette );
660 p_fmt->p_palette = NULL;
664 picture_Release( p_pic );
667 /*****************************************************************************
668 * SetOverlayTransparency: Set the transparency for this overlay fb,
669 * - true is make transparent
670 * - false is make non tranparent
671 *****************************************************************************/
672 static void SetOverlayTransparency( intf_thread_t *p_intf,
675 intf_sys_t *p_sys = p_intf->p_sys;
676 size_t i_size = p_sys->fmt_out.i_width * p_sys->fmt_out.i_height
677 * p_sys->i_bytes_per_pixel;
678 size_t i_page_size = (p_sys->i_page_size > i_size) ?
679 i_size : p_sys->i_page_size;
681 if( p_sys->p_overlay )
683 msg_Dbg( p_intf, "Make overlay %s",
684 b_transparent ? "transparent" : "opaque" );
686 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, i_page_size );
688 memset( p_sys->p_overlay->p[0].p_pixels, 0x00, i_page_size );
692 #if defined(FBOSD_BLENDING)
693 /*****************************************************************************
694 * BlendPicture: Blend two pictures together..
695 *****************************************************************************/
696 static int BlendPicture( intf_thread_t *p_intf, video_format_t *p_fmt_src,
697 video_format_t *p_fmt_dst, picture_t *p_pic_src,
698 picture_t *p_pic_dst )
700 intf_sys_t *p_sys = p_intf->p_sys;
701 if( p_sys->p_blend && p_sys->p_blend->p_module )
703 int i_x_offset = p_sys->i_x;
704 int i_y_offset = p_sys->i_y;
706 memcpy( &p_sys->p_blend->fmt_in.video, p_fmt_src, sizeof( video_format_t ) );
708 /* Update the output picture size */
709 p_sys->p_blend->fmt_out.video.i_width =
710 p_sys->p_blend->fmt_out.video.i_visible_width =
712 p_sys->p_blend->fmt_out.video.i_height =
713 p_sys->p_blend->fmt_out.video.i_visible_height =
716 i_x_offset = __MAX( i_x_offset, 0 );
717 i_y_offset = __MAX( i_y_offset, 0 );
719 p_sys->p_blend->pf_video_blend( p_sys->p_blend, p_pic_dst,
720 p_pic_src, p_pic_dst, i_x_offset, i_y_offset,
728 static int InvertAlpha( intf_thread_t *p_intf, picture_t **p_pic, video_format_t fmt )
730 uint8_t *p_begin = NULL, *p_end = NULL;
733 if( *p_pic && ((*p_pic)->i_planes != 1) )
736 "cannot invert alpha channel too many planes %d (only 1 supported)",
737 (*p_pic)->i_planes );
741 switch( fmt.i_chroma )
743 case VLC_FOURCC('R','V','2','4'):
744 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
745 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
746 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
749 case VLC_FOURCC('R','V','3','2'):
750 p_begin = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels;
751 p_end = (uint8_t *)(*p_pic)->p[Y_PLANE].p_pixels +
752 ( fmt.i_height * (*p_pic)->p[Y_PLANE].i_pitch );
756 msg_Err( p_intf, "cannot invert alpha channel chroma not supported %4.4s",
757 (char *)&fmt.i_chroma );
761 for( ; p_begin < p_end; p_begin += i_skip )
763 uint8_t i_opacity = 0;
765 if( *p_begin != 0xFF )
766 i_opacity = 255 - *p_begin;
767 *p_begin = i_opacity;
774 /*****************************************************************************
775 * RenderPicture: Render the picture into the p_dest buffer.
776 * We don't take transparent pixels into account, so we don't have to blend
777 * the two images together.
778 *****************************************************************************/
779 static int RenderPicture( intf_thread_t *p_intf, int i_x_offset, int i_y_offset,
780 picture_t *p_src, picture_t *p_dest )
783 VLC_UNUSED( p_intf );
785 if( !p_dest && !p_src ) return VLC_EGENERIC;
787 for( i = 0; i < p_src->i_planes ; i++ )
789 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
791 /* There are margins, but with the same width : perfect ! */
792 vlc_memcpy( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
793 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
797 /* We need to proceed line by line */
798 uint8_t *p_in = p_src->p[i].p_pixels;
799 uint8_t *p_out = p_dest->p[i].p_pixels;
801 int i_x = i_x_offset * p_src->p[i].i_pixel_pitch;
802 int i_x_clip, i_y_clip;
804 /* Check boundaries, clip the image if necessary */
805 i_x_clip = ( i_x + p_src->p[i].i_visible_pitch ) - p_dest->p[i].i_visible_pitch;
806 i_x_clip = ( i_x_clip > 0 ) ? i_x_clip : 0;
808 i_y_clip = ( i_y_offset + p_src->p[i].i_visible_lines ) - p_dest->p[i].i_visible_lines;
809 i_y_clip = ( i_y_clip > 0 ) ? i_y_clip : 0;
810 #if defined(FBOSD_DEBUG)
811 msg_Dbg( p_intf, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
812 p_dest->p[i].i_visible_pitch, p_src->p[i].i_visible_pitch,
813 i_x_offset, i_y_offset, i_x, i_x_clip );
815 if( ( i_y_offset <= p_dest->p[i].i_visible_lines ) &&
816 ( i_x <= p_dest->p[i].i_visible_pitch ) )
820 p_out += ( i_y_offset * p_dest->p[i].i_pitch );
821 for( i_line = 0; i_line < ( p_src->p[i].i_visible_lines - i_y_clip ); i_line++ )
823 vlc_memcpy( p_out + i_x, p_in,
824 p_src->p[i].i_visible_pitch - i_x_clip );
825 p_in += p_src->p[i].i_pitch;
826 p_out += p_dest->p[i].i_pitch;
834 /*****************************************************************************
835 * RenderText - Render text to the desired picture format
836 *****************************************************************************/
837 static picture_t *RenderText( intf_thread_t *p_intf, const char *psz_string,
838 text_style_t *p_style, video_format_t *p_fmt )
840 intf_sys_t *p_sys = p_intf->p_sys;
841 subpicture_region_t *p_region;
842 picture_t *p_dest = NULL;
844 if( !psz_string ) return p_dest;
846 if( p_sys->p_text && p_sys->p_text->p_module )
850 memset( &fmt, 0, sizeof(fmt) );
851 fmt.i_chroma = VLC_FOURCC('T','E','X','T');
853 fmt.i_width = fmt.i_visible_width = 0;
854 fmt.i_height = fmt.i_visible_height = 0;
858 p_region = subpicture_region_New( &fmt );
862 p_region->psz_text = strdup( psz_string );
863 if( !p_region->psz_text )
865 subpicture_region_Delete( p_region );
868 p_region->p_style = p_style;
869 p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
871 if( p_sys->p_text->pf_render_text )
873 video_format_t fmt_out;
875 memset( &fmt_out, 0, sizeof(video_format_t) );
877 p_sys->p_text->pf_render_text( p_sys->p_text,
878 p_region, p_region );
880 #if defined(FBOSD_BLENDING)
881 fmt_out = p_region->fmt;
882 fmt_out.i_bits_per_pixel = 32;
883 vlc_memcpy( p_fmt, &fmt_out, sizeof(video_format_t) );
885 /* FIXME not needed to copy the picture anymore no ? */
886 p_dest = AllocatePicture( VLC_OBJECT(p_intf), &fmt_out );
889 subpicture_region_Delete( p_region );
892 picture_Copy( p_dest, p_region->p_picture );
894 fmt_out.i_chroma = p_fmt->i_chroma;
895 p_dest = ConvertImage( p_intf, p_region->p_picture,
896 &p_region->fmt, &fmt_out );
898 subpicture_region_Delete( p_region );
901 subpicture_region_Delete( p_region );
906 /*****************************************************************************
907 * LoadImage: Load an image from file into a picture buffer.
908 *****************************************************************************/
909 static picture_t *LoadImage( intf_thread_t *p_intf, video_format_t *p_fmt,
912 picture_t *p_pic = NULL;
914 if( psz_file && p_intf->p_sys->p_image )
916 video_format_t fmt_in, fmt_out;
918 memset( &fmt_in, 0, sizeof(fmt_in) );
919 memset( &fmt_out, 0, sizeof(fmt_out) );
921 fmt_out.i_chroma = p_fmt->i_chroma;
922 p_pic = image_ReadUrl( p_intf->p_sys->p_image, psz_file,
925 msg_Dbg( p_intf, "image size %dx%d chroma %4.4s",
926 fmt_out.i_width, fmt_out.i_height,
927 (char *)&p_fmt->i_chroma );
932 #if ! defined(FBOSD_BLENDING)
933 /*****************************************************************************
934 * Convertmage: Convert image to another fourcc
935 *****************************************************************************/
936 static picture_t *ConvertImage( intf_thread_t *p_intf, picture_t *p_pic,
937 video_format_t *p_fmt_in, video_format_t *p_fmt_out )
939 intf_sys_t *p_sys = p_intf->p_sys;
940 picture_t *p_old = NULL;
944 p_old = image_Convert( p_sys->p_image, p_pic, p_fmt_in, p_fmt_out );
946 msg_Dbg( p_intf, "converted image size %dx%d chroma %4.4s",
947 p_fmt_out->i_width, p_fmt_out->i_height,
948 (char *)&p_fmt_out->i_chroma );
954 /*****************************************************************************
955 * Init: initialize framebuffer video thread output method
956 *****************************************************************************/
957 static int Init( intf_thread_t *p_intf )
959 intf_sys_t *p_sys = p_intf->p_sys;
961 /* Initialize the output structure: RGB with square pixels, whatever
962 * the input format is, since it's the only format we know */
963 switch( p_sys->var_info.bits_per_pixel )
965 case 8: /* FIXME: set the palette */
966 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','G','B','2'); break;
968 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','5'); break;
970 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','1','6'); break;
972 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','2','4'); break;
974 p_sys->fmt_out.i_chroma = VLC_FOURCC('R','V','3','2'); break;
976 msg_Err( p_intf, "unknown screen depth %i",
977 p_sys->var_info.bits_per_pixel );
981 p_sys->fmt_out.i_bits_per_pixel = p_sys->var_info.bits_per_pixel;
982 p_sys->fmt_out.i_width = p_sys->i_width;
983 p_sys->fmt_out.i_height = p_sys->i_height;
985 /* Assume we have square pixels */
986 if( p_sys->i_aspect < 0 )
988 p_sys->fmt_out.i_aspect = ( p_sys->i_width
989 * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
991 else p_sys->fmt_out.i_aspect = p_sys->i_aspect;
993 p_sys->fmt_out.i_sar_num = p_sys->fmt_out.i_sar_den = 1;
995 /* Allocate overlay buffer */
996 p_sys->p_overlay = AllocatePicture( &p_sys->fmt_out );
997 if( !p_sys->p_overlay ) return VLC_EGENERIC;
999 SetOverlayTransparency( p_intf, true );
1001 /* We know the chroma, allocate a buffer which will be used
1002 * to write to the overlay framebuffer */
1003 p_sys->p_overlay->p->i_pixel_pitch = p_sys->i_bytes_per_pixel;
1004 p_sys->p_overlay->p->i_lines = p_sys->var_info.yres;
1005 p_sys->p_overlay->p->i_visible_lines = p_sys->var_info.yres;
1007 if( p_sys->var_info.xres_virtual )
1009 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres_virtual
1010 * p_sys->i_bytes_per_pixel;
1014 p_sys->p_overlay->p->i_pitch = p_sys->var_info.xres
1015 * p_sys->i_bytes_per_pixel;
1018 p_sys->p_overlay->p->i_visible_pitch = p_sys->var_info.xres
1019 * p_sys->i_bytes_per_pixel;
1021 p_sys->p_overlay->i_planes = 1;
1026 /*****************************************************************************
1027 * End: terminate framebuffer interface
1028 *****************************************************************************/
1029 static void End( intf_thread_t *p_intf )
1031 intf_sys_t *p_sys = p_intf->p_sys;
1034 SetOverlayTransparency( p_intf, false );
1035 if( p_sys->p_overlay )
1038 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1039 p_sys->i_page_size );
1041 msg_Err( p_intf, "unable to clear overlay" );
1044 DeAllocatePicture( p_intf->p_sys->p_overlay,
1045 &p_intf->p_sys->fmt_out );
1046 p_intf->p_sys->p_overlay = NULL;
1049 /*****************************************************************************
1050 * OpenDisplay: initialize framebuffer
1051 *****************************************************************************/
1052 static int OpenDisplay( intf_thread_t *p_intf )
1054 intf_sys_t *p_sys = p_intf->p_sys;
1055 char *psz_device; /* framebuffer device path */
1056 struct fb_fix_screeninfo fix_info; /* framebuffer fix information */
1058 /* Open framebuffer device */
1059 if( !(psz_device = config_GetPsz( p_intf, "fbosd-dev" )) )
1061 msg_Err( p_intf, "don't know which fb osd/overlay device to open" );
1062 return VLC_EGENERIC;
1065 p_sys->i_fd = open( psz_device, O_RDWR );
1066 if( p_sys->i_fd == -1 )
1068 msg_Err( p_intf, "cannot open %s (%s)", psz_device, strerror(errno) );
1070 return VLC_EGENERIC;
1074 /* Get framebuffer device information */
1075 if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
1077 msg_Err( p_intf, "cannot get fb info (%s)", strerror(errno) );
1078 close( p_sys->i_fd );
1079 return VLC_EGENERIC;
1082 /* Get some info on the framebuffer itself */
1083 if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) == 0 )
1085 p_sys->i_width = p_sys->fmt_out.i_width = p_sys->var_info.xres;
1086 p_sys->i_height = p_sys->fmt_out.i_height = p_sys->var_info.yres;
1089 /* FIXME: if the image is full-size, it gets cropped on the left
1090 * because of the xres / xres_virtual slight difference */
1091 msg_Dbg( p_intf, "%ix%i (virtual %ix%i)",
1092 p_sys->var_info.xres, p_sys->var_info.yres,
1093 p_sys->var_info.xres_virtual,
1094 p_sys->var_info.yres_virtual );
1096 p_sys->fmt_out.i_width = p_sys->i_width;
1097 p_sys->fmt_out.i_height = p_sys->i_height;
1099 p_sys->p_palette = NULL;
1100 p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
1102 switch( p_sys->var_info.bits_per_pixel )
1105 p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
1106 if( !p_sys->p_palette )
1108 close( p_sys->i_fd );
1111 p_sys->fb_cmap.start = 0;
1112 p_sys->fb_cmap.len = 256;
1113 p_sys->fb_cmap.red = p_sys->p_palette;
1114 p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
1115 p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
1116 p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
1118 /* Save the colormap */
1119 ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
1121 p_sys->i_bytes_per_pixel = 1;
1126 p_sys->i_bytes_per_pixel = 2;
1130 p_sys->i_bytes_per_pixel = 3;
1134 p_sys->i_bytes_per_pixel = 4;
1138 msg_Err( p_intf, "screen depth %d is not supported",
1139 p_sys->var_info.bits_per_pixel );
1141 close( p_sys->i_fd );
1142 return VLC_EGENERIC;
1145 p_sys->i_page_size = p_sys->i_width * p_sys->i_height
1146 * p_sys->i_bytes_per_pixel;
1148 msg_Dbg( p_intf, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1149 "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
1150 fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
1154 /*****************************************************************************
1155 * CloseDisplay: terminate FB interface thread
1156 *****************************************************************************/
1157 static void CloseDisplay( intf_thread_t *p_intf )
1159 intf_sys_t *p_sys = p_intf->p_sys;
1161 /* Restore palette */
1162 if( p_sys->var_info.bits_per_pixel == 8 )
1164 ioctl( p_sys->i_fd, FBIOPUTCMAP, &p_sys->fb_cmap );
1165 free( p_sys->p_palette );
1166 p_sys->p_palette = NULL;
1170 close( p_sys->i_fd );
1173 static void Render( intf_thread_t *p_intf, struct fbosd_render_t *render )
1175 intf_sys_t *p_sys = p_intf->p_sys;
1177 if( render->i_state != FBOSD_STATE_RENDER ) return;
1178 if( !render->psz_string ) return;
1180 if( render->i_type == FBOSD_RENDER_IMAGE )
1183 p_pic = LoadImage( p_intf, &p_sys->fmt_out, render->psz_string );
1186 RenderPicture( p_intf, render->i_x, render->i_y,
1187 p_pic, p_sys->p_overlay );
1188 picture_Release( p_pic );
1191 else if( render->i_type == FBOSD_RENDER_TEXT )
1194 #if defined(FBOSD_BLENDING)
1195 video_format_t fmt_in;
1196 memset( &fmt_in, 0, sizeof(video_format_t) );
1197 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1201 BlendPicture( p_intf, &fmt_in, &p_sys->fmt_out,
1202 p_text, p_sys->p_overlay );
1203 msg_Dbg( p_intf, "releasing picture" );
1204 DeAllocatePicture( p_text, &fmt_in );
1207 p_text = RenderText( p_intf, render->psz_string, &render->text_style,
1211 RenderPicture( p_intf, render->i_x, render->i_y,
1212 p_text, p_sys->p_overlay );
1213 picture_Release( p_text );
1219 static void RenderClear( intf_thread_t *p_intf, struct fbosd_render_t *render )
1221 intf_sys_t *p_sys = p_intf->p_sys;
1223 vlc_memcpy( &render->text_style, &default_text_style,
1224 sizeof( text_style_t ) );
1225 free( render->psz_string );
1226 render->psz_string = NULL;
1228 render->i_x = p_sys->i_x;
1229 render->i_y = p_sys->i_y;
1230 render->i_pos = p_sys->i_pos;
1231 render->i_alpha = p_sys->i_alpha;
1232 render->b_absolute = p_sys->b_absolute;
1233 render->i_state = FBOSD_STATE_FREE;
1236 static bool isRendererReady( intf_thread_t *p_intf )
1238 intf_sys_t *p_sys = p_intf->p_sys;
1241 /* Check if there are more items to render */
1242 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1244 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1250 /*****************************************************************************
1252 *****************************************************************************
1253 * This part of the interface is in a separate thread so that we can call
1254 * exec() from within it without annoying the rest of the program.
1255 *****************************************************************************/
1256 static void Run( intf_thread_t *p_intf )
1258 intf_sys_t *p_sys = p_intf->p_sys;
1259 int canc = vlc_savecancel();
1261 while( vlc_object_alive( p_intf ) )
1265 /* Is there somthing to render? */
1266 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1268 if( p_sys->render[i].i_state == FBOSD_STATE_RENDER )
1270 Render( p_intf, &p_sys->render[i] );
1271 RenderClear( p_intf, &p_sys->render[i] );
1275 if( p_sys->b_clear )
1277 SetOverlayTransparency( p_intf, true );
1279 var_SetString( p_intf, "fbosd-image", "" );
1280 var_SetString( p_intf, "fbosd-text", "" );
1282 p_sys->b_clear = false;
1283 p_sys->b_need_update = true;
1286 if( p_sys->b_need_update && p_sys->p_overlay &&
1287 isRendererReady( p_intf ) )
1290 #if defined(FBOSD_BLENDING)
1291 /* Reverse alpha channel to work around FPGA bug */
1292 InvertAlpha( p_intf, &p_sys->p_overlay, p_sys->fmt_out );
1294 ret = write( p_sys->i_fd, p_sys->p_overlay->p[0].p_pixels,
1295 p_sys->i_page_size );
1297 msg_Err( p_intf, "unable to write to overlay" );
1298 lseek( p_sys->i_fd, 0, SEEK_SET );
1300 /* clear the picture */
1301 memset( p_sys->p_overlay->p[0].p_pixels, 0xFF, p_sys->i_page_size );
1302 p_sys->b_need_update = false;
1305 msleep( INTF_IDLE_SLEEP );
1309 vlc_restorecancel( canc );
1312 static int OverlayCallback( vlc_object_t *p_this, char const *psz_cmd,
1313 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1315 intf_thread_t *p_intf = (intf_thread_t *) p_this;
1316 intf_sys_t *p_sys = p_intf->p_sys;
1317 VLC_UNUSED(oldval); VLC_UNUSED(p_data);
1319 if( !strncmp( psz_cmd, "fbosd-display", 13 ) )
1321 p_sys->b_need_update = true;
1323 else if( !strncmp( psz_cmd, "fbosd-clear", 11 ) )
1326 /* Clear the entire render list */
1327 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1329 RenderClear( p_intf, &p_sys->render[i] );
1331 p_sys->b_clear = true;
1333 else if( !strncmp( psz_cmd, "fbosd-render", 12 ) )
1336 /* Are we already busy with on slot ? */
1337 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1339 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1341 p_sys->render[i].i_state = FBOSD_STATE_RENDER;
1349 /* Are we already busy with on slot ? */
1350 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1352 if( p_sys->render[i].i_state == FBOSD_STATE_RESERVED )
1355 /* No, then find first FREE slot */
1356 if( p_sys->render[i].i_state != FBOSD_STATE_RESERVED )
1358 for( i = 0; i < FBOSD_RENDER_MAX; i++ )
1360 if( p_sys->render[i].i_state == FBOSD_STATE_FREE )
1363 if( p_sys->render[i].i_state != FBOSD_STATE_FREE )
1365 msg_Warn( p_this, "render space depleated" );
1369 /* Found a free slot */
1370 p_sys->render[i].i_state = FBOSD_STATE_RESERVED;
1371 if( !strncmp( psz_cmd, "fbosd-image", 11 ) )
1373 free( p_sys->render[i].psz_string );
1374 p_sys->render[i].psz_string = strdup( newval.psz_string );
1375 p_sys->render[i].i_type = FBOSD_RENDER_IMAGE;
1377 else if( !strncmp( psz_cmd, "fbosd-text", 10 ) )
1379 free( p_sys->render[i].psz_string );
1380 p_sys->render[i].psz_string = strdup( newval.psz_string );
1381 p_sys->render[i].i_type = FBOSD_RENDER_TEXT;
1383 else if( !strncmp( psz_cmd, "fbosd-x", 7 ) )
1385 p_sys->render[i].b_absolute = false;
1386 p_sys->render[i].i_x = (newval.i_int < p_sys->i_width) ?
1387 newval.i_int : p_sys->i_width;
1389 else if( !strncmp( psz_cmd, "fbosd-y", 7 ) )
1391 p_sys->render[i].b_absolute = false;
1392 p_sys->render[i].i_y = (newval.i_int < p_sys->i_height) ?
1393 newval.i_int : p_sys->i_height;
1395 else if( !strncmp( psz_cmd, "fbosd-position", 14 ) )
1397 p_sys->render[i].b_absolute = true;
1398 p_sys->render[i].i_pos = newval.i_int;
1400 else if( !strncmp( psz_cmd, "fbosd-font-size", 15 ) )
1402 p_sys->render[i].text_style.i_font_size = newval.i_int;
1404 else if( !strncmp( psz_cmd, "fbosd-font-color", 16 ) )
1406 p_sys->render[i].text_style.i_font_color = newval.i_int;
1408 else if( !strncmp( psz_cmd, "fbosd-font-opacity", 18 ) )
1410 p_sys->render[i].text_style.i_font_alpha = 255 - newval.i_int;
1412 else if( !strncmp( psz_cmd, "fbosd-alpha", 11 ) )
1414 p_sys->render[i].i_alpha = newval.i_int;