]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
Drop audio when playing faster and not using resampler.
[vlc] / src / audio_output / input.c
1 /*****************************************************************************
2  * input.c : internal management of input streams for the audio output
3  *****************************************************************************
4  * Copyright (C) 2002-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>                            /* calloc(), malloc(), free() */
32 #include <string.h>
33
34 #include <vlc_input.h>                 /* for input_thread_t and i_pts_delay */
35
36 #ifdef HAVE_ALLOCA_H
37 #   include <alloca.h>
38 #endif
39 #include <vlc_aout.h>
40
41 #include "aout_internal.h"
42
43 /** FIXME: Ugly but needed to access the counters */
44 #include "input/input_internal.h"
45
46 static void inputFailure( aout_instance_t *, aout_input_t *, const char * );
47 static void inputDrop( aout_instance_t *, aout_input_t *, aout_buffer_t * );
48 static void inputResamplingStop( aout_input_t *p_input );
49
50 static int VisualizationCallback( vlc_object_t *, char const *,
51                                   vlc_value_t, vlc_value_t, void * );
52 static int EqualizerCallback( vlc_object_t *, char const *,
53                               vlc_value_t, vlc_value_t, void * );
54
55 /*****************************************************************************
56  * aout_InputNew : allocate a new input and rework the filter pipeline
57  *****************************************************************************/
58 int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
59 {
60     audio_sample_format_t chain_input_format;
61     audio_sample_format_t chain_output_format;
62     vlc_value_t val, text;
63     char * psz_filters, *psz_visual;
64     int i_visual;
65
66     aout_FormatPrint( p_aout, "input", &p_input->input );
67
68     p_input->i_nb_resamplers = p_input->i_nb_filters = 0;
69
70     /* Prepare FIFO. */
71     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
72     p_input->p_first_byte_to_mix = NULL;
73
74     /* Prepare format structure */
75     memcpy( &chain_input_format, &p_input->input,
76             sizeof(audio_sample_format_t) );
77     memcpy( &chain_output_format, &p_aout->mixer.mixer,
78             sizeof(audio_sample_format_t) );
79     chain_output_format.i_rate = p_input->input.i_rate;
80     aout_FormatPrepare( &chain_output_format );
81
82     /* Now add user filters */
83     if( var_Type( p_aout, "visual" ) == 0 )
84     {
85         module_t *p_module;
86         var_Create( p_aout, "visual", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
87         text.psz_string = _("Visualizations");
88         var_Change( p_aout, "visual", VLC_VAR_SETTEXT, &text, NULL );
89         val.psz_string = ""; text.psz_string = _("Disable");
90         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
91         val.psz_string = "spectrometer"; text.psz_string = _("Spectrometer");
92         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
93         val.psz_string = "scope"; text.psz_string = _("Scope");
94         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
95         val.psz_string = "spectrum"; text.psz_string = _("Spectrum");
96         var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
97
98         /* Look for goom plugin */
99         p_module = config_FindModule( VLC_OBJECT(p_aout), "goom" );
100         if( p_module )
101         {
102             val.psz_string = "goom"; text.psz_string = "Goom";
103             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
104         }
105
106         /* Look for galaktos plugin */
107         p_module = config_FindModule( VLC_OBJECT(p_aout), "galaktos" );
108         if( p_module )
109         {
110             val.psz_string = "galaktos"; text.psz_string = "GaLaktos";
111             var_Change( p_aout, "visual", VLC_VAR_ADDCHOICE, &val, &text );
112         }
113
114         if( var_Get( p_aout, "effect-list", &val ) == VLC_SUCCESS )
115         {
116             var_Set( p_aout, "visual", val );
117             if( val.psz_string ) free( val.psz_string );
118         }
119         var_AddCallback( p_aout, "visual", VisualizationCallback, NULL );
120     }
121
122     if( var_Type( p_aout, "equalizer" ) == 0 )
123     {
124         module_config_t *p_config;
125         int i;
126
127         p_config = config_FindConfig( VLC_OBJECT(p_aout), "equalizer-preset" );
128         if( p_config && p_config->i_list )
129         {
130                var_Create( p_aout, "equalizer",
131                            VLC_VAR_STRING | VLC_VAR_HASCHOICE );
132             text.psz_string = _("Equalizer");
133             var_Change( p_aout, "equalizer", VLC_VAR_SETTEXT, &text, NULL );
134
135             val.psz_string = ""; text.psz_string = _("Disable");
136             var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE, &val, &text );
137
138             for( i = 0; i < p_config->i_list; i++ )
139             {
140                 val.psz_string = (char *)p_config->ppsz_list[i];
141                 text.psz_string = (char *)p_config->ppsz_list_text[i];
142                 var_Change( p_aout, "equalizer", VLC_VAR_ADDCHOICE,
143                             &val, &text );
144             }
145
146             var_AddCallback( p_aout, "equalizer", EqualizerCallback, NULL );
147         }
148     }
149
150     if( var_Type( p_aout, "audio-filter" ) == 0 )
151     {
152         var_Create( p_aout, "audio-filter",
153                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
154         text.psz_string = _("Audio filters");
155         var_Change( p_aout, "audio-filter", VLC_VAR_SETTEXT, &text, NULL );
156     }
157     if( var_Type( p_aout, "audio-visual" ) == 0 )
158     {
159         var_Create( p_aout, "audio-visual",
160                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
161         text.psz_string = _("Audio visualizations");
162         var_Change( p_aout, "audio-visual", VLC_VAR_SETTEXT, &text, NULL );
163     }
164
165     var_Get( p_aout, "audio-filter", &val );
166     psz_filters = val.psz_string;
167     var_Get( p_aout, "audio-visual", &val );
168     psz_visual = val.psz_string;
169
170     /* parse user filter lists */
171     for( i_visual = 0; i_visual < 2; i_visual++ )
172     {
173         char *psz_next = NULL;
174         char *psz_parser = i_visual ? psz_visual : psz_filters;
175
176         if( psz_parser == NULL || !*psz_parser )
177             continue;
178
179         while( psz_parser && *psz_parser )
180         {
181             aout_filter_t * p_filter = NULL;
182
183             if( p_input->i_nb_filters >= AOUT_MAX_FILTERS )
184             {
185                 msg_Dbg( p_aout, "max filters reached (%d)", AOUT_MAX_FILTERS );
186                 break;
187             }
188
189             while( *psz_parser == ' ' && *psz_parser == ':' )
190             {
191                 psz_parser++;
192             }
193             if( ( psz_next = strchr( psz_parser , ':'  ) ) )
194             {
195                 *psz_next++ = '\0';
196             }
197             if( *psz_parser =='\0' )
198             {
199                 break;
200             }
201
202             /* Create a VLC object */
203             p_filter = vlc_object_create( p_aout, sizeof(aout_filter_t) );
204             if( p_filter == NULL )
205             {
206                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
207                          psz_parser );
208                 psz_parser = psz_next;
209                 continue;
210             }
211
212             vlc_object_attach( p_filter , p_aout );
213
214             /* try to find the requested filter */
215             if( i_visual == 1 ) /* this can only be a visualization module */
216             {
217                 /* request format */
218                 memcpy( &p_filter->input, &chain_output_format,
219                         sizeof(audio_sample_format_t) );
220                 memcpy( &p_filter->output, &chain_output_format,
221                         sizeof(audio_sample_format_t) );
222
223                 p_filter->p_module = module_Need( p_filter, "visualization",
224                                                   psz_parser, VLC_TRUE );
225             }
226             else /* this can be a audio filter module as well as a visualization module */
227             {
228                 /* request format */
229                 memcpy( &p_filter->input, &chain_input_format,
230                         sizeof(audio_sample_format_t) );
231                 memcpy( &p_filter->output, &chain_output_format,
232                         sizeof(audio_sample_format_t) );
233
234                 p_filter->p_module = module_Need( p_filter, "audio filter",
235                                               psz_parser, VLC_TRUE );
236
237                 if ( p_filter->p_module == NULL )
238                 {
239                     /* if the filter requested a special format, retry */
240                     if ( !( AOUT_FMTS_IDENTICAL( &p_filter->input,
241                                                  &chain_input_format )
242                             && AOUT_FMTS_IDENTICAL( &p_filter->output,
243                                                     &chain_output_format ) ) )
244                     {
245                         aout_FormatPrepare( &p_filter->input );
246                         aout_FormatPrepare( &p_filter->output );
247                         p_filter->p_module = module_Need( p_filter,
248                                                           "audio filter",
249                                                           psz_parser, VLC_TRUE );
250                     }
251                     /* try visual filters */
252                     else
253                     {
254                         memcpy( &p_filter->input, &chain_output_format,
255                                 sizeof(audio_sample_format_t) );
256                         memcpy( &p_filter->output, &chain_output_format,
257                                 sizeof(audio_sample_format_t) );
258                         p_filter->p_module = module_Need( p_filter,
259                                                           "visualization",
260                                                           psz_parser, VLC_TRUE );
261                     }
262                 }
263             }
264
265             /* failure */
266             if ( p_filter->p_module == NULL )
267             {
268                 msg_Err( p_aout, "cannot add user filter %s (skipped)",
269                          psz_parser );
270
271                 vlc_object_detach( p_filter );
272                 vlc_object_destroy( p_filter );
273
274                 psz_parser = psz_next;
275                 continue;
276             }
277
278             /* complete the filter chain if necessary */
279             if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &p_filter->input ) )
280             {
281                 if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
282                                                  &p_input->i_nb_filters,
283                                                  &chain_input_format,
284                                                  &p_filter->input ) < 0 )
285                 {
286                     msg_Err( p_aout, "cannot add user filter %s (skipped)",
287                              psz_parser );
288
289                     module_Unneed( p_filter, p_filter->p_module );
290                     vlc_object_detach( p_filter );
291                     vlc_object_destroy( p_filter );
292
293                     psz_parser = psz_next;
294                     continue;
295                 }
296             }
297
298             /* success */
299             p_filter->b_continuity = VLC_FALSE;
300             p_input->pp_filters[p_input->i_nb_filters++] = p_filter;
301             memcpy( &chain_input_format, &p_filter->output,
302                     sizeof( audio_sample_format_t ) );
303
304             /* next filter if any */
305             psz_parser = psz_next;
306         }
307     }
308     if( psz_filters ) free( psz_filters );
309     if( psz_visual ) free( psz_visual );
310
311     /* complete the filter chain if necessary */
312     if ( !AOUT_FMTS_IDENTICAL( &chain_input_format, &chain_output_format ) )
313     {
314         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
315                                          &p_input->i_nb_filters,
316                                          &chain_input_format,
317                                          &chain_output_format ) < 0 )
318         {
319             inputFailure( p_aout, p_input, "couldn't set an input pipeline" );
320             return -1;
321         }
322     }
323
324     /* Prepare hints for the buffer allocator. */
325     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
326     p_input->input_alloc.i_bytes_per_sec = -1;
327
328     /* Create resamplers. */
329     if ( !AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
330     {
331         chain_output_format.i_rate = (__MAX(p_input->input.i_rate,
332                                             p_aout->mixer.mixer.i_rate)
333                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
334         if ( chain_output_format.i_rate == p_aout->mixer.mixer.i_rate )
335         {
336             /* Just in case... */
337             chain_output_format.i_rate++;
338         }
339         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
340                                          &p_input->i_nb_resamplers,
341                                          &chain_output_format,
342                                          &p_aout->mixer.mixer ) < 0 )
343         {
344             inputFailure( p_aout, p_input, "couldn't set a resampler pipeline");
345             return -1;
346         }
347
348         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
349                                  p_input->i_nb_resamplers,
350                                  &p_input->input_alloc );
351         p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
352
353         /* Setup the initial rate of the resampler */
354         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
355     }
356     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
357
358     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
359                              p_input->i_nb_filters,
360                              &p_input->input_alloc );
361     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
362
363     /* i_bytes_per_sec is still == -1 if no filters */
364     p_input->input_alloc.i_bytes_per_sec = __MAX(
365                                     p_input->input_alloc.i_bytes_per_sec,
366                                     (int)(p_input->input.i_bytes_per_frame
367                                      * p_input->input.i_rate
368                                      / p_input->input.i_frame_length) );
369     /* Success */
370     p_input->b_error = VLC_FALSE;
371     p_input->b_restart = VLC_FALSE;
372     p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
373
374     return 0;
375 }
376
377 /*****************************************************************************
378  * aout_InputDelete : delete an input
379  *****************************************************************************
380  * This function must be entered with the mixer lock.
381  *****************************************************************************/
382 int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
383 {
384     if ( p_input->b_error ) return 0;
385
386     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
387                                  p_input->i_nb_filters );
388     p_input->i_nb_filters = 0;
389     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
390                                  p_input->i_nb_resamplers );
391     p_input->i_nb_resamplers = 0;
392     aout_FifoDestroy( p_aout, &p_input->fifo );
393
394     return 0;
395 }
396
397 /*****************************************************************************
398  * aout_InputPlay : play a buffer
399  *****************************************************************************
400  * This function must be entered with the input lock.
401  *****************************************************************************/
402 /* XXX Do not activate it !! */
403 //#define AOUT_PROCESS_BEFORE_CHEKS
404 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
405                     aout_buffer_t * p_buffer, int i_input_rate )
406 {
407     mtime_t start_date;
408
409     if( p_input->b_restart )
410     {
411         aout_fifo_t fifo, dummy_fifo;
412         byte_t      *p_first_byte_to_mix;
413
414         vlc_mutex_lock( &p_aout->mixer_lock );
415
416         /* A little trick to avoid loosing our input fifo */
417         aout_FifoInit( p_aout, &dummy_fifo, p_aout->mixer.mixer.i_rate );
418         p_first_byte_to_mix = p_input->p_first_byte_to_mix;
419         fifo = p_input->fifo;
420         p_input->fifo = dummy_fifo;
421         aout_InputDelete( p_aout, p_input );
422         aout_InputNew( p_aout, p_input );
423         p_input->p_first_byte_to_mix = p_first_byte_to_mix;
424         p_input->fifo = fifo;
425
426         vlc_mutex_unlock( &p_aout->mixer_lock );
427     }
428
429     if( i_input_rate != INPUT_RATE_DEFAULT && p_input->i_nb_resamplers <= 0 )
430     {
431         inputDrop( p_aout, p_input, p_buffer );
432         return 0;
433     }
434
435 #ifdef AOUT_PROCESS_BEFORE_CHEKS
436     /* Run pre-filters. */
437     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
438                       &p_buffer );
439
440     /* Actually run the resampler now. */
441     if ( p_input->i_nb_resamplers > 0 )
442     {
443         const mtime_t i_date = p_buffer->start_date;
444         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
445                           p_input->i_nb_resamplers,
446                           &p_buffer );
447     }
448
449     if( p_buffer->i_nb_samples <= 0 )
450     {
451         aout_BufferFree( p_buffer );
452         return 0;
453     }
454 #endif
455
456     /* Handle input rate change by modifying resampler input rate */
457     if( i_input_rate != p_input->i_last_input_rate )
458     {
459         unsigned int * const pi_rate = &p_input->pp_resamplers[0]->input.i_rate;
460 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
461         const int i_delta = *pi_rate - F(p_input->input.i_rate,p_input->i_last_input_rate);
462         *pi_rate = F(p_input->input.i_rate + i_delta, i_input_rate);
463 #undef F
464         p_input->i_last_input_rate = i_input_rate;
465     }
466
467     /* We don't care if someone changes the start date behind our back after
468      * this. We'll deal with that when pushing the buffer, and compensate
469      * with the next incoming buffer. */
470     vlc_mutex_lock( &p_aout->input_fifos_lock );
471     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
472     vlc_mutex_unlock( &p_aout->input_fifos_lock );
473
474     if ( start_date != 0 && start_date < mdate() )
475     {
476         /* The decoder is _very_ late. This can only happen if the user
477          * pauses the stream (or if the decoder is buggy, which cannot
478          * happen :). */
479         msg_Warn( p_aout, "computed PTS is out of range ("I64Fd"), "
480                   "clearing out", mdate() - start_date );
481         vlc_mutex_lock( &p_aout->input_fifos_lock );
482         aout_FifoSet( p_aout, &p_input->fifo, 0 );
483         p_input->p_first_byte_to_mix = NULL;
484         vlc_mutex_unlock( &p_aout->input_fifos_lock );
485         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
486             msg_Warn( p_aout, "timing screwed, stopping resampling" );
487         inputResamplingStop( p_input );
488         start_date = 0;
489     }
490
491     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
492     {
493         /* The decoder gives us f*cked up PTS. It's its business, but we
494          * can't present it anyway, so drop the buffer. */
495         msg_Warn( p_aout, "PTS is out of range ("I64Fd"), dropping buffer",
496                   mdate() - p_buffer->start_date );
497
498         inputDrop( p_aout, p_input, p_buffer );
499         inputResamplingStop( p_input );
500         return 0;
501     }
502
503     /* If the audio drift is too big then it's not worth trying to resample
504      * the audio. */
505     if ( start_date != 0 &&
506          ( start_date < p_buffer->start_date - 3 * AOUT_PTS_TOLERANCE ) )
507     {
508         msg_Warn( p_aout, "audio drift is too big ("I64Fd"), clearing out",
509                   start_date - p_buffer->start_date );
510         vlc_mutex_lock( &p_aout->input_fifos_lock );
511         aout_FifoSet( p_aout, &p_input->fifo, 0 );
512         p_input->p_first_byte_to_mix = NULL;
513         vlc_mutex_unlock( &p_aout->input_fifos_lock );
514         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
515             msg_Warn( p_aout, "timing screwed, stopping resampling" );
516         inputResamplingStop( p_input );
517         start_date = 0;
518     }
519     else if ( start_date != 0 &&
520               ( start_date > p_buffer->start_date + 3 * AOUT_PTS_TOLERANCE ) )
521     {
522         msg_Warn( p_aout, "audio drift is too big ("I64Fd"), dropping buffer",
523                   start_date - p_buffer->start_date );
524         inputDrop( p_aout, p_input, p_buffer );
525         return 0;
526     }
527
528     if ( start_date == 0 ) start_date = p_buffer->start_date;
529
530 #ifndef AOUT_PROCESS_BEFORE_CHEKS
531     /* Run pre-filters. */
532     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
533                       &p_buffer );
534 #endif
535
536     /* Run the resampler if needed.
537      * We first need to calculate the output rate of this resampler. */
538     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
539          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
540            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
541          p_input->i_nb_resamplers > 0 )
542     {
543         /* Can happen in several circumstances :
544          * 1. A problem at the input (clock drift)
545          * 2. A small pause triggered by the user
546          * 3. Some delay in the output stage, causing a loss of lip
547          *    synchronization
548          * Solution : resample the buffer to avoid a scratch.
549          */
550         mtime_t drift = p_buffer->start_date - start_date;
551
552         p_input->i_resamp_start_date = mdate();
553         p_input->i_resamp_start_drift = (int)drift;
554
555         if ( drift > 0 )
556             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
557         else
558             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
559
560         msg_Warn( p_aout, "buffer is "I64Fd" %s, triggering %ssampling",
561                           drift > 0 ? drift : -drift,
562                           drift > 0 ? "in advance" : "late",
563                           drift > 0 ? "down" : "up");
564     }
565
566     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
567     {
568         /* Resampling has been triggered previously (because of dates
569          * mismatch). We want the resampling to happen progressively so
570          * it isn't too audible to the listener. */
571
572         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
573         {
574             p_input->pp_resamplers[0]->input.i_rate += 2; /* Hz */
575         }
576         else
577         {
578             p_input->pp_resamplers[0]->input.i_rate -= 2; /* Hz */
579         }
580
581         /* Check if everything is back to normal, in which case we can stop the
582          * resampling */
583         if( p_input->pp_resamplers[0]->input.i_rate == 1000 * p_input->input.i_rate / i_input_rate )
584         {
585             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
586             msg_Warn( p_aout, "resampling stopped after "I64Fi" usec "
587                       "(drift: "I64Fi")",
588                       mdate() - p_input->i_resamp_start_date,
589                       p_buffer->start_date - start_date);
590         }
591         else if( abs( (int)(p_buffer->start_date - start_date) ) <
592                  abs( p_input->i_resamp_start_drift ) / 2 )
593         {
594             /* if we reduced the drift from half, then it is time to switch
595              * back the resampling direction. */
596             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
597                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
598             else
599                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
600             p_input->i_resamp_start_drift = 0;
601         }
602         else if( p_input->i_resamp_start_drift &&
603                  ( abs( (int)(p_buffer->start_date - start_date) ) >
604                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
605         {
606             /* If the drift is increasing and not decreasing, than something
607              * is bad. We'd better stop the resampling right now. */
608             msg_Warn( p_aout, "timing screwed, stopping resampling" );
609             inputResamplingStop( p_input );
610         }
611     }
612
613 #ifndef AOUT_PROCESS_BEFORE_CHEKS
614     /* Actually run the resampler now. */
615     if ( p_input->i_nb_resamplers > 0 )
616     {
617         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
618                           p_input->i_nb_resamplers,
619                           &p_buffer );
620     }
621
622     if( p_buffer->i_nb_samples <= 0 )
623     {
624         aout_BufferFree( p_buffer );
625         return 0;
626     }
627 #endif
628
629     /* Adding the start date will be managed by aout_FifoPush(). */
630     p_buffer->end_date = start_date +
631         (p_buffer->end_date - p_buffer->start_date);
632     p_buffer->start_date = start_date;
633
634     vlc_mutex_lock( &p_aout->input_fifos_lock );
635     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
636     vlc_mutex_unlock( &p_aout->input_fifos_lock );
637     return 0;
638 }
639
640 /*****************************************************************************
641  * static functions
642  *****************************************************************************/
643
644 static void inputFailure( aout_instance_t * p_aout, aout_input_t * p_input,
645                           const char * psz_error_message )
646 {
647     /* error message */
648     msg_Err( p_aout, "%s", psz_error_message );
649
650     /* clean up */
651     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
652                                  p_input->i_nb_filters );
653     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
654                                  p_input->i_nb_resamplers );
655     aout_FifoDestroy( p_aout, &p_input->fifo );
656     var_Destroy( p_aout, "visual" );
657     var_Destroy( p_aout, "equalizer" );
658     var_Destroy( p_aout, "audio-filter" );
659     var_Destroy( p_aout, "audio-visual" );
660
661     /* error flag */
662     p_input->b_error = 1;
663 }
664
665 static void inputDrop( aout_instance_t *p_aout, aout_input_t *p_input, aout_buffer_t *p_buffer )
666 {
667     aout_BufferFree( p_buffer );
668
669     if( !p_input->p_input_thread )
670         return;
671
672     vlc_mutex_lock( &p_input->p_input_thread->p->counters.counters_lock);
673     stats_UpdateInteger( p_aout, p_input->p_input_thread->p->counters.p_lost_abuffers, 1, NULL );
674     vlc_mutex_unlock( &p_input->p_input_thread->p->counters.counters_lock);
675 }
676
677 static void inputResamplingStop( aout_input_t *p_input )
678 {
679     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
680     if( p_input->i_nb_resamplers != 0 )
681     {
682         p_input->pp_resamplers[0]->input.i_rate = INPUT_RATE_DEFAULT *
683                             p_input->input.i_rate / p_input->i_last_input_rate;
684         p_input->pp_resamplers[0]->b_continuity = VLC_FALSE;
685     }
686 }
687
688 static int ChangeFiltersString( aout_instance_t * p_aout, const char* psz_variable,
689                                  const char *psz_name, vlc_bool_t b_add )
690 {
691     vlc_value_t val;
692     char *psz_parser;
693
694     var_Get( p_aout, psz_variable, &val );
695
696     if( !val.psz_string ) val.psz_string = strdup("");
697
698     psz_parser = strstr( val.psz_string, psz_name );
699
700     if( b_add )
701     {
702         if( !psz_parser )
703         {
704             psz_parser = val.psz_string;
705             asprintf( &val.psz_string, (*val.psz_string) ? "%s:%s" : "%s%s",
706                       val.psz_string, psz_name );
707             free( psz_parser );
708         }
709         else
710         {
711             return 0;
712         }
713     }
714     else
715     {
716         if( psz_parser )
717         {
718             memmove( psz_parser, psz_parser + strlen(psz_name) +
719                      (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
720                      strlen(psz_parser + strlen(psz_name)) + 1 );
721         }
722         else
723         {
724             free( val.psz_string );
725             return 0;
726         }
727     }
728
729     var_Set( p_aout, psz_variable, val );
730     free( val.psz_string );
731     return 1;
732 }
733
734 static int VisualizationCallback( vlc_object_t *p_this, char const *psz_cmd,
735                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
736 {
737     aout_instance_t *p_aout = (aout_instance_t *)p_this;
738     char *psz_mode = newval.psz_string;
739     vlc_value_t val;
740     int i;
741     (void)psz_cmd; (void)oldval; (void)p_data;
742
743     if( !psz_mode || !*psz_mode )
744     {
745         ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
746         ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
747         ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE );
748     }
749     else
750     {
751         if( !strcmp( "goom", psz_mode ) )
752         {
753             ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
754             ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_TRUE );
755             ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE);
756         }
757         else if( !strcmp( "galaktos", psz_mode ) )
758         {
759             ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_FALSE );
760             ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
761             ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_TRUE );
762         }
763         else
764         {
765             val.psz_string = psz_mode;
766             var_Create( p_aout, "effect-list", VLC_VAR_STRING );
767             var_Set( p_aout, "effect-list", val );
768
769             ChangeFiltersString( p_aout, "audio-visual", "goom", VLC_FALSE );
770             ChangeFiltersString( p_aout, "audio-visual", "visual", VLC_TRUE );
771             ChangeFiltersString( p_aout, "audio-visual", "galaktos", VLC_FALSE);
772         }
773     }
774
775     /* That sucks */
776     for( i = 0; i < p_aout->i_nb_inputs; i++ )
777     {
778         p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
779     }
780
781     return VLC_SUCCESS;
782 }
783
784 static int EqualizerCallback( vlc_object_t *p_this, char const *psz_cmd,
785                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
786 {
787     aout_instance_t *p_aout = (aout_instance_t *)p_this;
788     char *psz_mode = newval.psz_string;
789     vlc_value_t val;
790     int i;
791     int i_ret;
792     (void)psz_cmd; (void)oldval; (void)p_data;
793
794     if( !psz_mode || !*psz_mode )
795     {
796         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
797                                      VLC_FALSE );
798     }
799     else
800     {
801         val.psz_string = psz_mode;
802         var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING );
803         var_Set( p_aout, "equalizer-preset", val );
804         i_ret = ChangeFiltersString( p_aout, "audio-filter", "equalizer",
805                                      VLC_TRUE );
806
807     }
808
809     /* That sucks */
810     if( i_ret == 1 )
811     {
812         for( i = 0; i < p_aout->i_nb_inputs; i++ )
813         {
814             p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
815         }
816     }
817
818     return VLC_SUCCESS;
819 }