1 /*****************************************************************************
2 * input.c : internal management of input streams for the audio output
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_input.h>
35 #include <vlc_filter.h>
38 #include "aout_internal.h"
40 static void inputDrop( aout_input_t *, block_t * );
41 static void inputResamplingStop( audio_output_t *, aout_input_t * );
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)
51 aout_input_t *p_input = malloc (sizeof (*p_input));
52 if (unlikely(p_input == NULL))
55 p_input->samplerate = infmt->i_rate;
57 if (aout_FiltersNew (p_aout, infmt, outfmt, p_request_vout))
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;
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 )
76 aout_FiltersDestroy (p_aout);
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 )
90 aout_owner_t *owner = aout_owner(p_aout);
92 aout_assert_locked( p_aout );
94 if( i_input_rate != INPUT_RATE_DEFAULT && owner->rate_filter == NULL )
96 inputDrop( p_input, p_buffer );
100 /* Handle input rate change, but keep drift correction */
101 if( i_input_rate != p_input->i_last_input_rate )
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);
108 p_input->i_last_input_rate = i_input_rate;
111 mtime_t now = mdate();
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);
118 if ( start_date != VLC_TS_INVALID && start_date < now )
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
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;
133 if ( p_buffer->i_pts < now + AOUT_MIN_PREPARE_TIME )
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 );
144 /* If the audio drift is too big then it's not worth trying to resample
146 if( start_date == VLC_TS_INVALID )
148 start_date = p_buffer->i_pts;
149 date_Set (date, start_date);
152 mtime_t drift = start_date - p_buffer->i_pts;
154 if( drift < -i_input_rate * 3 * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT )
156 msg_Warn( p_aout, "buffer way too early (%"PRId64"), clearing queue",
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);
168 if( drift > +i_input_rate * 3 * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT )
170 msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
172 inputDrop( p_input, p_buffer );
176 /* Run pre-filters. */
177 aout_FiltersPlay( owner->filters, owner->nb_filters, &p_buffer );
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 )
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
192 * Solution : resample the buffer to avoid a scratch.
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 );
203 if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
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. */
209 if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
210 owner->resampler->fmt_in.audio.i_rate += 2; /* Hz */
212 owner->resampler->fmt_in.audio.i_rate -= 2; /* Hz */
214 /* Check if everything is back to normal, in which case we can stop the
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 )
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);
228 else if( abs( (int)(p_buffer->i_pts - start_date) ) <
229 abs( p_input->i_resamp_start_drift ) / 2 )
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;
236 p_input->i_resampling_type = AOUT_RESAMPLING_UP;
237 p_input->i_resamp_start_drift = 0;
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 ) )
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;
251 /* Actually run the resampler now. */
252 if ( owner->resampler != NULL )
253 aout_FiltersPlay( &owner->resampler, 1, &p_buffer );
257 if( p_buffer->i_nb_samples <= 0 )
259 block_Release( p_buffer );
263 p_buffer->i_pts = start_date;
267 /*****************************************************************************
269 *****************************************************************************/
271 static void inputDrop( aout_input_t *p_input, block_t *p_buffer )
273 block_Release( p_buffer );
275 p_input->i_buffer_lost++;
278 static void inputResamplingStop( audio_output_t *p_aout, aout_input_t *p_input )
280 aout_owner_t *owner = aout_owner(p_aout);
282 p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
283 if( owner->resampler != NULL )
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;