]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
8eedcc2db5a435c4dbf6d3a27b98fa0fdbd066df
[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.18 2002/11/08 10:26:53 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;
45
46     aout_FormatPrint( p_aout, "input", &p_input->input );
47
48     /* Prepare FIFO. */
49     aout_FifoInit( p_aout, &p_input->fifo, p_aout->mixer.mixer.i_rate );
50     p_input->p_first_byte_to_mix = NULL;
51
52     /* Create filters. */
53     memcpy( &intermediate_format, &p_aout->mixer.mixer,
54             sizeof(audio_sample_format_t) );
55     intermediate_format.i_rate = p_input->input.i_rate;
56     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
57                                      &p_input->i_nb_filters, &p_input->input,
58                                      &intermediate_format ) < 0 )
59     {
60         msg_Err( p_aout, "couldn't set an input pipeline" );
61
62         aout_FifoDestroy( p_aout, &p_input->fifo );
63         p_input->b_error = 1;
64
65         return -1;
66     }
67
68     /* Prepare hints for the buffer allocator. */
69     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
70     p_input->input_alloc.i_bytes_per_sec = -1;
71
72     if ( AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
73     {
74         p_input->i_nb_resamplers = 0;
75     }
76     else
77     {
78         /* Create resamplers. */
79         intermediate_format.i_rate = (p_input->input.i_rate
80                                  * (100 + AOUT_MAX_RESAMPLING)) / 100;
81         if ( intermediate_format.i_rate == p_aout->mixer.mixer.i_rate )
82         {
83             /* Just in case... */
84             intermediate_format.i_rate++;
85         }
86         if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_resamplers,
87                                          &p_input->i_nb_resamplers,
88                                          &intermediate_format,
89                                          &p_aout->mixer.mixer ) < 0 )
90         {
91             msg_Err( p_aout, "couldn't set a resampler pipeline" );
92
93             aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
94                                          p_input->i_nb_filters );
95             aout_FifoDestroy( p_aout, &p_input->fifo );
96             p_input->b_error = 1;
97
98             return -1;
99         }
100
101         aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
102                                  p_input->i_nb_resamplers,
103                                  &p_input->input_alloc );
104     }
105
106     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
107     p_input->input_alloc.i_bytes_per_sec = -1;
108     aout_FiltersHintBuffers( p_aout, p_input->pp_filters,
109                              p_input->i_nb_filters,
110                              &p_input->input_alloc );
111
112     /* i_bytes_per_sec is still == -1 if no filters */
113     p_input->input_alloc.i_bytes_per_sec = __MAX(
114                                     p_input->input_alloc.i_bytes_per_sec,
115                                     p_input->input.i_bytes_per_frame
116                                      * p_input->input.i_rate
117                                      / p_input->input.i_frame_length );
118     /* Allocate in the heap, it is more convenient for the decoder. */
119     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
120
121     p_input->b_error = 0;
122
123     return 0;
124 }
125
126 /*****************************************************************************
127  * aout_InputDelete : delete an input
128  *****************************************************************************
129  * This function must be entered with the mixer lock.
130  *****************************************************************************/
131 int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
132 {
133     if ( p_input->b_error ) return 0;
134
135     aout_FiltersDestroyPipeline( p_aout, p_input->pp_filters,
136                                  p_input->i_nb_filters );
137     aout_FiltersDestroyPipeline( p_aout, p_input->pp_resamplers,
138                                  p_input->i_nb_resamplers );
139     aout_FifoDestroy( p_aout, &p_input->fifo );
140
141     return 0;
142 }
143
144 /*****************************************************************************
145  * aout_InputPlay : play a buffer
146  *****************************************************************************
147  * This function must be entered with the input lock.
148  *****************************************************************************/
149 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
150                     aout_buffer_t * p_buffer )
151 {
152     mtime_t start_date, duration;
153
154     /* We don't care if someone changes the start date behind our back after
155      * this. We'll deal with that when pushing the buffer, and compensate
156      * with the next incoming buffer. */
157     vlc_mutex_lock( &p_aout->input_fifos_lock );
158     start_date = aout_FifoNextStart( p_aout, &p_input->fifo );
159     vlc_mutex_unlock( &p_aout->input_fifos_lock );
160
161     if ( start_date != 0 && start_date < mdate() )
162     {
163         /* The decoder is _very_ late. This can only happen if the user
164          * pauses the stream (or if the decoder is buggy, which cannot
165          * happen :). */
166         msg_Warn( p_aout, "computed PTS is out of range ("I64Fd"), "
167                   "clearing out", mdate() - start_date );
168         vlc_mutex_lock( &p_aout->input_fifos_lock );
169         aout_FifoSet( p_aout, &p_input->fifo, 0 );
170         vlc_mutex_unlock( &p_aout->input_fifos_lock );
171         start_date = 0;
172     } 
173
174     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
175     {
176         /* The decoder gives us f*cked up PTS. It's its business, but we
177          * can't present it anyway, so drop the buffer. */
178         msg_Warn( p_aout, "PTS is out of range ("I64Fd"), dropping buffer",
179                   mdate() - p_buffer->start_date );
180         aout_BufferFree( p_buffer );
181
182         return 0;
183     }
184
185     if ( start_date == 0 ) start_date = p_buffer->start_date;
186
187     /* Run pre-filters. */
188     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
189                       &p_buffer );
190
191     if ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
192           || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE )
193     {
194         /* Can happen in several circumstances :
195          * 1. A problem at the input (clock drift)
196          * 2. A small pause triggered by the user
197          * 3. Some delay in the output stage, causing a loss of lip
198          *    synchronization
199          * Solution : resample the buffer to avoid a scratch.
200          */
201         int i_ratio;
202         mtime_t old_duration;
203         mtime_t drift = p_buffer->start_date - start_date;
204
205         msg_Warn( p_aout, "buffer is "I64Fd" %s, resampling",
206                          drift > 0 ? drift : -drift,
207                          drift > 0 ? "in advance" : "late" );
208         old_duration = p_buffer->end_date - p_buffer->start_date;
209         duration = p_buffer->end_date - start_date;
210         i_ratio = (duration * 100) / old_duration;
211         /* If the ratio is too != 100, the sound quality will be awful. */
212         if ( i_ratio < 100 - AOUT_MAX_RESAMPLING /* % */ )
213         {
214             duration = (old_duration * (100 - AOUT_MAX_RESAMPLING)) / 100;
215         }
216         if ( i_ratio > 100 + AOUT_MAX_RESAMPLING /* % */ )
217         {
218             duration = (old_duration * (100 + AOUT_MAX_RESAMPLING)) / 100;
219         }
220         p_input->pp_resamplers[0]->input.i_rate 
221             = (p_input->input.i_rate * old_duration) / duration;
222
223         aout_FiltersPlay( p_aout, p_input->pp_resamplers,
224                           p_input->i_nb_resamplers,
225                           &p_buffer );
226     }
227     else
228     {
229         duration = p_buffer->end_date - p_buffer->start_date;
230
231         if ( p_input->input.i_rate != p_aout->mixer.mixer.i_rate )
232         {
233             /* Standard resampling is needed ! */
234             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
235
236             aout_FiltersPlay( p_aout, p_input->pp_resamplers,
237                               p_input->i_nb_resamplers,
238                               &p_buffer );
239         }
240     }
241
242     /* Adding the start date will be managed by aout_FifoPush(). */
243     p_buffer->start_date = start_date;
244     p_buffer->end_date = start_date + duration;
245
246     vlc_mutex_lock( &p_aout->input_fifos_lock );
247     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
248     vlc_mutex_unlock( &p_aout->input_fifos_lock );
249
250     return 0;
251 }