1 /*****************************************************************************
2 * visual.c : Visualisation system
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: visual.c,v 1.1 2003/08/19 21:20:00 zorglub 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." )
58 add_category_hint( N_("visualizer") , NULL , VLC_FALSE);
59 set_description( _("visualizer filter") );
60 add_string("effect-list", "dummy", NULL,
61 ELIST_TEXT, ELIST_LONGTEXT, VLC_TRUE );
62 add_integer("effect-width",VOUT_WIDTH,NULL,
63 WIDTH_TEXT, WIDTH_LONGTEXT, VLC_FALSE );
64 add_integer("effect-height" , VOUT_HEIGHT , NULL,
65 HEIGHT_TEXT, HEIGHT_LONGTEXT, VLC_FALSE );
66 set_capability( "audio filter", 0 );
67 set_callbacks( Open, Close );
68 add_shortcut( "visualizer");
71 /*****************************************************************************
72 * Open: open the visualizer
73 *****************************************************************************/
74 static int Open( vlc_object_t *p_this )
76 aout_filter_t *p_filter = (aout_filter_t *)p_this;
79 char *psz_eof; /* Used to parse effect list */
80 char *psz_eoa, *psz_boa; /* Used to parse arg lists */
82 vlc_bool_t b_end = VLC_FALSE;
84 visual_effect_t *p_current_effect = NULL;
86 if( (p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
87 && p_filter->input.i_format != VLC_FOURCC('f','i','3','2')) )
92 p_filter->p_sys = malloc(sizeof(struct aout_filter_sys_t));
93 if ( p_filter->p_sys == NULL )
95 msg_Err( p_filter, "out of memory" );
99 p_filter->p_sys->i_height = config_GetInt( p_filter , "effect-height");
100 p_filter->p_sys->i_width = config_GetInt( p_filter , "effect-width");
102 /* Parse the effect list */
103 psz_effects = config_GetPsz( p_filter, "effect-list" );
104 msg_Dbg( p_filter , "Building list of effects" );
106 p_filter->p_sys->p_first_effect =
107 (visual_effect_t *)malloc( sizeof( visual_effect_t ) );
108 if( !p_filter->p_sys->p_first_effect )
110 msg_Err( p_filter, "Out of memory" );
114 p_current_effect = p_filter->p_sys->p_first_effect;
115 p_current_effect->p_next = NULL;
117 #define SEARCH(name , function ) \
118 if(!strncmp( psz_effects , name, strlen(name) ) ) \
120 p_current_effect->p_next = \
121 (visual_effect_t *)malloc( sizeof( visual_effect_t ) ); \
122 if( !p_current_effect ) \
124 msg_Err( p_filter, "Out of memory" ); \
126 p_current_effect = p_current_effect -> p_next; \
127 p_current_effect->pf_run = NULL; \
128 p_current_effect->p_next = NULL; \
129 p_current_effect->i_width = p_filter->p_sys->i_width; \
130 p_current_effect->i_height = p_filter->p_sys->i_height; \
131 p_current_effect->pf_run = function ; \
132 p_current_effect->psz_args = NULL; \
133 psz_boa = strchr( psz_effects, '{' ); \
136 psz_eoa = strchr( psz_effects, '}'); \
139 msg_Err( p_filter, "Unable to parse effect list. Aborting"); \
143 p_current_effect->psz_args = strdup(++psz_boa); \
144 psz_effects = psz_eoa; \
146 msg_Dbg(p_filter, "Adding filter: %s ( %s )",name, \
147 p_current_effect->psz_args); \
152 psz_eof = strchr( psz_effects , ';' );
156 psz_eof = strchr( psz_effects,'\0');
164 SEARCH("dummy",dummy_Run);
165 SEARCH("scope",scope_Run);
166 SEARCH("random",random_Run);
167 SEARCH("spectrum",spectrum_Run);
169 psz_effects = psz_eof;
172 if( !* psz_effects || b_end == VLC_TRUE )
176 p_filter->pf_do_work = DoWork;
177 p_filter->b_in_place= 0;
179 /* Open the video output */
180 p_filter->p_sys->p_vout =
181 vout_Create( p_filter, p_filter->p_sys->i_width,
182 p_filter->p_sys->i_height,
183 VLC_FOURCC('I','4','2','0'),
184 VOUT_ASPECT_FACTOR * p_filter->p_sys->i_width/
185 p_filter->p_sys->i_height );
187 if( p_filter->p_sys->p_vout == NULL )
189 msg_Err( p_filter, "no suitable vout module" );
191 free( p_filter->p_sys );
195 msg_Dbg(p_filter,"Visualizer initialized");
199 /******************************************************************************
200 * SparseCopy: trivially downmix or upmix a buffer
201 ******************************************************************************
202 * Pasted from trivial.c *
203 *****************************************************************************/
204 static void SparseCopy( s32 * p_dest, const s32 * p_src, size_t i_len,
205 int i_output_stride, int i_input_stride )
208 for ( i = i_len; i--; )
211 for ( j = 0; j < i_output_stride; j++ )
213 p_dest[j] = p_src[j % i_input_stride];
215 p_src += i_input_stride;
216 p_dest += i_output_stride;
219 /*****************************************************************************
220 * DoWork: convert a buffer
221 *****************************************************************************
222 * Audio part pasted from trivial.c
223 ****************************************************************************/
224 static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
225 aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf )
229 visual_effect_t *p_current_effect;
231 int i_input_nb = aout_FormatNbChannels( &p_filter->input );
232 int i_output_nb = aout_FormatNbChannels( &p_filter->output );
233 s32 * p_dest = (s32 *)p_out_buf->p_buffer;
234 s32 * p_src = (s32 *)p_in_buf->p_buffer;
237 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
238 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
240 /* First, output the sound */
241 if ( (p_filter->output.i_original_channels & AOUT_CHAN_PHYSMASK)
242 != (p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK)
243 && (p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK)
244 == (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
247 /* This is a bit special. */
248 if ( !(p_filter->output.i_original_channels & AOUT_CHAN_LEFT) )
252 if ( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
255 for ( i = p_in_buf->i_nb_samples; i--; )
264 /* Fake-stereo mode */
265 for ( i = p_in_buf->i_nb_samples; i--; )
275 else if ( p_filter->output.i_original_channels
276 & AOUT_CHAN_REVERSESTEREO )
278 /* Reverse-stereo mode */
280 for ( i = p_in_buf->i_nb_samples; i--; )
291 SparseCopy( p_dest, p_src, p_in_buf->i_nb_samples, i_output_nb,
295 /* Ok, the sound is gone, we can think about our effects */
297 /* First, get a new picture */
298 while( ( p_outpic = vout_CreatePicture( p_filter->p_sys->p_vout,
299 VLC_FALSE, VLC_FALSE, 3 ) ) == NULL )
303 msleep( VOUT_OUTMEM_SLEEP );
306 /* Blank the picture */
307 for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ )
309 memset( p_outpic->p[i_index].p_pixels, i_index ? 0x80 : 0x00,
310 p_outpic->p[i_index].i_lines * p_outpic->p[i_index].i_pitch );
313 /* We can now call our visualization effects */
314 p_current_effect = p_filter->p_sys->p_first_effect;
316 while( p_current_effect )
318 /* FIXME: Find why it segfaults when we directly call
319 * p_current_effect->pf_run(....)
320 * (segfault in errno() ) */
321 if( p_current_effect->pf_run == dummy_Run )
323 dummy_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
325 else if (p_current_effect->pf_run == scope_Run )
327 scope_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
329 else if (p_current_effect->pf_run == random_Run )
331 random_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
333 else if (p_current_effect->pf_run == spectrum_Run )
335 spectrum_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
338 p_current_effect = p_current_effect->p_next;
341 vout_DatePicture ( p_filter->p_sys->p_vout, p_outpic,p_in_buf->start_date);
344 vout_DisplayPicture ( p_filter->p_sys->p_vout, p_outpic );
349 /*****************************************************************************
350 * Close: close the plugin
351 *****************************************************************************/
352 static void Close( vlc_object_t *p_this )
354 aout_filter_t * p_filter = (aout_filter_t *)p_this;
356 if( p_filter->p_sys->p_vout )
358 vlc_object_detach( p_filter->p_sys->p_vout) ;
359 vout_Destroy( p_filter->p_sys->p_vout );
362 if( p_filter->p_sys != NULL )
363 free( p_filter->p_sys);