]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
* Fixed miscellaneous cosmetic issues with lpcm and s16tofloat32swab modules.
[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.12 2002/09/20 23:27:04 massiot 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 static aout_input_t * InputNew( aout_instance_t * p_aout,
43                                 audio_sample_format_t * p_format )
44 {
45     aout_input_t * p_input;
46
47     vlc_mutex_lock( &p_aout->mixer_lock );
48
49     if ( p_aout->i_nb_inputs >= AOUT_MAX_INPUTS )
50     {
51         msg_Err( p_aout, "too many inputs already (%d)", p_aout->i_nb_inputs );
52         vlc_mutex_unlock( &p_aout->mixer_lock );
53         return NULL;
54     }
55
56     p_input = malloc(sizeof(aout_input_t));
57     if ( p_input == NULL )
58     {
59         msg_Err( p_aout, "out of memory" );
60         vlc_mutex_unlock( &p_aout->mixer_lock );
61         return NULL;
62     }
63
64     vlc_mutex_init( p_aout, &p_input->lock );
65     vlc_mutex_lock( &p_input->lock );
66
67     if ( p_aout->i_nb_inputs == 0 )
68     {
69         /* Recreate the output using the new format. */
70         if ( aout_OutputNew( p_aout, p_format ) < 0 )
71         {
72             vlc_mutex_unlock( &p_input->lock );
73             vlc_mutex_destroy( &p_input->lock );
74             free( p_input );
75             vlc_mutex_unlock( &p_aout->mixer_lock );
76             return NULL;
77         }
78     }
79     else
80     {
81         aout_MixerDelete( p_aout );
82     }
83
84     p_input->b_error = 0;
85     memcpy( &p_input->input, p_format,
86             sizeof(audio_sample_format_t) );
87     aout_FormatPrepare( &p_input->input );
88
89     /* Prepare FIFO. */
90     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
91     p_input->p_first_byte_to_mix = NULL;
92
93     p_aout->pp_inputs[p_aout->i_nb_inputs] = p_input;
94     p_aout->i_nb_inputs++;
95
96     if ( aout_MixerNew( p_aout ) < 0 )
97     {
98         p_aout->i_nb_inputs--;
99
100         if ( !p_aout->i_nb_inputs )
101         {
102             aout_OutputDelete( p_aout );
103         }
104         else
105         {
106             aout_MixerNew( p_aout );
107         }
108
109         aout_FifoDestroy( p_aout, &p_input->fifo );
110         vlc_mutex_unlock( &p_input->lock );
111         vlc_mutex_destroy( &p_input->lock );
112         free( p_input );
113         vlc_mutex_unlock( &p_aout->mixer_lock );
114
115         return NULL;
116     }
117
118     vlc_mutex_unlock( &p_aout->mixer_lock );
119
120     /* Create filters. */
121     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
122                                      &p_input->i_nb_filters, &p_input->input,
123                                      &p_aout->mixer.mixer ) < 0 )
124     {
125         msg_Err( p_aout, "couldn't set an input pipeline" );
126
127         p_aout->i_nb_inputs--;
128
129         aout_MixerDelete( p_aout );
130         if ( !p_aout->i_nb_inputs )
131         {
132             aout_OutputDelete( p_aout );
133         }
134         else
135         {
136             aout_MixerNew( p_aout );
137         }
138
139         aout_FifoDestroy( p_aout, &p_input->fifo );
140         vlc_mutex_unlock( &p_input->lock );
141         vlc_mutex_destroy( &p_input->lock );
142         free( p_input );
143         vlc_mutex_unlock( &p_aout->mixer_lock );
144
145         return NULL;
146     }
147
148     /* Prepare hints for the buffer allocator. */
149     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
150     p_input->input_alloc.i_bytes_per_sec = -1;
151
152     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
153                              p_input->i_nb_filters,
154                              &p_input->input_alloc );
155
156     /* i_bytes_per_sec is still == -1 if no filters */
157     p_input->input_alloc.i_bytes_per_sec = __MAX(
158                                     p_input->input_alloc.i_bytes_per_sec,
159                                     p_input->input.i_bytes_per_frame
160                                      * p_input->input.i_rate
161                                      / p_input->input.i_frame_length );
162     /* Allocate in the heap, it is more convenient for the decoder. */
163     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
164
165     vlc_mutex_unlock( &p_input->lock );
166
167     msg_Dbg( p_aout, "input 0x%x created", p_input );
168     return p_input;
169 }
170
171 aout_input_t * __aout_InputNew( vlc_object_t * p_this,
172                                 aout_instance_t ** pp_aout,
173                                 audio_sample_format_t * p_format )
174 {
175     /* Create an audio output if there is none. */
176     *pp_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
177
178     if( *pp_aout == NULL )
179     {
180         msg_Dbg( p_this, "no aout present, spawning one" );
181
182         *pp_aout = aout_NewInstance( p_this );
183         /* Everything failed, I'm a loser, I just wanna die */
184         if( *pp_aout == NULL )
185         {
186             return NULL;
187         }
188     }
189     else
190     {
191         vlc_object_release( *pp_aout );
192     }
193
194     return InputNew( *pp_aout, p_format );
195 }
196
197 /*****************************************************************************
198  * aout_InputDelete : delete an input
199  *****************************************************************************/
200 void aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
201 {
202     int i_input;
203
204     vlc_mutex_lock( &p_aout->mixer_lock );
205     vlc_mutex_lock( &p_input->lock );
206
207     for ( i_input = 0; i_input < p_aout->i_nb_inputs; i_input++ )
208     {
209         if ( p_aout->pp_inputs[i_input] == p_input )
210         {
211             break;
212         }
213     }
214
215     if ( i_input == p_aout->i_nb_inputs )
216     {
217         msg_Err( p_aout, "cannot find an input to delete" );
218         return;
219     }
220
221     /* Remove the input from the list. */
222     memmove( &p_aout->pp_inputs[i_input], &p_aout->pp_inputs[i_input + 1],
223              (AOUT_MAX_INPUTS - i_input - 1) * sizeof(aout_input_t *) );
224     p_aout->i_nb_inputs--;
225
226     if ( !p_aout->i_nb_inputs )
227     {
228         aout_OutputDelete( p_aout );
229         aout_MixerDelete( p_aout );
230     }
231
232     vlc_mutex_unlock( &p_aout->mixer_lock );
233
234     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
235                                  p_input->i_nb_filters );
236     aout_FifoDestroy( p_aout, &p_input->fifo );
237
238     vlc_mutex_unlock( &p_input->lock );
239     vlc_mutex_destroy( &p_input->lock );
240     free( p_input );
241
242     msg_Dbg( p_aout, "input 0x%x destroyed", p_input );
243 }
244
245 /*****************************************************************************
246  * aout_InputChange : recreate the pipeline framework, in case the output
247  *                    device has changed
248  *****************************************************************************
249  * You must own p_input->lock and the mixer lock before entering this function.
250  * It returns -1 if the input pipeline couldn't be created. Please remember
251  * to call aout_MixerNew() afterwards.
252  *****************************************************************************/
253 int aout_InputChange( aout_instance_t * p_aout, aout_input_t * p_input )
254 {
255     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
256                                  p_input->i_nb_filters );
257     aout_FifoDestroy( p_aout, &p_input->fifo );
258
259     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
260     p_input->p_first_byte_to_mix = NULL;
261
262     /* Create filters. */
263     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
264                                      &p_input->i_nb_filters, &p_input->input,
265                                      &p_aout->mixer.mixer ) < 0 )
266     {
267         p_input->b_error = 1;
268
269         return -1;
270     }
271
272     /* Prepare hints for the buffer allocator. */
273     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
274     p_input->input_alloc.i_bytes_per_sec = -1;
275
276     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
277                              p_input->i_nb_filters,
278                              &p_input->input_alloc );
279
280     /* i_bytes_per_sec is still == -1 if no filters */
281     p_input->input_alloc.i_bytes_per_sec = __MAX(
282                                     p_input->input_alloc.i_bytes_per_sec,
283                                     p_input->input.i_bytes_per_frame
284                                      * p_input->input.i_rate
285                                      / p_input->input.i_frame_length );
286     /* Allocate in the heap, it is more convenient for the decoder. */
287     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
288
289     return 0;
290 }
291
292 /*****************************************************************************
293  * aout_InputPlay : play a buffer
294  *****************************************************************************/
295 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
296                     aout_buffer_t * p_buffer )
297 {
298     mtime_t start_date, duration;
299
300     vlc_mutex_lock( &p_input->lock );
301
302     if ( p_input->b_error ) return -1;
303
304     /* We don't care if someone changes the start date behind our back after
305      * this. We'll deal with that when pushing the buffer, and compensate
306      * with the next incoming buffer. */
307     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
308
309     if ( start_date != 0 && start_date < mdate() )
310     {
311         /* The decoder is _very_ late. This can only happen if the user
312          * pauses the stream (or if the decoder is buggy, which cannot
313          * happen :). */
314         msg_Warn( p_aout, "computed PTS is out of range (%lld), clearing out",
315                   start_date );
316         vlc_mutex_lock( &p_aout->mixer_lock );
317         aout_FifoSet( p_aout, &p_input->fifo, 0 );
318         vlc_mutex_unlock( &p_aout->mixer_lock );
319         start_date = 0;
320     } 
321
322     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
323     {
324         /* The decoder gives us f*cked up PTS. It's its business, but we
325          * can't present it anyway, so drop the buffer. */
326         msg_Warn( p_aout, "PTS is out of range (%lld), dropping buffer",
327                   mdate() - p_buffer->start_date );
328         aout_BufferFree( p_buffer );
329
330         vlc_mutex_unlock( &p_input->lock );
331         return 0;
332     }
333
334     if ( start_date == 0 ) start_date = p_buffer->start_date;
335
336     if ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
337           || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE )
338     {
339         /* Can happen in several circumstances :
340          * 1. A problem at the input (clock drift)
341          * 2. A small pause triggered by the user
342          * 3. Some delay in the output stage, causing a loss of lip
343          *    synchronization
344          * Solution : resample the buffer to avoid a scratch.
345          */
346         audio_sample_format_t new_input;
347         int i_ratio, i_nb_filters;
348         mtime_t old_duration;
349         aout_filter_t * pp_filters[AOUT_MAX_FILTERS];
350         aout_buffer_t * p_new_buffer;
351         aout_alloc_t dummy_alloc;
352         mtime_t drift = p_buffer->start_date - start_date;
353
354         msg_Warn( p_aout, "buffer is %lld %s, resampling",
355                          drift > 0 ? drift : -drift,
356                          drift > 0 ? "in advance" : "late" );
357         memcpy( &new_input, &p_input->input,
358                 sizeof(audio_sample_format_t) );
359         old_duration = p_buffer->end_date - p_buffer->start_date;
360         duration = p_buffer->end_date - start_date;
361         i_ratio = duration * 100 / old_duration;
362         /* If the ratio is too != 100, the sound quality will be awful. */
363         if ( i_ratio < 66 /* % */ )
364         {
365             duration = old_duration * 66 / 100;
366         }
367         if ( i_ratio > 150 /* % */ )
368         {
369             duration = old_duration * 150 / 100;
370         }
371         new_input.i_rate = new_input.i_rate * old_duration / duration;
372         aout_FormatPrepare( &new_input );
373
374         if ( aout_FiltersCreatePipeline( p_aout, pp_filters,
375                                          &i_nb_filters, &new_input,
376                                          &p_aout->mixer.mixer ) < 0 )
377         {
378             msg_Err( p_aout, "couldn't set an input pipeline for resampling" );
379             vlc_mutex_lock( &p_aout->mixer_lock );
380             aout_FifoSet( p_aout, &p_input->fifo, 0 );
381             vlc_mutex_unlock( &p_aout->mixer_lock );
382             aout_BufferFree( p_buffer );
383
384             vlc_mutex_unlock( &p_input->lock );
385             return 0;
386         }
387
388         dummy_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
389         dummy_alloc.i_bytes_per_sec = -1;
390         aout_FiltersHintBuffers( p_aout, pp_filters, i_nb_filters,
391                                  &dummy_alloc );
392         dummy_alloc.i_bytes_per_sec = __MAX(
393                                     dummy_alloc.i_bytes_per_sec,
394                                     new_input.i_bytes_per_frame
395                                      * new_input.i_rate
396                                      / new_input.i_frame_length );
397         dummy_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
398
399         aout_BufferAlloc( &dummy_alloc, duration, NULL, p_new_buffer );
400         memcpy( p_new_buffer->p_buffer, p_buffer->p_buffer,
401                 p_buffer->i_nb_bytes );
402         p_new_buffer->i_nb_samples = p_buffer->i_nb_samples;
403         p_new_buffer->i_nb_bytes = p_buffer->i_nb_bytes;
404
405         aout_BufferFree( p_buffer );
406         p_buffer = p_new_buffer;
407
408         aout_FiltersPlay( p_aout, pp_filters, i_nb_filters,
409                           &p_buffer );
410
411         aout_FiltersDestroyPipeline( p_aout, pp_filters,
412                                      i_nb_filters );
413     }
414     else
415     {
416         /* No resampling needed (except maybe the one imposed by the
417          * output). */
418         duration = p_buffer->end_date - p_buffer->start_date;
419         aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
420                           &p_buffer );
421     }
422
423     vlc_mutex_unlock( &p_input->lock );
424
425     vlc_mutex_lock( &p_aout->input_fifos_lock );
426     /* Adding the start date will be managed by aout_FifoPush(). */
427     p_buffer->start_date = start_date;
428     p_buffer->end_date = start_date + duration;
429     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
430     vlc_mutex_unlock( &p_aout->input_fifos_lock );
431
432     return 0;
433 }