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 $
7 * Authors: Clément Stenac <zorglub@via.ecp.fr>
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 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
34 static int Open ( vlc_object_t * );
35 static void Close ( vlc_object_t * );
37 static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
40 /*****************************************************************************
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},..." )
49 #define WIDTH_TEXT N_( "Video width" )
50 #define HEIGHT_LONGTEXT N_( \
51 "The width of the effects video window, in pixels." )
53 #define HEIGHT_TEXT N_( "Video width" )
54 #define WIDTH_LONGTEXT N_( \
55 "The width of the effects video window, in pixels." )
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 };
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");
84 /*****************************************************************************
85 * Open: open the visualizer
86 *****************************************************************************/
87 static int Open( vlc_object_t *p_this )
89 aout_filter_t *p_filter = (aout_filter_t *)p_this;
92 char *psz_eof; /* Used to parse effect list */
93 char *psz_eoa, *psz_boa; /* Used to parse arg lists */
95 vlc_bool_t b_end = VLC_FALSE;
97 visual_effect_t *p_current_effect = NULL;
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')) )
105 p_filter->p_sys = malloc(sizeof(struct aout_filter_sys_t));
106 if ( p_filter->p_sys == NULL )
108 msg_Err( p_filter, "out of memory" );
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");
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;
120 if( (p_filter->p_sys->i_height % 2 ) != 0 )
121 p_filter->p_sys->i_height --;
123 if( (p_filter->p_sys->i_width % 2 ) != 0 )
124 p_filter->p_sys->i_width --;
126 /* Parse the effect list */
127 psz_effects = config_GetPsz( p_filter, "effect-list" );
128 msg_Dbg( p_filter , "Building list of effects" );
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 )
134 msg_Err( p_filter, "Out of memory" );
138 p_current_effect = p_filter->p_sys->p_first_effect;
139 p_current_effect->p_next = NULL;
142 psz_eof = strchr( psz_effects , ';' );
146 psz_eof = strchr( psz_effects,'\0');
153 p_current_effect->p_next =
154 (visual_effect_t *)malloc( sizeof( visual_effect_t ) );
155 if( !p_current_effect )
157 msg_Err( p_filter, "Out of memory" );
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;
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;
175 else if(! strncasecmp(psz_effects,"blur",4) )
176 p_current_effect->pf_run = blur_Run;
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, '{' );
184 psz_eoa = strchr( psz_effects, '}');
187 msg_Err( p_filter, "Unable to parse effect list. Aborting");
191 p_current_effect->psz_args = strdup(++psz_boa);
192 psz_effects = psz_eoa;
194 psz_effects = psz_eof;
197 if( b_end == VLC_TRUE )
201 p_filter->pf_do_work = DoWork;
202 p_filter->b_in_place= 1;
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 );
213 if( p_filter->p_sys->p_vout == NULL )
215 msg_Err( p_filter, "no suitable vout module" );
217 free( p_filter->p_sys );
221 msg_Dbg(p_filter,"Visualizer initialized");
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 )
234 for ( i = i_len; i--; )
237 for ( j = 0; j < i_output_stride; j++ )
239 p_dest[j] = p_src[j % i_input_stride];
241 p_src += i_input_stride;
242 p_dest += i_output_stride;
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 )
255 visual_effect_t *p_current_effect;
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;
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;
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) )
273 /* This is a bit special. */
274 if ( !(p_filter->output.i_original_channels & AOUT_CHAN_LEFT) )
278 if ( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
281 for ( i = p_in_buf->i_nb_samples; i--; )
290 /* Fake-stereo mode */
291 for ( i = p_in_buf->i_nb_samples; i--; )
301 else if ( p_filter->output.i_original_channels
302 & AOUT_CHAN_REVERSESTEREO )
304 /* Reverse-stereo mode */
306 for ( i = p_in_buf->i_nb_samples; i--; )
317 SparseCopy( p_dest, p_src, p_in_buf->i_nb_samples, i_output_nb,
321 /* Ok, the sound is gone, we can think about our effects */
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 )
332 /* Blank the picture */
333 for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ )
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 );
339 /* We can now call our visualization effects */
340 p_current_effect = p_filter->p_sys->p_first_effect;
342 while( p_current_effect )
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 )
351 dummy_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
353 else if (p_current_effect->pf_run == scope_Run )
355 scope_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
357 else if (p_current_effect->pf_run == random_Run )
359 random_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
361 else if (p_current_effect->pf_run == spectrum_Run )
363 spectrum_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
366 else if (p_current_effect->pf_run == blur_Run )
368 blur_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
372 p_current_effect->pf_run(p_current_effect, p_aout, p_out_buf , p_outpic );
374 p_current_effect = p_current_effect->p_next;
377 vout_DatePicture ( p_filter->p_sys->p_vout, p_outpic,p_in_buf->start_date);
380 vout_DisplayPicture ( p_filter->p_sys->p_vout, p_outpic );
384 /*****************************************************************************
385 * Close: close the plugin
386 *****************************************************************************/
387 static void Close( vlc_object_t *p_this )
389 aout_filter_t * p_filter = (aout_filter_t *)p_this;
391 visual_effect_t *p_old;
392 visual_effect_t *p_cur = p_filter->p_sys->p_first_effect;
394 if( p_filter->p_sys->p_vout )
396 vlc_object_detach( p_filter->p_sys->p_vout) ;
397 vout_Destroy( p_filter->p_sys->p_vout );
404 p_cur = p_cur->p_next;
405 if( p_old ) free( p_old );
408 if( p_filter->p_sys != NULL )
409 free( p_filter->p_sys);