]> git.sesse.net Git - vlc/blob - src/video_output/video_widgets.c
* src/video_output/video_widgets.c: Added OSD sliders when changing volume or positio...
[vlc] / src / video_output / video_widgets.c
1 /*****************************************************************************
2  * video_widgets.c : widgets manipulation functions
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
5  * $Id:$
6  *
7  * Author: Yoann Peronneau <yoann@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                                /* free() */
28 #include <vlc/vout.h>
29 #include <osd.h>
30
31 #define RECT_EMPTY 0
32 #define RECT_FILLED 1
33
34 /*****************************************************************************
35  * Local prototypes
36  *****************************************************************************/
37 static void DrawRect  ( vout_thread_t *, subpicture_t *, int, int, int, int,
38                         short );
39 static void Render    ( vout_thread_t *, picture_t *, const subpicture_t * );
40 static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
41                         int );
42 static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
43                         int );
44 static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
45                         int );
46 static void FreeWidget( subpicture_t * );
47
48 /**
49  * Private data in a subpicture.
50  */
51 struct subpicture_sys_t
52 {
53     int     i_x;
54     int     i_y;
55     int     i_width;
56     int     i_height;
57     uint8_t *p_pic;
58 };
59
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 )
66 {
67     int x, y;
68     subpicture_sys_t *p_widget = p_subpic->p_sys;
69
70     if( fill == RECT_FILLED )
71     {
72         for( y = i_y1; y <= i_y2; y++ )
73         {
74             for( x = i_x1; x <= i_x2; x++ )
75             {
76                 p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
77             }
78         }
79     }
80     else
81     {
82         for( y = i_y1; y <= i_y2; y++ )
83         {
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;
86         }
87         for( x = i_x1; x <= i_x2; x++ )
88         {
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;
91         }
92     }
93 }
94
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 )
102 {
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();
106
107     if( i_now >= i_fade_start )
108     {
109         i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
110                        ( p_subpic->i_stop - i_fade_start );
111     }
112
113     switch( p_vout->output.i_chroma )
114     {
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 );
120             break;
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 );
125             break;
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 );
129             break;
130
131         default:
132             msg_Err( p_vout, "unknown chroma, can't render SPU" );
133             break;
134     }
135 }
136
137 /**
138  * Draw a widget on a I420 (or similar) picture
139  */
140 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
141                     const subpicture_t *p_subpic, int i_fade_alpha )
142 {
143     subpicture_sys_t *p_widget = p_subpic->p_sys;
144     int i_plane, x, y, pen_x, pen_y;
145
146     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
147     {
148         uint8_t *p_in;
149         int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
150
151         p_in = p_pic->p[ i_plane ].p_pixels;
152
153         if ( i_plane == 0 )
154         {
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++ )
160             {
161                 for( x = 0; x < p_widget->i_width; x++ )
162                 {
163                     pen_y--;
164                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
165                     pen_y++; pen_x--;
166                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
167                     pen_x += 2;
168                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
169                     pen_y++; pen_x--;
170                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
171                     pen_y--;
172                 }
173             }
174             for( y = 0; y < p_widget->i_height; y++ )
175             {
176                 for( x = 0; x < p_widget->i_width; x++ )
177                 {
178                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
179                             ( 255 * alpha >> 8 );
180                  }
181              }
182 #undef alpha
183 #undef pixel
184         }
185         else
186         {
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 )
192             {
193                 for( x = 0; x < p_widget->i_width; x+=2 )
194                 {
195                     pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
196                         ( 0x80 * alpha >> 8 );
197                 }
198             }
199 #undef alpha
200 #undef pixel
201         }
202     }
203
204 }
205
206 /**
207  * Draw a widget on a YUY2 picture
208  */
209 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
210                         const subpicture_t *p_subpic, int i_fade_alpha )
211 {
212     subpicture_sys_t *p_widget = p_subpic->p_sys;
213     int x, y, pen_x, pen_y;
214     uint8_t *p_in;
215     int i_pic_pitch = p_pic->p[0].i_pitch;
216
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++ )
222     {
223         for( x = 0; x < p_widget->i_width; x++ )
224         {
225             pen_y--;
226             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
227             pen_y++; pen_x--;
228             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
229             pen_x += 2;
230             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
231             pen_y++; pen_x--;
232             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
233             pen_y--;
234         }
235     }
236     for( y = 0; y < p_widget->i_height; y++ )
237     {
238         for( x = 0; x < p_widget->i_width; x++ )
239         {
240             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
241                     ( 255 * alpha >> 8 );
242          }
243      }
244 #undef alpha
245 #undef pixel
246 }
247
248 /**
249  * Draw a widget on a RV32 picture
250  */
251 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
252                     const subpicture_t *p_subpic, int i_fade_alpha )
253 {
254     subpicture_sys_t *p_widget = p_subpic->p_sys;
255     int x, y, pen_x, pen_y;
256     uint8_t *p_in;
257     int i_pic_pitch = p_pic->p[0].i_pitch;
258
259     pen_x = p_widget->i_x;
260     pen_y = p_widget->i_y;
261
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++ )
265     {
266         for( x = 0; x < p_widget->i_width; x++ )
267         {
268             pen_y--;
269             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
270             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
271             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
272             pen_y++; pen_x--;
273             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
274             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
275             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
276             pen_x += 2;
277             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
278             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
279             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
280             pen_y++; pen_x--;
281             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
282             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
283             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
284             pen_y--;
285         }
286     }
287     for(y = 0; y < p_widget->i_height; y++ )
288     {
289         for( x = 0; x < p_widget->i_width; x++ )
290         {
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 );
297         }
298     }
299 #undef alpha
300 #undef pixel
301 }
302
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 )
308 {
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;
314
315     if( !config_GetInt( p_caller, "osd" ) || i_position < 0 ) return;
316
317     p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT, FIND_ANYWHERE );
318
319     if( p_vout )
320     {
321         p_subpic = 0;
322         p_widget = 0;
323
324         /* Create and initialize a subpicture */
325         p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
326         if( p_subpic == NULL )
327         {
328             return;
329         }
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;
335
336         p_widget = malloc( sizeof(subpicture_sys_t) );
337         if( p_widget == NULL )
338         {
339             FreeWidget( p_subpic );
340             vout_DestroySubPicture( p_vout, p_subpic );
341             return;
342         }
343         p_subpic->p_sys = p_widget;
344
345         i_y_margin = p_vout->render.i_height / 10;
346         i_x_margin = i_y_margin;
347         if( i_type == 0 )
348         {
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 -
353                             p_widget->i_height;
354         }
355         else
356         {
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 -
361                             p_widget->i_width;
362             p_widget->i_y = i_y_margin;
363         }
364
365         p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
366                                              p_widget->i_height );
367         if( p_widget->p_pic == NULL )
368         {
369             FreeWidget( p_subpic );
370             vout_DestroySubPicture( p_vout, p_subpic );
371             return;
372         }
373         memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
374
375         if( i_type == 0 )
376         {
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 );
383         }
384         else if( i_type == 1 )
385         {
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,
390                       RECT_FILLED );
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 );
396         }
397
398         vlc_mutex_lock( &p_vout->change_lock );
399
400         if( p_vout->p_last_osd_message )
401         {
402             vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
403         }
404         p_vout->p_last_osd_message = p_subpic;
405         vout_DisplaySubPicture( p_vout, p_subpic );
406
407         vlc_mutex_unlock( &p_vout->change_lock );
408
409         vlc_object_release( p_vout );
410     }
411     return;
412 }
413
414 /**
415  * Frees the widget.
416  */
417 static void FreeWidget( subpicture_t *p_subpic )
418 {
419     subpicture_sys_t *p_widget = p_subpic->p_sys;
420
421     if( p_subpic->p_sys == NULL ) return;
422
423     if( p_widget->p_pic != NULL )
424     {
425         free( p_widget->p_pic );
426     }
427     free( p_widget );
428 }