]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
* ./debian/woody-buildpackage: finished Woody build script.
[vlc] / src / audio_output / input.c
1 /*****************************************************************************
2  * input.c : internal management of input streams for the audio output
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: input.c,v 1.31 2003/01/26 13:37:09 gbazin Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                            /* calloc(), malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31
32 #ifdef HAVE_ALLOCA_H
33 #   include <alloca.h>
34 #endif
35
36 #include "audio_output.h"
37 #include "aout_internal.h"
38
39 /*****************************************************************************
40  * aout_InputNew : allocate a new input and rework the filter pipeline
41  *****************************************************************************/
42 int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
43 {
44     audio_sample_format_t intermediate_format, headphone_intermediate_format;
45     aout_filter_t * p_headphone_filter;
46     vlc_bool_t b_use_headphone_filter = VLC_FALSE;
47
48     aout_FormatPrint( p_aout, "input", &p_input->input );
49
50     /* Prepare FIFO. */
51     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
52     p_input->p_first_byte_to_mix = NULL;
53
54     /* Prepare format structure */
55     memcpy( &intermediate_format, &p_aout->mixer.mixer,
56             sizeof(audio_sample_format_t) );
57     intermediate_format.i_rate = p_input->input.i_rate;
58
59     /* Headphone filter add-ons. */
60     memcpy( &headphone_intermediate_format, &p_aout->mixer.mixer,
61             sizeof(audio_sample_format_t) );
62     headphone_intermediate_format.i_rate = p_input->input.i_rate;
63     if ( config_GetInt( p_aout , "headphone" ) )
64     {
65         /* Do we use heaphone filter ? */
66         if ( intermediate_format.i_physical_channels
67                 == ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT )
68             && ( intermediate_format.i_format != VLC_FOURCC('f','l','3','2')
69                 || intermediate_format.i_format != VLC_FOURCC('f','i','3','2')
70                 ) )
71         {
72             b_use_headphone_filter = VLC_TRUE;
73         }
74     }
75     if ( b_use_headphone_filter == VLC_TRUE )
76     {
77         /* Split the filter pipeline. */
78         headphone_intermediate_format.i_physical_channels = p_input->input.i_physical_channels;
79         headphone_intermediate_format.i_original_channels = p_input->input.i_original_channels;
80         headphone_intermediate_format.i_bytes_per_frame =
81                 headphone_intermediate_format.i_bytes_per_frame
82                 * aout_FormatNbChannels( &headphone_intermediate_format )
83                 / aout_FormatNbChannels( &intermediate_format );
84     }
85
86     /* Create filters. */
87     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
88                                      &p_input->i_nb_filters, &p_input->input,
89                                      &headphone_intermediate_format ) < 0 )
90     {
91         msg_Err( p_aout, "couldn't set an input pipeline" );
92
93         aout_FifoDestroy( p_aout, &p_input->fifo );
94         p_input->b_error = 1;
95
96         return -1;
97     }
98
99     /* Headphone filter add-ons. */
100     if ( b_use_headphone_filter == VLC_TRUE )
101     {
102         /* create a vlc object */
103         p_headphone_filter = vlc_object_create( p_aout
104                 , sizeof(aout_filter_t) );
105         if ( p_headphone_filter == NULL )
106         {
107             msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
108             aout_FifoDestroy( p_aout, &p_input->fifo );
109             p_input->b_error = 1;
110             return -1;
111         }
112         vlc_object_attach( p_headphone_filter, p_aout );
113
114         /* find the headphone filter */
115         memcpy( &p_headphone_filter->input, &headphone_intermediate_format
116                 , sizeof(audio_sample_format_t) );
117         memcpy( &p_headphone_filter->output, &intermediate_format
118                 , sizeof(audio_sample_format_t) );
119         p_headphone_filter->p_module = module_Need( p_headphone_filter, "audio filter"
120                 , "headphone" );
121         if ( p_headphone_filter->p_module == NULL )
122         {
123             vlc_object_detach( p_headphone_filter );
124             vlc_object_destroy( p_headphone_filter );
125
126             msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
127             aout_FifoDestroy( p_aout, &p_input->fifo );
128             p_input->b_error = 1;
129             return -1;
130         }
131
132         /* success */
133         p_headphone_filter->b_reinit = VLC_TRUE;
134         p_input->pp_filters[p_input->i_nb_filters++] = p_headphone_filter;
135     }
136
137     /* Prepare hints for the buffer allocator. */
138     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
139     p_input->input_alloc.i_bytes_per_sec = -1;
140
141     if ( AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
142     {
143         p_input->i_nb_resamplers = 0;
144     }
145     else
146     {
147         /* Create resamplers. */
148         intermediate_format.i_rate = (__MAX(p_input->input.i_rate,
149                                             p_aout->mixer.mixer.i_rate)
150                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
151         if ( intermediate_format.i_rate == p_aout->mixer.mixer.i_rate )
152         {
153             /* Just in case... */
154             intermediate_format.i_rate++;
155         }
156         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
157                                          &p_input->i_nb_resamplers,
158                                          &intermediate_format,
159                                          &p_aout->mixer.mixer ) < 0 )
160         {
161             msg_Err( p_aout, "couldn't set a resampler pipeline" );
162
163             aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
164                                          p_input->i_nb_filters );
165             aout_FifoDestroy( p_aout, &p_input->fifo );
166             p_input->b_error = 1;
167
168             return -1;
169         }
170
171         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
172                                  p_input->i_nb_resamplers,
173                                  &p_input->input_alloc );
174
175         /* Setup the initial rate of the resampler */
176         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
177     }
178     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
179
180     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
181     p_input->input_alloc.i_bytes_per_sec = -1;
182     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
183                              p_input->i_nb_filters,
184                              &p_input->input_alloc );
185
186     /* i_bytes_per_sec is still == -1 if no filters */
187     p_input->input_alloc.i_bytes_per_sec = __MAX(
188                                     p_input->input_alloc.i_bytes_per_sec,
189                                     (int)(p_input->input.i_bytes_per_frame
190                                      * p_input->input.i_rate
191                                      / p_input->input.i_frame_length) );
192     /* Allocate in the heap, it is more convenient for the decoder. */
193     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
194
195     p_input->b_error = 0;
196
197     return 0;
198 }
199
200 /*****************************************************************************
201  * aout_InputDelete : delete an input
202  *****************************************************************************
203  * This function must be entered with the mixer lock.
204  *****************************************************************************/
205 int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
206 {
207     if ( p_input->b_error ) return 0;
208
209     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
210                                  p_input->i_nb_filters );
211     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
212                                  p_input->i_nb_resamplers );
213     aout_FifoDestroy( p_aout, &p_input->fifo );
214
215     return 0;
216 }
217
218 /*****************************************************************************
219  * aout_InputPlay : play a buffer
220  *****************************************************************************
221  * This function must be entered with the input lock.
222  *****************************************************************************/
223 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
224                     aout_buffer_t * p_buffer )
225 {
226     mtime_t start_date;
227
228     /* We don't care if someone changes the start date behind our back after
229      * this. We'll deal with that when pushing the buffer, and compensate
230      * with the next incoming buffer. */
231     vlc_mutex_lock( &p_aout->input_fifos_lock );
232     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
233     vlc_mutex_unlock( &p_aout->input_fifos_lock );
234
235     if ( start_date != 0 && start_date < mdate() )
236     {
237         /* The decoder is _very_ late. This can only happen if the user
238          * pauses the stream (or if the decoder is buggy, which cannot
239          * happen :). */
240         msg_Warn( p_aout, "computed PTS is out of range ("I64Fd"), "
241                   "clearing out", mdate() - start_date );
242         vlc_mutex_lock( &p_aout->input_fifos_lock );
243         aout_FifoSet( p_aout, &p_input->fifo, 0 );
244         p_input->p_first_byte_to_mix = NULL;
245         vlc_mutex_unlock( &p_aout->input_fifos_lock );
246         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
247             msg_Warn( p_aout, "timing screwed, stopping resampling" );
248         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
249         if ( p_input->i_nb_resamplers != 0 )
250         {
251             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
252             p_input->pp_resamplers[0]->b_reinit = VLC_TRUE;
253         }
254         start_date = 0;
255     }
256
257     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
258     {
259         /* The decoder gives us f*cked up PTS. It's its business, but we
260          * can't present it anyway, so drop the buffer. */
261         msg_Warn( p_aout, "PTS is out of range ("I64Fd"), dropping buffer",
262                   mdate() - p_buffer->start_date );
263         aout_BufferFree( p_buffer );
264
265         return 0;
266     }
267
268     if ( start_date == 0 ) start_date = p_buffer->start_date;
269
270     /* Run pre-filters. */
271     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
272                       &p_buffer );
273
274     /* Run the resampler if needed.
275      * We first need to calculate the output rate of this resampler. */
276     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
277          ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
278            || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) &&
279          p_input->i_nb_resamplers > 0 )
280     {
281         /* Can happen in several circumstances :
282          * 1. A problem at the input (clock drift)
283          * 2. A small pause triggered by the user
284          * 3. Some delay in the output stage, causing a loss of lip
285          *    synchronization
286          * Solution : resample the buffer to avoid a scratch.
287          */
288         mtime_t drift = p_buffer->start_date - start_date;
289
290         p_input->i_resamp_start_date = mdate();
291         p_input->i_resamp_start_drift = (int)drift;
292
293         if ( drift > 0 )
294             p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
295         else
296             p_input->i_resampling_type = AOUT_RESAMPLING_UP;
297
298         msg_Warn( p_aout, "buffer is "I64Fd" %s, triggering %ssampling",
299                           drift > 0 ? drift : -drift,
300                           drift > 0 ? "in advance" : "late",
301                           drift > 0 ? "down" : "up");
302     }
303
304     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
305     {
306         /* Resampling has been triggered previously (because of dates
307          * mismatch). We want the resampling to happen progressively so
308          * it isn't too audible to the listener. */
309
310         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
311         {
312             p_input->pp_resamplers[0]->input.i_rate += 10; /* Hz */
313         }
314         else
315         {
316             p_input->pp_resamplers[0]->input.i_rate -= 10; /* Hz */
317         }
318
319         /* Check if everything is back to normal, in which case we can stop the
320          * resampling */
321         if( p_input->pp_resamplers[0]->input.i_rate ==
322               p_input->input.i_rate )
323         {
324             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
325             msg_Warn( p_aout, "resampling stopped after "I64Fi" usec",
326                       mdate() - p_input->i_resamp_start_date );
327         }
328         else if( abs( (int)(p_buffer->start_date - start_date) ) <
329                  abs( p_input->i_resamp_start_drift ) / 2 )
330         {
331             /* if we reduced the drift from half, then it is time to switch
332              * back the resampling direction. */
333             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
334                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
335             else
336                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
337             p_input->i_resamp_start_drift = 0;
338         }
339         else if( p_input->i_resamp_start_drift &&
340                  ( abs( (int)(p_buffer->start_date - start_date) ) >
341                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
342         {
343             /* If the drift is increasing and not decreasing, than something
344              * is bad. We'd better stop the resampling right now. */
345             msg_Warn( p_aout, "timing screwed, stopping resampling" );
346             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
347             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
348         }
349     }
350
351     /* Adding the start date will be managed by aout_FifoPush(). */
352     p_buffer->end_date = start_date +
353         (p_buffer->end_date - p_buffer->start_date);
354     p_buffer->start_date = start_date;
355
356     /* Actually run the resampler now. */
357     if ( p_input->i_nb_resamplers > 0 && p_aout->mixer.mixer.i_rate !=
358          p_input->pp_resamplers[0]->input.i_rate )
359     {
360         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
361                           p_input->i_nb_resamplers,
362                           &p_buffer );
363     }
364
365     vlc_mutex_lock( &p_aout->input_fifos_lock );
366     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
367     vlc_mutex_unlock( &p_aout->input_fifos_lock );
368
369     return 0;
370 }