]> git.sesse.net Git - vlc/blob - src/audio_output/input.c
3056809bf612e5f4bd83c6f295df31cfd5bf150f
[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 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_input.h>
34 #include <vlc_aout.h>
35 #include <vlc_filter.h>
36
37 #include <libvlc.h>
38 #include "aout_internal.h"
39
40 static void inputDrop( aout_input_t *, block_t * );
41 static void inputResamplingStop( audio_output_t *, aout_input_t * );
42
43 /*****************************************************************************
44  * aout_InputNew : allocate a new input and rework the filter pipeline
45  *****************************************************************************/
46 aout_input_t *aout_InputNew (audio_output_t * p_aout,
47                              const audio_sample_format_t *restrict infmt,
48                              const audio_sample_format_t *restrict outfmt,
49                              const aout_request_vout_t *p_request_vout)
50 {
51     aout_input_t *p_input = malloc (sizeof (*p_input));
52     if (unlikely(p_input == NULL))
53         return NULL;
54
55     p_input->samplerate = infmt->i_rate;
56
57     if (aout_FiltersNew (p_aout, infmt, outfmt, p_request_vout))
58     {
59         free(p_input);
60         return NULL;
61     }
62
63     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
64     p_input->i_last_input_rate = INPUT_RATE_DEFAULT;
65     p_input->i_buffer_lost = 0;
66     return p_input;
67 }
68
69 /*****************************************************************************
70  * aout_InputDelete : delete an input
71  *****************************************************************************
72  * This function must be entered with the mixer lock.
73  *****************************************************************************/
74 int aout_InputDelete( audio_output_t * p_aout, aout_input_t * p_input )
75 {
76     aout_FiltersDestroy (p_aout);
77     (void) p_input;
78     return 0;
79 }
80
81 /*****************************************************************************
82  * aout_InputPlay : play a buffer
83  *****************************************************************************
84  * This function must be entered with the input lock.
85  *****************************************************************************/
86 block_t *aout_InputPlay(audio_output_t *p_aout, aout_input_t *p_input,
87                         block_t *p_buffer, int i_input_rate, date_t *date )
88 {
89     mtime_t start_date;
90     aout_owner_t *owner = aout_owner(p_aout);
91
92     aout_assert_locked( p_aout );
93
94     if( i_input_rate != INPUT_RATE_DEFAULT && owner->rate_filter == NULL )
95     {
96         inputDrop( p_input, p_buffer );
97         return NULL;
98     }
99
100     /* Handle input rate change, but keep drift correction */
101     if( i_input_rate != p_input->i_last_input_rate )
102     {
103         unsigned int * const pi_rate = &owner->rate_filter->fmt_in.audio.i_rate;
104 #define F(r,ir) ( INPUT_RATE_DEFAULT * (r) / (ir) )
105         const int i_delta = *pi_rate - F(p_input->samplerate,p_input->i_last_input_rate);
106         *pi_rate = F(p_input->samplerate + i_delta, i_input_rate);
107 #undef F
108         p_input->i_last_input_rate = i_input_rate;
109     }
110
111     mtime_t now = mdate();
112
113     /* We don't care if someone changes the start date behind our back after
114      * this. We'll deal with that when pushing the buffer, and compensate
115      * with the next incoming buffer. */
116     start_date = date_Get (date);
117
118     if ( start_date != VLC_TS_INVALID && start_date < now )
119     {
120         /* The decoder is _very_ late. This can only happen if the user
121          * pauses the stream (or if the decoder is buggy, which cannot
122          * happen :). */
123         msg_Warn( p_aout, "computed PTS is out of range (%"PRId64"), "
124                   "clearing out", now - start_date );
125         aout_OutputFlush( p_aout, false );
126         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
127             msg_Warn( p_aout, "timing screwed, stopping resampling" );
128         inputResamplingStop( p_aout, p_input );
129         p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
130         start_date = VLC_TS_INVALID;
131     }
132
133     if ( p_buffer->i_pts < now + AOUT_MIN_PREPARE_TIME )
134     {
135         /* The decoder gives us f*cked up PTS. It's its business, but we
136          * can't present it anyway, so drop the buffer. */
137         msg_Warn( p_aout, "PTS is out of range (%"PRId64"), dropping buffer",
138                   now - p_buffer->i_pts );
139         inputDrop( p_input, p_buffer );
140         inputResamplingStop( p_aout, p_input );
141         return NULL;
142     }
143
144     /* If the audio drift is too big then it's not worth trying to resample
145      * the audio. */
146     if( start_date == VLC_TS_INVALID )
147     {
148         start_date = p_buffer->i_pts;
149         date_Set (date, start_date);
150     }
151
152     mtime_t drift = start_date - p_buffer->i_pts;
153
154     if( drift < -i_input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT )
155     {
156         msg_Warn( p_aout, "buffer way too early (%"PRId64"), clearing queue",
157                   drift );
158         aout_OutputFlush( p_aout, false );
159         if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
160             msg_Warn( p_aout, "timing screwed, stopping resampling" );
161         inputResamplingStop( p_aout, p_input );
162         p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
163         start_date = p_buffer->i_pts;
164         date_Set (date, start_date);
165         drift = 0;
166     }
167     else
168     if( drift > +i_input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT )
169     {
170         msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
171                   drift );
172         inputDrop( p_input, p_buffer );
173         return NULL;
174     }
175
176     /* Run pre-filters. */
177     aout_FiltersPlay( owner->filters, owner->nb_filters, &p_buffer );
178     if( !p_buffer )
179         return NULL;
180
181     /* Run the resampler if needed.
182      * We first need to calculate the output rate of this resampler. */
183     if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
184          ( drift < -AOUT_MAX_PTS_ADVANCE || drift > +AOUT_MAX_PTS_DELAY ) &&
185          owner->resampler != NULL )
186     {
187         /* Can happen in several circumstances :
188          * 1. A problem at the input (clock drift)
189          * 2. A small pause triggered by the user
190          * 3. Some delay in the output stage, causing a loss of lip
191          *    synchronization
192          * Solution : resample the buffer to avoid a scratch.
193          */
194         p_input->i_resamp_start_date = now;
195         p_input->i_resamp_start_drift = (int)-drift;
196         p_input->i_resampling_type = (drift < 0) ? AOUT_RESAMPLING_DOWN
197                                                  : AOUT_RESAMPLING_UP;
198         msg_Warn( p_aout, (drift < 0)
199                   ? "buffer too early (%"PRId64"), down-sampling"
200                   : "buffer too late  (%"PRId64"), up-sampling", drift );
201     }
202
203     if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
204     {
205         /* Resampling has been triggered previously (because of dates
206          * mismatch). We want the resampling to happen progressively so
207          * it isn't too audible to the listener. */
208
209         if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
210             owner->resampler->fmt_in.audio.i_rate += 2; /* Hz */
211         else
212             owner->resampler->fmt_in.audio.i_rate -= 2; /* Hz */
213
214         /* Check if everything is back to normal, in which case we can stop the
215          * resampling */
216         unsigned int i_nominal_rate =
217           (owner->resampler == owner->rate_filter)
218           ? INPUT_RATE_DEFAULT * p_input->samplerate / i_input_rate
219           : p_input->samplerate;
220         if( owner->resampler->fmt_in.audio.i_rate == i_nominal_rate )
221         {
222             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
223             msg_Warn( p_aout, "resampling stopped after %"PRIi64" usec "
224                       "(drift: %"PRIi64")",
225                       now - p_input->i_resamp_start_date,
226                       p_buffer->i_pts - start_date);
227         }
228         else if( abs( (int)(p_buffer->i_pts - start_date) ) <
229                  abs( p_input->i_resamp_start_drift ) / 2 )
230         {
231             /* if we reduced the drift from half, then it is time to switch
232              * back the resampling direction. */
233             if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
234                 p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
235             else
236                 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
237             p_input->i_resamp_start_drift = 0;
238         }
239         else if( p_input->i_resamp_start_drift &&
240                  ( abs( (int)(p_buffer->i_pts - start_date) ) >
241                    abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
242         {
243             /* If the drift is increasing and not decreasing, than something
244              * is bad. We'd better stop the resampling right now. */
245             msg_Warn( p_aout, "timing screwed, stopping resampling" );
246             inputResamplingStop( p_aout, p_input );
247             p_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
248         }
249     }
250
251     /* Actually run the resampler now. */
252     if ( owner->resampler != NULL )
253         aout_FiltersPlay( &owner->resampler, 1, &p_buffer );
254
255     if( !p_buffer )
256         return NULL;
257     if( p_buffer->i_nb_samples <= 0 )
258     {
259         block_Release( p_buffer );
260         return NULL;
261     }
262
263     p_buffer->i_pts = start_date;
264     return p_buffer;
265 }
266
267 /*****************************************************************************
268  * static functions
269  *****************************************************************************/
270
271 static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
272 {
273     block_Release( p_buffer );
274
275     p_input->i_buffer_lost++;
276 }
277
278 static void inputResamplingStop( audio_output_t *p_aout, aout_input_t *p_input )
279 {
280     aout_owner_t *owner = aout_owner(p_aout);
281
282     p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
283     if( owner->resampler != NULL )
284     {
285         owner->resampler->fmt_in.audio.i_rate =
286             ( owner->resampler == owner->rate_filter )
287             ? INPUT_RATE_DEFAULT * p_input->samplerate / p_input->i_last_input_rate
288             : p_input->samplerate;
289     }
290 }