1 /*****************************************************************************
2 * video_widgets.c : OSD widgets manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
7 * Author: Yoann Peronneau <yoann@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* free() */
34 /*****************************************************************************
36 *****************************************************************************/
37 static void DrawRect( vout_thread_t *, subpicture_t *, int, int, int, int,
39 static void DrawTriangle( vout_thread_t *, subpicture_t *, int, int, int, int,
41 static void Render ( vout_thread_t *, picture_t *, const subpicture_t * );
42 static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
44 static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
46 static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
48 static subpicture_t *vout_CreateWidget( vout_thread_t * );
49 static void FreeWidget( subpicture_t * );
52 * Private data in a subpicture.
54 struct subpicture_sys_t
63 /*****************************************************************************
64 * Draws a rectangle at the given position in the subpic.
65 * It may be filled (fill == RECT_FILLED) or empty (fill == RECT_EMPTY).
66 *****************************************************************************/
67 static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
68 int i_x1, int i_y1, int i_x2, int i_y2, short fill )
71 subpicture_sys_t *p_widget = p_subpic->p_sys;
73 if( fill == RECT_FILLED )
75 for( y = i_y1; y <= i_y2; y++ )
77 for( x = i_x1; x <= i_x2; x++ )
79 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
85 for( y = i_y1; y <= i_y2; y++ )
87 p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
88 p_widget->p_pic[ i_x2 + p_widget->i_width * y ] = 1;
90 for( x = i_x1; x <= i_x2; x++ )
92 p_widget->p_pic[ x + p_widget->i_width * i_y1 ] = 1;
93 p_widget->p_pic[ x + p_widget->i_width * i_y2 ] = 1;
98 /*****************************************************************************
99 * Draws a triangle at the given position in the subpic.
100 * It may be filled (fill == RECT_FILLED) or empty (fill == RECT_EMPTY).
101 *****************************************************************************/
102 static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
103 int i_x1, int i_y1, int i_x2, int i_y2, short fill )
106 subpicture_sys_t *p_widget = p_subpic->p_sys;
108 i_mid = i_y1 + ( ( i_y2 - i_y1 ) >> 1 );
110 if( fill == RECT_FILLED )
112 for( y = i_y1; y <= i_mid; y++ )
115 for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )
117 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
118 p_widget->p_pic[ x + p_widget->i_width * ( i_y2 - h ) ] = 1;
124 for( y = i_y1; y <= i_mid; y++ )
127 p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
128 p_widget->p_pic[ i_x1 + h + p_widget->i_width * y ] = 1;
129 p_widget->p_pic[ i_x1 + p_widget->i_width * ( i_y2 - h ) ] = 1;
130 p_widget->p_pic[ i_x1 + h + p_widget->i_width * ( i_y2 - h ) ] = 1;
135 /*****************************************************************************
136 * Render: place string in picture
137 *****************************************************************************
138 * This function merges the previously rendered freetype glyphs into a picture
139 *****************************************************************************/
140 static void Render( vout_thread_t *p_vout, picture_t *p_pic,
141 const subpicture_t *p_subpic )
143 int i_fade_alpha = 255;
144 mtime_t i_fade_start = ( p_subpic->i_stop + p_subpic->i_start ) / 2;
145 mtime_t i_now = mdate();
147 if( i_now >= i_fade_start )
149 i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
150 ( p_subpic->i_stop - i_fade_start );
153 switch( p_vout->output.i_chroma )
155 /* I420 target, no scaling */
156 case VLC_FOURCC('I','4','2','0'):
157 case VLC_FOURCC('I','Y','U','V'):
158 case VLC_FOURCC('Y','V','1','2'):
159 RenderI420( p_vout, p_pic, p_subpic, i_fade_alpha );
161 /* RV32 target, scaling */
162 case VLC_FOURCC('R','V','2','4'):
163 case VLC_FOURCC('R','V','3','2'):
164 RenderRV32( p_vout, p_pic, p_subpic, i_fade_alpha );
166 /* NVidia or BeOS overlay, no scaling */
167 case VLC_FOURCC('Y','U','Y','2'):
168 RenderYUY2( p_vout, p_pic, p_subpic, i_fade_alpha );
172 msg_Err( p_vout, "unknown chroma, can't render SPU" );
178 * Draw a widget on a I420 (or similar) picture
180 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
181 const subpicture_t *p_subpic, int i_fade_alpha )
183 subpicture_sys_t *p_widget = p_subpic->p_sys;
184 int i_plane, x, y, pen_x, pen_y;
186 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
188 uint8_t *p_in = p_pic->p[ i_plane ].p_pixels;
189 int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
193 pen_x = p_widget->i_x;
194 pen_y = p_widget->i_y;
195 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
196 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + pen_x + x ]
197 for( y = 0; y < p_widget->i_height; y++ )
199 for( x = 0; x < p_widget->i_width; x++ )
201 if( alpha == 0 ) continue;
203 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
205 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
207 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
209 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
213 for( y = 0; y < p_widget->i_height; y++ )
215 for( x = 0; x < p_widget->i_width; x++ )
217 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
218 ( 255 * alpha >> 8 );
226 pen_x = p_widget->i_x >> 1;
227 pen_y = p_widget->i_y >> 1;
228 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
229 #define pixel p_in[ ( pen_y + (y >> 1) ) * i_pic_pitch + pen_x + (x >> 1) ]
230 for( y = 0; y < p_widget->i_height; y+=2 )
232 for( x = 0; x < p_widget->i_width; x+=2 )
234 if( alpha == 0 ) continue;
235 pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
236 ( 0x80 * alpha >> 8 );
247 * Draw a widget on a YUY2 picture
249 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
250 const subpicture_t *p_subpic, int i_fade_alpha )
252 subpicture_sys_t *p_widget = p_subpic->p_sys;
253 int x, y, pen_x, pen_y;
254 uint8_t *p_in = p_pic->p[0].p_pixels;
255 int i_pic_pitch = p_pic->p[0].i_pitch;
257 pen_x = p_widget->i_x;
258 pen_y = p_widget->i_y;
259 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
260 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + 2 * ( pen_x + x ) ]
261 for( y = 0; y < p_widget->i_height; y++ )
263 for( x = 0; x < p_widget->i_width; x++ )
266 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
268 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
270 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
272 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
276 for( y = 0; y < p_widget->i_height; y++ )
278 for( x = 0; x < p_widget->i_width; x++ )
280 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
281 ( 255 * alpha >> 8 );
289 * Draw a widget on a RV32 picture
291 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
292 const subpicture_t *p_subpic, int i_fade_alpha )
294 subpicture_sys_t *p_widget = p_subpic->p_sys;
295 int x, y, pen_x, pen_y;
296 uint8_t *p_in = p_pic->p[0].p_pixels;
297 int i_pic_pitch = p_pic->p[0].i_pitch;
299 pen_x = p_widget->i_x;
300 pen_y = p_widget->i_y;
302 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
303 #define pixel( c ) p_in[ ( pen_y + y ) * i_pic_pitch + 4 * ( pen_x + x ) + c ]
304 for(y = 0; y < p_widget->i_height; y++ )
306 for( x = 0; x < p_widget->i_width; x++ )
309 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
310 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
311 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
313 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
314 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
315 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
317 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
318 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
319 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
321 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
322 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
323 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
327 for(y = 0; y < p_widget->i_height; y++ )
329 for( x = 0; x < p_widget->i_width; x++ )
331 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
332 ( 255 * alpha >> 8 );
333 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
334 ( 255 * alpha >> 8 );
335 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
336 ( 255 * alpha >> 8 );
343 /*****************************************************************************
344 * Creates and initializes an OSD widget.
345 *****************************************************************************/
346 subpicture_t *vout_CreateWidget( vout_thread_t *p_vout )
348 subpicture_t *p_subpic;
349 subpicture_sys_t *p_widget;
350 mtime_t i_now = mdate();
355 /* Create and initialize a subpicture */
356 p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
357 if( p_subpic == NULL )
361 p_subpic->pf_render = Render;
362 p_subpic->pf_destroy = FreeWidget;
363 p_subpic->i_start = i_now;
364 p_subpic->i_stop = i_now + 1200000;
365 p_subpic->b_ephemer = VLC_FALSE;
367 p_widget = malloc( sizeof(subpicture_sys_t) );
368 if( p_widget == NULL )
370 FreeWidget( p_subpic );
371 vout_DestroySubPicture( p_vout, p_subpic );
374 p_subpic->p_sys = p_widget;
379 /*****************************************************************************
380 * Displays an OSD slider.
381 * Type 0 is position slider-like, and type 1 is volume slider-like.
382 *****************************************************************************/
383 void vout_OSDSlider( vlc_object_t *p_caller, int i_position, short i_type )
385 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
387 subpicture_t *p_subpic;
388 subpicture_sys_t *p_widget;
389 int i_x_margin, i_y_margin;
391 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) || i_position < 0 )
396 p_subpic = vout_CreateWidget( p_vout );
397 if( p_subpic == NULL )
401 p_widget = p_subpic->p_sys;
403 i_y_margin = p_vout->render.i_height / 10;
404 i_x_margin = i_y_margin;
407 p_widget->i_width = p_vout->render.i_width - 2 * i_x_margin;
408 p_widget->i_height = p_vout->render.i_height / 20;
409 p_widget->i_x = i_x_margin;
410 p_widget->i_y = p_vout->render.i_height - i_y_margin -
415 p_widget->i_width = p_vout->render.i_width / 40;
416 p_widget->i_height = p_vout->render.i_height - 2 * i_y_margin;
417 p_widget->i_x = p_vout->render.i_width - i_x_margin -
419 p_widget->i_y = i_y_margin;
422 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
423 p_widget->i_height );
424 if( p_widget->p_pic == NULL )
426 FreeWidget( p_subpic );
427 vout_DestroySubPicture( p_vout, p_subpic );
430 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
434 int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
435 int i_y_pos = p_widget->i_height / 2;
436 DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
437 p_widget->i_height - 3, RECT_FILLED );
438 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
439 p_widget->i_height - 1, RECT_EMPTY );
441 else if( i_type == 1 )
443 int i_y_pos = p_widget->i_height / 2;
444 DrawRect( p_vout, p_subpic, 2, p_widget->i_height -
445 ( p_widget->i_height - 2 ) * i_position / 100,
446 p_widget->i_width - 3, p_widget->i_height - 3,
448 DrawRect( p_vout, p_subpic, 1, i_y_pos, 1, i_y_pos, RECT_FILLED );
449 DrawRect( p_vout, p_subpic, p_widget->i_width - 2, i_y_pos,
450 p_widget->i_width - 2, i_y_pos, RECT_FILLED );
451 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
452 p_widget->i_height - 1, RECT_EMPTY );
455 vlc_mutex_lock( &p_vout->change_lock );
457 if( p_vout->p_last_osd_message )
459 vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
461 p_vout->p_last_osd_message = p_subpic;
462 vout_DisplaySubPicture( p_vout, p_subpic );
464 vlc_mutex_unlock( &p_vout->change_lock );
466 vlc_object_release( p_vout );
470 /*****************************************************************************
471 * Displays an OSD icon.
472 * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON
473 *****************************************************************************/
474 void vout_OSDIcon( vlc_object_t *p_caller, short i_type )
476 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
478 subpicture_t *p_subpic;
479 subpicture_sys_t *p_widget;
480 int i_x_margin, i_y_margin;
482 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) )
487 p_subpic = vout_CreateWidget( p_vout );
488 if( p_subpic == NULL )
492 p_widget = p_subpic->p_sys;
494 i_y_margin = p_vout->render.i_height / 15;
495 i_x_margin = i_y_margin;
496 p_widget->i_width = p_vout->render.i_width / 22;
497 p_widget->i_height = p_widget->i_width;
498 p_widget->i_x = p_vout->render.i_width - i_x_margin -
500 p_widget->i_y = i_y_margin;
502 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
503 p_widget->i_height );
504 if( p_widget->p_pic == NULL )
506 FreeWidget( p_subpic );
507 vout_DestroySubPicture( p_vout, p_subpic );
510 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
512 if( i_type == OSD_PAUSE_ICON )
514 int i_bar_width = p_widget->i_width / 3;
515 DrawRect( p_vout, p_subpic, 0, 0, i_bar_width - 1,
516 p_widget->i_height - 1, RECT_FILLED );
517 DrawRect( p_vout, p_subpic, p_widget->i_width - i_bar_width, 0,
518 p_widget->i_width - 1, p_widget->i_height - 1, RECT_FILLED );
520 else if( i_type == OSD_PLAY_ICON )
522 int i_mid = p_widget->i_height >> 1;
523 int i_delta = ( p_widget->i_width - i_mid ) >> 1;
524 int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
525 DrawTriangle( p_vout, p_subpic, i_delta, 0,
526 p_widget->i_width - i_delta, i_y2, RECT_FILLED );
529 vlc_mutex_lock( &p_vout->change_lock );
531 if( p_vout->p_last_osd_message )
533 vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
535 p_vout->p_last_osd_message = p_subpic;
536 vout_DisplaySubPicture( p_vout, p_subpic );
538 vlc_mutex_unlock( &p_vout->change_lock );
540 vlc_object_release( p_vout );
547 static void FreeWidget( subpicture_t *p_subpic )
549 subpicture_sys_t *p_widget = p_subpic->p_sys;
551 if( p_subpic->p_sys == NULL ) return;
553 if( p_widget->p_pic != NULL )
555 free( p_widget->p_pic );