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() */
32 #define STYLE_FILLED 1
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 *, int );
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 == STYLE_FILLED) or empty (fill == STYLE_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 == STYLE_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 == STYLE_FILLED) or empty (fill == STYLE_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 );
112 if( fill == STYLE_FILLED )
114 for( y = i_y1; y <= i_mid; y++ )
117 for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )
119 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
120 p_widget->p_pic[ x + p_widget->i_width * ( i_y2 - h ) ] = 1;
126 for( y = i_y1; y <= i_mid; y++ )
129 p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
130 p_widget->p_pic[ i_x1 + h + p_widget->i_width * y ] = 1;
131 p_widget->p_pic[ i_x1 + p_widget->i_width * ( i_y2 - h ) ] = 1;
132 p_widget->p_pic[ i_x1 + h + p_widget->i_width * ( i_y2 - h ) ] = 1;
138 if( fill == STYLE_FILLED )
140 for( y = i_y1; y <= i_mid; y++ )
143 for( x = i_x1; x >= i_x1 - h && x >= i_x2; x-- )
145 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
146 p_widget->p_pic[ x + p_widget->i_width * ( i_y2 - h ) ] = 1;
152 for( y = i_y1; y <= i_mid; y++ )
155 p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
156 p_widget->p_pic[ i_x1 - h + p_widget->i_width * y ] = 1;
157 p_widget->p_pic[ i_x1 + p_widget->i_width * ( i_y2 - h ) ] = 1;
158 p_widget->p_pic[ i_x1 - h + p_widget->i_width * ( i_y2 - h ) ] = 1;
164 /*****************************************************************************
165 * Render: place widget in picture
166 *****************************************************************************
167 * This function merges the previously drawn widget into a picture
168 *****************************************************************************/
169 static void Render( vout_thread_t *p_vout, picture_t *p_pic,
170 const subpicture_t *p_subpic )
172 int i_fade_alpha = 255;
173 mtime_t i_fade_start = ( p_subpic->i_stop + p_subpic->i_start ) / 2;
174 mtime_t i_now = mdate();
176 if( i_now >= i_fade_start )
178 i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
179 ( p_subpic->i_stop - i_fade_start );
182 switch( p_vout->output.i_chroma )
184 /* I420 target, no scaling */
185 case VLC_FOURCC('I','4','2','0'):
186 case VLC_FOURCC('I','Y','U','V'):
187 case VLC_FOURCC('Y','V','1','2'):
188 RenderI420( p_vout, p_pic, p_subpic, i_fade_alpha );
190 /* RV32 target, scaling */
191 case VLC_FOURCC('R','V','2','4'):
192 case VLC_FOURCC('R','V','3','2'):
193 RenderRV32( p_vout, p_pic, p_subpic, i_fade_alpha );
195 /* NVidia or BeOS overlay, no scaling */
196 case VLC_FOURCC('Y','U','Y','2'):
197 RenderYUY2( p_vout, p_pic, p_subpic, i_fade_alpha );
201 msg_Err( p_vout, "unknown chroma, can't render SPU" );
207 * Draw a widget on a I420 (or similar) picture
209 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
210 const subpicture_t *p_subpic, int i_fade_alpha )
212 subpicture_sys_t *p_widget = p_subpic->p_sys;
213 int i_plane, x, y, pen_x, pen_y;
215 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
217 uint8_t *p_in = p_pic->p[ i_plane ].p_pixels;
218 int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
222 pen_x = p_widget->i_x;
223 pen_y = p_widget->i_y;
224 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
225 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + pen_x + x ]
226 for( y = 0; y < p_widget->i_height; y++ )
228 for( x = 0; x < p_widget->i_width; x++ )
230 if( alpha == 0 ) continue;
232 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
234 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
236 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
238 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
242 for( y = 0; y < p_widget->i_height; y++ )
244 for( x = 0; x < p_widget->i_width; x++ )
246 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
247 ( 255 * alpha >> 8 );
255 pen_x = p_widget->i_x >> 1;
256 pen_y = p_widget->i_y >> 1;
257 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
258 #define pixel p_in[ ( pen_y + (y >> 1) ) * i_pic_pitch + pen_x + (x >> 1) ]
259 for( y = 0; y < p_widget->i_height; y+=2 )
261 for( x = 0; x < p_widget->i_width; x+=2 )
263 if( alpha == 0 ) continue;
264 pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
265 ( 0x80 * alpha >> 8 );
276 * Draw a widget on a YUY2 picture
278 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
279 const subpicture_t *p_subpic, int i_fade_alpha )
281 subpicture_sys_t *p_widget = p_subpic->p_sys;
282 int x, y, pen_x, pen_y;
283 uint8_t *p_in = p_pic->p[0].p_pixels;
284 int i_pic_pitch = p_pic->p[0].i_pitch;
286 pen_x = p_widget->i_x;
287 pen_y = p_widget->i_y;
288 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
289 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + 2 * ( pen_x + x ) ]
290 for( y = 0; y < p_widget->i_height; y++ )
292 for( x = 0; x < p_widget->i_width; x++ )
295 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
297 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
299 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
301 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
305 for( y = 0; y < p_widget->i_height; y++ )
307 for( x = 0; x < p_widget->i_width; x++ )
309 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
310 ( 255 * alpha >> 8 );
318 * Draw a widget on a RV32 picture
320 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
321 const subpicture_t *p_subpic, int i_fade_alpha )
323 subpicture_sys_t *p_widget = p_subpic->p_sys;
324 int x, y, pen_x, pen_y;
325 uint8_t *p_in = p_pic->p[0].p_pixels;
326 int i_pic_pitch = p_pic->p[0].i_pitch;
328 pen_x = p_widget->i_x;
329 pen_y = p_widget->i_y;
331 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
332 #define pixel( c ) p_in[ ( pen_y + y ) * i_pic_pitch + 4 * ( pen_x + x ) + c ]
333 for(y = 0; y < p_widget->i_height; y++ )
335 for( x = 0; x < p_widget->i_width; x++ )
338 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
339 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
340 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
342 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
343 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
344 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
346 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
347 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
348 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
350 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
351 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
352 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
356 for(y = 0; y < p_widget->i_height; y++ )
358 for( x = 0; x < p_widget->i_width; x++ )
360 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
361 ( 255 * alpha >> 8 );
362 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
363 ( 255 * alpha >> 8 );
364 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
365 ( 255 * alpha >> 8 );
372 /*****************************************************************************
373 * Creates and initializes an OSD widget.
374 *****************************************************************************/
375 subpicture_t *vout_CreateWidget( vout_thread_t *p_vout, int i_channel )
377 subpicture_t *p_subpic;
378 subpicture_sys_t *p_widget;
379 mtime_t i_now = mdate();
384 /* Create and initialize a subpicture */
385 p_subpic = spu_CreateSubpicture( p_vout->p_spu );
386 if( p_subpic == NULL )
390 p_subpic->i_channel = i_channel;
391 p_subpic->pf_render = Render;
392 p_subpic->pf_destroy = FreeWidget;
393 p_subpic->i_start = i_now;
394 p_subpic->i_stop = i_now + 1200000;
395 p_subpic->b_ephemer = VLC_FALSE;
397 p_widget = malloc( sizeof(subpicture_sys_t) );
398 if( p_widget == NULL )
400 FreeWidget( p_subpic );
401 spu_DestroySubpicture( p_vout->p_spu, p_subpic );
404 p_subpic->p_sys = p_widget;
409 /*****************************************************************************
410 * Displays an OSD slider.
411 * Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
412 *****************************************************************************/
413 void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position,
416 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
418 subpicture_t *p_subpic;
419 subpicture_sys_t *p_widget;
420 int i_x_margin, i_y_margin;
422 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) || i_position < 0 )
427 p_subpic = vout_CreateWidget( p_vout, i_channel );
428 if( p_subpic == NULL )
432 p_widget = p_subpic->p_sys;
434 i_y_margin = p_vout->render.i_height / 10;
435 i_x_margin = i_y_margin;
436 if( i_type == OSD_HOR_SLIDER )
438 p_widget->i_width = p_vout->render.i_width - 2 * i_x_margin;
439 p_widget->i_height = p_vout->render.i_height / 20;
440 p_widget->i_x = i_x_margin;
441 p_widget->i_y = p_vout->render.i_height - i_y_margin -
446 p_widget->i_width = p_vout->render.i_width / 40;
447 p_widget->i_height = p_vout->render.i_height - 2 * i_y_margin;
448 p_widget->i_x = p_vout->render.i_width - i_x_margin -
450 p_widget->i_y = i_y_margin;
453 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
454 p_widget->i_height );
455 if( p_widget->p_pic == NULL )
457 FreeWidget( p_subpic );
458 spu_DestroySubpicture( p_vout->p_spu, p_subpic );
461 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
463 if( i_type == OSD_HOR_SLIDER )
465 int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
466 DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
467 p_widget->i_height - 3, STYLE_FILLED );
468 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
469 p_widget->i_height - 1, STYLE_EMPTY );
471 else if( i_type == OSD_VERT_SLIDER )
473 int i_y_pos = p_widget->i_height / 2;
474 DrawRect( p_vout, p_subpic, 2, p_widget->i_height -
475 ( p_widget->i_height - 2 ) * i_position / 100,
476 p_widget->i_width - 3, p_widget->i_height - 3,
478 DrawRect( p_vout, p_subpic, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );
479 DrawRect( p_vout, p_subpic, p_widget->i_width - 2, i_y_pos,
480 p_widget->i_width - 2, i_y_pos, STYLE_FILLED );
481 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
482 p_widget->i_height - 1, STYLE_EMPTY );
485 spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
487 vlc_object_release( p_vout );
491 /*****************************************************************************
492 * Displays an OSD icon.
493 * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
494 *****************************************************************************/
495 void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type )
497 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
499 subpicture_t *p_subpic;
500 subpicture_sys_t *p_widget;
501 int i_x_margin, i_y_margin;
503 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) )
508 p_subpic = vout_CreateWidget( p_vout, i_channel );
509 if( p_subpic == NULL )
513 p_widget = p_subpic->p_sys;
515 i_y_margin = p_vout->render.i_height / 15;
516 i_x_margin = i_y_margin;
517 p_widget->i_width = p_vout->render.i_width / 20;
518 p_widget->i_height = p_widget->i_width;
519 p_widget->i_x = p_vout->render.i_width - i_x_margin -
521 p_widget->i_y = i_y_margin;
523 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
524 p_widget->i_height );
525 if( p_widget->p_pic == NULL )
527 FreeWidget( p_subpic );
528 spu_DestroySubpicture( p_vout->p_spu, p_subpic );
531 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
533 if( i_type == OSD_PAUSE_ICON )
535 int i_bar_width = p_widget->i_width / 3;
536 DrawRect( p_vout, p_subpic, 0, 0, i_bar_width - 1,
537 p_widget->i_height - 1, STYLE_FILLED );
538 DrawRect( p_vout, p_subpic, p_widget->i_width - i_bar_width, 0,
539 p_widget->i_width - 1, p_widget->i_height - 1, STYLE_FILLED );
541 else if( i_type == OSD_PLAY_ICON )
543 int i_mid = p_widget->i_height >> 1;
544 int i_delta = ( p_widget->i_width - i_mid ) >> 1;
545 int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
546 DrawTriangle( p_vout, p_subpic, i_delta, 0,
547 p_widget->i_width - i_delta, i_y2, STYLE_FILLED );
549 else if( i_type == OSD_SPEAKER_ICON || i_type == OSD_MUTE_ICON )
551 int i_mid = p_widget->i_height >> 1;
552 int i_delta = ( p_widget->i_width - i_mid ) >> 1;
553 int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
554 DrawRect( p_vout, p_subpic, i_delta, i_mid / 2,
555 p_widget->i_width - i_delta,
556 p_widget->i_height - 1 - i_mid / 2, STYLE_FILLED );
557 DrawTriangle( p_vout, p_subpic, p_widget->i_width - i_delta, 0,
558 i_delta, i_y2, STYLE_FILLED );
559 if( i_type == OSD_MUTE_ICON )
562 for( i = 1; i < p_widget->i_width; i++ )
564 int k = i + ( p_widget->i_height - i - 1 ) * p_widget->i_width;
565 p_widget->p_pic[ k ] = 1 - p_widget->p_pic[ k ];
570 spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
572 vlc_object_release( p_vout );
579 static void FreeWidget( subpicture_t *p_subpic )
581 subpicture_sys_t *p_widget = p_subpic->p_sys;
583 if( p_subpic->p_sys == NULL ) return;
585 if( p_widget->p_pic != NULL )
587 free( p_widget->p_pic );