]> git.sesse.net Git - vlc/blob - src/video_output/video_widgets.c
* Fixed the YUY2 and RV Render() of the OSD widgets.
[vlc] / src / video_output / video_widgets.c
1 /*****************************************************************************
2  * video_widgets.c : widgets manipulation functions
3  *****************************************************************************
4  * Copyright (C) 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 = p_pic->p[ i_plane ].p_pixels;
149         int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
150
151         if ( i_plane == 0 )
152         {
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++ )
158             {
159                 for( x = 0; x < p_widget->i_width; x++ )
160                 {
161                     pen_y--;
162                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
163                     pen_y++; pen_x--;
164                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
165                     pen_x += 2;
166                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
167                     pen_y++; pen_x--;
168                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
169                     pen_y--;
170                 }
171             }
172             for( y = 0; y < p_widget->i_height; y++ )
173             {
174                 for( x = 0; x < p_widget->i_width; x++ )
175                 {
176                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
177                             ( 255 * alpha >> 8 );
178                  }
179              }
180 #undef alpha
181 #undef pixel
182         }
183         else
184         {
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 )
190             {
191                 for( x = 0; x < p_widget->i_width; x+=2 )
192                 {
193                     pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
194                         ( 0x80 * alpha >> 8 );
195                 }
196             }
197 #undef alpha
198 #undef pixel
199         }
200     }
201
202 }
203
204 /**
205  * Draw a widget on a YUY2 picture
206  */
207 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
208                         const subpicture_t *p_subpic, int i_fade_alpha )
209 {
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;
214
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++ )
220     {
221         for( x = 0; x < p_widget->i_width; x++ )
222         {
223             pen_y--;
224             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
225             pen_y++; pen_x--;
226             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
227             pen_x += 2;
228             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
229             pen_y++; pen_x--;
230             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
231             pen_y--;
232         }
233     }
234     for( y = 0; y < p_widget->i_height; y++ )
235     {
236         for( x = 0; x < p_widget->i_width; x++ )
237         {
238             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
239                     ( 255 * alpha >> 8 );
240          }
241      }
242 #undef alpha
243 #undef pixel
244 }
245
246 /**
247  * Draw a widget on a RV32 picture
248  */
249 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
250                     const subpicture_t *p_subpic, int i_fade_alpha )
251 {
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;
256
257     pen_x = p_widget->i_x;
258     pen_y = p_widget->i_y;
259
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++ )
263     {
264         for( x = 0; x < p_widget->i_width; x++ )
265         {
266             pen_y--;
267             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
268             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
269             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
270             pen_y++; pen_x--;
271             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
272             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
273             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
274             pen_x += 2;
275             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
276             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
277             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
278             pen_y++; pen_x--;
279             pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
280             pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
281             pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
282             pen_y--;
283         }
284     }
285     for(y = 0; y < p_widget->i_height; y++ )
286     {
287         for( x = 0; x < p_widget->i_width; x++ )
288         {
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 );
295         }
296     }
297 #undef alpha
298 #undef pixel
299 }
300
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 )
306 {
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;
312
313     if( !config_GetInt( p_caller, "osd" ) || i_position < 0 ) return;
314
315     p_vout = vlc_object_find( p_caller, VLC_OBJECT_VOUT, FIND_ANYWHERE );
316
317     if( p_vout )
318     {
319         p_subpic = 0;
320         p_widget = 0;
321
322         /* Create and initialize a subpicture */
323         p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
324         if( p_subpic == NULL )
325         {
326             return;
327         }
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;
333
334         p_widget = malloc( sizeof(subpicture_sys_t) );
335         if( p_widget == NULL )
336         {
337             FreeWidget( p_subpic );
338             vout_DestroySubPicture( p_vout, p_subpic );
339             return;
340         }
341         p_subpic->p_sys = p_widget;
342
343         i_y_margin = p_vout->render.i_height / 10;
344         i_x_margin = i_y_margin;
345         if( i_type == 0 )
346         {
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 -
351                             p_widget->i_height;
352         }
353         else
354         {
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 -
359                             p_widget->i_width;
360             p_widget->i_y = i_y_margin;
361         }
362
363         p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
364                                              p_widget->i_height );
365         if( p_widget->p_pic == NULL )
366         {
367             FreeWidget( p_subpic );
368             vout_DestroySubPicture( p_vout, p_subpic );
369             return;
370         }
371         memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
372
373         if( i_type == 0 )
374         {
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 );
381         }
382         else if( i_type == 1 )
383         {
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,
388                       RECT_FILLED );
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 );
394         }
395
396         vlc_mutex_lock( &p_vout->change_lock );
397
398         if( p_vout->p_last_osd_message )
399         {
400             vout_DestroySubPicture( p_vout, p_vout->p_last_osd_message );
401         }
402         p_vout->p_last_osd_message = p_subpic;
403         vout_DisplaySubPicture( p_vout, p_subpic );
404
405         vlc_mutex_unlock( &p_vout->change_lock );
406
407         vlc_object_release( p_vout );
408     }
409     return;
410 }
411
412 /**
413  * Frees the widget.
414  */
415 static void FreeWidget( subpicture_t *p_subpic )
416 {
417     subpicture_sys_t *p_widget = p_subpic->p_sys;
418
419     if( p_subpic->p_sys == NULL ) return;
420
421     if( p_widget->p_pic != NULL )
422     {
423         free( p_widget->p_pic );
424     }
425     free( p_widget );
426 }