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() */
31 #include "vlc_video.h"
32 #include "vlc_filter.h"
35 #define STYLE_FILLED 1
37 /*****************************************************************************
39 *****************************************************************************/
40 static void DrawRect( subpicture_t *, int, int, int, int, short );
41 static void DrawTriangle( subpicture_t *, int, int, int, int, short );
42 static void CreatePicture( vout_thread_t *, subpicture_t * );
43 static subpicture_t *vout_CreateWidget( vout_thread_t *, int );
44 static void FreeWidget( subpicture_t * );
47 * Private data in a subpicture.
49 struct subpicture_sys_t
57 /*****************************************************************************
58 * Draws a rectangle at the given position in the subpic.
59 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
60 *****************************************************************************/
61 static void DrawRect( subpicture_t *p_subpic, int i_x1, int i_y1,
62 int i_x2, int i_y2, short fill )
65 uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
66 int i_pitch = p_subpic->p_region->picture.Y_PITCH;
68 if( fill == STYLE_FILLED )
70 for( y = i_y1; y <= i_y2; y++ )
72 for( x = i_x1; x <= i_x2; x++ )
74 p_a[ x + i_pitch * y ] = 0xff;
80 for( y = i_y1; y <= i_y2; y++ )
82 p_a[ i_x1 + i_pitch * y ] = 0xff;
83 p_a[ i_x2 + i_pitch * y ] = 0xff;
85 for( x = i_x1; x <= i_x2; x++ )
87 p_a[ x + i_pitch * i_y1 ] = 0xff;
88 p_a[ x + i_pitch * i_y2 ] = 0xff;
93 /*****************************************************************************
94 * Draws a triangle at the given position in the subpic.
95 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
96 *****************************************************************************/
97 static void DrawTriangle( subpicture_t *p_subpic, int i_x1, int i_y1,
98 int i_x2, int i_y2, short fill )
101 uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
102 int i_pitch = p_subpic->p_region->picture.Y_PITCH;
104 i_mid = i_y1 + ( ( i_y2 - i_y1 ) >> 1 );
108 if( fill == STYLE_FILLED )
110 for( y = i_y1; y <= i_mid; y++ )
113 for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )
115 p_a[ x + i_pitch * y ] = 0xff;
116 p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
122 for( y = i_y1; y <= i_mid; y++ )
125 p_a[ i_x1 + i_pitch * y ] = 0xff;
126 p_a[ i_x1 + h + i_pitch * y ] = 0xff;
127 p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;
128 p_a[ i_x1 + h + i_pitch * ( i_y2 - h ) ] = 0xff;
134 if( fill == STYLE_FILLED )
136 for( y = i_y1; y <= i_mid; y++ )
139 for( x = i_x1; x >= i_x1 - h && x >= i_x2; x-- )
141 p_a[ x + i_pitch * y ] = 0xff;
142 p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
148 for( y = i_y1; y <= i_mid; y++ )
151 p_a[ i_x1 + i_pitch * y ] = 0xff;
152 p_a[ i_x1 - h + i_pitch * y ] = 0xff;
153 p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;
154 p_a[ i_x1 - h + i_pitch * ( i_y2 - h ) ] = 0xff;
160 /*****************************************************************************
161 * Create Picture: creates subpicture region and picture
162 *****************************************************************************/
163 static void CreatePicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
165 subpicture_sys_t *p_widget = p_subpic->p_sys;
166 spu_t *p_spu = p_vout->p_spu;
167 uint8_t *p_y, *p_u, *p_v, *p_a;
171 /* Create a new subpicture region */
172 memset( &fmt, 0, sizeof(video_format_t) );
173 fmt.i_chroma = VLC_FOURCC('Y','U','V','A');
174 fmt.i_aspect = VOUT_ASPECT_FACTOR;
175 fmt.i_width = fmt.i_visible_width = p_widget->i_width;
176 fmt.i_height = fmt.i_visible_height = p_widget->i_height;
177 fmt.i_x_offset = fmt.i_y_offset = 0;
178 p_subpic->p_region = p_subpic->pf_create_region( VLC_OBJECT(p_spu), &fmt );
179 if( !p_subpic->p_region )
181 msg_Err( p_spu, "cannot allocate SPU region" );
185 p_subpic->p_region->i_x = p_widget->i_x;
186 p_subpic->p_region->i_y = p_widget->i_y;
187 p_y = p_subpic->p_region->picture.Y_PIXELS;
188 p_u = p_subpic->p_region->picture.U_PIXELS;
189 p_v = p_subpic->p_region->picture.V_PIXELS;
190 p_a = p_subpic->p_region->picture.A_PIXELS;
191 i_pitch = p_subpic->p_region->picture.Y_PITCH;
193 /* Initialize the region pixels (only the alpha will be changed later) */
194 memset( p_y, 0xff, i_pitch * p_subpic->p_region->fmt.i_height );
195 memset( p_u, 0x80, i_pitch * p_subpic->p_region->fmt.i_height );
196 memset( p_v, 0x80, i_pitch * p_subpic->p_region->fmt.i_height );
197 memset( p_a, 0x00, i_pitch * p_subpic->p_region->fmt.i_height );
200 /*****************************************************************************
201 * Creates and initializes an OSD widget.
202 *****************************************************************************/
203 subpicture_t *vout_CreateWidget( vout_thread_t *p_vout, int i_channel )
205 subpicture_t *p_subpic;
206 subpicture_sys_t *p_widget;
207 mtime_t i_now = mdate();
212 /* Create and initialize a subpicture */
213 p_subpic = spu_CreateSubpicture( p_vout->p_spu );
214 if( p_subpic == NULL )
218 p_subpic->i_channel = i_channel;
219 p_subpic->pf_destroy = FreeWidget;
220 p_subpic->i_start = i_now;
221 p_subpic->i_stop = i_now + 1200000;
222 p_subpic->b_ephemer = VLC_TRUE;
223 p_subpic->b_fade = VLC_TRUE;
225 p_widget = malloc( sizeof(subpicture_sys_t) );
226 if( p_widget == NULL )
228 FreeWidget( p_subpic );
229 spu_DestroySubpicture( p_vout->p_spu, p_subpic );
232 p_subpic->p_sys = p_widget;
237 /*****************************************************************************
238 * Displays an OSD slider.
239 * Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
240 *****************************************************************************/
241 void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position,
244 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
246 subpicture_t *p_subpic;
247 subpicture_sys_t *p_widget;
248 int i_x_margin, i_y_margin;
250 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) || i_position < 0 )
255 p_subpic = vout_CreateWidget( p_vout, i_channel );
256 if( p_subpic == NULL )
260 p_widget = p_subpic->p_sys;
262 i_y_margin = p_vout->render.i_height / 10;
263 i_x_margin = i_y_margin;
264 if( i_type == OSD_HOR_SLIDER )
266 p_widget->i_width = p_vout->render.i_width - 2 * i_x_margin;
267 p_widget->i_height = p_vout->render.i_height / 20;
268 p_widget->i_x = i_x_margin;
269 p_widget->i_y = p_vout->render.i_height - i_y_margin -
274 p_widget->i_width = p_vout->render.i_width / 40;
275 p_widget->i_height = p_vout->render.i_height - 2 * i_y_margin;
276 p_widget->i_x = p_vout->render.i_width - i_x_margin -
278 p_widget->i_y = i_y_margin;
281 /* Create subpicture region and picture */
282 CreatePicture( p_vout, p_subpic );
284 if( i_type == OSD_HOR_SLIDER )
286 int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
287 DrawRect( p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
288 p_widget->i_height - 3, STYLE_FILLED );
289 DrawRect( p_subpic, 0, 0, p_widget->i_width - 1,
290 p_widget->i_height - 1, STYLE_EMPTY );
292 else if( i_type == OSD_VERT_SLIDER )
294 int i_y_pos = p_widget->i_height / 2;
295 DrawRect( p_subpic, 2, p_widget->i_height -
296 ( p_widget->i_height - 2 ) * i_position / 100,
297 p_widget->i_width - 3, p_widget->i_height - 3,
299 DrawRect( p_subpic, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );
300 DrawRect( p_subpic, p_widget->i_width - 2, i_y_pos,
301 p_widget->i_width - 2, i_y_pos, STYLE_FILLED );
302 DrawRect( p_subpic, 0, 0, p_widget->i_width - 1,
303 p_widget->i_height - 1, STYLE_EMPTY );
306 spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
308 vlc_object_release( p_vout );
312 /*****************************************************************************
313 * Displays an OSD icon.
314 * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
315 *****************************************************************************/
316 void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type )
318 vout_thread_t *p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT,
320 subpicture_t *p_subpic;
321 subpicture_sys_t *p_widget;
322 int i_x_margin, i_y_margin;
324 if( p_vout == NULL || !config_GetInt( p_caller, "osd" ) )
329 p_subpic = vout_CreateWidget( p_vout, i_channel );
330 if( p_subpic == NULL )
334 p_widget = p_subpic->p_sys;
336 i_y_margin = p_vout->render.i_height / 15;
337 i_x_margin = i_y_margin;
338 p_widget->i_width = p_vout->render.i_width / 20;
339 p_widget->i_height = p_widget->i_width;
340 p_widget->i_x = p_vout->render.i_width - i_x_margin -
342 p_widget->i_y = i_y_margin;
344 /* Create subpicture region and picture */
345 CreatePicture( p_vout, p_subpic );
347 if( i_type == OSD_PAUSE_ICON )
349 int i_bar_width = p_widget->i_width / 3;
350 DrawRect( p_subpic, 0, 0, i_bar_width - 1,
351 p_widget->i_height - 1, STYLE_FILLED );
352 DrawRect( p_subpic, p_widget->i_width - i_bar_width, 0,
353 p_widget->i_width - 1, p_widget->i_height - 1, STYLE_FILLED );
355 else if( i_type == OSD_PLAY_ICON )
357 int i_mid = p_widget->i_height >> 1;
358 int i_delta = ( p_widget->i_width - i_mid ) >> 1;
359 int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
360 DrawTriangle( p_subpic, i_delta, 0, p_widget->i_width - i_delta, i_y2,
363 else if( i_type == OSD_SPEAKER_ICON || i_type == OSD_MUTE_ICON )
365 int i_mid = p_widget->i_height >> 1;
366 int i_delta = ( p_widget->i_width - i_mid ) >> 1;
367 int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
368 DrawRect( p_subpic, i_delta, i_mid / 2, p_widget->i_width - i_delta,
369 p_widget->i_height - 1 - i_mid / 2, STYLE_FILLED );
370 DrawTriangle( p_subpic, p_widget->i_width - i_delta, 0, i_delta, i_y2,
372 if( i_type == OSD_MUTE_ICON )
374 uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
375 int i_pitch = p_subpic->p_region->picture.Y_PITCH;
377 for( i = 1; i < i_pitch; i++ )
379 int k = i + ( p_widget->i_height - i - 1 ) * i_pitch;
380 p_a[ k ] = 0xff - p_a[ k ];
385 spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
387 vlc_object_release( p_vout );
394 static void FreeWidget( subpicture_t *p_subpic )
396 subpicture_sys_t *p_widget = p_subpic->p_sys;
398 if( p_subpic->p_sys == NULL ) return;