1 /*****************************************************************************
2 * video_widgets.c : 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 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++ )
148 uint8_t *p_in = p_pic->p[ i_plane ].p_pixels;
149 int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
153 pen_x = p_widget->i_x;
154 pen_y = p_widget->i_y;
155 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
156 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + pen_x + x ]
157 for( y = 0; y < p_widget->i_height; y++ )
159 for( x = 0; x < p_widget->i_width; x++ )
162 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
164 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
166 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
168 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
172 for( y = 0; y < p_widget->i_height; y++ )
174 for( x = 0; x < p_widget->i_width; x++ )
176 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
177 ( 255 * alpha >> 8 );
185 pen_x = p_widget->i_x >> 1;
186 pen_y = p_widget->i_y >> 1;
187 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
188 #define pixel p_in[ ( pen_y + (y >> 1) ) * i_pic_pitch + pen_x + (x >> 1) ]
189 for( y = 0; y < p_widget->i_height; y+=2 )
191 for( x = 0; x < p_widget->i_width; x+=2 )
193 pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
194 ( 0x80 * alpha >> 8 );
205 * Draw a widget on a YUY2 picture
207 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
208 const subpicture_t *p_subpic, int i_fade_alpha )
210 subpicture_sys_t *p_widget = p_subpic->p_sys;
211 int x, y, pen_x, pen_y;
212 uint8_t *p_in = p_pic->p[0].p_pixels;
213 int i_pic_pitch = p_pic->p[0].i_pitch;
215 pen_x = p_widget->i_x;
216 pen_y = p_widget->i_y;
217 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
218 #define pixel p_in[ ( pen_y + y ) * i_pic_pitch + 2 * ( pen_x + x ) ]
219 for( y = 0; y < p_widget->i_height; y++ )
221 for( x = 0; x < p_widget->i_width; x++ )
224 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
226 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
228 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
230 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
234 for( y = 0; y < p_widget->i_height; y++ )
236 for( x = 0; x < p_widget->i_width; x++ )
238 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
239 ( 255 * alpha >> 8 );
247 * Draw a widget on a RV32 picture
249 static void RenderRV32( 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;
260 #define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
261 #define pixel( c ) p_in[ ( pen_y + y ) * i_pic_pitch + 4 * ( pen_x + x ) + c ]
262 for(y = 0; y < p_widget->i_height; y++ )
264 for( x = 0; x < p_widget->i_width; x++ )
267 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
268 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
269 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
271 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
272 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
273 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
275 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
276 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
277 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
279 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
280 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
281 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
285 for(y = 0; y < p_widget->i_height; y++ )
287 for( x = 0; x < p_widget->i_width; x++ )
289 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
290 ( 255 * alpha >> 8 );
291 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
292 ( 255 * alpha >> 8 );
293 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
294 ( 255 * alpha >> 8 );
301 /*****************************************************************************
302 * Displays an OSD slider.
303 * Type 0 is position slider-like, and type 1 is volume slider-like.
304 *****************************************************************************/
305 void vout_OSDSlider( vlc_object_t *p_caller, int i_position, short i_type )
307 vout_thread_t *p_vout;
308 subpicture_t *p_subpic;
309 subpicture_sys_t *p_widget;
310 mtime_t i_now = mdate();
311 int i_x_margin, i_y_margin;
313 if( !config_GetInt( p_caller, "osd" ) || i_position < 0 ) return;
315 p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT, FIND_ANYWHERE );
322 /* Create and initialize a subpicture */
323 p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
324 if( p_subpic == NULL )
328 p_subpic->pf_render = Render;
329 p_subpic->pf_destroy = FreeWidget;
330 p_subpic->i_start = i_now;
331 p_subpic->i_stop = i_now + 1200000;
332 p_subpic->b_ephemer = VLC_FALSE;
334 p_widget = malloc( sizeof(subpicture_sys_t) );
335 if( p_widget == NULL )
337 FreeWidget( p_subpic );
338 vout_DestroySubPicture( p_vout, p_subpic );
341 p_subpic->p_sys = p_widget;
343 i_y_margin = p_vout->render.i_height / 10;
344 i_x_margin = i_y_margin;
347 p_widget->i_width = p_vout->render.i_width - 2 * i_x_margin;
348 p_widget->i_height = p_vout->render.i_height / 20;
349 p_widget->i_x = i_x_margin;
350 p_widget->i_y = p_vout->render.i_height - i_y_margin -
355 p_widget->i_width = p_vout->render.i_width / 40;
356 p_widget->i_height = p_vout->render.i_height - 2 * i_y_margin;
357 p_widget->i_height = ( ( p_widget->i_height - 2 ) >> 2 ) * 4 + 2;
358 p_widget->i_x = p_vout->render.i_width - i_x_margin -
360 p_widget->i_y = i_y_margin;
363 p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
364 p_widget->i_height );
365 if( p_widget->p_pic == NULL )
367 FreeWidget( p_subpic );
368 vout_DestroySubPicture( p_vout, p_subpic );
371 memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
375 int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
376 int i_y_pos = p_widget->i_height / 2;
377 DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
378 p_widget->i_height - 3, RECT_FILLED );
379 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
380 p_widget->i_height - 1, RECT_EMPTY );
382 else if( i_type == 1 )
384 int i_y_pos = p_widget->i_height / 2;
385 DrawRect( p_vout, p_subpic, 2, p_widget->i_height -
386 ( p_widget->i_height - 2 ) * i_position / 100,
387 p_widget->i_width - 3, p_widget->i_height - 3,
389 DrawRect( p_vout, p_subpic, 1, i_y_pos, 1, i_y_pos, RECT_FILLED );
390 DrawRect( p_vout, p_subpic, p_widget->i_width - 2, i_y_pos,
391 p_widget->i_width - 2, i_y_pos, RECT_FILLED );
392 DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
393 p_widget->i_height - 1, RECT_EMPTY );
396 vlc_mutex_lock( &p_vout->change_lock );
398 if( p_vout->p_last_osd_message )
400 vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
402 p_vout->p_last_osd_message = p_subpic;
403 vout_DisplaySubPicture( p_vout, p_subpic );
405 vlc_mutex_unlock( &p_vout->change_lock );
407 vlc_object_release( p_vout );
415 static void FreeWidget( subpicture_t *p_subpic )
417 subpicture_sys_t *p_widget = p_subpic->p_sys;
419 if( p_subpic->p_sys == NULL ) return;
421 if( p_widget->p_pic != NULL )
423 free( p_widget->p_pic );