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/fb1", NULL
, DEVICE_TEXT
, DEVICE_LONGTEXT
,
184 add_string( "fbosd-aspect-ratio", "", NULL
, ASPECT_RATIO_TEXT
,
185 ASPECT_RATIO_LONGTEXT
, true );
187 add_string( "fbosd-image", NULL
, NULL
, FBOSD_IMAGE_TEXT
,
188 FBOSD_IMAGE_LONGTEXT
, true );
189 add_string( "fbosd-text", NULL
, NULL
, FBOSD_TEXT
,
190 FBOSD_LONGTEXT
, true );
192 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
= malloc( sizeof( intf_sys_t
) );
312 memset( p_sys
, 0, sizeof(intf_sys_t
) );
314 p_sys
->p_style
= malloc( sizeof( text_style_t
) );
315 if( !p_sys
->p_style
)
317 free( p_intf
->p_sys
);
320 vlc_memcpy( p_sys
->p_style
, &default_text_style
, sizeof( text_style_t
) );
322 p_intf
->pf_run
= Run
;
324 p_sys
->p_image
= image_HandlerCreate( p_this
);
325 if( !p_sys
->p_image
)
327 free( p_intf
->p_sys
->p_style
);
328 free( p_intf
->p_sys
);
332 p_sys
->i_alpha
= var_CreateGetIntegerCommand( p_intf
, "fbosd-alpha" );
333 var_AddCallback( p_intf
, "fbosd-alpha", OverlayCallback
, NULL
);
335 p_sys
->i_aspect
= -1;
337 var_CreateGetNonEmptyString( p_intf
, "fbosd-aspect-ratio" );
340 char *psz_parser
= strchr( psz_aspect
, ':' );
344 *psz_parser
++ = '\0';
345 p_sys
->i_aspect
= ( atoi( psz_aspect
)
346 * VOUT_ASPECT_FACTOR
) / atoi( psz_parser
);
347 p_sys
->fmt_out
.i_aspect
= p_sys
->i_aspect
;
349 msg_Dbg( p_intf
, "using aspect ratio %d:%d",
350 atoi( psz_aspect
), atoi( psz_parser
) );
356 /* Use PAL by default */
357 p_sys
->i_width
= p_sys
->fmt_out
.i_width
= 704;
358 p_sys
->i_height
= p_sys
->fmt_out
.i_height
= 576;
360 psz_tmp
= var_CreateGetNonEmptyStringCommand( p_intf
, "fbosd-image" );
361 var_AddCallback( p_intf
, "fbosd-image", OverlayCallback
, NULL
);
362 if( psz_tmp
&& *psz_tmp
)
364 p_sys
->render
[0].i_type
= FBOSD_RENDER_IMAGE
;
365 p_sys
->render
[0].i_state
= FBOSD_STATE_RENDER
;
366 p_sys
->render
[0].psz_string
= strdup( psz_tmp
);
370 psz_tmp
= var_CreateGetNonEmptyStringCommand( p_intf
, "fbosd-text" );
371 var_AddCallback( p_intf
, "fbosd-text", OverlayCallback
, NULL
);
372 if( psz_tmp
&& *psz_tmp
)
374 p_sys
->render
[1].i_type
= FBOSD_RENDER_TEXT
;
375 p_sys
->render
[1].i_state
= FBOSD_STATE_RENDER
;
376 p_sys
->render
[1].psz_string
= strdup( psz_tmp
);
380 p_sys
->i_pos
= var_CreateGetIntegerCommand( p_intf
, "fbosd-position" );
381 p_sys
->i_x
= var_CreateGetIntegerCommand( p_intf
, "fbosd-x" );
382 p_sys
->i_y
= var_CreateGetIntegerCommand( p_intf
, "fbosd-y" );
384 var_AddCallback( p_intf
, "fbosd-position", OverlayCallback
, NULL
);
385 var_AddCallback( p_intf
, "fbosd-x", OverlayCallback
, NULL
);
386 var_AddCallback( p_intf
, "fbosd-y", OverlayCallback
, NULL
);
388 p_sys
->p_style
->i_font_size
=
389 var_CreateGetIntegerCommand( p_intf
, "fbosd-font-size" );
390 p_sys
->p_style
->i_font_color
=
391 var_CreateGetIntegerCommand( p_intf
, "fbosd-font-color" );
392 p_sys
->p_style
->i_font_alpha
= 255 -
393 var_CreateGetIntegerCommand( p_intf
, "fbosd-font-opacity" );
395 var_AddCallback( p_intf
, "fbosd-font-color", OverlayCallback
, NULL
);
396 var_AddCallback( p_intf
, "fbosd-font-size", OverlayCallback
, NULL
);
397 var_AddCallback( p_intf
, "fbosd-font-opacity", OverlayCallback
, NULL
);
399 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
401 vlc_memcpy( &p_sys
->render
[i
].text_style
, &default_text_style
,
402 sizeof( text_style_t
) );
405 p_sys
->b_clear
= var_CreateGetBoolCommand( p_intf
, "fbosd-clear" );
406 p_sys
->b_render
= var_CreateGetBoolCommand( p_intf
, "fbosd-render" );
407 p_sys
->b_need_update
= var_CreateGetBoolCommand( p_intf
, "fbosd-display" );
409 var_AddCallback( p_intf
, "fbosd-clear", OverlayCallback
, NULL
);
410 var_AddCallback( p_intf
, "fbosd-render", OverlayCallback
, NULL
);
411 var_AddCallback( p_intf
, "fbosd-display", OverlayCallback
, NULL
);
413 /* Check if picture position was overridden */
414 p_sys
->b_absolute
= true;
415 if( ( p_sys
->i_x
>= 0 ) && ( p_sys
->i_y
>= 0 ) )
417 p_sys
->b_absolute
= false;
418 p_sys
->i_y
= (p_sys
->i_y
< p_sys
->i_height
) ?
419 p_sys
->i_y
: p_sys
->i_height
;
420 p_sys
->i_x
= (p_sys
->i_x
< p_sys
->i_width
) ?
421 p_sys
->i_x
: p_sys
->i_width
;
424 p_sys
->render
[0].i_x
= p_sys
->render
[1].i_x
= p_sys
->i_x
;
425 p_sys
->render
[0].i_y
= p_sys
->render
[1].i_y
= p_sys
->i_y
;
426 p_sys
->render
[0].i_pos
= p_sys
->render
[1].i_pos
= p_sys
->i_pos
;
427 p_sys
->render
[0].i_alpha
= p_sys
->render
[1].i_alpha
= p_sys
->i_alpha
;
429 /* Initialize framebuffer */
430 if( OpenDisplay( p_intf
) )
432 Destroy( VLC_OBJECT(p_intf
) );
438 #if defined(FBOSD_BLENDING)
439 /* Load the blending module */
440 if( OpenBlending( p_intf
) )
442 msg_Err( p_intf
, "Unable to load image blending module" );
443 Destroy( VLC_OBJECT(p_intf
) );
448 /* Load text renderer module */
449 if( OpenTextRenderer( p_intf
) )
451 msg_Err( p_intf
, "Unable to load text rendering module" );
452 Destroy( VLC_OBJECT(p_intf
) );
456 p_sys
->b_render
= true;
457 p_sys
->b_need_update
= true;
462 /*****************************************************************************
463 * Destroy: destroy FB interface thread output method
464 *****************************************************************************
465 * Terminate an output method created by Create
466 *****************************************************************************/
467 static void Destroy( vlc_object_t
*p_this
)
469 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
470 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
473 p_sys
->b_need_update
= false;
474 p_sys
->b_render
= false;
475 p_sys
->b_clear
= false;
477 var_DelCallback( p_intf
, "fbosd-alpha", OverlayCallback
, NULL
);
478 var_Destroy( p_intf
, "fbosd-alpha" );
480 var_DelCallback( p_intf
, "fbosd-x", OverlayCallback
, NULL
);
481 var_DelCallback( p_intf
, "fbosd-y", OverlayCallback
, NULL
);
482 var_DelCallback( p_intf
, "fbosd-position", OverlayCallback
, NULL
);
483 var_DelCallback( p_intf
, "fbosd-image", OverlayCallback
, NULL
);
484 var_DelCallback( p_intf
, "fbosd-text", OverlayCallback
, NULL
);
485 var_DelCallback( p_intf
, "fbosd-font-size", OverlayCallback
, NULL
);
486 var_DelCallback( p_intf
, "fbosd-font-color", OverlayCallback
, NULL
);
487 var_DelCallback( p_intf
, "fbosd-font-opacity", OverlayCallback
, NULL
);
488 var_DelCallback( p_intf
, "fbosd-clear", OverlayCallback
, NULL
);
489 var_DelCallback( p_intf
, "fbosd-render", OverlayCallback
, NULL
);
490 var_DelCallback( p_intf
, "fbosd-display", OverlayCallback
, NULL
);
492 var_Destroy( p_intf
, "fbosd-x" );
493 var_Destroy( p_intf
, "fbosd-y" );
494 var_Destroy( p_intf
, "fbosd-position" );
495 var_Destroy( p_intf
, "fbosd-image" );
496 var_Destroy( p_intf
, "fbosd-text" );
497 var_Destroy( p_intf
, "fbosd-font-size" );
498 var_Destroy( p_intf
, "fbosd-font-color" );
499 var_Destroy( p_intf
, "fbosd-font-opacity" );
500 var_Destroy( p_intf
, "fbosd-clear" );
501 var_Destroy( p_intf
, "fbosd-render" );
502 var_Destroy( p_intf
, "fbosd-display" );
504 var_Destroy( p_intf
, "fbosd-aspect-ratio" );
506 CloseDisplay( p_intf
);
508 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
510 free( p_sys
->render
[i
].psz_string
);
511 p_sys
->render
[i
].i_state
= FBOSD_STATE_FREE
;
514 #if defined(FBOSD_BLENDING)
515 if( p_sys
->p_blend
) CloseBlending( p_intf
);
517 if( p_sys
->p_text
) CloseTextRenderer( p_intf
);
520 image_HandlerDelete( p_sys
->p_image
);
521 if( p_sys
->p_overlay
)
522 picture_Release( p_sys
->p_overlay
);
524 free( p_sys
->p_style
);
528 #if defined(FBOSD_BLENDING)
529 static int OpenBlending( intf_thread_t
*p_intf
)
531 if( p_intf
->p_sys
->p_blend
) return VLC_EGENERIC
;
533 p_intf
->p_sys
->p_blend
=
534 vlc_object_create( p_intf
, sizeof(filter_t
) );
535 vlc_object_attach( p_intf
->p_sys
->p_blend
, p_intf
);
536 p_intf
->p_sys
->p_blend
->fmt_out
.video
.i_x_offset
=
537 p_intf
->p_sys
->p_blend
->fmt_out
.video
.i_y_offset
= 0;
538 p_intf
->p_sys
->p_blend
->fmt_out
.video
.i_aspect
=
539 p_intf
->p_sys
->fmt_out
.i_aspect
;
540 p_intf
->p_sys
->p_blend
->fmt_out
.video
.i_chroma
=
541 p_intf
->p_sys
->fmt_out
.i_chroma
;
542 if( config_GetInt( p_intf
, "freetype-yuvp" ) )
543 p_intf
->p_sys
->p_blend
->fmt_in
.video
.i_chroma
=
544 VLC_FOURCC('Y','U','V','P');
546 p_intf
->p_sys
->p_blend
->fmt_in
.video
.i_chroma
=
547 VLC_FOURCC('Y','U','V','A');
549 p_intf
->p_sys
->p_blend
->p_module
=
550 module_need( p_intf
->p_sys
->p_blend
, "video blending", 0, 0 );
552 if( !p_intf
->p_sys
->p_blend
->p_module
)
558 static void CloseBlending( intf_thread_t
*p_intf
)
560 if( p_intf
->p_sys
->p_blend
)
562 if( p_intf
->p_sys
->p_blend
->p_module
)
563 module_unneed( p_intf
->p_sys
->p_blend
,
564 p_intf
->p_sys
->p_blend
->p_module
);
566 vlc_object_detach( p_intf
->p_sys
->p_blend
);
567 vlc_object_release( p_intf
->p_sys
->p_blend
);
572 static int OpenTextRenderer( intf_thread_t
*p_intf
)
574 char *psz_modulename
= NULL
;
576 if( p_intf
->p_sys
->p_text
) return VLC_EGENERIC
;
578 p_intf
->p_sys
->p_text
=
579 vlc_object_create( p_intf
, sizeof(filter_t
) );
580 vlc_object_attach( p_intf
->p_sys
->p_text
, p_intf
);
582 p_intf
->p_sys
->p_text
->fmt_out
.video
.i_width
=
583 p_intf
->p_sys
->p_text
->fmt_out
.video
.i_visible_width
=
584 p_intf
->p_sys
->i_width
;
585 p_intf
->p_sys
->p_text
->fmt_out
.video
.i_height
=
586 p_intf
->p_sys
->p_text
->fmt_out
.video
.i_visible_height
=
587 p_intf
->p_sys
->i_height
;
589 psz_modulename
= var_CreateGetString( p_intf
, "text-renderer" );
590 if( psz_modulename
&& *psz_modulename
)
592 p_intf
->p_sys
->p_text
->p_module
=
593 module_need( p_intf
->p_sys
->p_text
, "text renderer",
594 psz_modulename
, true );
596 if( !p_intf
->p_sys
->p_text
->p_module
)
598 p_intf
->p_sys
->p_text
->p_module
=
599 module_need( p_intf
->p_sys
->p_text
, "text renderer", 0, 0 );
601 free( psz_modulename
);
603 if( !p_intf
->p_sys
->p_text
->p_module
)
609 static void CloseTextRenderer( intf_thread_t
*p_intf
)
611 if( p_intf
->p_sys
->p_text
)
613 if( p_intf
->p_sys
->p_text
->p_module
)
614 module_unneed( p_intf
->p_sys
->p_text
,
615 p_intf
->p_sys
->p_text
->p_module
);
617 vlc_object_detach( p_intf
->p_sys
->p_text
);
618 vlc_object_release( p_intf
->p_sys
->p_text
);
622 /*****************************************************************************
624 * allocate a picture buffer for use with the overlay fb.
625 *****************************************************************************/
626 static picture_t
*AllocatePicture( video_format_t
*p_fmt
)
628 picture_t
*p_picture
= picture_New( p_fmt
->i_chroma
,
629 p_fmt
->i_width
, p_fmt
->i_height
,
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
)
640 picture_Release( p_picture
);
646 p_fmt
->p_palette
= NULL
;
652 /*****************************************************************************
654 * Deallocate a picture buffer and free all associated memory.
655 *****************************************************************************/
656 static void DeAllocatePicture( picture_t
*p_pic
, video_format_t
*p_fmt
)
660 free( p_fmt
->p_palette
);
661 p_fmt
->p_palette
= NULL
;
665 picture_Release( p_pic
);
668 /*****************************************************************************
669 * SetOverlayTransparency: Set the transparency for this overlay fb,
670 * - true is make transparent
671 * - false is make non tranparent
672 *****************************************************************************/
673 static void SetOverlayTransparency( intf_thread_t
*p_intf
,
676 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
677 size_t i_size
= p_sys
->fmt_out
.i_width
* p_sys
->fmt_out
.i_height
678 * p_sys
->i_bytes_per_pixel
;
679 size_t i_page_size
= (p_sys
->i_page_size
> i_size
) ?
680 i_size
: p_sys
->i_page_size
;
682 if( p_sys
->p_overlay
)
684 msg_Dbg( p_intf
, "Make overlay %s",
685 b_transparent
? "transparent" : "opaque" );
687 memset( p_sys
->p_overlay
->p
[0].p_pixels
, 0xFF, i_page_size
);
689 memset( p_sys
->p_overlay
->p
[0].p_pixels
, 0x00, i_page_size
);
693 #if defined(FBOSD_BLENDING)
694 /*****************************************************************************
695 * BlendPicture: Blend two pictures together..
696 *****************************************************************************/
697 static int BlendPicture( intf_thread_t
*p_intf
, video_format_t
*p_fmt_src
,
698 video_format_t
*p_fmt_dst
, picture_t
*p_pic_src
,
699 picture_t
*p_pic_dst
)
701 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
702 if( p_sys
->p_blend
&& p_sys
->p_blend
->p_module
)
704 int i_x_offset
= p_sys
->i_x
;
705 int i_y_offset
= p_sys
->i_y
;
707 memcpy( &p_sys
->p_blend
->fmt_in
.video
, p_fmt_src
, sizeof( video_format_t
) );
709 /* Update the output picture size */
710 p_sys
->p_blend
->fmt_out
.video
.i_width
=
711 p_sys
->p_blend
->fmt_out
.video
.i_visible_width
=
713 p_sys
->p_blend
->fmt_out
.video
.i_height
=
714 p_sys
->p_blend
->fmt_out
.video
.i_visible_height
=
717 i_x_offset
= __MAX( i_x_offset
, 0 );
718 i_y_offset
= __MAX( i_y_offset
, 0 );
720 p_sys
->p_blend
->pf_video_blend( p_sys
->p_blend
, p_pic_dst
,
721 p_pic_src
, p_pic_dst
, i_x_offset
, i_y_offset
,
729 static int InvertAlpha( intf_thread_t
*p_intf
, picture_t
**p_pic
, video_format_t fmt
)
731 uint8_t *p_begin
= NULL
, *p_end
= NULL
;
734 if( *p_pic
&& ((*p_pic
)->i_planes
!= 1) )
737 "cannot invert alpha channel too many planes %d (only 1 supported)",
738 (*p_pic
)->i_planes
);
742 switch( fmt
.i_chroma
)
744 case VLC_FOURCC('R','V','2','4'):
745 p_begin
= (uint8_t *)(*p_pic
)->p
[Y_PLANE
].p_pixels
;
746 p_end
= (uint8_t *)(*p_pic
)->p
[Y_PLANE
].p_pixels
+
747 ( fmt
.i_height
* (*p_pic
)->p
[Y_PLANE
].i_pitch
);
750 case VLC_FOURCC('R','V','3','2'):
751 p_begin
= (uint8_t *)(*p_pic
)->p
[Y_PLANE
].p_pixels
;
752 p_end
= (uint8_t *)(*p_pic
)->p
[Y_PLANE
].p_pixels
+
753 ( fmt
.i_height
* (*p_pic
)->p
[Y_PLANE
].i_pitch
);
757 msg_Err( p_intf
, "cannot invert alpha channel chroma not supported %4.4s",
758 (char *)&fmt
.i_chroma
);
762 for( ; p_begin
< p_end
; p_begin
+= i_skip
)
764 uint8_t i_opacity
= 0;
766 if( *p_begin
!= 0xFF )
767 i_opacity
= 255 - *p_begin
;
768 *p_begin
= i_opacity
;
775 /*****************************************************************************
776 * RenderPicture: Render the picture into the p_dest buffer.
777 * We don't take transparent pixels into account, so we don't have to blend
778 * the two images together.
779 *****************************************************************************/
780 static int RenderPicture( intf_thread_t
*p_intf
, int i_x_offset
, int i_y_offset
,
781 picture_t
*p_src
, picture_t
*p_dest
)
784 VLC_UNUSED( p_intf
);
786 if( !p_dest
&& !p_src
) return VLC_EGENERIC
;
788 for( i
= 0; i
< p_src
->i_planes
; i
++ )
790 if( p_src
->p
[i
].i_pitch
== p_dest
->p
[i
].i_pitch
)
792 /* There are margins, but with the same width : perfect ! */
793 vlc_memcpy( p_dest
->p
[i
].p_pixels
, p_src
->p
[i
].p_pixels
,
794 p_src
->p
[i
].i_pitch
* p_src
->p
[i
].i_visible_lines
);
798 /* We need to proceed line by line */
799 uint8_t *p_in
= p_src
->p
[i
].p_pixels
;
800 uint8_t *p_out
= p_dest
->p
[i
].p_pixels
;
802 int i_x
= i_x_offset
* p_src
->p
[i
].i_pixel_pitch
;
803 int i_x_clip
, i_y_clip
;
805 /* Check boundaries, clip the image if necessary */
806 i_x_clip
= ( i_x
+ p_src
->p
[i
].i_visible_pitch
) - p_dest
->p
[i
].i_visible_pitch
;
807 i_x_clip
= ( i_x_clip
> 0 ) ? i_x_clip
: 0;
809 i_y_clip
= ( i_y_offset
+ p_src
->p
[i
].i_visible_lines
) - p_dest
->p
[i
].i_visible_lines
;
810 i_y_clip
= ( i_y_clip
> 0 ) ? i_y_clip
: 0;
811 #if defined(FBOSD_DEBUG)
812 msg_Dbg( p_intf
, "i_pitch (%d,%d), (%d,%d)/(%d,%d)",
813 p_dest
->p
[i
].i_visible_pitch
, p_src
->p
[i
].i_visible_pitch
,
814 i_x_offset
, i_y_offset
, i_x
, i_x_clip
);
816 if( ( i_y_offset
<= p_dest
->p
[i
].i_visible_lines
) &&
817 ( i_x
<= p_dest
->p
[i
].i_visible_pitch
) )
821 p_out
+= ( i_y_offset
* p_dest
->p
[i
].i_pitch
);
822 for( i_line
= 0; i_line
< ( p_src
->p
[i
].i_visible_lines
- i_y_clip
); i_line
++ )
824 vlc_memcpy( p_out
+ i_x
, p_in
,
825 p_src
->p
[i
].i_visible_pitch
- i_x_clip
);
826 p_in
+= p_src
->p
[i
].i_pitch
;
827 p_out
+= p_dest
->p
[i
].i_pitch
;
835 /*****************************************************************************
836 * RenderText - Render text to the desired picture format
837 *****************************************************************************/
838 static picture_t
*RenderText( intf_thread_t
*p_intf
, const char *psz_string
,
839 text_style_t
*p_style
, video_format_t
*p_fmt
)
841 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
842 subpicture_region_t
*p_region
;
843 picture_t
*p_dest
= NULL
;
845 if( !psz_string
) return p_dest
;
847 if( p_sys
->p_text
&& p_sys
->p_text
->p_module
)
851 memset( &fmt
, 0, sizeof(fmt
) );
852 fmt
.i_chroma
= VLC_FOURCC('T','E','X','T');
854 fmt
.i_width
= fmt
.i_visible_width
= 0;
855 fmt
.i_height
= fmt
.i_visible_height
= 0;
859 p_region
= subpicture_region_New( &fmt
);
863 p_region
->psz_text
= strdup( psz_string
);
864 if( !p_region
->psz_text
)
866 subpicture_region_Delete( p_region
);
869 p_region
->p_style
= p_style
;
870 p_region
->i_align
= OSD_ALIGN_LEFT
| OSD_ALIGN_TOP
;
872 if( p_sys
->p_text
->pf_render_text
)
874 video_format_t fmt_out
;
876 memset( &fmt_out
, 0, sizeof(video_format_t
) );
878 p_sys
->p_text
->pf_render_text( p_sys
->p_text
,
879 p_region
, p_region
);
881 #if defined(FBOSD_BLENDING)
882 fmt_out
= p_region
->fmt
;
883 fmt_out
.i_bits_per_pixel
= 32;
884 vlc_memcpy( p_fmt
, &fmt_out
, sizeof(video_format_t
) );
886 /* FIXME not needed to copy the picture anymore no ? */
887 p_dest
= AllocatePicture( VLC_OBJECT(p_intf
), &fmt_out
);
890 subpicture_region_Delete( p_region
);
893 picture_Copy( p_dest
, p_region
->p_picture
);
895 fmt_out
.i_chroma
= p_fmt
->i_chroma
;
896 p_dest
= ConvertImage( p_intf
, &p_region
->p_picture
,
897 &p_region
->fmt
, &fmt_out
);
899 subpicture_region_Delete( p_region
);
902 subpicture_region_Delete( p_region
);
907 /*****************************************************************************
908 * LoadImage: Load an image from file into a picture buffer.
909 *****************************************************************************/
910 static picture_t
*LoadImage( intf_thread_t
*p_intf
, video_format_t
*p_fmt
,
913 picture_t
*p_pic
= NULL
;
915 if( psz_file
&& p_intf
->p_sys
->p_image
)
917 video_format_t fmt_in
, fmt_out
;
919 memset( &fmt_in
, 0, sizeof(fmt_in
) );
920 memset( &fmt_out
, 0, sizeof(fmt_out
) );
922 fmt_out
.i_chroma
= p_fmt
->i_chroma
;
923 p_pic
= image_ReadUrl( p_intf
->p_sys
->p_image
, psz_file
,
926 msg_Dbg( p_intf
, "image size %dx%d chroma %4.4s",
927 fmt_out
.i_width
, fmt_out
.i_height
,
928 (char *)&p_fmt
->i_chroma
);
933 #if ! defined(FBOSD_BLENDING)
934 /*****************************************************************************
935 * Convertmage: Convert image to another fourcc
936 *****************************************************************************/
937 static picture_t
*ConvertImage( intf_thread_t
*p_intf
, picture_t
*p_pic
,
938 video_format_t
*p_fmt_in
, video_format_t
*p_fmt_out
)
940 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
941 picture_t
*p_old
= NULL
;
945 p_old
= image_Convert( p_sys
->p_image
, p_pic
, p_fmt_in
, p_fmt_out
);
947 msg_Dbg( p_intf
, "converted image size %dx%d chroma %4.4s",
948 p_fmt_out
->i_width
, p_fmt_out
->i_height
,
949 (char *)&p_fmt_out
->i_chroma
);
955 /*****************************************************************************
956 * Init: initialize framebuffer video thread output method
957 *****************************************************************************/
958 static int Init( intf_thread_t
*p_intf
)
960 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
962 /* Initialize the output structure: RGB with square pixels, whatever
963 * the input format is, since it's the only format we know */
964 switch( p_sys
->var_info
.bits_per_pixel
)
966 case 8: /* FIXME: set the palette */
967 p_sys
->fmt_out
.i_chroma
= VLC_FOURCC('R','G','B','2'); break;
969 p_sys
->fmt_out
.i_chroma
= VLC_FOURCC('R','V','1','5'); break;
971 p_sys
->fmt_out
.i_chroma
= VLC_FOURCC('R','V','1','6'); break;
973 p_sys
->fmt_out
.i_chroma
= VLC_FOURCC('R','V','2','4'); break;
975 p_sys
->fmt_out
.i_chroma
= VLC_FOURCC('R','V','3','2'); break;
977 msg_Err( p_intf
, "unknown screen depth %i",
978 p_sys
->var_info
.bits_per_pixel
);
982 p_sys
->fmt_out
.i_bits_per_pixel
= p_sys
->var_info
.bits_per_pixel
;
983 p_sys
->fmt_out
.i_width
= p_sys
->i_width
;
984 p_sys
->fmt_out
.i_height
= p_sys
->i_height
;
986 /* Assume we have square pixels */
987 if( p_sys
->i_aspect
< 0 )
989 p_sys
->fmt_out
.i_aspect
= ( p_sys
->i_width
990 * VOUT_ASPECT_FACTOR
) / p_sys
->i_height
;
992 else p_sys
->fmt_out
.i_aspect
= p_sys
->i_aspect
;
994 p_sys
->fmt_out
.i_sar_num
= p_sys
->fmt_out
.i_sar_den
= 1;
996 /* Allocate overlay buffer */
997 p_sys
->p_overlay
= AllocatePicture( &p_sys
->fmt_out
);
998 if( !p_sys
->p_overlay
) return VLC_EGENERIC
;
1000 SetOverlayTransparency( p_intf
, true );
1002 /* We know the chroma, allocate a buffer which will be used
1003 * to write to the overlay framebuffer */
1004 p_sys
->p_overlay
->p
->i_pixel_pitch
= p_sys
->i_bytes_per_pixel
;
1005 p_sys
->p_overlay
->p
->i_lines
= p_sys
->var_info
.yres
;
1006 p_sys
->p_overlay
->p
->i_visible_lines
= p_sys
->var_info
.yres
;
1008 if( p_sys
->var_info
.xres_virtual
)
1010 p_sys
->p_overlay
->p
->i_pitch
= p_sys
->var_info
.xres_virtual
1011 * p_sys
->i_bytes_per_pixel
;
1015 p_sys
->p_overlay
->p
->i_pitch
= p_sys
->var_info
.xres
1016 * p_sys
->i_bytes_per_pixel
;
1019 p_sys
->p_overlay
->p
->i_visible_pitch
= p_sys
->var_info
.xres
1020 * p_sys
->i_bytes_per_pixel
;
1022 p_sys
->p_overlay
->i_planes
= 1;
1027 /*****************************************************************************
1028 * End: terminate framebuffer interface
1029 *****************************************************************************/
1030 static void End( intf_thread_t
*p_intf
)
1032 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1035 SetOverlayTransparency( p_intf
, false );
1036 if( p_sys
->p_overlay
)
1039 ret
= write( p_sys
->i_fd
, p_sys
->p_overlay
->p
[0].p_pixels
,
1040 p_sys
->i_page_size
);
1042 msg_Err( p_intf
, "unable to clear overlay" );
1045 DeAllocatePicture( p_intf
->p_sys
->p_overlay
,
1046 &p_intf
->p_sys
->fmt_out
);
1047 p_intf
->p_sys
->p_overlay
= NULL
;
1050 /*****************************************************************************
1051 * OpenDisplay: initialize framebuffer
1052 *****************************************************************************/
1053 static int OpenDisplay( intf_thread_t
*p_intf
)
1055 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1056 char *psz_device
; /* framebuffer device path */
1057 struct fb_fix_screeninfo fix_info
; /* framebuffer fix information */
1059 /* Open framebuffer device */
1060 if( !(psz_device
= config_GetPsz( p_intf
, "fbosd-dev" )) )
1062 msg_Err( p_intf
, "don't know which fb osd/overlay device to open" );
1063 return VLC_EGENERIC
;
1066 p_sys
->i_fd
= open( psz_device
, O_RDWR
);
1067 if( p_sys
->i_fd
== -1 )
1069 msg_Err( p_intf
, "cannot open %s (%s)", psz_device
, strerror(errno
) );
1071 return VLC_EGENERIC
;
1075 /* Get framebuffer device information */
1076 if( ioctl( p_sys
->i_fd
, FBIOGET_VSCREENINFO
, &p_sys
->var_info
) )
1078 msg_Err( p_intf
, "cannot get fb info (%s)", strerror(errno
) );
1079 close( p_sys
->i_fd
);
1080 return VLC_EGENERIC
;
1083 /* Get some info on the framebuffer itself */
1084 if( ioctl( p_sys
->i_fd
, FBIOGET_FSCREENINFO
, &fix_info
) == 0 )
1086 p_sys
->i_width
= p_sys
->fmt_out
.i_width
= p_sys
->var_info
.xres
;
1087 p_sys
->i_height
= p_sys
->fmt_out
.i_height
= p_sys
->var_info
.yres
;
1090 /* FIXME: if the image is full-size, it gets cropped on the left
1091 * because of the xres / xres_virtual slight difference */
1092 msg_Dbg( p_intf
, "%ix%i (virtual %ix%i)",
1093 p_sys
->var_info
.xres
, p_sys
->var_info
.yres
,
1094 p_sys
->var_info
.xres_virtual
,
1095 p_sys
->var_info
.yres_virtual
);
1097 p_sys
->fmt_out
.i_width
= p_sys
->i_width
;
1098 p_sys
->fmt_out
.i_height
= p_sys
->i_height
;
1100 p_sys
->p_palette
= NULL
;
1101 p_sys
->b_pan
= ( fix_info
.ypanstep
|| fix_info
.ywrapstep
);
1103 switch( p_sys
->var_info
.bits_per_pixel
)
1106 p_sys
->p_palette
= malloc( 8 * 256 * sizeof( uint16_t ) );
1107 if( !p_sys
->p_palette
)
1109 close( p_sys
->i_fd
);
1112 p_sys
->fb_cmap
.start
= 0;
1113 p_sys
->fb_cmap
.len
= 256;
1114 p_sys
->fb_cmap
.red
= p_sys
->p_palette
;
1115 p_sys
->fb_cmap
.green
= p_sys
->p_palette
+ 256 * sizeof( uint16_t );
1116 p_sys
->fb_cmap
.blue
= p_sys
->p_palette
+ 2 * 256 * sizeof( uint16_t );
1117 p_sys
->fb_cmap
.transp
= p_sys
->p_palette
+ 3 * 256 * sizeof( uint16_t );
1119 /* Save the colormap */
1120 ioctl( p_sys
->i_fd
, FBIOGETCMAP
, &p_sys
->fb_cmap
);
1122 p_sys
->i_bytes_per_pixel
= 1;
1127 p_sys
->i_bytes_per_pixel
= 2;
1131 p_sys
->i_bytes_per_pixel
= 3;
1135 p_sys
->i_bytes_per_pixel
= 4;
1139 msg_Err( p_intf
, "screen depth %d is not supported",
1140 p_sys
->var_info
.bits_per_pixel
);
1142 close( p_sys
->i_fd
);
1143 return VLC_EGENERIC
;
1146 p_sys
->i_page_size
= p_sys
->i_width
* p_sys
->i_height
1147 * p_sys
->i_bytes_per_pixel
;
1149 msg_Dbg( p_intf
, "framebuffer type=%d, visual=%d, ypanstep=%d, "
1150 "ywrap=%d, accel=%d", fix_info
.type
, fix_info
.visual
,
1151 fix_info
.ypanstep
, fix_info
.ywrapstep
, fix_info
.accel
);
1155 /*****************************************************************************
1156 * CloseDisplay: terminate FB interface thread
1157 *****************************************************************************/
1158 static void CloseDisplay( intf_thread_t
*p_intf
)
1160 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
;
1162 /* Restore palette */
1163 if( p_sys
->var_info
.bits_per_pixel
== 8 )
1165 ioctl( p_sys
->i_fd
, FBIOPUTCMAP
, &p_sys
->fb_cmap
);
1166 free( p_sys
->p_palette
);
1167 p_sys
->p_palette
= NULL
;
1171 close( p_sys
->i_fd
);
1174 static void Render( intf_thread_t
*p_intf
, struct fbosd_render_t
*render
)
1176 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1178 if( render
->i_state
!= FBOSD_STATE_RENDER
) return;
1179 if( !render
->psz_string
) return;
1181 if( render
->i_type
== FBOSD_RENDER_IMAGE
)
1184 p_pic
= LoadImage( p_intf
, &p_sys
->fmt_out
, render
->psz_string
);
1187 RenderPicture( p_intf
, render
->i_x
, render
->i_y
,
1188 p_pic
, p_sys
->p_overlay
);
1189 picture_Release( p_pic
);
1192 else if( render
->i_type
== FBOSD_RENDER_TEXT
)
1195 #if defined(FBOSD_BLENDING)
1196 video_format_t fmt_in
;
1197 memset( &fmt_in
, 0, sizeof(video_format_t
) );
1198 p_text
= RenderText( p_intf
, render
->psz_string
, &render
->text_style
,
1202 BlendPicture( p_intf
, &fmt_in
, &p_sys
->fmt_out
,
1203 p_text
, p_sys
->p_overlay
);
1204 msg_Dbg( p_intf
, "releasing picture" );
1205 DeAllocatePicture( p_text
, &fmt_in
);
1208 p_text
= RenderText( p_intf
, render
->psz_string
, &render
->text_style
,
1212 RenderPicture( p_intf
, render
->i_x
, render
->i_y
,
1213 p_text
, p_sys
->p_overlay
);
1214 picture_Release( p_text
);
1220 static void RenderClear( intf_thread_t
*p_intf
, struct fbosd_render_t
*render
)
1222 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1224 vlc_memcpy( &render
->text_style
, &default_text_style
,
1225 sizeof( text_style_t
) );
1226 free( render
->psz_string
);
1227 render
->psz_string
= NULL
;
1229 render
->i_x
= p_sys
->i_x
;
1230 render
->i_y
= p_sys
->i_y
;
1231 render
->i_pos
= p_sys
->i_pos
;
1232 render
->i_alpha
= p_sys
->i_alpha
;
1233 render
->b_absolute
= p_sys
->b_absolute
;
1234 render
->i_state
= FBOSD_STATE_FREE
;
1237 static bool isRendererReady( intf_thread_t
*p_intf
)
1239 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1242 /* Check if there are more items to render */
1243 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1245 if( p_sys
->render
[i
].i_state
== FBOSD_STATE_RESERVED
)
1251 /*****************************************************************************
1253 *****************************************************************************
1254 * This part of the interface is in a separate thread so that we can call
1255 * exec() from within it without annoying the rest of the program.
1256 *****************************************************************************/
1257 static void Run( intf_thread_t
*p_intf
)
1259 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1260 int canc
= vlc_savecancel();
1262 while( vlc_object_alive( p_intf
) )
1266 /* Is there somthing to render? */
1267 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1269 if( p_sys
->render
[i
].i_state
== FBOSD_STATE_RENDER
)
1271 Render( p_intf
, &p_sys
->render
[i
] );
1272 RenderClear( p_intf
, &p_sys
->render
[i
] );
1276 if( p_sys
->b_clear
)
1278 SetOverlayTransparency( p_intf
, true );
1280 var_SetString( p_intf
, "fbosd-image", "" );
1281 var_SetString( p_intf
, "fbosd-text", "" );
1283 p_sys
->b_clear
= false;
1284 p_sys
->b_need_update
= true;
1287 if( p_sys
->b_need_update
&& p_sys
->p_overlay
&&
1288 isRendererReady( p_intf
) )
1291 #if defined(FBOSD_BLENDING)
1292 /* Reverse alpha channel to work around FPGA bug */
1293 InvertAlpha( p_intf
, &p_sys
->p_overlay
, p_sys
->fmt_out
);
1295 ret
= write( p_sys
->i_fd
, p_sys
->p_overlay
->p
[0].p_pixels
,
1296 p_sys
->i_page_size
);
1298 msg_Err( p_intf
, "unable to write to overlay" );
1299 lseek( p_sys
->i_fd
, 0, SEEK_SET
);
1301 /* clear the picture */
1302 memset( p_sys
->p_overlay
->p
[0].p_pixels
, 0xFF, p_sys
->i_page_size
);
1303 p_sys
->b_need_update
= false;
1306 msleep( INTF_IDLE_SLEEP
);
1310 vlc_restorecancel( canc
);
1313 static int OverlayCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
1314 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
1316 intf_thread_t
*p_intf
= (intf_thread_t
*) p_this
;
1317 intf_sys_t
*p_sys
= (intf_sys_t
*) p_intf
->p_sys
;
1318 VLC_UNUSED(oldval
); VLC_UNUSED(p_data
);
1320 if( !strncmp( psz_cmd
, "fbosd-display", 13 ) )
1322 p_sys
->b_need_update
= true;
1324 else if( !strncmp( psz_cmd
, "fbosd-clear", 11 ) )
1327 /* Clear the entire render list */
1328 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1330 RenderClear( p_intf
, &p_sys
->render
[i
] );
1332 p_sys
->b_clear
= true;
1334 else if( !strncmp( psz_cmd
, "fbosd-render", 12 ) )
1337 /* Are we already busy with on slot ? */
1338 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1340 if( p_sys
->render
[i
].i_state
== FBOSD_STATE_RESERVED
)
1342 p_sys
->render
[i
].i_state
= FBOSD_STATE_RENDER
;
1350 /* Are we already busy with on slot ? */
1351 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1353 if( p_sys
->render
[i
].i_state
== FBOSD_STATE_RESERVED
)
1356 /* No, then find first FREE slot */
1357 if( p_sys
->render
[i
].i_state
!= FBOSD_STATE_RESERVED
)
1359 for( i
= 0; i
< FBOSD_RENDER_MAX
; i
++ )
1361 if( p_sys
->render
[i
].i_state
== FBOSD_STATE_FREE
)
1364 if( p_sys
->render
[i
].i_state
!= FBOSD_STATE_FREE
)
1366 msg_Warn( p_this
, "render space depleated" );
1370 /* Found a free slot */
1371 p_sys
->render
[i
].i_state
= FBOSD_STATE_RESERVED
;
1372 if( !strncmp( psz_cmd
, "fbosd-image", 11 ) )
1374 free( p_sys
->render
[i
].psz_string
);
1375 p_sys
->render
[i
].psz_string
= strdup( newval
.psz_string
);
1376 p_sys
->render
[i
].i_type
= FBOSD_RENDER_IMAGE
;
1378 else if( !strncmp( psz_cmd
, "fbosd-text", 10 ) )
1380 free( p_sys
->render
[i
].psz_string
);
1381 p_sys
->render
[i
].psz_string
= strdup( newval
.psz_string
);
1382 p_sys
->render
[i
].i_type
= FBOSD_RENDER_TEXT
;
1384 else if( !strncmp( psz_cmd
, "fbosd-x", 7 ) )
1386 p_sys
->render
[i
].b_absolute
= false;
1387 p_sys
->render
[i
].i_x
= (newval
.i_int
< p_sys
->i_width
) ?
1388 newval
.i_int
: p_sys
->i_width
;
1390 else if( !strncmp( psz_cmd
, "fbosd-y", 7 ) )
1392 p_sys
->render
[i
].b_absolute
= false;
1393 p_sys
->render
[i
].i_y
= (newval
.i_int
< p_sys
->i_height
) ?
1394 newval
.i_int
: p_sys
->i_height
;
1396 else if( !strncmp( psz_cmd
, "fbosd-position", 14 ) )
1398 p_sys
->render
[i
].b_absolute
= true;
1399 p_sys
->render
[i
].i_pos
= newval
.i_int
;
1401 else if( !strncmp( psz_cmd
, "fbosd-font-size", 15 ) )
1403 p_sys
->render
[i
].text_style
.i_font_size
= newval
.i_int
;
1405 else if( !strncmp( psz_cmd
, "fbosd-font-color", 16 ) )
1407 p_sys
->render
[i
].text_style
.i_font_color
= newval
.i_int
;
1409 else if( !strncmp( psz_cmd
, "fbosd-font-opacity", 18 ) )
1411 p_sys
->render
[i
].text_style
.i_font_alpha
= 255 - newval
.i_int
;
1413 else if( !strncmp( psz_cmd
, "fbosd-alpha", 11 ) )
1415 p_sys
->render
[i
].i_alpha
= newval
.i_int
;