]> git.sesse.net Git - vlc/blob - modules/visualization/visual/visual.c
use the configuration system, that is what it is there for
[vlc] / modules / visualization / visual / visual.c
1 /*****************************************************************************
2  * visual.c : Visualisation system
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: visual.c,v 1.3 2003/09/02 22:06:51 sigmunau Exp $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@via.ecp.fr>
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 "visual.h"
28
29 #include <vlc/vlc.h>
30
31 /*****************************************************************************
32  * Local prototypes
33  *****************************************************************************/
34 static int  Open         ( vlc_object_t * );             
35 static void Close        ( vlc_object_t * );                   
36
37 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
38                                         aout_buffer_t * );
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43 #define ELIST_TEXT N_( "Effects list" )
44 #define ELIST_LONGTEXT N_( \
45       "A list of visual effect, separated by semi-commas." \
46       "Arguments may be passed to effects using syntax " \
47       " effect={arg=val,arg=val};effect={arg=val,arg=val},..." )
48
49 #define WIDTH_TEXT N_( "Video width" )
50 #define HEIGHT_LONGTEXT N_( \
51       "The width of the effects video window, in pixels." )
52
53 #define HEIGHT_TEXT N_( "Video width" )
54 #define WIDTH_LONGTEXT N_( \
55       "The width of the effects video window, in pixels." )
56
57 #define NB_TEXT N_( "Number of bands" )
58 #define NB_LONGTEXT N_( \
59       "Number of bands used by spectrum analizer, should be 20 or 80" )
60 static char *effect_list[] = { "dummy", "random", "scope", "spectrum", NULL };
61
62 vlc_module_begin();
63     add_category_hint( N_("visualizer") , NULL , VLC_FALSE);
64     set_description( _("visualizer filter") ); 
65     add_string_from_list("effect-list", "dummy", effect_list, NULL,
66             ELIST_TEXT, ELIST_LONGTEXT, VLC_TRUE );
67     add_integer("effect-width",VOUT_WIDTH,NULL,
68              WIDTH_TEXT, WIDTH_LONGTEXT, VLC_FALSE );
69     add_integer("effect-height" , VOUT_HEIGHT , NULL,
70              HEIGHT_TEXT, HEIGHT_LONGTEXT, VLC_FALSE );
71     add_integer("visual-nb", 80, NULL,
72              NB_TEXT, NB_LONGTEXT, VLC_FALSE );
73     add_integer("visual-separ", 1, NULL,
74              NB_TEXT, NB_LONGTEXT, VLC_FALSE );
75     add_integer("visual-amp", 3, NULL,
76              NB_TEXT, NB_LONGTEXT, VLC_FALSE );
77     add_bool("visual-peaks", VLC_TRUE, NULL,
78              NB_TEXT, NB_LONGTEXT, VLC_FALSE );
79     set_capability( "audio filter", 0 );
80     set_callbacks( Open, Close );
81     add_shortcut( "visualizer");
82 vlc_module_end();
83
84 /*****************************************************************************
85  * Open: open the visualizer
86  *****************************************************************************/
87 static int Open( vlc_object_t *p_this )
88 {
89     aout_filter_t *p_filter = (aout_filter_t *)p_this;
90
91     char *psz_effects;
92     char  *psz_eof; /* Used to parse effect list */
93     char *psz_eoa, *psz_boa;     /* Used to parse arg lists */
94      
95     vlc_bool_t b_end = VLC_FALSE;
96     
97     visual_effect_t *p_current_effect = NULL;
98
99     if(  (p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
100           && p_filter->input.i_format != VLC_FOURCC('f','i','3','2')) )
101     {
102             return -1;
103     }
104
105     p_filter->p_sys = malloc(sizeof(struct aout_filter_sys_t));
106     if ( p_filter->p_sys == NULL )
107     {
108         msg_Err( p_filter, "out of memory" );
109         return -1;
110     }
111
112     p_filter->p_sys->i_height = config_GetInt( p_filter , "effect-height");
113     p_filter->p_sys->i_width  = config_GetInt( p_filter , "effect-width");
114
115     if ( p_filter->p_sys->i_height < 20 ) 
116         p_filter->p_sys->i_height =  20;
117     if ( p_filter->p_sys->i_width < 20 ) 
118         p_filter->p_sys->i_width =  20;
119     
120     if( (p_filter->p_sys->i_height % 2 ) != 0 )
121         p_filter->p_sys->i_height --;
122    
123     if( (p_filter->p_sys->i_width % 2 ) != 0 )
124         p_filter->p_sys->i_width --;
125     
126     /* Parse the effect list */
127     psz_effects = config_GetPsz( p_filter, "effect-list" );
128     msg_Dbg( p_filter , "Building list of effects" );
129     
130     p_filter->p_sys->p_first_effect = 
131             (visual_effect_t *)malloc( sizeof( visual_effect_t ) );
132     if( !p_filter->p_sys->p_first_effect ) 
133     {
134         msg_Err( p_filter, "Out of memory" );
135         return -1;
136     }
137
138     p_current_effect = p_filter->p_sys->p_first_effect;
139     p_current_effect->p_next = NULL;
140     while(1)
141     {
142         psz_eof = strchr( psz_effects , ';'  );
143         if( !psz_eof )
144         {
145             b_end = VLC_TRUE;
146             psz_eof = strchr( psz_effects,'\0');
147         }
148         if( psz_eof )
149         {
150             *psz_eof = '\0';
151         }
152
153         p_current_effect->p_next =
154                 (visual_effect_t *)malloc( sizeof( visual_effect_t ) );
155         if( !p_current_effect )
156         {
157             msg_Err( p_filter, "Out of memory" );
158         }
159         p_current_effect = p_current_effect -> p_next;
160         p_current_effect->pf_run = NULL;
161         p_current_effect->p_next = NULL;
162         p_current_effect->i_width = p_filter->p_sys->i_width;
163         p_current_effect->i_height = p_filter->p_sys->i_height;
164         p_current_effect->p_data = NULL;
165
166         if(! strncasecmp(psz_effects,"dummy",5))
167             p_current_effect->pf_run = dummy_Run;
168         else if(! strncasecmp(psz_effects,"scope",5) )
169             p_current_effect->pf_run = scope_Run;
170         else if(! strncasecmp(psz_effects,"spectrum",8) )
171             p_current_effect->pf_run = spectrum_Run;
172         else if(! strncasecmp(psz_effects,"random",6) )
173             p_current_effect->pf_run = random_Run;
174 #if 0
175         else if(! strncasecmp(psz_effects,"blur",4) )
176             p_current_effect->pf_run = blur_Run;
177 #endif
178         p_current_effect->psz_args  = NULL;
179         p_current_effect->i_nb_chans =
180                 aout_FormatNbChannels( &p_filter->input);
181         psz_boa = strchr( psz_effects, '{' );
182         if( psz_boa )
183         {
184             psz_eoa = strchr( psz_effects, '}');
185             if( ! psz_eoa )
186             {
187                msg_Err( p_filter, "Unable to parse effect list. Aborting");
188                return -1;
189             }
190             *psz_eoa = '\0';
191             p_current_effect->psz_args = strdup(++psz_boa);
192             psz_effects = psz_eoa;
193         }
194         psz_effects =  psz_eof;
195         psz_effects ++;
196
197         if( b_end == VLC_TRUE )
198             break;
199     }
200                 
201     p_filter->pf_do_work = DoWork;
202     p_filter->b_in_place= 1;
203
204     /* Open the video output */
205     p_filter->p_sys->p_vout =
206          vout_Request( p_filter, NULL,
207                          p_filter->p_sys->i_width, 
208                          p_filter->p_sys->i_height,
209                   VLC_FOURCC('I','4','2','0'), 
210                   VOUT_ASPECT_FACTOR * p_filter->p_sys->i_width/
211                   p_filter->p_sys->i_height  );        
212     
213     if( p_filter->p_sys->p_vout == NULL )
214     {
215         msg_Err( p_filter, "no suitable vout module" );
216         if(p_filter->p_sys)
217             free( p_filter->p_sys );
218         return -1;
219     }
220             
221     msg_Dbg(p_filter,"Visualizer initialized");
222     return 0 ;
223 }
224
225 /******************************************************************************
226  * SparseCopy: trivially downmix or upmix a buffer
227  ******************************************************************************
228  * Pasted from trivial.c                                                      *
229  *****************************************************************************/
230 static void SparseCopy( s32 * p_dest, const s32 * p_src, size_t i_len,
231                         int i_output_stride, int i_input_stride )
232 {
233     int i;
234     for ( i = i_len; i--; )
235     {
236         int j;
237         for ( j = 0; j < i_output_stride; j++ )
238         {
239             p_dest[j] = p_src[j % i_input_stride];
240         }
241         p_src += i_input_stride;
242         p_dest += i_output_stride;
243     }
244 }
245 /*****************************************************************************
246  * DoWork: convert a buffer
247  *****************************************************************************
248  * Audio part pasted from trivial.c
249  ****************************************************************************/
250 static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
251                     aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf )
252 {
253     picture_t *p_outpic;
254        
255     visual_effect_t *p_current_effect;
256     
257     int i_input_nb = aout_FormatNbChannels( &p_filter->input );
258     int i_output_nb = aout_FormatNbChannels( &p_filter->output );
259     s32 * p_dest = (s32 *)p_out_buf->p_buffer;
260     s32 * p_src = (s32 *)p_in_buf->p_buffer;
261     int i_index;
262         
263     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
264     p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
265
266     /* First, output the sound */
267     if ( (p_filter->output.i_original_channels & AOUT_CHAN_PHYSMASK)
268          != (p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK)
269          && (p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK)
270            == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
271     {
272         int i;
273         /* This is a bit special. */
274         if ( !(p_filter->output.i_original_channels & AOUT_CHAN_LEFT) )
275         {
276              p_src++;
277         }
278         if ( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
279         {
280             /* Mono mode */
281             for ( i = p_in_buf->i_nb_samples; i--; )
282             {
283                 *p_dest = *p_src;
284                 p_dest++;
285                 p_src += 2;
286             }
287         }
288         else
289         {
290             /* Fake-stereo mode */
291             for ( i = p_in_buf->i_nb_samples; i--; )
292             {
293                 *p_dest = *p_src;
294                 p_dest++;
295                 *p_dest = *p_src;
296                 p_dest++;
297                 p_src += 2;
298             }
299         }
300     }
301     else if ( p_filter->output.i_original_channels
302              & AOUT_CHAN_REVERSESTEREO )
303     {
304         /* Reverse-stereo mode */
305         int i;
306         for ( i = p_in_buf->i_nb_samples; i--; )
307         {
308             *p_dest = p_src[1];
309             p_dest++;
310             *p_dest = p_src[0];
311             p_dest++;
312             p_src += 2;
313         }
314     }
315     else
316     {
317         SparseCopy( p_dest, p_src, p_in_buf->i_nb_samples, i_output_nb,
318                             i_input_nb );
319     }
320
321     /* Ok, the sound is gone, we can think about our effects */
322     
323     /* First, get a new picture */
324     while( ( p_outpic = vout_CreatePicture( p_filter->p_sys->p_vout,
325               VLC_FALSE, VLC_FALSE, 3  ) ) == NULL )
326     {
327             if(p_aout->b_die )
328                return;
329             msleep( 2 );
330     }
331
332     /* Blank the picture */
333     for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ )
334     {
335         memset( p_outpic->p[i_index].p_pixels, i_index ? 0x80 : 0x00,
336                 p_outpic->p[i_index].i_lines * p_outpic->p[i_index].i_pitch );
337     }
338
339     /* We can now call our visualization effects */
340     p_current_effect = p_filter->p_sys->p_first_effect;
341
342     while( p_current_effect )  
343     {
344
345 #if 1
346         /* FIXME: Find why it segfaults when we directly call
347          * p_current_effect->pf_run(....)
348          *  (segfault in errno()  ) */
349         if( p_current_effect->pf_run == dummy_Run )
350         {
351             dummy_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
352         }
353         else if (p_current_effect->pf_run == scope_Run )
354         {
355             scope_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
356         }
357         else if (p_current_effect->pf_run == random_Run )
358         {
359             random_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
360         }
361         else if (p_current_effect->pf_run == spectrum_Run )
362         {
363             spectrum_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
364         }
365 #if 0
366         else if (p_current_effect->pf_run == blur_Run )
367         {
368             blur_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
369         }
370 #endif
371 #else
372         p_current_effect->pf_run(p_current_effect, p_aout, p_out_buf , p_outpic );
373 #endif
374         p_current_effect = p_current_effect->p_next;
375     }
376    
377     vout_DatePicture ( p_filter->p_sys->p_vout, p_outpic,p_in_buf->start_date);
378     
379     
380     vout_DisplayPicture ( p_filter->p_sys->p_vout, p_outpic );
381
382 }
383
384 /*****************************************************************************
385  * Close: close the plugin
386  *****************************************************************************/
387 static void Close( vlc_object_t *p_this )
388 {
389     aout_filter_t * p_filter = (aout_filter_t *)p_this;
390
391     visual_effect_t *p_old;
392     visual_effect_t *p_cur = p_filter->p_sys->p_first_effect;
393     
394     if( p_filter->p_sys->p_vout ) 
395     {
396         vlc_object_detach( p_filter->p_sys->p_vout) ;
397         vout_Destroy( p_filter->p_sys->p_vout );
398     }
399    
400     /* Free the list */ 
401     while( p_cur )
402     {
403         p_old = p_cur;
404         p_cur = p_cur->p_next;
405         if( p_old ) free( p_old );
406     }
407                     
408     if( p_filter->p_sys != NULL )
409         free( p_filter->p_sys);
410 }