1 /*****************************************************************************
2 * video_widgets.c : widgets manipulation functions
3 *****************************************************************************
4 * Copyright (C) 1999-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 Render ( vout_thread_t *, picture_t *, const subpicture_t * );
40 static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
42 static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
44 static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
46 static void FreeWidget( subpicture_t * );
49 * Private data in a subpicture.
51 struct subpicture_sys_t
60 /*****************************************************************************
61 * Draws a rectangle at the given position in the subpic.
62 * It may be filled (fill == RECT_FILLED) or empty (fill == RECT_EMPTY).
63 *****************************************************************************/
64 static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
65 int i_x1, int i_y1, int i_x2, int i_y2, short fill )
68 subpicture_sys_t *p_widget = p_subpic->p_sys;
70 if( fill == RECT_FILLED )
72 for( y = i_y1; y <= i_y2; y++ )
74 for( x = i_x1; x <= i_x2; x++ )
76 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
82 for( y = i_y1; y <= i_y2; y++ )
84 p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
85 p_widget->p_pic[ i_x2 + p_widget->i_width * y ] = 1;
87 for( x = i_x1; x <= i_x2; x++ )
89 p_widget->p_pic[ x + p_widget->i_width * i_y1 ] = 1;
90 p_widget->p_pic[ x + p_widget->i_width * i_y2 ] = 1;
95 /*****************************************************************************
96 * Render: place string in picture
97 *****************************************************************************
98 * This function merges the previously rendered freetype glyphs into a picture
99 *****************************************************************************/
100 static void Render( vout_thread_t *p_vout, picture_t *p_pic,
101 const subpicture_t *p_subpic )
103 int i_fade_alpha = 255;
104 mtime_t i_fade_start = ( p_subpic->i_stop + p_subpic->i_start ) / 2;
105 mtime_t i_now = mdate();
107 if( i_now >= i_fade_start )
109 i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
110 ( p_subpic->i_stop - i_fade_start );
113 switch( p_vout->output.i_chroma )
115 /* I420 target, no scaling */
116 case VLC_FOURCC('I','4','2','0'):
117 case VLC_FOURCC('I','Y','U','V'):
118 case VLC_FOURCC('Y','V','1','2'):
119 RenderI420( p_vout, p_pic, p_subpic, i_fade_alpha );
121 /* RV32 target, scaling */
122 case VLC_FOURCC('R','V','2','4'):
123 case VLC_FOURCC('R','V','3','2'):
124 RenderRV32( p_vout, p_pic, p_subpic, i_fade_alpha );
126 /* NVidia or BeOS overlay, no scaling */
127 case VLC_FOURCC('Y','U','Y','2'):
128 RenderYUY2( p_vout, p_pic, p_subpic, i_fade_alpha );
132 msg_Err( p_vout, "unknown chroma, can't render SPU" );
138 * Draw a widget on a I420 (or similar) picture
140 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
141 const subpicture_t *p_subpic, int i_fade_alpha )
143 subpicture_sys_t *p_widget = p_subpic->p_sys;
144 int i_plane, x, y, pen_x, pen_y;
146 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
149 int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
151 p_in = p_pic->p[ i_plane ].p_pixels;
155 pen_x = p_widget->i_x;
156 pen_y = p_widget->i_y;
157 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
158 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + pen_x + x ]
159 for( y = 0; y < p_widget->i_height; y++ )
161 for( x = 0; x < p_widget->i_width; x++ )
164 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
166 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
168 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
170 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
174 for( y = 0; y < p_widget->i_height; y++ )
176 for( x = 0; x < p_widget->i_width; x++ )
178 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
179 ( 255 * alpha >> 8 );
187 pen_x = p_widget->i_x >> 1;
188 pen_y = p_widget->i_y >> 1;
189 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
190 #define pixel p_in[ ( pen_y + (y >> 1) ) * i_pic_pitch + pen_x + (x >> 1) ]
191 for( y = 0; y < p_widget->i_height; y+=2 )
193 for( x = 0; x < p_widget->i_width; x+=2 )
195 pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
196 ( 0x80 * alpha >> 8 );
207 * Draw a widget on a YUY2 picture
209 static void RenderYUY2( 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 x, y, pen_x, pen_y;
215 int i_pic_pitch = p_pic->p[0].i_pitch;
217 pen_x = p_widget->i_x;
218 pen_y = p_widget->i_y;
219 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
220 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + 2 * ( pen_x + x ) ]
221 for( y = 0; y < p_widget->i_height; y++ )
223 for( x = 0; x < p_widget->i_width; x++ )
226 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
228 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
230 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
232 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
236 for( y = 0; y < p_widget->i_height; y++ )
238 for( x = 0; x < p_widget->i_width; x++ )
240 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
241 ( 255 * alpha >> 8 );
249 * Draw a widget on a RV32 picture
251 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
252 const subpicture_t *p_subpic, int i_fade_alpha )
254 subpicture_sys_t *p_widget = p_subpic->p_sys;
255 int x, y, pen_x, pen_y;
257 int i_pic_pitch = p_pic->p[0].i_pitch;
259 pen_x = p_widget->i_x;
260 pen_y = p_widget->i_y;
262 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
263 #define pixel( c ) p_in[ ( pen_y + y ) * i_pic_pitch + 4 * ( pen_x + x ) + c ]
264 for(y = 0; y < p_widget->i_height; y++ )
266 for( x = 0; x < p_widget->i_width; x++ )
269 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
270 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
271 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
273 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
274 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
275 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
277 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
278 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
279 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
281 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
282 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
283 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
287 for(y = 0; y < p_widget->i_height; y++ )
289 for( x = 0; x < p_widget->i_width; x++ )
291 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
292 ( 255 * alpha >> 8 );
293 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
294 ( 255 * alpha >> 8 );
295 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
296 ( 255 * alpha >> 8 );
303 /*****************************************************************************
304 * Displays an OSD slider.
305 * Type 0 is position slider-like, and type 1 is volume slider-like.
306 *****************************************************************************/
307 void vout_OSDSlider( vlc_object_t *p_caller, int i_position, short i_type )
309 vout_thread_t *p_vout;
310 subpicture_t *p_subpic;
311 subpicture_sys_t *p_widget;
312 mtime_t i_now = mdate();
313 int i_x_margin, i_y_margin;
315 if( !config_GetInt( p_caller, "osd" ) || i_position < 0 ) return;
317 p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT, FIND_ANYWHERE );
324 /* Create and initialize a subpicture */
325 p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
326 if( p_subpic == NULL )
330 p_subpic->pf_render = Render;
331 p_subpic->pf_destroy = FreeWidget;
332 p_subpic->i_start = i_now;
333 p_subpic->i_stop = i_now + 1200000;
334 p_subpic->b_ephemer = VLC_FALSE;
336 p_widget = malloc( sizeof(subpicture_sys_t) );
337 if( p_widget == NULL )
339 FreeWidget( p_subpic );
340 vout_DestroySubPicture( p_vout, p_subpic );
343 p_subpic->p_sys = p_widget;
345 i_y_margin = p_vout->render.i_height / 10;
346 i_x_margin = i_y_margin;
349 p_widget->i_width = p_vout->render.i_width - 2 * i_x_margin;
350 p_widget->i_height = p_vout->render.i_height / 20;
351 p_widget->i_x = i_x_margin;
352 p_widget->i_y = p_vout->render.i_height - i_y_margin -
357 p_widget->i_width = p_vout->render.i_width / 40;
358 p_widget->i_height = p_vout->render.i_height - 2 * i_y_margin;
359 p_widget->i_height = ( ( p_widget->i_height - 2 ) >> 2 ) * 4 + 2;
360 p_widget->i_x = p_vout->render.i_width - i_x_margin -
362 p_widget->i_y = i_y_margin;
365 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
366 p_widget->i_height );
367 if( p_widget->p_pic == NULL )
369 FreeWidget( p_subpic );
370 vout_DestroySubPicture( p_vout, p_subpic );
373 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
377 int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
378 int i_y_pos = p_widget->i_height / 2;
379 DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
380 p_widget->i_height - 3, RECT_FILLED );
381 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
382 p_widget->i_height - 1, RECT_EMPTY );
384 else if( i_type == 1 )
386 int i_y_pos = p_widget->i_height / 2;
387 DrawRect( p_vout, p_subpic, 2, p_widget->i_height -
388 ( p_widget->i_height - 2 ) * i_position / 100,
389 p_widget->i_width - 3, p_widget->i_height - 3,
391 DrawRect( p_vout, p_subpic, 1, i_y_pos, 1, i_y_pos, RECT_FILLED );
392 DrawRect( p_vout, p_subpic, p_widget->i_width - 2, i_y_pos,
393 p_widget->i_width - 2, i_y_pos, RECT_FILLED );
394 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
395 p_widget->i_height - 1, RECT_EMPTY );
398 vlc_mutex_lock( &p_vout->change_lock );
400 if( p_vout->p_last_osd_message )
402 vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
404 p_vout->p_last_osd_message = p_subpic;
405 vout_DisplaySubPicture( p_vout, p_subpic );
407 vlc_mutex_unlock( &p_vout->change_lock );
409 vlc_object_release( p_vout );
417 static void FreeWidget( subpicture_t *p_subpic )
419 subpicture_sys_t *p_widget = p_subpic->p_sys;
421 if( p_subpic->p_sys == NULL ) return;
423 if( p_widget->p_pic != NULL )
425 free( p_widget->p_pic );